E2E: per-worker DB isolation to re-enable parallel Playwright runs #67

Open
opened 2026-07-07 00:13:38 +02:00 by myrmidex · 0 comments
Owner

Context

The Playwright e2e suite runs against a single shared dev stack (one php + one database container, via the Vite /api proxy). When a second spec was added (#54's add-bucket e2e), enabling real parallelism (fullyParallel: true, 2 workers), the suite went flaky: concurrent register/login flows race on shared backend state — observed as an intermittent failure at the post-register toHaveURL(/\/login$/) assertion in auth.spec.ts (passed on rerun; serial --workers=1 was stable 3/3).

Interim fix (already applied): e2e/playwright.config.ts now sets fullyParallel: false + workers: 1. Serial is cheap today (~3s/spec), so this is fine short-term — but it won't scale as the suite grows.

Goal

Re-enable parallel e2e by giving each Playwright worker an isolated database, so concurrent specs can't race on shared state. Then flip fullyParallel/workers back on in the config.

The real problem (not just data collisions)

Note the observed race was in the auth flow (register→login), not scenario/bucket data — the emails are already unique per run and it still flaked. So "unique test data" alone is insufficient; the fix needs genuine backend-state isolation between workers.

Options to evaluate during scoping

  • DB-per-worker compose topology: spin up N postgres databases (or N schemas), map each Playwright worker (process.env.TEST_WORKER_INDEX) to its own, point the php service at the right one per request. Most robust; most infra work (compose + app DB-selection seam, which doesn't exist today).
  • Transactional rollback / reset seam: a test-only endpoint or hook that resets/rolls back DB state between tests. Simpler topology, but needs the app to expose a reset seam (test-env only) and careful ordering under parallelism.
  • Keep serial: accept workers: 1 permanently if the suite stays small. Revisit only if e2e run time becomes a real bottleneck.

Depends on / relates to

  • Surfaced by #54 (add-bucket e2e — the second spec that turned on parallelism).
  • Relates to the "no seed/fixtures" constraint: the stack has no data-provisioning seam today, which is why seeding goes through the API in-test.

Out of scope

  • The add-bucket / auth specs themselves (they work; this is purely about parallel isolation).

Testing

  • After isolation lands: flip fullyParallel: true + remove the workers: 1 cap, run the full e2e suite repeatedly (e.g. 5×) to confirm no flakes.
## Context The Playwright e2e suite runs against a single shared dev stack (one `php` + one `database` container, via the Vite `/api` proxy). When a second spec was added (#54's add-bucket e2e), enabling real parallelism (`fullyParallel: true`, 2 workers), the suite went flaky: concurrent register/login flows race on shared backend state — observed as an intermittent failure at the post-register `toHaveURL(/\/login$/)` assertion in `auth.spec.ts` (passed on rerun; serial `--workers=1` was stable 3/3). **Interim fix (already applied):** `e2e/playwright.config.ts` now sets `fullyParallel: false` + `workers: 1`. Serial is cheap today (~3s/spec), so this is fine short-term — but it won't scale as the suite grows. ## Goal Re-enable parallel e2e by giving each Playwright worker an isolated database, so concurrent specs can't race on shared state. Then flip `fullyParallel`/`workers` back on in the config. ## The real problem (not just data collisions) Note the observed race was in the **auth flow** (register→login), not scenario/bucket data — the emails are already unique per run and it still flaked. So "unique test data" alone is insufficient; the fix needs genuine backend-state isolation between workers. ## Options to evaluate during scoping - **DB-per-worker compose topology**: spin up N postgres databases (or N schemas), map each Playwright worker (`process.env.TEST_WORKER_INDEX`) to its own, point the `php` service at the right one per request. Most robust; most infra work (compose + app DB-selection seam, which doesn't exist today). - **Transactional rollback / reset seam**: a test-only endpoint or hook that resets/rolls back DB state between tests. Simpler topology, but needs the app to expose a reset seam (test-env only) and careful ordering under parallelism. - **Keep serial**: accept `workers: 1` permanently if the suite stays small. Revisit only if e2e run time becomes a real bottleneck. ## Depends on / relates to - Surfaced by #54 (add-bucket e2e — the second spec that turned on parallelism). - Relates to the "no seed/fixtures" constraint: the stack has no data-provisioning seam today, which is why seeding goes through the API in-test. ## Out of scope - The add-bucket / auth specs themselves (they work; this is purely about parallel isolation). ## Testing - After isolation lands: flip `fullyParallel: true` + remove the `workers: 1` cap, run the full e2e suite repeatedly (e.g. 5×) to confirm no flakes.
myrmidex added the
enhancement
label 2026-07-07 00:13:38 +02:00
myrmidex self-assigned this 2026-07-07 00:13:39 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lvl0/buckets#67
No description provided.