Add comprehensive testing covering 420 unit/handler tests across 24 Vitest files, 9 Playwright E2E specs, accessibility scans, and visual regression. Includes GitHub Actions CI, Husky pre-push hook, and TESTING.md docs.
3.2 KiB
Testing
Quick Reference
npm test # Vitest watch mode
npm run test:run # Vitest single run (used by pre-push hook)
npm run test:e2e # Playwright E2E tests
npm run test:e2e:ui # Playwright with interactive UI
npm run test:a11y # Accessibility scans (axe-core)
npm run test:visual # Visual regression screenshots
npm run test:all # Vitest + Playwright together
Vitest (Unit / Handler Tests)
Tests live in tests/ mirroring the source structure. Two vitest projects:
- server (
tests/server/) — Node environment,setup.jsstubs Nitro auto-imports - client (
tests/client/) — jsdom environment for composables
Test patterns
Behavioral tests mock models/services with vi.mock(), import the handler, and call it with createMockEvent():
vi.mock('../../../server/models/member.js', () => ({ default: { findOne: vi.fn() } }))
import handler from '../../../server/api/some/route.js'
import { createMockEvent } from '../helpers/createMockEvent.js'
Source inspection tests use readFileSync to verify structural properties (auth guards, import order) without executing handlers.
Nitro auto-imports in tests
Handlers use Nitro auto-imports for requireAuth, requireAdmin, validateBody, and schemas. These are stubbed as globals in tests/server/setup.js. Individual tests can configure their behavior with .mockResolvedValue() etc.
Playwright (E2E Tests)
Tests live in e2e/. Requires a running dev server and MongoDB.
Auth helpers
e2e/helpers/auth.js provides loginAsAdmin(page) and loginAsMember(page, email) using the dev login endpoints. These set real JWT cookies.
e2e/helpers/fixtures.js extends Playwright's test with adminPage and memberPage fixtures.
Running locally
# Start dev server (Playwright config does this automatically)
npm run dev
# Run tests
npm run test:e2e
# Interactive mode
npm run test:e2e:ui
Visual regression
Baselines stored in e2e/__screenshots__/. Generate or update:
npm run test:visual:update
Note: Linux CI and macOS local produce different renders. Generate baselines in CI with --update-snapshots, then commit.
Pre-Push Hook
Husky runs npm run test:run (Vitest only) before git push. All mocked, runs in ~1s. Playwright is not included — too slow and requires MongoDB.
CI (GitHub Actions)
.github/workflows/test.yml defines three jobs:
- vitest — runs on every push/PR to main
- playwright — runs after vitest passes, uses MongoDB service container
- visual — runs after vitest,
continue-on-error: trueduring stabilization
CI uses dummy secrets (JWT_SECRET: ci-test-jwt-secret). No real Helcim/Resend/Slack tokens — those paths are mocked at Vitest level, and E2E skips the Helcim iframe.
Known Limitations
- Helcim iframe — cannot be tested in E2E (cross-origin). Payment flows are tested at the Vitest handler level. E2E tests stop before the iframe opens.
- Email delivery — mocked at Vitest level. E2E verifies form submission, not actual email.
- Slack invitations — mocked at Vitest level.
- Visual baseline OS drift — generate baselines in CI, not locally.