mrkeyoor.com_
Sat 19 Sept 21:39 UTC
npmTestingupdated 19 Sept 2026

jest review

Jest 30.4.2 is a Node test system that packages discovery, isolation, assertions, spies, module mocks, fake clocks, snapshots, coverage, watch mode, and parallel workers behind one CLI. That integrated model still suits established React, React Native, and Node suites, especially when their tests depend on Jest-specific mocks or serializers. Version 30.4 rewrites the custom module runtime, adds discovery through `--collect-tests`, accepts `.mts` and `.cts` for coverage, supports React 19 snapshot formatting, and exposes a worker shutdown timeout. Patch 30.4.2 fixes named imports from CommonJS modules whose exported function also owns properties. Our install confirms that convenience arrives with a large Node-only dependency graph.

42.2Mdownloads / wk
Verdict

Jest 30.4.2 took 16 seconds, installed 264 packages using 48 MB, printed 3 deprecation warnings, and returned 0 audit findings in our sandbox. Keep it where Jest-specific mocks and presets already pay that cost; start a new Vite-first project with Vitest unless a Jest-only integration decides the choice.

We installed it

Lab card: what happened when we installed jestScreenshot of jest documentation
Install✓ · 16s264 packages on disk · 48 MB · 3 deprecation warnings
ImportESM import works · require() works · CommonJS package with exports map
Browsern/acould not be bundled for the browser (Node-only code, most likely)
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does jest install cleanly?

Yes. In a fresh container with an empty cache, npm install jest finished in 16 seconds, leaving 264 packages and 48 MB on disk. npm audit reported no known vulnerabilities. The install printed 3 deprecation warnings.

Can jest run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does jest work with both ESM and CommonJS?

Yes. Both import 'jest' and require('jest') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does jest include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

jest or vitest: which should you use?

vitest: Use it for Vite-native transforms, ESM-first projects, and an API deliberately close to Jest's common test style. Jest 30.4.2 took 16 seconds, installed 264 packages using 48 MB, printed 3 deprecation warnings, and returned 0 audit findings in our sandbox.

When should you not use jest?

The application is built around Vite. Jest's own README says Vite's plugin system is not fully supported, while Vitest reads the Vite configuration directly.

API stability4/5Ordinary suites still use the familiar `describe`, `test`, `expect`, `jest.fn`, `jest.mock`, lifecycle hooks, and snapshot matchers across major releases. Module semantics are the less stable edge. Version 30.4 replaced much of Jest's custom runtime, 30.4.1 changed CommonJS default-export handling to match Node, and 30.4.2 patched named imports from a particular callable CommonJS export shape. ESM module mocking still carries an `unstable` API name.
Docs5/5The official site has separate guides and references for matchers, asynchronous tests, mocks, snapshots, timers, configuration, CLI flags, transforms, webpack, ESM, TypeScript, and migration. The ESM page states its experimental status and startup flag near the instructions. The README also admits that Vite is not fully supported and that Babel does not type-check TypeScript. Those direct limits make the documentation more useful than an optimistic quick start alone.
Maintenance5/5GitHub reported 45,474 stars, 184 open issues and pull requests, an unarchived repository, and a push on August 25, 2026. Release 30.4.0 shipped a broad runtime rewrite plus React 19 formatting, worker shutdown configuration, new coverage extensions, and test-only discovery. Two patches followed within 2 days to adjust CommonJS and ESM interop. The quick fixes are reassuring, while the release note's regression warning is a reason to pin and test upgrades.
Ecosystem5/5npm recorded 47,303,993 Jest downloads in the week ending August 25, 2026. React Native presets, Testing Library matchers, snapshot serializers, IDE adapters, reporters, and TypeScript integrations already understand Jest conventions. That reach lowers migration pressure in old repositories. It does not settle the choice for new frontend code: Jest's README documents incomplete Vite support, and Vitest has become the closer fit when Vite owns source transformation.

Use it if

  • An existing suite already relies on `jest.mock`, Jest snapshots, custom matchers, presets, or watch plugins.
  • A Node or React project wants one tool family to supply assertions, mocks, fake timers, coverage, discovery, and reporting.
  • CommonJS modules need deep replacement and call inspection through `jest.fn()` or `jest.spyOn()`.
  • A monorepo needs multiple project configurations with one command and a combined report.
Skip it if

Setup reality

We installed Jest 30.4.2 in a fresh Node 22 Bookworm container. npm needed 16 seconds, installed 264 packages, used 48 MB, and printed 3 deprecation warnings. npm audit found 0 known vulnerabilities. The top-level package declares 4 direct dependencies and 1 peer dependency and is 40 KB unpacked. Bundled types are present. Supported Node versions are ^18.14, ^20, ^22, and 24 or newer.

The package is CommonJS with an exports map; require() and ESM import both worked in our sandbox. An esbuild browser bundle failed because Jest is a Node CLI with filesystem and worker assumptions. DOM tests need jest-environment-jsdom installed separately and selected in configuration. jsdom gives tests browser-like globals, yet it cannot validate actual layout, painting, or all browser security behavior. Use Playwright or another browser runner for those claims.

Source transformation creates most setup mistakes. Babel can handle JavaScript, JSX, and TypeScript syntax, but its TypeScript preset removes types without checking them. Keep tsc --noEmit in CI or choose a transformer whose checking behavior you understand. ESM projects still follow Jest's experimental VM-module path and must register jest.unstable_mockModule() before dynamically importing the subject. The new jest.config.mts support only covers configuration parsing; it does not turn ESM mocking into CommonJS hoisting.

Parallel workers have isolated module registries, while ports, databases, files, and remote services remain shared. Allocate those resources per worker or cap maxWorkers when CI memory and service limits are tight. Restore spies and real timers after each test. Close servers and database pools in afterAll. --detectOpenHandles is useful for a hanging suite, but it adds enough overhead that it should stay a diagnostic command rather than the default test script.

Patterns

Test a pure function assert-sync-result

import { describe, expect, test } from '@jest/globals';
import { subtotal } from './subtotal.js';

describe('subtotal', () => {
  test('adds prices', () => {
    expect(subtotal([120, 80])).toBe(200);
  });
});

Explicit imports work when Jest globals are disabled and give TypeScript a clear source for the test API.

Wait for a rejected promise assert-async-rejection

test('rejects an expired session', async () => {
  await expect(loadSession('expired')).rejects.toThrow('expired');
});

Keep the `await`. Without it, the test may finish before the rejection matcher runs.

Exercise several input rows run-table-cases

test.each([
  [0, 0, 0],
  [4, 7, 11],
  [-3, 3, 0],
])('add(%i, %i) returns %i', (a, b, expected) => {
  expect(add(a, b)).toBe(expected);
});

Each failed row prints its 3 values, which is clearer than a hand-written loop with one generic assertion location.

Record calls with jest.fn inspect-callback-calls

test('reports saved invoice IDs', () => {
  const report = jest.fn();
  saveInvoices([{ id: 12 }, { id: 19 }], report);

  expect(report).toHaveBeenCalledTimes(2);
  expect(report).toHaveBeenNthCalledWith(2, 19);
});

Assert the call that carries behavior. A snapshot of the entire `mock.calls` array tends to preserve irrelevant details.

Replace a CommonJS module mock-commonjs-dependency

jest.mock('./mailer.js', () => ({
  send: jest.fn().mockResolvedValue({ id: 'mail-1' }),
}));

const { send } = require('./mailer.js');
const { register } = require('./register.js');

Jest hoists this CommonJS mock. Native ESM requires `jest.unstable_mockModule()` before a dynamic import.

Undo a Date.now spy restore-method-spy

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

test('uses the current timestamp', () => {
  jest.spyOn(Date, 'now').mockReturnValue(1_700_000_000_000);
  expect(makeStamp()).toBe('1700000000000');
});

`restoreAllMocks()` reinstalls original methods. `clearAllMocks()` only clears history and leaves replacements active.

Run delayed promise work advance-fake-clock

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

test('retries after one second', async () => {
  jest.useFakeTimers();
  const result = retryOnce(fetchValue);
  await jest.advanceTimersByTimeAsync(1_000);
  await expect(result).resolves.toBe('ok');
});

The async advance method lets queued promises settle between timer callbacks. Real timers must be restored for later tests.

Keep volatile data out of a snapshot snapshot-stable-fields

test('formats invoice lines', () => {
  const invoice = buildInvoice(order);
  expect({
    currency: invoice.currency,
    lines: invoice.lines,
    total: invoice.total,
  }).toMatchSnapshot();
});

Exclude generated IDs and timestamps. Review the diff from `jest -u` instead of accepting a full replacement without inspection.

Close a test server manage-suite-resource

let server;

beforeAll(async () => {
  server = await startTestServer();
});

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

Files can run in separate workers, but TCP ports are shared. Allocate a unique port or serialize suites that use the same one.

Use jsdom for DOM APIs configure-dom-environment

// jest.config.mjs
export default {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/test/setup.js'],
};

Install `jest-environment-jsdom` separately. It simulates DOM APIs but does not calculate real browser layout or paint.

Count files with no tests enforce-coverage-floor

// jest.config.mjs
export default {
  collectCoverageFrom: ['src/**/*.{js,ts}', '!src/**/*.d.ts'],
  coverageThreshold: {
    global: { lines: 85, branches: 80 },
  },
};

`collectCoverageFrom` keeps untouched source files in the denominator. Set the 85 and 80 values from your current baseline.

Reduce parallelism in CI cap-ci-workers

{
  "scripts": {
    "test:ci": "jest --maxWorkers=50% --ci"
  }
}

A 50% cap can lower memory and database contention. Measure elapsed time because fewer workers may lengthen the run.

Alternatives

PackageRegistryPick it when
vitestnpmUse it for Vite-native transforms, ESM-first projects, and an API deliberately close to Jest's common test style.
mochanpmUse it when the team wants a runner and prefers selecting assertions, spies, transpilation, and coverage independently.
avanpmUse it for isolated concurrent tests with explicit imports and a smaller, opinionated test API.

More testing guides

pytest · chai · vitest · jsdom · playwright · coverage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.