FRAMEWORKSADVANCED

Building an Enterprise Playwright Framework from Scratch

Fixtures, config, tagging, data-driven tests, custom reporters — the architecture behind a production-ready Playwright framework.

iff Solution Academy July 3, 2026 18 min read Updated July 7, 2026
Playwright Framework Enterprise Fixtures Advanced

Recommended Repo Layout

text
playwright-framework/
├── tests/
│   ├── ui/
│   ├── api/
│   └── e2e/
├── pages/
├── fixtures/
├── data/
├── utils/
├── playwright.config.ts
└── .github/workflows/e2e.yml

playwright.config.ts

playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  reporter: [['list'], ['html', { open: 'never' }], ['junit', { outputFile: 'reports/junit.xml' }]],
  use: {
    baseURL: process.env.BASE_URL ?? 'https://staging.example.com',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
  ],
});

Custom Fixtures

Fixtures are the beating heart of a Playwright framework — inject auth, API clients, and page objects with zero boilerplate in tests.

fixtures/index.ts
import { test as base, APIRequestContext } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';

type Fixtures = { login: LoginPage; api: APIRequestContext };

export const test = base.extend<Fixtures>({
  login: async ({ page }, use) => use(new LoginPage(page)),
  api: async ({ playwright }, use) => {
    const api = await playwright.request.newContext({ baseURL: process.env.API_URL });
    await use(api);
    await api.dispose();
  },
});
export { expect } from '@playwright/test';

Data-Driven Tests

ts
const users = [{ role: 'admin' }, { role: 'editor' }, { role: 'viewer' }];
for (const u of users) {
  test(`${u.role} sees the right menu`, async ({ login, page }) => {
    await login.loginAs(u.role, 'secret');
    await expect(page.getByRole('navigation')).toContainText(u.role);
  });
}

Test Tagging & Selection

ts
test('checkout @smoke @critical', async () => { /* ... */ });
// Run: npx playwright test --grep @smoke

Reporting & Traceability

  • HTML reporter for humans (npx playwright show-report).
  • JUnit for CI dashboards.
  • Trace Viewer for debugging failures — trace: 'on-first-retry'.
  • Publish reports as build artifacts in CI.

Get Playwright tutorials in your inbox

Weekly tips, real-world examples, and framework patterns – no spam, unsubscribe anytime.

Recommended Next Articles