import process from 'node:process'; import { defineConfig, devices } from '@playwright/test'; // UI-E2E config (ersatztv#445). These specs drive a REAL headless Chromium against a REAL running // instance — the handful of contracts that `scripts/e2e-functional.sh`'s curl harness cannot express // (see docs/e2e-local.md → "UI-E2E harness"). // // Deliberate choices: // - NO `webServer`. The instance is booted by `scripts/e2e-ui.sh` (via `scripts/e2e-local.sh`), which // owns the wwwroot copy + readiness probe + a FRESH config dir. Letting Playwright boot the app // would duplicate that logic and lose the fresh-config guarantee the setup-claim flow depends on. // - `retries: 0` everywhere, including CI. #445 asks for *deterministic* flows; a retry would let a // genuinely flaky flow merge looking green. A failure here should be read as a real defect. // - Chromium only. This is a boot-gate/session smoke, not a cross-browser matrix; the browser is // baked into the CI toolchain image (docker/ci/Dockerfile) and one browser keeps that image lean. // - `workers: 1`. Every spec shares ONE server instance whose auth state is global and partly // one-shot (the setup-claim). Parallel workers would race on that shared state. export default defineConfig({ testDir: './e2e', // The SPA is served under /app/ on the same port as the API (no dev server / proxy in this flow). // ETV_BASE_URL is set by scripts/e2e-ui.sh from the port e2e-local.sh actually bound. use: { baseURL: process.env.ETV_BASE_URL ?? 'http://localhost:8409', trace: 'retain-on-failure', screenshot: 'only-on-failure' }, projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], fullyParallel: false, workers: 1, retries: 0, // Fail fast in CI rather than burning the job on a hung flow; each of these flows is seconds. timeout: 30_000, expect: { timeout: 10_000 }, forbidOnly: !!process.env.CI, // `list` only, in CI too. No workflow in this repo uploads artifacts, so an `html` report would be // written and then discarded with the runner; the list reporter's inline failure output (assertion + // call log + the accessibility snapshot Playwright prints) is what actually lands in the CI log. // `trace`/`screenshot` above still write into outputDir, which is what a local re-run wants. reporter: [['list']], outputDir: './e2e/.output' });