Testing
The test suite uses Vitest with Testing Library in a JSDOM environment. All tests live in src/test/ and mirror the src/ directory structure. There are no end-to-end tests in regular use.
Running tests
The npm test:browser script exists (from the template) but runs Playwright browser tests that are dormant — do not rely on it.
Test directory layout
In src/components/, individual component files also have co-located tests (*.test.tsx) for config-drawer, confirm-dialog, password-input, and sign-out-dialog.
Test configuration
vitest.config.ts — the primary test runner config:
src/test/setup.ts imports @testing-library/jest-dom/vitest (adds toBeInTheDocument etc.) and polyfills ResizeObserver for JSDOM, which Radix UI components require.
The separate vite.config.ts also contains Vitest browser configuration (Playwright/Chromium), but browser-mode tests are not part of npm test.
Mocking approach
No MSW, no network calls. All HTTP is mocked at the fetch global level.
fetch mocking
Tests construct real Response objects, giving precise control over status codes and body shapes. vi.unstubAllGlobals() in afterEach restores the real fetch.
Environment variable mocking
vitest.config.ts sets unstubEnvs: true so env stubs are auto-cleaned, but explicit cleanup is also present in most files for clarity.
Router mocking
TanStack Router hooks are mocked per-test-file. Tests that need navigation assertions capture the mock and use expect(mockNavigate).toHaveBeenCalledWith(...).
Test utilities
src/test/utils/renderWithClient.tsx
Wraps a component in a fresh QueryClient (with retry: false) + QueryClientProvider. Returns all Testing Library render results plus the queryClient instance. Use this instead of the bare render for any component that calls TanStack Query hooks.
src/test-utils/tanstack-table.ts
Minimal TanStack Table mock with getFilteredSelectedRowModel() and a resetRowSelection spy. Used for bulk-action dialog tests that need a table context without a full useReactTable setup.
src/test-utils/cookies.ts
Removes cookies from document.cookie by prefix/regex. Used in auth tests that rely on cookie-persisted state.
Test types
Coverage areas
The most tested areas:
src/lib/httpClient.ts— Three dedicated test files covering bearer headers, 401 → refresh → retry, concurrent-request deduplication,onSessionDead/onForbiddenevents, andApiErrorparsing.src/auth/— AuthContext lifecycle,can()logic,RequirePermission, OTP flow, token drift.src/features/diagnostics/— 18 test files covering all four sections (events, devices, bundles, commands), download flow, command cancellation, and section-level lazy loading.src/features/stores/— 17 test files covering list/detail/devices/entitlements/booking.
Areas with lighter coverage:
src/features/settings/— mostly scaffolded UI, not meaningfully testedsrc/features/dashboard/— static demo content, not tested- Route files in
src/routes/are excluded from coverage
What to check when changing things
Always run npm test and npm run lint before deploying. There is no CI pipeline.