Testing
Hard rule: code without tests is rejected at PR review. No exceptions.
Test types
| Type | Framework | Where | Target |
|---|---|---|---|
| Unit | Vitest | co-located *.test.ts | 80%+ line coverage |
| Integration | Vitest + Testcontainers | tests/integration/ | every API endpoint, every service boundary |
| E2E | Playwright | tests/e2e/ | every critical user flow |
| Contract | OpenAPI schema diff | CI | every API PR |
| Load | k6 | tests/load/ | release candidates only |
TDD workflow
For new features, follow the strict order:
- Write a failing unit test (red)
- Implement the minimum code to make it pass (green)
- Refactor with the test still green
- Add integration tests for the boundary
- Add an E2E test for the user-visible behaviour
- Run all tests; fix anything that broke
For bug fixes, the order is different:
- Write a failing test that reproduces the bug
- Investigate root cause (not symptom)
- Fix the root cause
- Verify the failing test now passes
- Add regression tests if root cause reveals broader risk
Coverage
- Target: 80%+ line coverage per repo.
- Tool:
vitest --coverage --coverage.thresholds.lines=80. - CI gate: PRs that drop coverage below 80% fail.
- Excludes: generated files, type-only files, barrel
index.ts.
Mocking
- HTTP: use MSW (Mock Service Worker), never mock
fetchdirectly. - DB: prefer Testcontainers for integration tests over hand-rolled stubs.
- Time:
vi.useFakeTimers()for time-dependent logic. - Avoid mocking the system under test — mock dependencies, not the unit you're testing.
E2E expectations
- Run on every PR against staging via headless Playwright.
- Use Page Object Model for selectors — never inline raw selectors in test files.
- Take screenshots on failure to
.artifacts/playwright/screenshots/YYYY-MM-DD_HHmm/. - Clean test data before each run, not after — fail-loud is preferable to flaky cleanup.
Performance tests
- Run
k6against staging before any release that touches the policy engine or detection pipeline. - Targets: p50 detection <50ms, p99 <250ms, 1000 RPS sustained.
- Regression budget: <5% slowdown vs. previous release. Larger regressions block release.
Anti-patterns to avoid
- Disabling tests to make CI green — fix the test or the code, never silence the signal.
- Tests that don't actually assert —
expect(true).toBe(true)patterns. - Tests that pass without running the code — verify the test fails when the code is removed.
- Tests that require manual setup — every test must run with a single command.
- Tests that depend on test ordering — each test must be independently runnable.
CI matrix
- Node 20 on Ubuntu-latest (primary)
- Node 20 on macOS-latest (extension only — webkit testing)
- Node 20 on Windows-latest (extension only — Edge testing)
Browser verification (mandatory for UI changes)
For any UI/API/server change:
- Start the dev server.
- Use Playwright to navigate to the affected route.
- Screenshot to
.artifacts/playwright/screenshots/YYYY-MM-DD_HHmm/. - Check both browser console and server console — both must be clean.
- Fix all errors.
- Repeat until clean.
This is not optional. PRs claiming "verified" without an artifact directory are rejected.