Testing
Playwright end-to-end tests in two tiers with different jobs, plus the static gates.
The two tiers
| Tier | Where | Question answered | Data |
|---|---|---|---|
| Journey tests | example/e2e/*.spec.ts | does the app do the right thing? | seeded accounts and projects |
| Block tests | example/e2e/sandbox/*.spec.ts | does the building block work? | a fresh user per test (site-admin blocks use the seeded admin) |
Block tests drive the sandbox pages — one seam each, seconds per test. When something breaks, the failing tier tells you whether to look at the block or at the app around it.
Running
cd example
bun run e2e # everything
bunx playwright test sandbox # block tests only
bunx playwright test site-admin # one journey file
E2E_BASE_URL=http://localhost:3000 bunx playwright test … # against an already-running serverWithout E2E_BASE_URL, Playwright starts its own dev server — and reuses any
server already listening on :3000.
The static gates
From the repo root — these are the definition of "green" for any change:
bun run typecheck # every package + the app
bun run lint # oxlint
bun run fmt # oxfmtPitfalls (all learned the hard way)
- Shared dev database drifts. Journey tests mutate seeded data (status changes accumulate across runs). A journey spec that turns red after many runs can mean "re-seed", not "bug". Block tests are immune — they create their own data.
- Port reuse can bite. If a dev server already owns
:3000, Playwright tests run against that process — with its environment, not yours. Check who owns the port before debugging "impossible" failures. - Selectors are contracts. Sandbox pages and admin sections expose stable
data-testids and accessible labels (Markera <email>); specs rely on them, so treat renames as breaking changes.