Jest Testing Framework
Jest is a batteries-included JavaScript/TypeScript testing framework: a fast test runner, an expressive assertion library, built-in mocking, snapshot testing, and coverage — all with near-zero configuration. It's the long-standing default for React projects (and works with any JS codebase), pairing naturally with React Testing Library for component tests.
If you're on Vite, Vitest offers a near-identical API with faster startup; everything you learn here transfers. For the underlying principles, see Unit Testing and Mocking & Stubbing.
TL;DR
- Zero-config runner with built-in mocking and coverage.
- Snapshot testing for UI components.
- Parallel execution and a fast watch mode.
- Excellent TypeScript support via
ts-jest.
Quick Example
A test file is describe blocks of test cases with expect assertions:
Setup
Matchers
Async Tests
Mocking
Snapshot Testing
Update snapshots intentionally with jest --updateSnapshot. Inline snapshots (toMatchInlineSnapshot) keep the expected value next to the test.
⚠️ Use snapshots sparingly — they're easy to approve blindly and hard to maintain. Prefer explicit assertions for anything you can express directly.
Setup, Teardown & Coverage
Run jest --coverage (add --watch for rapid local feedback).
Testing React Components
Best Practices
- Test behavior, not implementation — assert on what the user sees, not internal state.
- Mock only external dependencies (network, time); let your code run.
- Always
awaitasync tests so failures actually surface. - Clean up timers and mocks between tests.
- Set coverage thresholds in CI, but chase signal — not 100%. See Test Coverage.
Common Mistakes
Forgetting to await
Over-mocking
FAQ
Jest or Vitest — which should I use?
Use Jest for established projects, Create React App, Next.js, and anything not on Vite — it's mature, ubiquitous, and well-documented. Use Vitest for Vite-based apps where you want faster startup and native ESM/TS, with an almost identical API. The testing concepts are the same; the choice is mostly about your build tooling.
How do I test asynchronous code reliably?
Make the test async and await the operation (or return the promise), and use resolves/rejects matchers. The most common bug is forgetting to await — the test finishes before the assertion runs and falsely passes. For callbacks, use the done parameter and call it when complete, but prefer promises/async-await.
When should I use snapshot tests?
For stable, serializable output where an explicit assertion would be tedious — small config objects or component markup you want to guard against accidental change. Avoid large or frequently-changing snapshots: they get approved without review and become noise. Prefer targeted assertions (getByText, toHaveProperty) for anything you can state directly.
How do I avoid testing implementation details?
Assert on observable behavior — rendered text, returned values, calls to external boundaries — not on private state or internal method calls. With React Testing Library, query by role/text the way a user would, and drive interactions with userEvent. Tests written this way survive refactors and actually verify the thing users care about.
Related Topics
- Unit Testing — Principles behind the tests
- Mocking & Stubbing — Test doubles in depth
- Vitest — The Vite-native alternative
- Integration Testing — Beyond units
- React — What you're testing