Skip to main content

Testing overview

There are two suites, and every run of either is offline. Neither needs a Gemini key, Neon, the AI Gateway or a Cloudflare login, and neither touches the dev server on :8787 or its data.

ToolRuns againstCommandTime
Unit and integrationVitest 5Node (shared, API) and jsdom (front end)npm testseconds
End to endPlaywrightChromium against the real Worker under wrangler dev, serving the built SPAnpm run test:e2eabout 30 seconds plus the build

The one idea that makes it work: the scripted model​

api/src/ai/scripted.ts is a second AiProvider adapter. It plays the model's part deterministically: it calls get_claim_section for the section the question is about (and highlight_panel when offered), then streams "Scripted answer about {claim id} — {title}. I looked up: {tools}.". A question containing [scripted:fail] throws.

So the whole real pipeline runs (prompt assembly, the tool loop, the tools reading a real claim, screen actions, SSE, turn ids, prompt fingerprints, feedback) and only the language model is replaced. The answer names the claim from the prompt's brief, so a test can tell the right claim reached the model.

Gemini itself, the Live voice relay, the browser voice client and the generator talk to Google over the network or a live socket. They are excluded from coverage and checked by hand against the real service. A unit test with a mocked SDK would only prove the mock agrees with itself.

Commands​

npm test # every Vitest project, once
npm run test:watch # Vitest in watch mode
npm run test:coverage # with v8 coverage and the per-layer gates; HTML in coverage/
npm run test:e2e # build, start the e2e Worker, run every Playwright spec
npm run test:e2e:ui # the same in Playwright's UI mode
npm run test:all # typecheck + Vitest + Playwright: what CI runs

First Playwright run on a machine: npx playwright install chromium.

Coverage gates​

npm run test:coverage fails if a layer drops below its gate:

LayerStatementsBranchesFunctionsLines
packages/shared/src95959595
api/src95809595
frontend/src/{lib,region,chat,embed,brand}80707580
promptStore.ts, claimView.ts90809090

The gates sit just under what the suite reaches. Page and layout components have no gate: they are presentation over claimView.ts, which is unit-tested, and Playwright exercises them in a real browser. The blended "All files" figure is low for the same reason, so read the per-layer numbers.

Excluded from coverage: the prompt catalogue and scenario briefs (prose and data), the network-bound modules above, main.tsx, and the unlisted /status page.