facebook/reactMITd083ec1Report / request removal

Jest Test Infrastructure

React’s Jest infrastructure makes the same tests run against source modules, release-channel variants, and compiled bundles. It combines Jest configuration, setup files, feature-flag inspection, host-config mocking, and internal scheduling assertions.

This exists because React’s behavior depends on both build mode and renderer. The test helpers therefore make asynchronous work, console output, expected failures, and renderer-specific module forks observable and deterministic.

Sources: scripts/jest/config.build.js:57-75, packages/internal-test-utils/ReactInternalTestUtils.js:43-90, packages/internal-test-utils/internalAct.js:42-195, scripts/jest/setupHostConfigs.js:188-213

Core concepts

Release-channel flags

A release-channel flag set is a computed view of build globals, environment state, and feature-flag modules. getTestFlags derives modern, classic, source, www, and fb, while environmentFlags supplies experimental, stable, and other environment values; the result exposes feature flags through a proxy that rejects unknown names.

Sources: scripts/jest/TestFlags.js:56-126, scripts/jest/TestFlags.js:35-54, scripts/jest/TestFlags.js:114-123

Gated test expectations

A gated test condition is either a flag name or a predicate over the flag set. coerceGateConditionToFunction converts a string such as foo into a function that reads flags[foo], while an existing function is used unchanged. When a test is expected to fail, expectTestToFail runs its callback, captures thrown errors and console failures, and throws a Jest failure if nothing went wrong.

Sources: scripts/jest/setupTests.js:235-241, scripts/jest/setupTests.js:181-233

Scheduler assertions

A scheduler assertion compares the expected sequence of logged work with the Scheduler mock’s cleared log. assertLog clears the log, returns when it matches, and otherwise throws a diff.

Sources: packages/internal-test-utils/ReactInternalTestUtils.js:312-325

Internal act scope

The internal act scope is a test-only flush boundary that controls Scheduler work, timers, console assertions, and globally reported errors. act requires the special Scheduler mock and Jest timer mocks, starts after a microtask, and deliberately sets global.IS_REACT_ACT_ENVIRONMENT to false for its outermost scope.

Sources: packages/internal-test-utils/internalAct.js:42-195

Host-config fork

A host-config fork is the renderer-specific implementation selected for a reconciler configuration module. mockAllConfigs derives candidate fork filenames from rendererInfo.shortName, tries progressively shorter names, and loads the first existing candidate.

Sources: scripts/jest/setupHostConfigs.js:188-213

How Jest selects the test world

The source configurations extend a shared base configuration and add environment-specific setup files. The www configuration adds setupTests.www.js and setupHostConfigs.js; the persistent configuration adds setupTests.persistent.js and setupHostConfigs.js; and the xplat configuration adds setupTests.xplat.js and setupHostConfigs.js.

The build configuration redirects imports to compiled bundles through moduleNameMapper, ignores internal test files, excludes build output from transforms, and adds setupTests.build.js. This is the boundary that lets Jest exercise built artifacts rather than only source modules.

ConfigurationMain selectionAdditional setup
Source wwwShared base configuration with www-specific ignored packagessetupTests.www.js, setupHostConfigs.js
Source persistentShared base configuration with persistent-specific ignored testssetupTests.persistent.js, setupHostConfigs.js
Source xplatShared base configurationsetupTests.xplat.js, setupHostConfigs.js
BuildCompiled-bundle module mappingsetupTests.build.js

These configurations explain why setup files are part of the test contract: the selected environment determines both which modules Jest resolves and which initialization code runs before tests.

The flag set determines the active channel from __WWW__ and __EXPERIMENTAL__: Meta builds become modern or classic, while other builds become experimental or stable. It also marks whether the test is running from source using process.env.IS_BUILD.

The gate condition itself may be a string or function, but the shown helper does not hide the result: the string form directly indexes the flags object. Because getTestFlags throws for a missing flag, a misspelled gate name fails loudly instead of silently selecting a channel.

When the gated path expects failure, expectTestToFail treats either a rejected callback or a captured global error as the expected outcome; if the callback completes without error, it throws errorToThrowIfTestSucceeds. This is why a test can be marked as expected to fail when its feature flag is off: success under that channel is itself reported as a failure.

Sources: scripts/jest/config.source-persistent.js:1-23, scripts/jest/config.source-xplat.js:27-32, scripts/jest/config.build.js:57-75, scripts/jest/config.source-www.js:5-17, scripts/jest/TestFlags.js:56-126, scripts/jest/TestFlags.js:35-54, scripts/jest/setupTests.js:235-241, scripts/jest/TestFlags.js:114-123, scripts/jest/setupTests.js:181-233

How internal test utilities control work

waitFor first verifies that no prior Scheduler yields or console logs remain. It waits for a microtask, flushes only enough Scheduler yields to reach the expected sequence, clears those yields, and performs one additional microtask once the expected count is reached.

waitForAll uses the same clean-start requirement, but repeatedly calls SchedulerMock.unstable_flushAllWithoutAsserting until no work remains, then compares the complete cleared log.

The following workflow shows the common partial-versus-complete flushing path.

The workflow answers how an expected Scheduler log becomes an assertion.

Scheduler log flushing — How do test helpers flush and verify scheduled work?

Evidence

assertLog is the immediate form: it clears the Scheduler mock once and compares the result, without waiting or flushing. The separate console helpers assert development logs, warnings, and errors through assertConsoleLogDev, assertConsoleWarnDev, and assertConsoleErrorDev.

Internal act differs from public act() in several deliberate ways. It requires a special mock build of Scheduler and fake timers, inserts an asynchronous gap before invoking the scope, disables React’s act warning environment for its outermost scope, and flushes pending ticks and timers to expose Suspense fallbacks. The timer loop is isolated in waitForTasksAndTimers, which throws if the Jest environment has been torn down, flushes pending ticks and timers while timers remain, and stops once no timers remain.

Errors raised globally during the internal scope are collected in thrownErrors and rethrown after the scope completes; multiple errors are combined by aggregateErrors. This lets DOM error events and Node uncaught exceptions participate in the same deterministic assertion boundary.

Sources: packages/internal-test-utils/ReactInternalTestUtils.js:25-35, packages/internal-test-utils/ReactInternalTestUtils.js:43-90, packages/internal-test-utils/ReactInternalTestUtils.js:92-121, packages/internal-test-utils/ReactInternalTestUtils.js:312-325, packages/internal-test-utils/ReactInternalTestUtils.js:327-331, packages/internal-test-utils/ReactInternalTestUtils.js:332-336, packages/internal-test-utils/ReactInternalTestUtils.js:337-341, packages/internal-test-utils/internalAct.js:42-195, packages/internal-test-utils/internalAct.js:197-228, packages/internal-test-utils/internalAct.js:27, packages/internal-test-utils/internalAct.js:35-40

How renderer forks are mapped

The reconciler and server packages expose five configuration paths through configPaths: the reconciler host config, Flight client config, server stream config, Fizz config, and Flight server config. mockAllConfigs installs a Jest mock for each path and searches under a forks directory using the renderer’s short name.

The mapping is progressive rather than a single exact lookup. For a renderer short name split on hyphens, the helper tries the full joined name, then removes trailing parts until fs.statSync finds an existing candidate; it then returns that candidate with jest.requireActual.

The setup also defines shim paths for the host, server-stream, server, and Flight configurations, while shimFlightClientConfigPath covers the client Flight configuration. These paths identify the module boundaries that Jest replaces before the reconciler imports them.

The following sequence shows the fork-selection hand-off.

The sequence answers how a renderer name reaches the selected host-config implementation.

Host-config fork selection — How does setupHostConfigs select a renderer fork?

Evidence

Entry-point resolution is a related but separate fork mechanism. resolveEntryFork chooses Facebook-specific modern, classic, or generic forks when available, otherwise tries experimental or stable forks, then development and plain entries. For Facebook react-dom entries, it aliases related entry points to the appropriate shared implementation.

Sources: scripts/jest/setupHostConfigs.js:180-186, scripts/jest/setupHostConfigs.js:188-213, scripts/jest/setupHostConfigs.js:137, scripts/jest/setupHostConfigs.js:144, scripts/jest/setupHostConfigs.js:145, scripts/jest/setupHostConfigs.js:146, scripts/jest/setupHostConfigs.js:172, scripts/jest/setupHostConfigs.js:7-99

How it connects

The test configuration connects Jest to Build, Test, and Feature Flags, because the build configuration redirects imports to compiled bundles while getTestFlags exposes channel and build state.

The internal Scheduler assertions connect to Testing with act() and Test Renderer and Scheduler Priorities & Task Queue: the helpers flush mocked work, compare yielded logs, and provide the internal act boundary used by renderer tests.

The renderer mapping connects to Rollup Bundles & Module Forks, because both Jest and the bundle system select renderer-specific fork files from renderer metadata and fork naming conventions.

Sources: scripts/jest/config.build.js:57-75, scripts/jest/TestFlags.js:56-126, packages/internal-test-utils/ReactInternalTestUtils.js:43-90, packages/internal-test-utils/ReactInternalTestUtils.js:92-121, packages/internal-test-utils/internalAct.js:42-195, scripts/jest/setupHostConfigs.js:188-213, scripts/rollup/forks.js:357-378

Key takeaways

  • Jest selects source or built-bundle behavior through configuration-specific setup files and module mapping.
  • getTestFlags derives release-channel state and rejects unknown feature flags.
  • waitFor flushes toward an expected Scheduler sequence; waitForAll flushes until no work remains; assertLog only compares the current log.
  • Internal act adds fake-timer handling, an asynchronous entry gap, and global error collection beyond public act().
  • mockAllConfigs maps each renderer’s short name to the first existing host-config fork.

Want this for your repos?

Try Angada AI Wiki