| name | e2e |
| description | Run, debug, and manage Playwright e2e tests. Use when running e2e tests, debugging test failures, regenerating seed databases, or investigating test infrastructure issues. |
E2E Test Runner
Architecture overview
- Tests live in
e2e/*.spec.ts, config in playwright.config.ts
- Global setup (
e2e/global-setup.ts) builds the app, creates per-worker databases, and starts one server per worker
- Port calculation:
E2E_BASE_PORT = PORT (from .env) + 500. Default PORT is typically 4001, so base port = 4501. Workers use ports base+0 through base+3
- Worker databases:
db-test-e2e-0.sqlite3 through db-test-e2e-3.sqlite3 in the project root
- Seed databases (pre-seeded snapshots):
e2e/seeds/db-seed-*.sqlite3
- MinIO (S3-compatible storage) is started via Docker Compose if not already running
Pre-flight checks (run before every test execution)
Before running tests, check for these common issues:
-
Stale worker databases — Files matching db-test-e2e-*.sqlite3 in the project root can cause "table already exists" migration errors if the schema has changed since they were created. Run pnpm run test:e2e:generate-seeds to regenerate these from the seed databases.
-
Port conflicts — Check if anything is already listening on the e2e ports (base port through base+3):
lsof -i :4501-4504 2>/dev/null
If ports are occupied by leftover e2e servers, kill them. If occupied by something else, warn the user.
-
Seed databases exist — Verify e2e/seeds/ contains the expected seed files. If missing, run pnpm run test:e2e:generate-seeds.
-
Docker running — MinIO requires Docker. Check with docker info if there are storage-related failures.
Running tests
Run all tests
pnpm run test:e2e
Run a specific test file
pnpm exec playwright test e2e/<name>.spec.ts
Flaky detection (repeats each test 10 times, stops on first failure)
pnpm run test:e2e:flaky-detect
Regenerate seed databases (after schema/migration changes)
pnpm run test:e2e:generate-seeds
Debugging failures
Follow this funnel when tests fail:
Step 1: Read the error output
- Look for the actual assertion or timeout that failed
- Check if it's an infrastructure error (server didn't start, migration failed) vs. a test logic error
Step 2: Check infrastructure issues
Common infrastructure errors and fixes:
- "table already exists" → Stale worker DBs. Run
rm -f db-test-e2e-*.sqlite3
- "Server on port X did not start within timeout" → Port conflict or app build error. Check ports with
lsof -i :<port> and check for build errors
- "MinIO failed to start" → Docker not running or compose issue. Check
docker info
- Seed-related errors → Run
pnpm run test:e2e:generate-seeds
Step 3: Reduce to single debug worker
If the error is unclear, re-run with debug output and a single worker to see server logs:
E2E_DEBUG=true E2E_WORKERS=1 pnpm exec playwright test e2e/<failing-test>.spec.ts
This shows stdout/stderr from the test server, which is hidden by default.
Step 4: Examine trace artifacts
Playwright is configured with trace: "retain-on-failure". After a failure, view the trace:
pnpm exec playwright show-trace test-results/<test-folder>/trace.zip
Test pattern reference
Every test follows this pattern — use these imports from ./helpers/playwright, NOT raw Playwright APIs:
import { expect, impersonate, navigate, seed, test } from "./helpers/playwright";
test.describe("Feature", () => {
test("does something", async ({ page }) => {
await seed(page);
await impersonate(page, USER_ID);
await navigate({ page, url: "..." });
await submit(page);
});
});
Key rules:
- Use
navigate() instead of page.goto() — it waits for hydration
- Use
submit() instead of clicking submit buttons directly — it waits for the POST response
- Use
seed(page, variation?) to reset the database. Available variations: DEFAULT, NO_TOURNAMENT_TEAMS, REG_OPEN, SMALL_SOS, NZAP_IN_TEAM, NO_SCRIMS, NO_SQ_GROUPS
- Use
impersonate(page, userId?) to authenticate. Default is admin (ADMIN_ID)
- Avoid
page.waitForTimeout — use assertions or waitFor patterns instead
- Import
test from ./helpers/playwright (not from @playwright/test) — it includes worker port fixtures
Environment variables
| Variable | Purpose | Default |
|---|
E2E_WORKERS | Number of parallel workers | 4 |
E2E_DEBUG | Show server stdout/stderr when "true" | unset |
PORT | Base port for dev server (e2e adds 500) | 5173 |