Calafai Docs

ADR-006: Vitest for Web App Testing

ADR-006: Vitest for Web App Testing

Status: Accepted Date: 2024-12-15 Deciders: Platform architect

Context

The Next.js 14 web application needed a test runner for unit tests, component tests, and integration tests. The application uses TypeScript, ES modules, and path aliases (@/ imports).

Requirements:

  • Native TypeScript support without separate compilation step
  • ES module support (the project uses "type": "module" patterns)
  • Fast execution for developer feedback loop
  • Compatible with @testing-library/react for component tests
  • Compatible with path aliases (@/src/)

Decision

Use Vitest as the test runner with @vitest/coverage-v8 for coverage reporting. Vitest shares Vite's transform pipeline, providing native TypeScript and ESM support without additional configuration.

Configuration lives in apps/web/vitest.config.ts with tests in src/__tests__/.

Alternatives Considered

1. Jest

The established standard for React testing. However, Jest's ESM support requires experimental flags and additional configuration (--experimental-vm-modules). TypeScript support requires ts-jest or @swc/jest transformer. Path alias support requires moduleNameMapper configuration. The overall setup is significantly more complex for a modern ESM TypeScript project.

2. Node.js built-in test runner

Available since Node.js 20. Lightweight but lacks the ecosystem: no built-in coverage, no snapshot testing, no watch mode with HMR, no TypeScript support without a separate transform step. Too minimal for a production application.

3. Bun test runner

Fast and TypeScript-native. Rejected because the project uses Node.js (not Bun) as the runtime, and Bun's test runner has compatibility gaps with some @testing-library features.

Consequences

Positive:

  • Zero-config TypeScript and ESM support — Vitest uses Vite's transform pipeline
  • Path aliases work via the resolve.alias config (shared with Vite)
  • Fast watch mode with HMR-based re-runs
  • API-compatible with Jest (describe, it, expect) — low migration cost if switching later
  • @vitest/coverage-v8 provides V8-based coverage without additional setup
  • Globals mode (globals: true) allows importing test functions implicitly

Negative:

  • Smaller ecosystem than Jest — some Jest plugins may not have Vitest equivalents
  • Vitest configuration is separate from Next.js configuration (not shared with the dev server)
  • Component tests require explicit environment: "jsdom" configuration (the default is node)

Risks:

  • Vitest major version updates may introduce breaking changes. Mitigated by pinning the version and updating intentionally.

On this page