Testing architecture — story-driven, local-first, deployed-target bounded
CareerVector's testing strategy is a stack, not a single tool. Each lane
exists because a kind of mistake would otherwise reach production. The
common rule across every lane: stay inside the Cloudflare Workers quota
policy. See cf-workers-quota-policy.md.
Story catalog traceability
wiki/content/stories/USER-STORIES.md is the canonical story catalog. Every
story has an ID P<persona>-G<goal>-S<n> and a severity. The story-spec
helper in ui/e2e/helpers/stories/story.ts accepts that ID, so each spec
file in ui/e2e/stories/ claims one or more stories it covers. The graph
projection links spec → story → behaviour → idea, so a missing spec for a
critical story shows up as a coverage hole rather than as silence.
Local e2e against wrangler dev
ui/playwright.config.ts runs Playwright against the local wrangler dev
server by default. The CF quota cost is zero — every request is served by
the local Miniflare runtime — so the suite can be as exhaustive as needed
without bargaining with the account-wide budget.
ui/scripts/link-shared-state.mjs is the small helper that points
sibling Miniflare instances at the same D1 state file, so a spec that
spans two browsers (one editor, one viewer) sees the same workspace
without going through a deployed relay.
A11y as assertion
ui/e2e/helpers/stories/a11y.ts lets a story spec assert a11y as a
test outcome instead of an after-the-fact audit. A regression that breaks
the dashboard's screen-reader path fails the spec for the story it broke,
not "a separate a11y job that nobody reads".
Adversarial probes
ui/e2e/helpers/adversarial/probes.ts is the catalogue of hostile inputs
and destructive sequences referenced from the "Adversarial" severity tier
in the story catalog. Probes include: malformed JSON from a provider,
provider rate-limit storms, surprise WS disconnects mid-write, oversized
pastes, concurrent writes from two actors on the same field, and so on.
Adversarial probes live in helpers so they can be composed into any spec that needs them — they are not a separate run lane.
Known-bugs suite
ui/playwright.known-bugs.config.ts is a quarantine config for tests that
currently fail because of a real product bug that is documented but not
yet fixed. The suite runs but does not gate merges — it gates the inverse:
when a known-bugs spec starts passing, the developer who fixed the bug
moves the spec back into the main suite. This stops the well-known anti-
pattern of "skipped, then forgotten."
Live journey opt-in
ui/e2e/helpers/live-capture.ts enables a small, named set of specs to
run against deployed targets for trust signal — never on push, only via
explicit dispatch or a tightly bounded schedule. The opt-in is the only
sanctioned path from local e2e to deployed-target traffic and exists
because some bugs (provider quirks, CF edge oddities) cannot be reproduced
under Miniflare.
The opt-in is the explicit exception to "never run e2e against deployed
workers"; the policy in cf-workers-quota-policy.md still caps the volume.
Durability contracts
ui/e2e/helpers/persistence/*.ts provides lifecycle helpers and the
D1 corruption probe so persistence tests can assert what is durable
rather than just "did the request return 200". The contract: every
canonical write lands in D1 before any broadcast; a reload after a write
must see the write; a recovered D1 must reject torn data. These are
specs that protect the assumption every other spec implicitly leans on.
Shared wrangler / Miniflare state
dev-shared-wrangler-state and shared-miniflare-state are two names
for the same setup: the dev helpers under ui/scripts/ plus
ui/svelte.config.js and ui/vite.config.ts align the dev server, the
relay, and Playwright on one Miniflare backing store. Without that, a
spec that starts the editor and then opens a viewer in a second context
would see two unrelated D1 databases and never converge.