cheat sheet

Jest

Day-to-day Jest CLI commands and config patterns — running tests, mocks, snapshots, coverage, watch mode, and migration tips.

#jest#cli#testing#toolingupdated 05-31-2026

Jest — CLI and configuration

What it is

Jest is the long-incumbent JavaScript test runner: zero-config (mostly), built-in assertions, mocking, snapshots, and coverage. It still powers most legacy React, Next.js (pre-15), and large monorepos. For new Vite-based work, vitest is the modern alternative — same API, faster, ESM-native. This article focuses on day-to-day CLI use and config patterns assuming you already have Jest in the project.

Install

bash
npm install -D jest @types/jest

# TypeScript projects — pick a transformer
npm install -D @swc/jest          # SWC (10-20× faster, no type check)
# OR
npm install -D ts-jest             # ts-jest (slow, includes type check)

# DOM testing (since Jest v28)
npm install -D jest-environment-jsdom

Output: (none — exits 0)

Add scripts:

json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:ci": "jest --ci --coverage --reporters=default --reporters=jest-junit",
    "coverage": "jest --coverage"
  }
}

Day-to-day commands

CommandWhat it does
jestRun every test file. Defaults to __tests__/** and *.test.{js,ts}.
jest path/to/file.test.tsRun one specific file.
jest --testNamePattern="adds two" (-t)Run tests whose name matches a regex.
jest --watchRe-run tests on file change. Uses git to find changed files.
jest --watchAllWatch every test file (no git heuristic).
jest --coverageGenerate coverage report. Defaults to coverage/.
jest --ciCI-friendly mode: never write snapshots automatically, exit non-zero on missing snapshots.
jest -u (--updateSnapshot)Update snapshot files in place.
jest --findRelatedTests src/foo.tsRun tests that import the given source files.
jest --shard=N/MPartition test files deterministically — for parallel CI jobs.
jest --detectOpenHandlesFind leaked timers / sockets after the suite ends.
jest --listTestsPrint resolved test files; don't run anything.

Common scenarios

Run a single test by name

bash
jest -t "uppercases the user name"

Output:

text
PASS  src/user.test.ts
  ✓ uppercases the user name (3 ms)

Tests:       1 passed, 1 total

-t is a regex against describe + it names. Quote it if it has spaces.

Watch mode with name filter

bash
jest --watch
# Press `p` to filter by filename, `t` to filter by test name

Output:

text
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.

The watch UI is the best in the runner space — interactive prompts beat re-typing flags.

Coverage with thresholds

javascript
// jest.config.js
export default {
  collectCoverage: true,
  coverageDirectory: "coverage",
  coverageReporters: ["text", "lcov", "json-summary"],
  collectCoverageFrom: [
    "src/**/*.{ts,tsx}",
    "!src/**/*.d.ts",
    "!src/**/index.ts",
  ],
  coverageThreshold: {
    global: { branches: 75, functions: 80, lines: 80, statements: 80 },
  },
};
bash
jest --coverage

Output:

text
Tests:       42 passed, 42 total
-------|---------|----------|---------|---------|
File   | % Stmts | % Branch | % Funcs | % Lines |
-------|---------|----------|---------|---------|
All    |   84.21 |    77.13 |   87.50 |   84.21 |
-------|---------|----------|---------|---------|

Exits non-zero if any metric falls below the floor — wire as a required PR check.

Snapshot testing

javascript
test("renders banner HTML", () => {
  const html = renderToString(<Banner title="Hi" />);
  expect(html).toMatchSnapshot();
});

First run writes __snapshots__/banner.test.ts.snap. After intentional UI changes:

bash
jest -u                              # update all snapshots
jest -u path/to/banner.test.ts       # update for one file

Output:

text
PASS  src/banner.test.ts
  › 1 snapshot updated.

Snapshots:   1 updated, 1 total
Tests:       1 passed, 1 total

For tiny outputs, prefer inline snapshots:

javascript
expect(formatPrice(99.5)).toMatchInlineSnapshot(`"$99.50"`);

Mocking modules

jest.mock is hoisted above imports — factory closures can't reference uninitialised local variables:

javascript
// src/user.test.ts
import { jest } from "@jest/globals";
import { fetchUser } from "./api.js";
import { getUserName } from "./user.js";

jest.mock("./api.js");

const mockedFetch = jest.mocked(fetchUser);

beforeEach(() => mockedFetch.mockReset());

test("uppercases name", async () => {
  mockedFetch.mockResolvedValue({ name: "alice" });
  expect(await getUserName(1)).toBe("ALICE");
});

jest.mocked() gives you a typed mock wrapper — much better than casting as jest.Mock.

Sharding across CI runners

yaml
strategy:
  matrix:
    shard: [1, 2, 3, 4]
steps:
  - run: jest --shard=${{ matrix.shard }}/4 --ci

Each runner takes 25% of files; total wall time roughly quartered.

React Testing Library setup

javascript
// jest.config.js
export default {
  testEnvironment: "jsdom",
  setupFilesAfterEach: ["<rootDir>/jest.setup.js"],
};
javascript
// jest.setup.js
import "@testing-library/jest-dom";
javascript
// Button.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Button } from "./Button";

test("calls onClick when clicked", async () => {
  const onClick = jest.fn();
  render(<Button onClick={onClick}>Click me</Button>);
  await userEvent.click(screen.getByRole("button"));
  expect(onClick).toHaveBeenCalledTimes(1);
});

Useful flags

FlagPurpose
--bailStop after the first failure. Cuts CI time when most tests pass.
--maxWorkers=2Cap parallel workers — useful on memory-limited CI runners.
--maxWorkers=50%Half of available cores.
--runInBandDisable parallelism. Sequential. Useful for debugging order-dependent tests.
--silentSuppress console output from tests.
--verbosePrint every test name (good for debugging which test hung).
--clearCacheWipe Jest's transform cache. Try if you get spurious errors after dep upgrades.
--config jest.config.ci.jsUse an alternate config — common for CI-specific overrides.
--reporters=default --reporters=jest-junitMultiple reporters (e.g. JUnit XML for CI dashboards).
--changedSince=mainOnly tests for files changed vs the given ref.

Configuration

Jest loads config from (in order):

  1. jest key in package.json
  2. jest.config.js / .ts / .cjs / .mjs
  3. jest.config.json

Modern TS + React config

javascript
// jest.config.ts
import type { Config } from "jest";

const config: Config = {
  testEnvironment: "jsdom",
  setupFilesAfterEach: ["<rootDir>/jest.setup.ts"],
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest", {
      jsc: { transform: { react: { runtime: "automatic" } } },
    }],
  },
  moduleNameMapper: {
    "\\.(css|less|scss)$": "identity-obj-proxy",
    "^@/(.*)$": "<rootDir>/src/$1",
  },
  testMatch: ["**/__tests__/**/*.test.{ts,tsx}", "**/?(*.)+(spec|test).{ts,tsx}"],
  collectCoverageFrom: ["src/**/*.{ts,tsx}", "!**/*.d.ts"],
};

export default config;

Multi-project (monorepo)

javascript
// jest.config.js (root)
export default {
  projects: [
    "<rootDir>/packages/api",
    "<rootDir>/packages/web",
    "<rootDir>/packages/shared",
  ],
};

Each sub-project has its own jest.config.js. The root aggregates results — coverage and reports merge.

Per-file environment override

javascript
/**
 * @jest-environment jsdom
 */
import { render } from "@testing-library/react";
// ...

Useful when most tests are Node but a handful need a DOM.

Globals via setupFiles vs setupFilesAfterEach

HookWhen
setupFilesBefore Jest globals are available. Use for polyfills only.
setupFilesAfterEachAfter expect, jest, etc. are wired. Use for matcher extensions, global mocks.

Common pitfalls

  1. jest-environment-jsdom not installed (v28+)Cannot find module 'jest-environment-jsdom'. Install it explicitly.
  2. ESM source with CJS JestSyntaxError: Cannot use import statement outside a module. Use @swc/jest or babel-jest, or enable experimental ESM with NODE_OPTIONS=--experimental-vm-modules.
  3. jest.mock reference error — referencing local variables in a jest.mock factory. Use jest.doMock after imports, or inline the value.
  4. Tests pass alone, fail together — global state leaking. Set resetModules: true and clearMocks: true in config.
  5. Jest did not exit one second after the test run — open handle (timer, server, DB pool). Run with --detectOpenHandles to find it.
  6. Watch mode does nothing — non-git directory or no committed git history. Use --watchAll instead.
  7. @swc/jest skips type checking — run tsc --noEmit separately, ideally as a parallel CI step.
  8. Coverage is 0% for some files — they're not imported by any test, OR collectCoverageFrom excludes them, OR they're in testPathIgnorePatterns.

See also