Setting up JavaScript test runners like Jest and Vitest involves configuring test environments (jsdom for browser APIs, node for server code), transform pipelines for TypeScript/JSX, and integration with testing libraries like React Testing Library.
Jest is batteries-included and framework-agnostic; Vitest is faster for Vite projects by sharing the transform pipeline and provides a Jest-compatible API for easy migration.
jsdom simulates browser APIs for component tests, node provides server-side globals for utility/API tests, and happy-dom offers a faster alternative to jsdom.
Test runners need transforms for TypeScript and JSX — Vitest uses esbuild natively, Jest requires babel-jest, ts-jest, or @swc/jest for non-JS syntax.
jest.mock()/vi.mock() replaces entire modules, jest.fn()/vi.fn() creates tracked mock functions, and spyOn wraps methods while preserving their implementation.
A properly configured test environment is the foundation of a reliable test suite. Interviewers frequently ask about test runner setup to gauge whether you have hands-on experience with testing infrastructure, not just writing test assertions.
Jest, created by Facebook, has been the dominant JavaScript test runner since 2016. It provides a complete solution: test runner, assertion library, mocking system, code coverage, and snapshot testing in one package. Vitest is the modern alternative, designed for Vite-based projects. It uses Vite's transformation pipeline, so TypeScript and JSX work without additional configuration. Vitest is significantly faster than Jest for projects already using Vite because it shares the same config and transform cache. It also provides a Jest-compatible API, making migration straightforward.
The test environment determines what global APIs are available during tests. jsdom (default for Jest) simulates a browser environment with DOM APIs like document.querySelector, window.localStorage, and fetch. Use it for testing React components and any code that interacts with browser APIs. node environment provides only Node.js globals — use it for testing utility functions, API routes, and server-side logic. Vitest also supports happy-dom, a lighter and faster alternative to jsdom.
Test runners need to transform non-standard syntax (TypeScript, JSX, ESM) into JavaScript that Node.js can execute. Jest uses transform configuration — typically babel-jest for Babel or ts-jest for TypeScript. Vitest uses Vite's built-in esbuild transform, which is faster and requires no additional configuration. SWC-based transforms (@swc/jest) offer a middle ground — Jest compatibility with near-native speed.
Key configuration options: testMatch/testPathPattern (which files are tests), setupFiles and setupFilesAfterFramework (run before tests for global setup like polyfills or custom matchers), moduleNameMapper/moduleDirectories (resolve path aliases like @/components), collectCoverage and coverageThreshold (enforce minimum coverage), and transform (how to process non-JS files).
@testing-library/react provides utilities for testing React components by simulating user interactions rather than testing implementation details. It requires a DOM environment (jsdom or happy-dom). The companion package @testing-library/jest-dom adds custom matchers like toBeInTheDocument(), toHaveTextContent(), and toBeVisible(). Setup typically involves importing @testing-library/jest-dom in a setup file so matchers are available in all tests.
Both Jest and Vitest provide comprehensive mocking: jest.fn()/vi.fn() creates mock functions that track calls. jest.mock()/vi.mock() replaces entire modules. jest.spyOn()/vi.spyOn() wraps existing methods to track calls while preserving implementation. Module mocking is essential for isolating units — replacing API calls, timers, and external dependencies with controlled test doubles.
Both runners offer watch mode that re-runs affected tests when files change. Vitest's watch mode is particularly fast because it leverages Vite's module graph to determine which tests are affected by a change, skipping unrelated tests. This tight feedback loop is essential for test-driven development.
Jest is a complete, batteries-included test framework that works with any project. Vitest is optimized for Vite-based projects and is faster in that context. Both provide the same core capabilities (assertions, mocking, coverage, snapshots). Choose Vitest for new Vite/React projects; keep Jest for existing projects or non-Vite setups. The testing library choice (React Testing Library) is independent of the test runner.
Fun Fact
Vitest's logo is a yellow lightning bolt inside a green triangle — a mashup of Vite's lightning bolt and the green of testing success. It was created in December 2021 by Anthony Fu, who also created Vue's build tools, and reached 1.0 in less than two years.