SoftwareTestPilot
Module 10 · Lab 1 · Capstone
Advanced
16 min read

Build a Production Playwright Framework — Architecture & Best Practices

Architect a production-grade Playwright framework — config management, logging, reporting, retries, and the 12-factor test approach.

1. Folder layout

Each folder has one job. Tests describe behaviour; everything else is plumbing — and tests never touch selectors directly. They go through POMs.

my-framework/
├── tests/                # *.spec.ts — describes behaviour only
├── pages/                # Page object classes (selectors live here)
├── fixtures/             # test.extend() — authed page, seeded data
├── utils/                # logger, date helpers, API helpers
├── config/               # env-specific URLs, users, feature flags
└── playwright.config.ts  # the one entry point

2. Centralized config

One playwright.config.ts, three environments. Everything that changes between dev / staging / prod comes from env vars — never hard-coded.

import { defineConfig } from '@playwright/test';
import 'dotenv/config';

export default defineConfig({
  timeout: Number(process.env.TIMEOUT ?? 30_000),
  retries: process.env.CI ? 2 : 0,
  use: {
    baseURL: process.env.BASE_URL!,
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
});

3. Logging — winston + per-test log files

Every action logs to logs/<test-name>.log. When CI fails at 3am, you read the log instead of re-running the test.

// utils/logger.ts
import { createLogger, format, transports } from 'winston';

export const makeLogger = (testName: string) =>
  createLogger({
    level: 'info',
    format: format.combine(format.timestamp(), format.simple()),
    transports: [
      new transports.File({ filename: `logs/${testName}.log` }),
    ],
  });

4. Reporting

  • Allure — trends across runs, ownership tags, history.
  • Playwright HTML — one-off debug with trace viewer baked in.
  • Slack — team-visible alert on red builds, with a link to the run.
reporter: [
  ['list'],
  ['html', { outputFolder: 'playwright-report', open: 'never' }],
  ['allure-playwright'],
],

5. Retries & flake quarantine

Retry twice in CI, zero times locally — local retries hide real bugs. Persistently-flaky tests move to a flaky/ folder, NOT .skip — visibility is the cure.

retries: process.env.CI ? 2 : 0,

// flaky/ has its own project so reds don't block CI
projects: [
  { name: 'main',  testDir: './tests' },
  { name: 'flaky', testDir: './flaky', retries: 3 },
],

6. The 12-factor test

  • Hermetic — no shared state between tests. Each test seeds and cleans up its own data.
  • Deterministic — same input, same result, every run.
  • Fast — under 60 seconds per test. Past that, split it.
  • Isolated — runs in any order, in parallel, on any worker.
  • Owned — every test has a name in CODEOWNERS.

7. Hands-on capstone

Ship your framework. Push it to a public GitHub repo with: README, the workflow from Module 08, at least one POM, one API test, one visual test, and a green CI badge in the README.

Recruiters will read this repo before they read your CV.

8. You are Automation-Ready

Capstone complete

You are Automation-Ready 🎉

You've shipped a production Playwright framework end-to-end — locators, assertions, POM, API, CI/CD, visual diffs, and architecture. Time to tell the world.