Jesse A. Green / notebook

Jest User Guide

Generated June 2026 from jestjs/jest at 4c3091b

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Jest is a JavaScript and TypeScript testing framework with a focus on simplicity. It works out of the box for most projects, runs your tests in parallel across isolated worker processes, and ships with everything you need to write tests: a test runner, an assertion library (expect), built-in mocking, snapshot testing, and code-coverage reporting — with zero configuration required to get started.

This guide is for people who write tests with Jest. It covers installing Jest, writing your first test, the global test functions, the full matcher reference, mocking, snapshot testing, asynchronous tests, the command-line options, and everyday configuration. For Jest's internal architecture, the complete configuration reference, and how to build custom runners, environments, and reporters, see the Admin Guide.

Note

Every command, flag, configuration key, and default value in this guide is taken directly from Jest's source code. Where a default is shown, it is the value Jest actually ships.


1. Quick Start

Get a passing test running in under two minutes.

1. Install Jest as a development dependency:

npm install --save-dev jest

2. Create a function to test — sum.js:

function sum(a, b) {
  return a + b;
}
module.exports = sum;

3. Create a test file — sum.test.js:

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

4. Add a test script to package.json:

{
  "scripts": {
    "test": "jest"
  }
}

5. Run your tests:

npm test
 PASS  ./sum.test.js
  ✓ adds 1 + 2 to equal 3 (5 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.5 s
Ran all test suites.

That is a complete, working test suite. No configuration file is needed — Jest discovered sum.test.js automatically because it matches the default test pattern.

Tip

You do not need to create a jest.config.js to start. Jest's defaults are designed to work for the majority of projects. Add configuration only when you need to change a default.


2. Installation & Requirements

2.1 Requirements

Requirement Detail
Node.js ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 (Node 18.14+, 20, 22, or 24+)
Package manager npm, yarn, or pnpm
OS Linux, macOS, Windows

Important

Jest will not install on Node versions outside the supported range above. Odd-numbered Node releases (19, 21, 23) are not in the supported set — use an active LTS line (18.14+, 20, 22) or Node 24+.

2.2 Installing

npm

npm install --save-dev jest

yarn

yarn add --dev jest

pnpm

pnpm add --save-dev jest

This installs the jest package, which bundles the command-line runner (jest-cli), the assertion library (expect), the default test runner (jest-circus), and the configuration loader (jest-config).

2.3 Running the jest binary

After installation, the jest command is available through your package manager:

npx jest
 PASS  src/__tests__/example.test.js
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total

You can also run a specific file or filter by a path substring:

npx jest path/to/my-test.js
npx jest wallet     # runs every test whose path contains "wallet"

2.4 Generating a configuration file (optional)

Jest ships a companion package, create-jest, that scaffolds a configuration file by asking you a few questions:

npm init jest@latest
The following questions will help Jest to create a suitable configuration for your project

✔ Would you like to use Jest when running "test" script in "package.json"? … yes
✔ Would you like to use Typescript for the configuration file? … no
✔ Choose the test environment that will be used for testing › node
✔ Do you want Jest to add coverage reports? … no
✔ Which provider should be used to instrument code for coverage? › babel
✔ Automatically clear mock calls, instances, contexts and results before every test? … no

📝  Configuration file created at /your/project/jest.config.js

Note

The old jest --init flag has been removed. Use the create-jest package (npm init jest@latest) instead.


3. Writing Tests

3.1 Test files

Jest automatically finds and runs files that match its default patterns. By default a file is treated as a test if it is:

  • inside a __tests__ directory, or
  • named with a .test. or .spec. suffix

The exact default testMatch globs are:

**/__tests__/**/*.?([mc])[jt]s?(x)
**/?(*.)+(spec|test).?([mc])[jt]s?(x)

This means all of the following are discovered automatically: Button.test.js, Button.spec.ts, __tests__/button.tsx, api.test.mjs, utils.spec.cts.

3.2 The test / it function

A test is declared with test() (or its alias it()), which takes a name and a function containing your assertions:

test('a number is itself', () => {
  expect(1).toBe(1);
});

// `it` is an alias — identical behavior, reads naturally in BDD style
it('returns the user name', () => {
  expect(getUser().name).toBe('Ada');
});

A test passes if it runs to completion without any assertion throwing.

3.3 Grouping with describe

Use describe() to group related tests into a block. Blocks can be nested and are reflected in the output hierarchy:

describe('calculator', () => {
  describe('add', () => {
    test('adds positive numbers', () => {
      expect(add(2, 3)).toBe(5);
    });

    test('adds negative numbers', () => {
      expect(add(-2, -3)).toBe(-5);
    });
  });
});

3.4 Setup and teardown hooks

Jest provides four hooks to run shared setup and cleanup code:

Hook Runs
beforeAll(fn) Once, before all tests in the current block
afterAll(fn) Once, after all tests in the current block
beforeEach(fn) Before every test in the current block
afterEach(fn) After every test in the current block
let db;

beforeAll(async () => {
  db = await connectToDatabase();
});

afterAll(async () => {
  await db.close();
});

beforeEach(async () => {
  await db.seed();
});

afterEach(async () => {
  await db.clear();
});

test('reads a record', async () => {
  expect(await db.get(1)).toEqual({id: 1, name: 'Ada'});
});

Hooks defined at the top level of a file apply to every test in that file. Hooks inside a describe apply only to tests within that block. Hooks return a Promise (or accept a done callback) to handle asynchronous setup — see Section 7.

Tip

beforeEach/afterEach execute in declaration order before each test; outer-block hooks run before inner-block hooks. Use afterEach for cleanup that must happen even if a test fails — Jest still runs it.

3.5 Focusing and skipping tests

During development you often want to run a single test or temporarily disable one. Use the .only and .skip modifiers on both test and describe:

test.only('only this test runs in the file', () => {
  expect(true).toBe(true);
});

test.skip('temporarily disabled', () => {
  expect(brokenThing()).toBe(42);
});

test.todo('write a test for the edge case');  // shows as TODO in output

describe.only('only this block runs', () => { /* ... */ });
describe.skip('skipped block', () => { /* ... */ });
Modifier Effect
test.only / it.only Run only this test (and other .only tests) in the file
test.skip / it.skip Skip this test; report it as skipped
test.todo Mark a test as planned but not yet written
describe.only Run only tests inside this block
describe.skip Skip every test inside this block

3.6 Parameterized tests with test.each

Run the same test logic against a table of inputs using test.each (and describe.each):

test.each([
  [1, 1, 2],
  [2, 3, 5],
  [10, -5, 5],
])('add(%i, %i) returns %i', (a, b, expected) => {
  expect(add(a, b)).toBe(expected);
});

You can also use a tagged-template form with named columns:

test.each`
  a    | b    | expected
  ${1} | ${1} | ${2}
  ${2} | ${3} | ${5}
`('add($a, $b) returns $expected', ({a, b, expected}) => {
  expect(add(a, b)).toBe(expected);
});

Printf-style placeholders available in the test name include %s (string), %i/%d (number), %j/%o/%p (object), and %# (index of the row).

3.7 Concurrent tests

Run independent tests within a file in parallel with test.concurrent:

test.concurrent('fetch A', async () => {
  expect(await fetchA()).toBeDefined();
});

test.concurrent('fetch B', async () => {
  expect(await fetchB()).toBeDefined();
});

The maximum number of concurrent tests per file is controlled by maxConcurrency (default 5).

Warning

test.concurrent runs the test callbacks simultaneously. Do not use it for tests that share mutable state or rely on a specific execution order.


4. The expect API: Matchers

You make assertions by passing a value to expect() and chaining a matcher. Every matcher can be negated with .not:

expect(value).toBe(4);
expect(value).not.toBe(5);

4.1 Equality and truthiness

Matcher Asserts that the value…
toBe(expected) Is the same value (Object.is, reference/primitive identity). Do not use with floats.
toEqual(expected) Recursively equals expected by value (ignores undefined properties).
toStrictEqual(expected) Recursively equals expected, also checking types, undefined properties, and sparse arrays.
toBeDefined() Is not undefined.
toBeUndefined() Is undefined.
toBeNull() Is null.
toBeNaN() Is NaN.
toBeTruthy() Is truthy in a boolean context.
toBeFalsy() Is falsy (false, 0, '', null, undefined, NaN).
expect({a: 1, b: undefined}).toEqual({a: 1});       // passes
expect({a: 1, b: undefined}).toStrictEqual({a: 1});  // fails — b is present

4.2 Numbers

Matcher Asserts
toBeGreaterThan(n) Value > n
toBeGreaterThanOrEqual(n) Value >= n
toBeLessThan(n) Value < n
toBeLessThanOrEqual(n) Value <= n
toBeCloseTo(n, precision?) Value is within precision decimal places of n (default precision 2)
expect(0.1 + 0.2).toBeCloseTo(0.3);     // passes — toBe(0.3) would FAIL
expect(0.1 + 0.2).toBeCloseTo(0.3, 5);  // passes

Caution

Never use toBe or toEqual to compare floating-point numbers. 0.1 + 0.2 === 0.3 is false in JavaScript. Use toBeCloseTo.

Both toBeGreaterThan, toBeLessThan, and friends accept bigint values as well as number.

4.3 Strings

Matcher Asserts
toMatch(string | RegExp) String contains the substring, or matches the regular expression
toContain(substring) String contains the substring (also works on arrays/iterables)
expect('Hello world').toMatch('world');
expect('Hello world').toMatch(/^Hello/);

4.4 Arrays, iterables, and objects

Matcher Asserts
toContain(item) Array/Set/string contains item (uses ===)
toContainEqual(item) Array/iterable contains an item deeply equal to item
toHaveLength(n) Value has a .length of n
toHaveProperty(keyPath, value?) Object has the property at keyPath; optionally equal to value
toMatchObject(subset) Object matches the given subset of properties
toBeInstanceOf(Class) Value is an instanceof Class
expect(['a', 'b']).toContain('a');
expect([{id: 1}]).toContainEqual({id: 1});
expect({a: {b: 20}}).toHaveProperty('a.b', 20);
expect({name: 'Ada', age: 36}).toMatchObject({name: 'Ada'});
expect(new Date()).toBeInstanceOf(Date);

4.5 Exceptions

toThrow asserts that a function throws when called. You must wrap the call in a function so Jest can catch the error:

expect(() => parse('')).toThrow();
expect(() => parse('')).toThrow('empty input');     // message contains substring
expect(() => parse('')).toThrow(/empty/);           // message matches regex
expect(() => parse('')).toThrow(SyntaxError);        // error is instance of class

Warning

expect(parse('')).toThrow() (without the arrow function) does not work — the call happens immediately and the error escapes before Jest can observe it. Always pass () => parse('').

4.6 Mock function matchers

These matchers work on mock functions (see Section 5):

Matcher Asserts the mock…
toHaveBeenCalled() Was called at least once
toHaveBeenCalledTimes(n) Was called exactly n times
toHaveBeenCalledWith(...args) Was called at least once with the given arguments
toHaveBeenLastCalledWith(...args) Was last called with the given arguments
toHaveBeenNthCalledWith(n, ...args) The n-th call had the given arguments (1-based)
toHaveReturned() Returned (without throwing) at least once
toHaveReturnedTimes(n) Returned successfully exactly n times
toHaveReturnedWith(value) Returned value from at least one call
toHaveLastReturnedWith(value) Last successful return was value
toHaveNthReturnedWith(n, value) The n-th call returned value
const fn = jest.fn();
fn('hello');
expect(fn).toHaveBeenCalledWith('hello');
expect(fn).toHaveBeenCalledTimes(1);

4.7 Snapshot matchers

Matcher Behavior
toMatchSnapshot() Compares against a stored snapshot in a __snapshots__ file
toMatchInlineSnapshot() Compares against a snapshot written inline in the test file
toThrowErrorMatchingSnapshot() Snapshots the message of a thrown error
toThrowErrorMatchingInlineSnapshot() Inline variant of the above

See Section 6 for the full workflow.

4.8 Asymmetric matchers

When you don't know (or don't care about) an exact value, use an asymmetric matcher as part of a larger assertion. They are available as static methods on expect:

Matcher Matches
expect.anything() Any value except null or undefined
expect.any(Constructor) Any value created by Constructor (e.g. expect.any(Number))
expect.arrayContaining([...]) An array containing all listed elements
expect.objectContaining({...}) An object with at least the listed properties
expect.stringContaining(str) A string containing str
expect.stringMatching(regexp) A string matching the regular expression
expect.closeTo(number, precision?) A number close to number

Each also has a negated form: expect.not.arrayContaining, expect.not.objectContaining, expect.not.stringContaining, expect.not.stringMatching, expect.not.closeTo.

expect(user).toEqual({
  id: expect.any(Number),
  name: expect.stringContaining('Ada'),
  roles: expect.arrayContaining(['admin']),
  createdAt: expect.anything(),
});

4.9 Assertion-count helpers and custom matchers

Method Purpose
expect.assertions(n) Verify that exactly n assertions are called during a test
expect.hasAssertions() Verify that at least one assertion is called
expect.extend({...}) Register custom matchers
expect.addEqualityTesters([...]) Add custom equality logic used by toEqual and friends

expect.assertions is especially valuable in asynchronous tests, where it guarantees a callback actually ran:

test('the callback fires', () => {
  expect.assertions(1);
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

You can teach Jest new matchers with expect.extend:

expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling;
    return {
      pass,
      message: () =>
        `expected ${received} ${pass ? 'not ' : ''}to be within ${floor}–${ceiling}`,
    };
  },
});

test('range', () => {
  expect(100).toBeWithinRange(90, 110);
});

5. Mock Functions

Mocks let you replace real implementations, observe how functions are called, and control return values.

5.1 Creating a mock with jest.fn()

const callback = jest.fn();
[1, 2, 3].forEach(callback);

expect(callback).toHaveBeenCalledTimes(3);
expect(callback).toHaveBeenNthCalledWith(1, 1, 0, [1, 2, 3]);

Every mock records its calls on a .mock property:

callback.mock.calls;    // array of argument arrays for each call
callback.mock.results;  // array of {type, value} for each return/throw
callback.mock.instances;
callback.mock.contexts;
callback.mock.lastCall;  // arguments of the most recent call

5.2 Controlling return values and implementations

A mock function exposes a fluent API to control its behavior. These are the methods Jest provides on every mock:

Method Effect
mockReturnValue(value) Always return value
mockReturnValueOnce(value) Return value for the next call only (queueable)
mockResolvedValue(value) Return a Promise resolving to value
mockResolvedValueOnce(value) One-shot resolved value
mockRejectedValue(value) Return a Promise rejecting with value
mockRejectedValueOnce(value) One-shot rejected value
mockImplementation(fn) Use fn as the implementation
mockImplementationOnce(fn) Use fn for the next call only
mockReturnThis() Return the this context
withImplementation(fn, callback) Use fn only for the duration of callback
mockName(name) Set a name shown in error messages
getMockName() Read the mock's name
mockClear() Reset .mock.calls, .results, .instances, .contexts
mockReset() mockClear() plus remove any implementation/return values
mockRestore() mockReset() plus restore the original (non-mocked) implementation
const fn = jest.fn();
fn.mockReturnValueOnce(10).mockReturnValueOnce(20).mockReturnValue(0);

fn(); // 10
fn(); // 20
fn(); // 0
fn(); // 0

const fetchUser = jest.fn().mockResolvedValue({name: 'Ada'});
await expect(fetchUser()).resolves.toEqual({name: 'Ada'});

Note

mockClear, mockReset, and mockRestore form a ladder of increasing aggressiveness: clear wipes call history, reset also drops behavior, restore also brings back the real function (only meaningful for spies created with jest.spyOn).

5.3 Spying with jest.spyOn

jest.spyOn wraps an existing method so you can observe it while keeping (or replacing) its behavior:

const video = {play: () => true};
const spy = jest.spyOn(video, 'play');

video.play();
expect(spy).toHaveBeenCalled();

spy.mockRestore();  // restore the original method

5.4 Mocking modules with jest.mock

Replace an entire module with an automatic mock, or provide a factory:

// Automatic mock — every export becomes a jest.fn()
jest.mock('./api');

// Factory mock — full control
jest.mock('./api', () => ({
  fetchUser: jest.fn().mockResolvedValue({name: 'Ada'}),
}));

import {fetchUser} from './api';

test('uses the mocked module', async () => {
  expect(await fetchUser()).toEqual({name: 'Ada'});
});

To use the real module inside a test, call jest.requireActual('./api'). Related module-mocking helpers on the jest object are listed in Section 9.2.

5.5 Resetting mocks between tests

Rather than calling reset methods manually, you can have Jest do it automatically before every test via configuration:

Config / CLI option Equivalent manual call
clearMocks: true / --clearMocks jest.clearAllMocks() before each test
resetMocks: true / --resetMocks jest.resetAllMocks() before each test
restoreMocks: true / --restoreMocks jest.restoreAllMocks() before each test

Tip

restoreMocks: true is a good default for projects that use jest.spyOn heavily — it guarantees every spy is torn down between tests so state never leaks.


6. Snapshot Testing

Snapshot tests capture the rendered output of a value and fail if it changes unexpectedly — ideal for serializable structures like component trees, API responses, or large objects.

6.1 Writing a snapshot test

test('renders correctly', () => {
  const tree = renderToJSON(<Button label="Submit" />);
  expect(tree).toMatchSnapshot();
});

The first run writes a __snapshots__/<file>.snap file next to your test. Every subsequent run compares against it. If the output changes:

 FAIL  src/Button.test.js
  ✕ renders correctly

  - Snapshot  - 1
  + Received  + 1

    <button>
  -   Submit
  +   Send
    </button>

6.2 Updating snapshots

When a change is intentional, re-record the snapshots:

npx jest --updateSnapshot
# or the short alias
npx jest -u

You can scope the update to specific tests by combining with --testNamePattern:

npx jest -u -t "renders correctly"

6.3 Inline snapshots

Inline snapshots are written directly into your test file (Jest fills the empty string on first run):

test('inline', () => {
  expect(user).toMatchInlineSnapshot();
  // After first run Jest rewrites this to:
  // expect(user).toMatchInlineSnapshot(`{ "name": "Ada" }`);
});

Note

Inline snapshots require the prettier package to format the written value. The module used is controlled by the prettierPath configuration option (default "prettier").

6.4 Property matchers in snapshots

For values with non-deterministic fields (timestamps, generated IDs), pass a shape of asymmetric matchers so those fields don't break the snapshot:

expect(user).toMatchSnapshot({
  id: expect.any(Number),
  createdAt: expect.any(Date),
});

Caution

Commit your __snapshots__ directory to version control. Snapshots are part of your test suite — a reviewer should see snapshot changes in the diff. In CI, Jest refuses to write new snapshots by default (see --ci) so an obsolete or missing snapshot fails the build instead of silently passing.


7. Testing Asynchronous Code

Jest supports four idioms for asynchronous tests. Pick whichever reads best.

test('fetches the user', async () => {
  const user = await fetchUser(1);
  expect(user.name).toBe('Ada');
});

7.2 Returning a Promise

If you return a Promise from a test, Jest waits for it to settle:

test('resolves', () => {
  return fetchUser(1).then(user => {
    expect(user.name).toBe('Ada');
  });
});

7.3 The .resolves / .rejects modifiers

Unwrap a Promise inside the assertion itself:

await expect(fetchUser(1)).resolves.toEqual({name: 'Ada'});
await expect(fetchUser(-1)).rejects.toThrow('not found');

7.4 The done callback

For callback-style APIs, accept a done parameter and call it when finished:

test('calls back', done => {
  fetchData((err, data) => {
    try {
      expect(data).toBe('peanut butter');
      done();
    } catch (error) {
      done(error);
    }
  });
});

Warning

A common mistake is forgetting to await or return the Promise. Without it, the test finishes before the assertions run and may report a false pass. Add expect.assertions(n) to guard against this.

Important

By default, each test has a 5000 ms (testTimeout) limit. A test that never resolves will fail with Exceeded timeout of 5000 ms for a test. Increase it per test with test('slow', async () => {...}, 10000) or globally with the testTimeout config option.


8. Fake Timers

Fake timers let you control time so you can test setTimeout, setInterval, and date-based logic without actually waiting.

beforeEach(() => {
  jest.useFakeTimers();
});

afterEach(() => {
  jest.useRealTimers();
});

test('calls the callback after one second', () => {
  const callback = jest.fn();
  setTimeout(callback, 1000);

  expect(callback).not.toHaveBeenCalled();
  jest.advanceTimersByTime(1000);  // fast-forward time
  expect(callback).toHaveBeenCalledTimes(1);
});

Common timer-control methods on the jest object:

Method Effect
jest.useFakeTimers() Replace timer functions with controllable fakes
jest.useRealTimers() Restore the real timer functions
jest.advanceTimersByTime(ms) Advance time by ms, running any timers that fire
jest.runAllTimers() Run every pending timer (and timers they schedule)
jest.runOnlyPendingTimers() Run only the timers currently queued
jest.advanceTimersToNextTimer() Advance to the next scheduled timer
jest.clearAllTimers() Remove all pending timers
jest.setSystemTime(now) Set the mocked current time
jest.getTimerCount() Number of pending fake timers

You can also enable fake timers for the whole project in configuration:

// jest.config.js
module.exports = {
  fakeTimers: {enableGlobally: true},
};

Tip

Async variants exist for promise-based code: jest.advanceTimersByTimeAsync, jest.runAllTimersAsync, and jest.runOnlyPendingTimersAsync. Use them when a timer callback awaits a Promise.


9. Command-Line Reference

Run Jest with jest [options] [test path patterns]. Any non-flag arguments are treated as patterns matched against test file paths:

jest                      # run everything
jest src/wallet           # run tests whose path contains "src/wallet"
jest --watch              # interactive watch mode
jest --coverage           # run with coverage reporting

9.1 Everyday options

Option Alias Description
--watch Watch files and re-run tests related to changed files
--watchAll Watch files and re-run all tests on any change
--coverage Collect and report code-coverage information
--verbose Show each individual test result with the suite hierarchy
--bail -b Exit immediately after n failing test suites
--testNamePattern <regex> -t Run only tests whose name matches the regex
--testPathPatterns <regex> Run only test files whose path matches the regex
--runTestsByPath Treat the provided patterns as exact file paths
--updateSnapshot -u Re-record snapshots
--ci CI mode: never write new snapshots unless explicitly requested
--silent Prevent tests from printing through the console
--expand -e Show full diffs instead of a patch
--config <path> -c Path to a config file, or a JSON config string

9.2 Selecting which tests run

Option Alias Description
--onlyChanged -o Run only tests related to files changed in the current repo (git/hg)
--changedSince <branch> Run tests related to changes since the given branch
--changedFilesWithAncestor Include changes from the last commit too
--lastCommit Run tests affected by the last commit
--onlyFailures -f Run only tests that failed in the previous run
--findRelatedTests <files...> Run tests that cover the given source files
--listTests Print the list of test files Jest would run, then exit
--collectTests Discover and print all test cases as a tree without running them
--selectProjects <names...> Run only the named projects (by displayName)
--ignoreProjects <names...> Skip the named projects
--shard <c/n> Run shard c of n (e.g. 3/5) for distributing across machines
--passWithNoTests Do not fail when no tests are found

9.3 Execution and performance options

Option Alias Description
--runInBand -i Run all tests serially in the current process
--maxWorkers <n|%> -w Maximum worker pool size (e.g. 4 or 50%)
--maxConcurrency <n> Max simultaneous test.concurrent tests (default 5)
--workerThreads Use worker threads instead of child processes
--detectOpenHandles Print remaining open handles preventing exit (implies --runInBand)
--detectLeaks Experimental: fail tests that leak the global object
--logHeapUsage Log heap usage after each test (use with --runInBand)
--forceExit Force Jest to exit after all tests finish
--randomize Shuffle the order of tests within each file
--seed <n> Set the randomization seed (retrievable via jest.getSeed())
--showSeed Print the seed in the result summary

Caution

--runInBand and --maxWorkers cannot be used together — Jest exits with Both --runInBand and --maxWorkers were specified, only one is allowed. Likewise, --onlyChanged/--lastCommit/--changedSince/--changedFilesWithAncestor cannot be combined with --watchAll.

9.4 Coverage options

Option Description
--coverage (alias --collectCoverage) Enable coverage collection
--coverageProvider <babel|v8> Choose the instrumentation engine
--coverageDirectory <dir> Where to write coverage reports
--coverageReporters <names...> Reporters to use (any Istanbul reporter)
--collectCoverageFrom <glob> Glob of files to collect coverage from
--coverageThreshold <json> Minimum coverage enforcement (fails the run if not met)

9.5 Introspection options

Option Description
--showConfig Print the resolved Jest config and exit
--debug Print debugging info about your config
--clearCache Delete the configured cache directory and exit
--version (alias -v) Print the Jest version
--help (alias -h) Print the full options list

Tip

Run jest --showConfig whenever Jest behaves unexpectedly. It prints the fully-resolved configuration — including every default — so you can see exactly what Jest is using.


10. Configuring Jest

10.1 Where configuration lives

Jest reads configuration from the first of these it finds:

  1. A jest key in package.json
  2. A dedicated config file: jest.config.js, jest.config.ts, jest.config.mjs, jest.config.mts, jest.config.cjs, jest.config.cts, or jest.config.json (searched in that order)
  3. A --config path or JSON string passed on the command line
// jest.config.js
/** @type {import('jest').Config} */
const config = {
  testEnvironment: 'node',
  verbose: true,
};

module.exports = config;

You can also use the defineConfig helper for editor autocomplete:

const {defineConfig} = require('jest-config');

module.exports = defineConfig({
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
});

Note

<rootDir> is a token Jest replaces with your project root in path-valued options. Always prefer <rootDir>/path over absolute paths so the config stays portable.

10.2 The most common options

These are the options most projects touch. For the full reference — every option, type, and default — see the Admin Guide.

Option Default Purpose
testEnvironment "jest-environment-node" The environment tests run in (node or jsdom)
testMatch ["**/__tests__/**/*.?([mc])[jt]s?(x)", "**/?(*.)+(spec|test).?([mc])[jt]s?(x)"] Globs for discovering test files
setupFiles [] Modules run once before the test framework is installed
setupFilesAfterEnv [] Modules run before each test file (after the framework is ready)
moduleNameMapper {} Map import paths to modules/stubs (e.g. CSS or asset stubs)
transform (babel-jest for JS/TS) Map file patterns to transformers
collectCoverage false Whether to collect coverage
coverageProvider "babel" "babel" or "v8"
clearMocks false Clear mock state before each test
verbose false Report each individual test
testTimeout 5000 Per-test timeout in milliseconds
maxWorkers "50%" Worker pool size

10.3 Choosing a test environment

For backend / Node code, the default node environment is correct. For code that touches the DOM (browser code, React components), install and select jsdom:

npm install --save-dev jest-environment-jsdom
// jest.config.js
module.exports = {testEnvironment: 'jsdom'};

You can also set the environment per file with a docblock at the top of the test:

/**
 * @jest-environment jsdom
 */
test('uses the DOM', () => {
  document.body.innerHTML = '<div id="root"></div>';
  expect(document.getElementById('root')).not.toBeNull();
});

Important

As of Jest 28, jest-environment-jsdom is no longer bundled with Jest — you must install it separately. If you see Test environment jest-environment-jsdom cannot be found, run npm install --save-dev jest-environment-jsdom.

10.4 Coverage configuration

// jest.config.js
module.exports = {
  collectCoverage: true,
  coverageProvider: 'v8',
  collectCoverageFrom: ['src/**/*.{js,ts}', '!src/**/*.d.ts'],
  coverageReporters: ['text', 'lcov'],
  coverageThreshold: {
    global: {branches: 80, functions: 80, lines: 80, statements: 80},
  },
};

If coverage falls below a threshold, the run fails — useful as a CI gate.

Tip

The v8 provider is faster and needs no Babel instrumentation, using Node's built-in coverage. The babel provider (the default) produces more precise results for transpiled code. Try v8 first; switch to babel if a report looks off.


11. Using Jest with TypeScript

Jest runs TypeScript test files through a transformer. The two common setups:

Babel (babel-jest, zero type-checking)

npm install --save-dev babel-jest @babel/core @babel/preset-env @babel/preset-typescript
// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', {targets: {node: 'current'}}],
    '@babel/preset-typescript',
  ],
};

babel-jest is used automatically when a Babel config is present. It strips types but does not type-check.

ts-jest (with type-checking)

npm install --save-dev ts-jest
// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};

For editor autocomplete on the global expect/jest/describe, install the type packages and add them to your tsconfig.json types:

npm install --save-dev @types/jest

Note

babel-jest reads the BABEL_ENV or NODE_ENV environment variable to pick a Babel environment. Jest sets NODE_ENV to "test" automatically if it is not already set.


12. Watch Mode

jest --watch starts an interactive session that re-runs tests related to files you change. While watching, press a key to filter:

Watch Usage
 › Press a to run all tests.
 › Press f to run only failed tests.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press q to quit watch mode.
 › Press Enter to trigger a test run.
Key Action
a Run all tests
f Run only previously-failed tests
o Run only tests related to changed files (default in --watch)
p Filter by filename pattern
t Filter by test-name pattern
u Update snapshots
q Quit

Tip

--watch only re-runs tests related to changed files and requires a git or hg repository. If you are not in a VCS repo, use --watchAll, which watches everything.


13. Troubleshooting

Each entry below uses an exact message Jest emits, its cause, and the fix.

Error: Both --runInBand and --maxWorkers were specified, only one is allowed.

Cause: You passed both flags (or a script sets one and you added the other). They are mutually exclusive — --runInBand means "one process", --maxWorkers configures the pool. Solution: Remove one. Use --runInBand for serial debugging; use --maxWorkers to size the pool. Prevention: Check your test script and CI command for a duplicate flag.

Error: The --maxWorkers (-w) option requires a number or string to be specified.

Cause: --maxWorkers was given without a value. Solution: Provide a value: jest --maxWorkers 2 or jest --maxWorkers 50%. Prevention: If you meant interactive mode, you probably wanted --watch.

Error: jest: No configuration found for any project.

Cause: Jest could not locate a config file or a jest key, and the directory it scanned has no recognizable Jest configuration. Solution: Add a jest.config.js (or a jest key in package.json), or pass --config. Run npm init jest@latest to scaffold one. Prevention: Keep a config file at your project root.

Error: Test environment jest-environment-jsdom cannot be found.

Cause: You set testEnvironment: 'jsdom' but the package is not installed (it is no longer bundled since Jest 28). Solution: npm install --save-dev jest-environment-jsdom. Prevention: Add jest-environment-jsdom to devDependencies for any project that tests DOM code.

Error: Exceeded timeout of 5000 ms for a test.

Cause: An async test (or hook) did not finish within the default testTimeout. Often an un-awaited Promise or a callback that is never called. Solution: await/return the Promise, call done(), or raise the timeout: test('slow', fn, 10000) or set testTimeout in config. Prevention: Add expect.assertions(n) to async tests so a silently-skipped assertion surfaces.

Warning: Jest did not exit one second after the test run has completed.

Cause: Asynchronous operations (open sockets, timers, DB connections) were still running after tests finished. Solution: Close resources in afterAll/afterEach. Diagnose with jest --detectOpenHandles. Prevention: Pair every connection/listener with a teardown hook. As a last resort, --forceExit.

Snapshot keeps failing in CI but passes locally

Cause: A new or changed snapshot was not committed, or a non-deterministic value (date, random ID) is embedded in the snapshot. In CI (--ci) Jest refuses to write new snapshots. Solution: Run jest -u locally and commit the __snapshots__ change. Use property matchers (expect.any(Date)) for volatile fields. Prevention: Always commit snapshots; review them in PRs.

Memory usage grows when upgrading from Jest 29 to 30

Cause: A reported behavior (issue #15743) where heap usage increases across runs in some projects. Solution: Run with --workerIdleMemoryLimit to recycle workers that exceed a memory budget, and --logHeapUsage to identify the leaking suite. Consider --runInBand to isolate. Prevention: Tear down large globals in afterEach; avoid retaining references across tests.

Tests don't pick up changes to a mocked module

Cause: Module registry caching, or a jest.mock factory referencing out-of-scope variables. Solution: Call jest.resetModules() between tests, or enable resetModules: true. Ensure the factory only references variables prefixed with mock. Prevention: Keep mock factories self-contained.


14. Frequently Asked Questions

Q: Do I need a configuration file to use Jest? No. Jest works with zero configuration. Add a jest.config.js only when you need to change a default.

Q: What's the difference between toBe and toEqual? toBe checks reference/primitive identity (Object.is). toEqual checks deep, recursive value equality. Use toBe for primitives and toEqual for objects and arrays.

Q: What's the difference between toEqual and toStrictEqual? toStrictEqual additionally fails on type mismatches, undefined properties, and sparse-array differences. Use it when those distinctions matter.

Q: Why does my toThrow assertion fail even though the function throws? You probably called the function instead of passing it. Use expect(() => fn()).toThrow(), not expect(fn()).toThrow().

Q: How do I run a single test file? jest path/to/file.test.js, or filter by a path substring: jest wallet.

Q: How do I run a single test by name? jest -t "the test name regex".

Q: How do I update snapshots? jest -u (or --updateSnapshot). Scope with -t to a specific test name.

Q: it or test — which should I use? They are identical aliases. Pick one and be consistent. it('should …') reads as a sentence; test('…') is plainer.

Q: How do I test a function that returns a Promise? Make the test async and await the result, or return the Promise, or use await expect(promise).resolves.toEqual(...).

Q: Why are my tests slow? Worker startup, large jsdom environments, and un-cached transforms are common causes. Try --maxWorkers=50%, the v8 coverage provider, and ensure cache is enabled (it is by default). For a single machine in CI, sharding with --shard distributes across runners.

Q: How do I make Jest fail when no tests are found? That is the default. To allow empty runs (e.g. filtered shards), pass --passWithNoTests.

Q: Can I use ES modules (ESM)? Yes. Jest supports native ESM. Run Node with --experimental-vm-modules and use extensionsToTreatAsEsm for non-.mjs files. See the Admin Guide for the full setup.

Q: How do I see exactly what config Jest is using? jest --showConfig prints the fully-resolved configuration including all defaults.

Q: Where is Jest's cache stored? In your OS temp directory under jest (per-user on POSIX systems). Clear it with jest --clearCache. Override with cacheDirectory.

Q: How do I run tests for multiple packages in one repo? Use the projects option (or --selectProjects / --ignoreProjects) to run several configurations in a single Jest invocation. Each project can have its own environment and settings.

Q: What replaced jest --init? The create-jest package. Run npm init jest@latest.