BillTracker/playwright.config.js

101 lines
3.7 KiB
JavaScript

// Playwright E2E / visual-regression / a11y harness for BillTracker.
// See docs/QA_PLAN.md §4.4 and the B-UI / B14 / B15 batches.
//
// Setup (one-time): npm install && npx playwright install chromium
// Run: npm run test:e2e (headless)
// npm run test:e2e:ui (watch/debug)
// npm run test:e2e:update (re-baseline screenshots)
//
// SAFETY: the two `webServer` entries boot the app against a SCRATCH DB
// (e2e/setup/prepare-db.js seeds it) on DEDICATED ports (5199 UI / 3099 API), so
// E2E never touches your real db/bills.db and never reuses a dev server running
// on 5173/3000. `reuseExistingServer` is false for the same reason.
const { defineConfig, devices } = require('@playwright/test');
const { scratchDbPath, API_PORT, UI_PORT } = require('./e2e/constants');
const baseURL = `http://localhost:${UI_PORT}`;
module.exports = defineConfig({
testDir: './e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [['list'], ['html', { open: 'never' }]],
use: {
baseURL,
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
// Visual-regression tolerance. Screenshots are OS/font-sensitive, so baselines
// are committed per-platform (Playwright suffixes them with the platform).
expect: {
toHaveScreenshot: { maxDiffPixelRatio: 0.02, animations: 'disabled' },
},
projects: [
// Logs in once and writes STORAGE_STATE; browser projects depend on it.
{ name: 'setup', testMatch: /auth\.setup\.js/ },
{
name: 'chromium-desktop',
use: { ...devices['Desktop Chrome'] },
dependencies: ['setup'],
testIgnore: [/auth\.setup\.js/, /api\.probe\.spec\.js/, /a11y\.authed\.spec\.js/],
},
{
name: 'chromium-mobile',
use: { ...devices['Pixel 5'] },
dependencies: ['setup'],
testIgnore: [/auth\.setup\.js/, /api\.probe\.spec\.js/, /a11y\.authed\.spec\.js/],
},
// Find-mode diagnostics (adversarial API probe + authenticated a11y scan).
// Own project so they don't run concurrently with / pollute the UI specs, and
// so open findings here don't turn the default suite red. Run on demand:
// `npm run test:e2e:probe`. Fold a spec into the default projects once its
// findings are fixed (it becomes a passing regression guard).
{
name: 'probe',
testMatch: /(api\.probe|a11y\.authed)\.spec\.js/,
use: { ...devices['Desktop Chrome'] },
dependencies: ['setup'],
},
// Cross-browser (WebAuthn/Select behavior differs) — enable when ready:
// { name: 'firefox', use: { ...devices['Desktop Firefox'] }, dependencies: ['setup'], testIgnore: /auth\.setup\.js/ },
// { name: 'webkit', use: { ...devices['Desktop Safari'] }, dependencies: ['setup'], testIgnore: /auth\.setup\.js/ },
],
// Two servers: the API (node) and the Vite UI that proxies /api to it. Both
// run against the scratch DB on dedicated ports. Playwright waits for each
// `url` to respond before starting tests.
webServer: [
{
command: 'node server.js',
url: `http://localhost:${API_PORT}/api/version`,
reuseExistingServer: false,
timeout: 120_000,
stdout: 'ignore',
stderr: 'pipe',
env: {
DB_PATH: scratchDbPath(),
PORT: String(API_PORT),
BIND_HOST: '127.0.0.1',
},
},
{
command: `npm run dev:ui -- --port ${UI_PORT} --strictPort`,
url: baseURL,
reuseExistingServer: false,
timeout: 120_000,
stdout: 'ignore',
stderr: 'pipe',
env: {
API_PORT: String(API_PORT),
},
},
],
});