86d uses two test layers. Unit tests (Vitest) cover module logic, controllers, and endpoint handlers. End-to-end tests (Playwright) cover real user flows in a real browser, with visual snapshots for every screen in light and dark mode at desktop and mobile widths.Documentation Index
Fetch the complete documentation index at: https://86d.app/docs/llms.txt
Use this file to discover all available pages before exploring further.
Run all tests
From the repository root:Unit tests (Vitest)
Every module ships unit tests undermodules/<name>/src/__tests__/. The starter test scaffolded by 86d module create validates the factory:
What to test
For a typical module, write tests for:- Factory and configuration. The module returns the right
idand accepts options correctly. - Controllers. Every business rule (state transitions, guards, calculations) has at least one happy-path test and one failure-path test.
- Endpoint handlers. Input validation, auth checks, and the response shape.
- Cross-module contracts. When your module exports something via
exports.read, test that the right value is exposed.
Run a single module’s tests
End-to-end tests (Playwright)
Playwright tests live intests/e2e/. The config defines several projects:
| Project | Viewport | Purpose |
|---|---|---|
visual-desktop | 1280 x 720 | Desktop visual snapshots |
visual-tablet | 768 x 1024 | Tablet visual snapshots |
visual-mobile | 375 x 667 | Mobile visual snapshots |
store-chromium | desktop | Smoke tests for the storefront |
Visual snapshots
Visual tests live intests/e2e/visual.spec.ts. They capture screenshots of every public route and admin screen, in both light and dark mode, across desktop, tablet, and mobile viewports.
To update baselines after intentional UI changes:
Test selectors
Always usedata-testid selectors. CSS class selectors are fragile and break under refactors. Use await page.waitForLoadState('networkidle') instead of waitForTimeout(); the latter is non-deterministic.
CI gates
GitHub Actions runs every gate on every pull request. The minimum bar to merge is:bun run typecheckpassesbun run checkpasses (Biome lint + format)bun run testpasses (Vitest)bun run test:e2epasses (Playwright + visual snapshots)bun run buildsucceeds
Writing testable modules
A few patterns make modules easier to test:- Inject
ModuleDataServiceat construction time. The runtime hands it to yourinitfunction viactx.data. Pass it explicitly to your controllers; never reach for a global. - Keep controllers pure where you can. Anything that does not need I/O should live in a small helper that takes inputs and returns outputs.
- Mock at the boundary, not in the middle. For external HTTP, swap
fetchitself rather than your wrapper. - Use
@86d-app/core/test-utilswhen you need an in-memory mock data service.
Coverage
Runbun run test:coverage for a coverage report. There is no hard threshold, but the convention for first-party modules is “every endpoint handler and every controller method has at least one happy-path test plus failure-path coverage for each documented error”.
