Skip to content

0009. Testing tools: Jest, Vitest with Testing Library, Playwright

  • Status: Accepted
  • Date: 2026-10-01

Context

Every implemented Must requirement needs a test that names its requirement ID, and module boundaries must stay safe to refactor. We need one tool per test level so tests look the same across modules, run in pnpm test and CI through Nx, and fit the build tools already chosen: NestJS on the backend and Vite for the React apps.

Options considered

  1. One runner everywhere (Jest or Vitest for both backend and frontend): one API to learn, but Jest needs extra transforms for Vite projects, and Vitest is a weaker fit for NestJS decorators and the Nx Nest generators.
  2. Jest for the backend, Vitest for the frontend, Playwright for end-to-end: each matches its build tool and Nx generator defaults; the two unit runners share almost the same describe/it/expect API.
  3. Cypress instead of Playwright for end-to-end: mature, but slower in CI, weaker multi-tab and multi-origin support (tenant subdomains and the admin portal), and paid parallelisation.

Decision

Option 2. Backend unit and integration tests use Jest (with @swc/jest). Frontend unit and component tests use Vitest with Testing Library (@testing-library/react, @testing-library/user-event, and @testing-library/jest-dom matchers) in jsdom. End-to-end tests use Playwright, one project per app (apps/<app>-e2e), run through @nx/playwright.

Consequences

  • pnpm test runs Jest and Vitest projects together; pnpm e2e runs Playwright and starts each app's dev server when none is running.
  • Contributors learn two unit runners, but their APIs are nearly identical.
  • Playwright browsers are installed separately (pnpm exec playwright install chromium), locally and in CI.
  • End-to-end projects run Chromium only for now; add Firefox and WebKit when a browser-specific issue appears.