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.jsto 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 --initflag has been removed. Use thecreate-jestpackage (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/afterEachexecute in declaration order before each test; outer-block hooks run before inner-block hooks. UseafterEachfor 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.concurrentruns 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
toBeortoEqualto compare floating-point numbers.0.1 + 0.2 === 0.3isfalsein JavaScript. UsetoBeCloseTo.
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, andmockRestoreform 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 withjest.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: trueis a good default for projects that usejest.spyOnheavily — 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
prettierpackage to format the written value. The module used is controlled by theprettierPathconfiguration 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.
7.1 async / await (recommended)
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
awaitorreturnthe Promise. Without it, the test finishes before the assertions run and may report a false pass. Addexpect.assertions(n)to guard against this.
Important
By default, each test has a 5000 ms (
testTimeout) limit. A test that never resolves will fail withExceeded timeout of 5000 ms for a test. Increase it per test withtest('slow', async () => {...}, 10000)or globally with thetestTimeoutconfig 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, andjest.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
--runInBandand--maxWorkerscannot be used together — Jest exits withBoth --runInBand and --maxWorkers were specified, only one is allowed.Likewise,--onlyChanged/--lastCommit/--changedSince/--changedFilesWithAncestorcannot 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 --showConfigwhenever 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:
- A
jestkey inpackage.json - A dedicated config file:
jest.config.js,jest.config.ts,jest.config.mjs,jest.config.mts,jest.config.cjs,jest.config.cts, orjest.config.json(searched in that order) - A
--configpath 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>/pathover 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-jsdomis no longer bundled with Jest — you must install it separately. If you seeTest environment jest-environment-jsdom cannot be found, runnpm 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
v8provider is faster and needs no Babel instrumentation, using Node's built-in coverage. Thebabelprovider (the default) produces more precise results for transpiled code. Tryv8first; switch tobabelif 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-jestreads theBABEL_ENVorNODE_ENVenvironment variable to pick a Babel environment. Jest setsNODE_ENVto"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
--watchonly 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.