Playwright Cheatsheet
Configuration
Use this Playwright reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
playwright.config.ts skeleton
import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ // --- Test discovery --- testDir: './tests', testMatch: '**/*.spec.ts', // default testIgnore: '**/fixtures/**', // --- Parallelism --- fullyParallel: true, // all tests in parallel (default: false) workers: process.env.CI ? 2 : undefined, // undefined = auto (# CPUs) // --- Retries --- retries: process.env.CI ? 2 : 0, // --- Timeouts --- timeout: 30_000, // per test expect: { timeout: 5_000 }, // per assertion // --- Global hooks --- globalSetup: './global-setup.ts', globalTeardown: './global-teardown.ts', // --- Reporting --- reporter: [ ['list'], ['html', { open: 'on-failure' }], ], // --- Default options for all tests --- use: { baseURL: 'http://localhost:3000', trace: 'retain-on-failure', screenshot: 'only-on-failure', video: 'retain-on-failure', headless: true, viewport: { width: 1280, height: 720 }, locale: 'en-US', timezoneId: 'America/New_York', actionTimeout: 10_000, navigationTimeout: 30_000, }, // --- Projects (cross-browser / device matrix) --- projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'webkit', use: { ...devices['Desktop Safari'] } }, { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } }, { name: 'mobile-safari', use: { ...devices['iPhone 13'] } }, ], // --- Dev server --- webServer: { command: 'npm run dev', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, timeout: 120_000, }, });
Top-level options
| Option | Default | Description |
|---|---|---|
testDir | 'tests' | Test root directory |
testMatch | '**/*.{spec,test}.{ts,js}' | Glob/regex for test files |
testIgnore | — | Exclude patterns |
fullyParallel | false | Parallelize within files too |
workers | CPU count | Worker process count |
retries | 0 | Retry count on failure |
timeout | 30000 | Per-test timeout ms |
globalTimeout | — | Total run timeout ms |
maxFailures | 0 | Stop after N failures (0 = never) |
forbidOnly | false | Fail if test.only exists (CI safety) |
preserveOutput | 'always' | 'always' | 'never' | 'failures-only' |
outputDir | 'test-results' | Artifacts directory |
snapshotDir | testDir | Snapshot storage |
snapshotPathTemplate | — | Custom snapshot path pattern |
updateSnapshots | 'missing' | 'all' | 'missing' | 'none' |
reporter | 'list' | Reporter(s) |
globalSetup | — | Path to global setup module |
globalTeardown | — | Path to global teardown module |
metadata | — | Arbitrary metadata passed to reporters |
use options (BrowserContextOptions + more)
Browser & display
| Option | Default | Description |
|---|---|---|
headless | true | Headless mode |
channel | — | 'chrome', 'msedge', 'chrome-beta' etc |
viewport | {w:1280, h:720} | Viewport size (null for no viewport) |
deviceScaleFactor | 1 | DPR |
isMobile | false | Mobile emulation |
hasTouch | false | Touch emulation |
colorScheme | 'light' | 'light' | 'dark' | 'no-preference' |
reducedMotion | 'no-preference' | 'reduce' | 'no-preference' |
forcedColors | 'none' | 'active' | 'none' |
locale | system | BCP 47 locale |
timezoneId | system | IANA timezone |
geolocation | — | { latitude, longitude, accuracy? } |
permissions | [] | Permissions to grant |
Timeouts
| Option | Default | Description |
|---|---|---|
actionTimeout | 0 (test timeout) | Per-action timeout |
navigationTimeout | 0 (test timeout) | Per-navigation timeout |
Network
| Option | Default | Description |
|---|---|---|
baseURL | — | Base for relative goto() calls |
extraHTTPHeaders | {} | Headers added to every request |
httpCredentials | — | { username, password } for HTTP auth |
ignoreHTTPSErrors | false | Ignore TLS errors |
offline | false | Simulate offline |
proxy | — | { server, bypass?, username?, password? } |
storageState | — | Path or object with cookies/localStorage |
Artifacts
| Option | Default | Description |
|---|---|---|
screenshot | 'off' | 'off' | 'on' | 'only-on-failure' |
video | 'off' | 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' |
trace | 'off' | 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' |
Misc
| Option | Default | Description |
|---|---|---|
testIdAttribute | 'data-testid' | Attribute used by getByTestId |
launchOptions | {} | Options passed to browser.launch() |
contextOptions | {} | Options passed to browser.newContext() |
bypassCSP | false | Bypass Content-Security-Policy |
javaScriptEnabled | true | Enable JS |
serviceWorkers | 'allow' | 'allow' | 'block' |
userAgent | browser default | Override User-Agent |
acceptDownloads | true | Allow downloads |
downloadsPath | temp dir | Download destination |
Projects — multi-browser & device matrix
import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ projects: [ // Desktop browsers { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'webkit', use: { ...devices['Desktop Safari'] } }, // Mobile { name: 'pixel5', use: { ...devices['Pixel 5'] } }, { name: 'iphone13', use: { ...devices['iPhone 13'] } }, // Branded channels { name: 'chrome', use: { channel: 'chrome' } }, { name: 'edge', use: { channel: 'msedge' } }, // Tagged subsets { name: 'setup', testMatch: /.*\.setup\.ts/, }, { name: 'auth-tests', use: { storageState: 'auth.json' }, dependencies: ['setup'], // run setup project first }, ], });
webServer
webServer: {
command: 'npm run start',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120_000, // ms to wait for server to be ready
stdout: 'pipe', // 'pipe' | 'ignore'
stderr: 'pipe',
env: { NODE_ENV: 'test' },
},
// Multiple servers
webServer: [
{ command: 'npm run api', url: 'http://localhost:4000' },
{ command: 'npm run web', url: 'http://localhost:3000' },
],Reporters
reporter: 'list' // simple shorthand reporter: [['list'], ['html']] // multiple // Built-in reporters ['list'] // stdout (default non-CI) ['dot'] // compact dots ['line'] // one line per test ['html', { open: 'on-failure', outputFolder: 'report' }] ['json', { outputFile: 'results.json' }] ['junit', { outputFile: 'results.xml' }] ['github'] // GitHub Actions annotations ['blob', { outputDir: 'blob-report' }] // for merge-reports ['null'] // suppress all output
CLI flag overrides
Many config options can be overridden at the CLI without editing the config:
npx playwright test --headed npx playwright test --workers=4 npx playwright test --retries=1 npx playwright test --timeout=60000 npx playwright test --reporter=dot npx playwright test --project=chromium npx playwright test --grep @smoke npx playwright test --grep-invert @slow npx playwright test --update-snapshots npx playwright test --forbid-only
Global setup / teardown
// global-setup.ts import { chromium, FullConfig } from '@playwright/test'; export default async function globalSetup(config: FullConfig) { const { baseURL } = config.projects[0].use; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto(baseURL + '/login'); // ... login steps await page.context().storageState({ path: 'auth.json' }); await browser.close(); } // global-teardown.ts export default async function globalTeardown() { // clean up DBs, temp files, etc. }
For auth, prefer a setup project with
dependencies(above) overglobalSetup— setup projects run inside the test runner, so they get fixtures, tracing, and HTML-report visibility.