Open-Source Wikis

/

Next.js

/

How to contribute

/

Testing

vercel/next.js

Testing

The Next.js test pyramid has four tiers: unit, development-mode integration, production-mode integration, and end-to-end. They run via Jest with a custom orchestrator at scripts/run-jest.sh plus run-tests.js.

The test matrix

Mode Bundler Command Used for
dev Turbopack pnpm test-dev-turbo <path> Default. Dev server with Turbopack
dev webpack pnpm test-dev-webpack <path> Dev server with webpack
dev rspack pnpm test-dev-rspack <path> Dev server with rspack
start Turbopack pnpm test-start-turbo <path> Production build + start with Turbopack
start webpack pnpm test-start-webpack <path> Production build + start with webpack
start rspack pnpm test-start-rspack <path> Production build + start with rspack
deploy webpack pnpm test-deploy <path> Vercel deploy mode
unit n/a pnpm test-unit Pure-Node unit tests under test/unit/
headless current pnpm testheadless <path> Skip rebuild; reuse current dist/

Each test mode is exposed both as a top-level test-* (with rebuild + headless) and a testonly-* (skip rebuild). Use testheadless for the fastest single-test iteration.

Where tests live

Directory Purpose
test/unit/ Pure-Node unit tests; no browser, fastest
test/development/ Dev-server scenarios
test/production/ Build + start scenarios
test/e2e/ End-to-end browser tests via Playwright Chromium
test/integration/ Older integration suite that predates test/e2e/
test/lib/ Shared test helpers (next-test-setup, next-test-utils)

The big test suite that exercises the App Router lives at test/e2e/app-dir/. The Pages Router e2e suite lives at test/e2e/.

Generating new tests

Use the test generator — it's mandatory rather than optional:

# Interactive
pnpm new-test

# Non-interactive (for agents and scripts)
# pnpm new-test -- --args <appDir> <name> <type>
# appDir: true | false
# name: kebab-case name
# type: e2e | production | development | unit
pnpm new-test -- --args true my-feature e2e

The generator creates a fixture directory with the right shape (app/page.tsx, next.config.js, package.json, etc.) and a *.test.ts skeleton under the chosen suite directory. Driven by turbo gen test from turbo/generators/.

Test conventions

Use real fixture directories, not inline files

// Good
const { next } = nextTestSetup({
  files: __dirname, // points at the fixture directory next to this test file
});

// Avoid
const { next } = nextTestSetup({
  files: {
    'app/page.tsx': `export default function Page() { ... }`,
  },
});

The pnpm new-test generator follows the first pattern.

Use retry() from next-test-utils, not setTimeout

// Good
import { retry } from 'next-test-utils';

await retry(async () => {
  const text = await browser.elementByCss('p').text();
  expect(text).toBe('expected value');
});

// Bad — flaky and slow
await new Promise((resolve) => setTimeout(resolve, 1000));

check() is deprecated

The legacy check() helper has been replaced by retry() + expect(). Do not use check() in new tests.

Mode-specific tests

Tests that only apply in one mode need skipStart: true plus a manual next.start() in beforeAll after a mode check. The nextTestSetup helper accepts this.

Don't rely on exact log messages

Filter by content patterns (regex match, includes) rather than asserting an exact equality. Look for sequences ("did the system reach this state and then this state?") not positions.

Snapshot tests vary by env flags

If your test uses inline snapshots:

  • Update them with the exact env vars the failing CI job uses — they are listed in pr-status output under "Job Environment Variables" and in .github/workflows/build_and_test.yml.
  • Watch out for Turbopack-vs-webpack divergence: Turbopack resolves react-dom/server.edge (no renderToPipeableStream) while webpack resolves the .node build (has it). The same test can produce different stacks in each.

Cache components implies PPR

When __NEXT_CACHE_COMPONENTS=true, most app-dir pages use PPR implicitly. The dedicated ppr-full/ and ppr/ test suites are mostly describe.skip while migrating to cache components. To validate PPR codepaths, run regular app-dir e2e tests with __NEXT_CACHE_COMPONENTS=true.

Router act tests

Tests that need to control the timing of internal Next.js requests (such as prefetches) use createRouterAct and LinkAccordion from the test lib. Never use browser.back() to return to a page where accordion links are visible — BFCache will restore state and trigger uncontrolled re-prefetches. The agent skill router-act documents the patterns in detail.

Analyzing output efficiently

Don't re-run the same test with different greps. Capture once, analyze repeatedly:

HEADLESS=true pnpm test-dev-turbo test/path/to/test.ts > /tmp/test-output.log 2>&1

grep "" /tmp/test-output.log            # failed test names
grep -A5 "Error:" /tmp/test-output.log   # error details
tail -5 /tmp/test-output.log             # summary

Quick smoke testing

For fast feedback on a hang or crash, generate a minimal fixture and run the dev server directly:

pnpm new-test -- --args true probe e2e
node packages/next/dist/bin/next dev --port 3000 test/e2e/probe
curl --max-time 10 http://localhost:3000

This bypasses the full test harness and surfaces errors immediately.

Reproducing CI failures locally

CI matrix and env vars matter. Match them exactly:

CI env Effect
IS_WEBPACK_TEST=1 Forces webpack
IS_TURBOPACK_TEST=1 Forces Turbopack
NEXT_SKIP_ISOLATE=1 Skip packing; module-resolution bugs hide
__NEXT_CACHE_COMPONENTS=true Cache components on, PPR implicit

For module-resolution work, drop NEXT_SKIP_ISOLATE so the test installs Next.js as a real package.

Stable vs flaky

The repo maintains a "Known Flaky Tests" list (used by scripts/pr-status.js) but the rule is:

Assume failures are real until disproven. Use the flaky list as context, not auto-dismissal.

If you are confident a failure is flaky, you can re-run via .github/workflows/retry_test.yml — but spend time verifying first.

Test setup files

File Role
test/jest-global-setup.ts Global setup that runs once
test/jest-setup-after-env.ts Per-test-file setup; loads matchers and env
jest.config.js Jest config for webpack/dev/start runs
jest.config.turbopack.js Turbopack-specific Jest config
test/lib/next-test-setup.ts The nextTestSetup helper used by every integration test
test/lib/next-test-utils.ts retry(), helpers for waiting, fetching, asserting

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Testing – Next.js wiki | Factory