Architecture

Testing

Two suites with a hard line between them, and a 100% gate that means something.

Two suites, one boundary

SuiteFilesScope
Vitest**/*.test.tspure logic only — no DOM, no Supabase
Playwrighte2e/*.spec.tsfull flows against a seeded local Supabase

The boundary is the point. Unit tests that mock a database client mostly assert that the mock was called, which is why the coverage gate below is credible.

The 100% gate

Vitest enforces 100% lines, branches, functions and statements — but only over the pure-logic layer (app/utils, server/utils, layers/**/server/utils). Platform-bound files are excluded, not mocked to hit a number:

exclude: [
  'app/utils/download.ts',               // browser DOM
  'server/utils/requireAdmin.ts',        // H3 + Supabase
  'layers/email/server/utils/emails.ts', // renders .vue templates
]

A gate that counts fake-mocked platform code reports 100% while testing nothing. This one covers a smaller surface honestly.

Playwright projects

A spec only runs once it's added to a project's testMatch:

  • chromium — public smoke, no session
  • a11y — axe against every page, in light and dark
  • app — authenticated feature flows on the seeded admin session
  • isolation — logs in as a second tenant; runs with no saved session
  • screenshots — opt-in, see below

Screenshots

pnpm screenshots

Captures every route in both themes at 1920×1080, plus a Pixel 7 mobile pass, into docs/screenshots/. It's gated behind a SCREENSHOTS env var so a bare pnpm test:e2e never regenerates PNGs and dirties your working tree.

Not a visual-regression baseline — there's no pixel diffing. It exists so README images and design review keep up with the app instead of aging into fiction.