Technology handbook
Jest — Unit Testing, Mocks & Coverage
Unit testing with Jest’s assertions, mocks, timers, isolation and coverage workflows.
- Topics
- 16
- Sections
- 5
Test foundations
Test structure
Organize behavior with describe, test, expect and focused lifecycle hooks.
- Name each test after an observable behavior.
- Arrange inputs, execute the operation and assert its outcome.
- Use describe groups to organize related scenarios without hidden state.
Setup and teardown
Create predictable per-test and per-suite setup without leaking state across cases.
- Use beforeEach for state that each test must receive freshly.
- Return or await asynchronous setup and teardown.
- Release resources even when an assertion fails.
Assertions
Matchers
Choose identity, structural, partial and exception matchers that express the behavior under test.
- Use toBe for identity and toEqual for structural comparison.
- Match only relevant fields when extra output is legitimate.
- Assert thrown errors through a function passed to expect.
Snapshot testing
Use focused snapshots for stable serialized output and review changes deliberately.
- Snapshot small, stable representations with useful review value.
- Remove timestamps and other irrelevant nondeterministic fields.
- Review changed snapshots before accepting updated baselines.
Custom matchers
Express domain-specific expectations with readable failure messages.
- Register a matcher with expect.extend.
- Return a clear pass result and diagnostic message.
- Add typings so test authors get checked matcher arguments.
Test doubles
Mock functions
Track calls and control return values without replacing the contract with implementation trivia.
- Use jest.fn to record calls and provide controlled results.
- Configure one-time results for meaningful successive behaviors.
- Assert calls only when the dependency interaction is part of the contract.
Module mocking
Replace a dependency at the module boundary and restore isolation between tests.
- Mock a stable dependency boundary rather than internal helpers.
- Account for the difference between CommonJS and ESM mocking.
- Restore module isolation when singleton state affects another test.
Spies and implementations
Observe a real method or replace it temporarily while preserving restoration discipline.
- jest.spyOn observes the original method unless its implementation is replaced.
- Configure a temporary return or implementation when needed.
- Restore the spy so later tests call the real method.
Manual mocks
Provide deterministic module behavior from a __mocks__ boundary when appropriate.
- Place reusable module doubles in the supported __mocks__ location.
- Keep the mock's public contract aligned with the actual dependency.
- Avoid using a manual mock to hide important integration behavior.
Async testing
Fake timers
Advance time deterministically when code uses timers, intervals or scheduled retries.
- Enable fake timers before the code schedules its work.
- Advance the relevant timer interval instead of sleeping.
- Restore real timers after pending work is handled.
Async tests
Return or await promises so Jest waits for the behavior being asserted.
- Return or await the operation whose completion is asserted.
- Use resolves or rejects for promise outcomes.
- Do not combine a done callback with a returned promise.
Mock timers and dates
Control scheduled work and clock-dependent logic without waiting in real time.
- Set a controlled system time for date-dependent behavior.
- Advancing timers and changing the system clock are separate operations.
- Exercise boundary times without waiting for real time to pass.
Testing rejected promises
Assert asynchronous failures explicitly so a passing test cannot hide an unhandled rejection.
- Await expect(promise).rejects with the expected failure shape.
- Confirm the failure path actually ran when using try/catch.
- Avoid a test that passes because an unawaited promise rejects later.
Quality
Coverage
Use branch and statement coverage to find gaps, not as a substitute for meaningful assertions.
- Inspect branches as well as executed statements.
- Include untested source files in coverage collection deliberately.
- Treat uncovered behavior as a test-design question, not just a percentage.
Test isolation
Reset modules, mocks and shared state so order and parallel execution do not change results.
- Create fresh input state for independent scenarios.
- Distinguish clearing call history from resetting implementations and restoring spies.
- Close handles so test order and worker reuse do not affect results.
Jest configuration
Configure transforms, environments, roots, reporters and coverage for the repository.
- Choose node or jsdom according to the code's environment.
- Configure transforms and module aliases to match the project.
- Keep test discovery and coverage patterns intentional.