Skip to content

Config Walkthrough

When to Use

Use this as a reference when configuring playwright.config.ts for a VR project.

Pattern

Annotated config

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

export default defineConfig({
  testDir: 'e2e',                                        // where tests live
  fullyParallel: true,                                   // all tests parallel by default
  forbidOnly: !!process.env.CI,                          // CI fails if `test.only` slipped in
  retries: process.env.CI ? 2 : 0,                       // 2 retries in CI; 0 locally
  workers: process.env.CI ? 1 : 2,                       // cap: one web container can't serve 50%-of-cores
  reporter: 'html',                                      // required for VR diff viewer
  outputDir: 'test-results',                             // diff PNGs land here on failure

  use: {
    baseURL: 'https://mysite.ddev.site',
    ignoreHTTPSErrors: true,                             // for DDEV self-signed
    trace: 'on-first-retry',                             // record trace on retry
    colorScheme: 'light',                                // pin to avoid OS dark mode
    locale: 'en-US',
    timezoneId: 'UTC',
  },

  expect: {
    timeout: 5000,                                       // expect() web-first wait
    toHaveScreenshot: {
      threshold: 0.15,                                   // per-pixel YIQ tolerance
      stylePath: './screenshot.css',
      animations: 'disabled',
      caret: 'hide',
      // no maxDiffPixels / maxDiffPixelRatio — unset already means a zero budget
    },
  },

  snapshotPathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',

  projects: [
    { name: 'chromium-1440',
      use: { ...devices['Desktop Chrome'], viewport: { width: 1440, height: 900 } } },
    { name: 'chromium-768',
      use: { ...devices['Desktop Chrome'], viewport: { width: 768, height: 1024 } } },
    { name: 'chromium-375',
      use: { ...devices['Desktop Chrome'], viewport: { width: 375, height: 667 } } },
  ],
});

Key Reference (VR-relevant)

Key Purpose
testDir Where tests live; relative to config file
fullyParallel Parallelize all tests across files
forbidOnly Fail CI if test.only is committed
retries Per-test retry count
workers Parallel worker count; defaults to "50%" of logical CPU cores
outputDir Where actual/diff PNGs land (default test-results/)
reporter 'html' is required for the visual diff viewer
use.baseURL Default URL for page.goto('/')
use.ignoreHTTPSErrors Trust self-signed TLS (DDEV)
use.colorScheme / locale / timezoneId Pin for reproducibility
expect.timeout expect() web-first wait time
expect.toHaveScreenshot Defaults for every screenshot assertion
snapshotPathTemplate Where baselines are stored
updateSnapshots Default 'missing'; usually overridden via CLI
ignoreSnapshots Skip snapshot assertions entirely (e.g. dev-only)
projects[] Browser × viewport matrix
webServer Auto-start a dev server before tests; rarely used for Drupal

Common Mistakes

  • Wrong: reporter: 'list' without 'html'Right: no visual diff viewer; triage becomes painful
  • Wrong: workers unset in CI → Right: random parallelism; tests touching shared Drupal state collide
  • Wrong: workers left at the default locally → Right: the default is 50% of your logical cores, and a single-container Drupal backend cannot serve that many; captures start failing in batches that read as flake
  • Wrong: Missing ignoreHTTPSErrorsRight: DDEV TLS errors fail every navigation

See Also