prd/tests/ that drives the real app in a real browser and records everything. The test is written as a story: it seeds a starting state, acts as a specific user, performs the flow one step at a time, and asserts the specific outcomes the requirement claims.
prd.step(label, fn)— one user action, ending on its visible result. Each step becomes a beat in the recording: the timeline highlights it, and playback holds on the result before moving on.prd.verify(label, fn)— one assertion, labeled with the acceptance criterion in plain language. It shows as ✓/✗ in the timeline, andprd.highlightspotlights the element being confirmed.
Seeding the starting state
Most behavior only shows up against specific data, and clicking through the app to build that data would bury the flow under test, so the test seeds it directly:prd/fixtures/ so e2e and API specs seed from the same definitions. Every run resets the database first; seeds never leak between tests.
Seeding is also what makes assertions honest. A test of “users see only their own tasks” against a database with nothing to exclude passes vacuously. The rule is to seed both sides of every boundary: the data the user should see and adjacent data they shouldn’t, with a recognizable marker, then assert both directions.
Acting as different users
prd.actAs creates a signed-in user for the test. Many requirements are about who sees what, so most tests use it:
actAs more than once to compare permission levels in the same story: the member who can’t see the admin panel, then the admin who can. Each step shows the current user and their permissions, so the reviewer always knows which user is on screen.
This composes with everything else on this page. A single hero can seed two users with different roles and different data, run a workflow that processes both, and prove each user sees exactly their own result. See Services and workflows for the workflow end of that story.
Assertions must be able to fail
The harness enforces structure, but an entry is only as good as its assertions. The test for every entry: if this feature were broken, would this test fail?- A test seeds the preconditions that make the behavior happen, then asserts the specific items, values, and states the user should see. “1 of 6 scores submitted”, not “the page loads”.
- Assertions must be unconditional. A check wrapped in “if the element exists” passes when the element is missing.
- “No error page” proves nothing. A page rendering the wrong data renders without errors.
- After seeding, the test asserts the seeded values actually surfaced. This catches a query that silently filters everything out.
- The
verifylabel is the requirement, and the assertion inside must check exactly that.

