# Testing signals — vercel/next.js

> Canonical page: https://codevetter.com/unpack/nextjs/testing-signals

# Testing signals — vercel/next.js

Scanned commit 2861a364fcbe75fe96b0b9127f9b335edfcf288c (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Jest 29 is the single test runner for JS, configured through `next/jest` itself (dogfooding) in the root `jest.config.js`, with `rootDir: 'test'` plus extra roots into `packages/next/src`, `packages/next-codemod`, `packages/font/src`, `packages/next-routing`, and `packages/eslint-plugin-internal`. Integration coverage is very large — roughly 1183 test files in `test/e2e`, 375 in `test/production`, 314 in `test/development`, 116 in `test/unit` — and every one of them runs under a mode × bundler × experimental-axis matrix selected by env vars in `scripts/run-jest.sh`. Rust has its own lane (`test-cargo-unit`, `test-cargo-unit-miri`, `rust-check`, `rustdoc-check`) in CI. The notable gap is that the harness itself, the CI orchestration in `run-tests.js`, and the deploy mode are lightly covered by anything other than running them.
- `jest.config.js` is built from `nextJest()` — the framework tests itself through its own `next/jest` transformer — and then wrapped by `withGateTransformer(await createConfig())` so the `@gate` pragma rewrite chains in front of next/jest's SWC transform rather than replacing it. — [jest.config.js#L1-L10](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/jest.config.js#L1-L10) [jest.config.js#L70-L90](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/jest.config.js#L70-L90) [test/lib/gate/jest-transformer.js](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/gate/jest-transformer.js)
- The test matrix is expressed purely as environment variables: `scripts/run-jest.sh` maps `--mode` to `NEXT_TEST_MODE`, `--bundler` to `IS_WEBPACK_TEST` / `IS_TURBOPACK_TEST` / `NEXT_RSPACK`+`NEXT_TEST_USE_RSPACK`, `--experimental` to `__NEXT_CACHE_COMPONENTS=true`, and `--headless` to `HEADLESS=true`, then `exec jest --runInBand`. — [scripts/run-jest.sh#L17-L56](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/scripts/run-jest.sh#L17-L56) [scripts/run-jest.sh#L96-L100](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/scripts/run-jest.sh#L96-L100)
- `__NEXT_TEST_AXIS` implements a lettered flag-matrix dimension: setting the axis implies `__NEXT_CACHE_COMPONENTS=true` and vice-versa, and a fixture opts in by keying a flag on it (`concurrentRouterQueue: process.env.__NEXT_TEST_AXIS !== 'A'`) paired with a `// @gate concurrentRouterQueue` on affected tests. — [scripts/run-jest.sh#L58-L94](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/scripts/run-jest.sh#L58-L94) [test/lib/gate/README.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/gate/README.md)
- The `@gate` registry has two tiers: `staticCondition` (run mode, bundler, React version — known at collection time and the only kind `@force-gate` accepts) and `lazyCondition` (a predicate over the fixture's *resolved* `next.config` read inside the test body); an undeclared condition name fails the whole suite at collection time, so typos cannot silently disable a gate. — [test/lib/gate/conditions.ts#L1-L70](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/gate/conditions.ts#L1-L70) [test/lib/gate/resolved-config.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/gate/resolved-config.ts)
- `nextTestSetup()` in `test/lib/e2e-utils/index.ts` is the mandated entry point; it internally calls `createNext()` (explicitly documented as not for direct test use), builds a `NextInstance` from one of `NextDevInstance` / `NextStartInstance` / `NextDeployInstance`, and returns a `Proxy<NextInstance>` so the instance can be referenced before it exists. — [test/lib/e2e-utils/index.ts#L267-L347](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/e2e-utils/index.ts#L267-L347) [test/lib/e2e-utils/index.ts#L384-L470](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/e2e-utils/index.ts#L384-L470)
- Test timeouts are enforced by proxying jest's `it`/`test`: `wrapJestTestFn` injects a 60s `individualTestTimeout` when a test supplies no explicit timeout, while setup hooks get a longer 120s (240s on win32) budget overridable by `NEXT_E2E_TEST_TIMEOUT`. — [test/lib/e2e-utils/index.ts#L26-L76](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/e2e-utils/index.ts#L26-L76)
- `retry()` in `test/lib/next-test-utils.ts` is the sanctioned wait primitive and `check()` still exists at line 844 but is deprecated by project convention — new tests are required to use `retry()` + `expect()`. — [test/lib/next-test-utils.ts#L844](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/next-test-utils.ts#L844) [test/lib/next-test-utils.ts#L926](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/next-test-utils.ts#L926) [AGENTS.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/AGENTS.md)
- Integration tests install a real tarball rather than symlinking: `NextInstance` calls `createNextInstall(...)` from `test/lib/create-next-install.js`, and `test/lib/pnpm-security-settings.js` copies `blockExoticSubdeps` / `minimumReleaseAge` from `pnpm-workspace.yaml` into the isolated fixture dir. — [test/lib/next-modes/base.ts#L10](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/next-modes/base.ts#L10) [test/lib/next-modes/base.ts#L402](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/next-modes/base.ts#L402) [pnpm-workspace.yaml#L20-L30](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/pnpm-workspace.yaml#L20-L30) [test/lib/pnpm-security-settings.js](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/pnpm-security-settings.js)
- Deploy mode shells out: `NextDeployInstance` runs `execa(process.env.NEXT_TEST_DEPLOY_SCRIPT_PATH)` and expects the deployment URL on stdout, with separate logs and cleanup scripts — so `pnpm test-deploy` needs external credentials and cannot run hermetically. — [test/lib/next-modes/next-deploy.ts#L66-L190](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/next-modes/next-deploy.ts#L66-L190)
- `run-tests.js` (1164 lines) is the CI orchestrator, not jest: it reads/writes test timings to Vercel KV (`@vercel/kv`, `KV_TIMINGS_KEY = 'test-timings'`), applies `getTestFilter()`, defaults to `DEFAULT_CONCURRENCY = 2` and `DEFAULT_NUM_RETRIES = 2`, and emits `##[group]` markers when `CI` is set. — [run-tests.js#L1-L220](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/run-tests.js#L1-L220) [turbo.json#L28-L33](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/turbo.json#L28-L33)
- Bundler-specific expected-failure lists are checked-in manifests — `test/rspack-build-tests-manifest.json`, `test/rspack-dev-tests-manifest.json`, `test/cache-components-tests-manifest.json`, `test/deploy-tests-manifest.json` — maintained by `test/update-bundler-manifest.js`, so 'known failing under rspack' is data, not a skip. — [test/cache-components-tests-manifest.json](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/cache-components-tests-manifest.json) [test/rspack-build-tests-manifest.json](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/rspack-build-tests-manifest.json) [test/update-bundler-manifest.js](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/update-bundler-manifest.js)
- JUnit reporting is opt-in via `NEXT_JUNIT_TEST_REPORT` and routes output to a bundler-specific directory (`turbopack-test-junit-report`, `rspack-test-junit-report`, or `test-junit-report`), deliberately not counting retries so flaky-but-passing tests still report as failed. — [jest.config.js#L45-L70](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/jest.config.js#L45-L70)
- Unit tests are colocated with source and run separately: `pnpm test-unit` targets `test/unit/`, `packages/next/`, and `packages/font`, picking up files like `packages/next/src/server/is-private-ip.test.ts`, `config.test.ts`, `load-manifest.test.ts`, and `patch-fetch.test.ts`. — [package.json#L22](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/package.json#L22) [packages/next/src/server/is-private-ip.test.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/is-private-ip.test.ts) [packages/next/src/server/lib/patch-fetch.test.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/lib/patch-fetch.test.ts)
- CI runs a distinct lint/type lane separate from tests: `pnpm lint` parallelises `test-types`, `lint-typescript`, `prettier-check`, `lint-eslint`, `lint-ast-grep`, `lint-language` (alex), and `check-unused-turbo-tasks`, plus a `types-and-precompiled` job that also type-checks every `crates/next-custom-transforms/tests/fixture/**/tsconfig.json`. — [package.json#L86-L100](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/package.json#L86-L100) [.github/workflows/build_and_test.yml#L236-L290](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/.github/workflows/build_and_test.yml#L236-L290)
- `createRouterAct` / `LinkAccordion` exist as a dedicated harness for deterministically controlling prefetch timing in router tests (`test/lib/router-act.ts`), which is the documented way to avoid flakiness from BFCache-triggered re-prefetches. — [test/lib/router-act.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/router-act.ts) [.agents/skills/router-act/SKILL.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/.agents/skills/router-act/SKILL.md) [AGENTS.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/AGENTS.md)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
