skip to content

Runner Preset & Transforms

The react-native Jest preset wires Babel transforms, a Node test environment and native mocks, while transformIgnorePatterns picks which packages compile. Interviewers ask why a library breaks tests.

part ofReact Nativeoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In a React Native 0.87 app, what does @react-native/jest-preset configure, and why can't plain Jest run React Native code?

level: juniorimportance: must knowfreq 55%

answer

  1. Flow, JSX and TypeScript need compiling
  2. node_modules allowlist for react-native
  3. image requires become testUri stubs
  4. setup file: __DEV__ plus core mocks
  5. separate package since 0.85

basics

~10 s

@react-native/jest-preset makes Jest able to load React Native code: it compiles JS and TS through babel-jest, transforms React Native's own untranspiled packages, stubs image requires, uses a Node-based environment and mocks core native modules.

solid answer

~40 s

React Native ships its JavaScript as untranspiled source (Flow types, JSX, ES modules) and expects native modules that only exist on a device, so plain Jest either fails to parse it or crashes calling native code. The preset, a separate package `@react-native/jest-preset` since 0.85, fixes both: `transform` runs `.js`, `.ts` and `.tsx` through `babel-jest` and image files through a stub transformer; `transformIgnorePatterns` lets `react-native` and `@react-native/*` packages be compiled; `setupFiles` loads a script that defines `__DEV__`, `requestAnimationFrame` and friends and mocks core modules such as `Linking`, `AppState` and `NativeModules`; `testEnvironment` is its Node-based `react-native-env`. In 0.87 you install it and set `preset: '@react-native/jest-preset'`.

code

javascript · 4 lines
javascript
// jest.config.js
module.exports = {
  preset: '@react-native/jest-preset',
};

go deeper

for a junior

Recall that React Native code needs compiling and native mocks before Jest can run it, and that the preset is the package @react-native/jest-preset set in jest.config.js.

for a middle

Walk through the preset's keys: babel-jest transform, the node_modules allowlist in transformIgnorePatterns, the setup file with globals and core mocks, and the Node-based react-native-env.

for a senior

Use the preset's boundaries to triage failures: parse errors mean an untranspiled dependency, crashes in native calls mean a missing mock, device-only behaviour means the test is at the wrong layer.

for a principal

Treat the preset as a pinned dependency that moves with each React Native upgrade, and decide how much native behaviour a team may trust from Node-side tests before paying for device runs.

## Why plain Jest cannot run React Native code Jest is a test runner for JavaScript that executes in **Node.js**. A React Native app is written for a very different host: Metro bundles it, Hermes runs it on the phone, and the framework's components talk to native iOS and Android code. Two things break when you point an unconfigured Jest at a React Native project: 1. **Syntax.** The `react-native` package and many `@react-native/*` packages are published as source that still contains Flow type annotations, JSX and `import`/`export` statements. Node's module loader inside Jest cannot parse that, and Jest by default does **not** transform anything under `node_modules`. 2. **Native dependencies.** Core modules such as `Linking`, `AppState`, `Vibration` or the view manager expect a native implementation. In Node there is no device, so calling them without a mock throws. The **Jest preset** is a ready-made bundle of Jest configuration that solves both problems so that a component test can simply `import { View } from 'react-native'`. ## What the preset configures The preset is published as **`@react-native/jest-preset`**. React Native 0.85 moved it out of the `react-native` package, and the 0.87 release notes say it must now be consumed as that package, so `preset: 'react-native'` no longer resolves. Its `jest-preset.js` sets these keys: | Key | Value in the preset | Why it matters | |---|---|---| | `transform` | `.js`, `.ts`, `.tsx` through `babel-jest`; image and video files through an asset transformer | Your code and React Native's source get compiled with your Babel config | | `transformIgnorePatterns` | `node_modules/(?!((jest-)?react-native\|@react-native(-community)?)/)` | Everything in `node_modules` is skipped **except** `react-native`, `jest-react-native` and the `@react-native/` and `@react-native-community/` scopes | | `setupFiles` | the preset's `jest/setup.js` | Globals and core mocks exist before any test file loads | | `testEnvironment` | `jest/react-native-env.js` | A Node environment with React Native export conditions, not a browser DOM | | `haste` | `defaultPlatform: 'ios'`, platforms `android`, `ios`, `native` | Platform-specific files such as `Button.ios.tsx` resolve in tests | | `moduleNameMapper` and `resolver` | map `react-native` subpaths to the installed package | Deep paths such as the `Libraries/...` modules can still be resolved and mocked | ## What the setup file does The file listed in `setupFiles` runs once per test file, before the test code. It: - sets `__DEV__` to `true` and `IS_REACT_ACT_ENVIRONMENT` to `true`; - defines `requestAnimationFrame` on top of `setTimeout` and `performance.now` as a Jest mock of `Date.now`; - makes `window` an alias of the Node global object; - registers mocks for core modules and components, among them `AppState`, `AccessibilityInfo`, `Clipboard`, `Image`, `Linking`, `Modal`, `ScrollView`, `Text`, `TextInput`, `View`, `UIManager`, `NativeModules` and `Vibration`. The asset transformer turns `require('./logo.png')` into an object with a `testUri` field holding the file's relative path, so snapshots show which image a component asked for instead of failing on binary data. ## Installing it in React Native 0.87 1. Install the package as a dev dependency at the same version as `react-native` (the package is versioned in lockstep, for example 0.87.1). 2. Point Jest at it in `jest.config.js` with `preset: '@react-native/jest-preset'`. 3. Keep a `babel.config.js` that uses `@react-native/babel-preset`, because `babel-jest` reads the project's Babel configuration. 4. Add your own options on top: extra `setupFiles`, a widened `transformIgnorePatterns`, `setupFilesAfterEnv` for matcher libraries. Projects created with Expo usually use the `jest-expo` preset instead, which Expo's docs describe as mocking the native part of the Expo SDK and handling most of the configuration an Expo project needs. ## What the preset does not do - It does **not** run your code on a device or simulator: rendering happens in Node, so real layout, gestures and native behaviour are not exercised. - Its native mocks cover **core** React Native modules. Third-party native libraries bring their own Jest mocks or need one written for them. - It does **not** type-check TypeScript: Babel strips types and moves on. - It does not choose a component testing library; React Native Testing Library is added separately. Knowing this boundary is what lets you explain a failing test: a syntax error in a dependency points at `transformIgnorePatterns`, a crash inside a native call points at a missing mock, and a behaviour that only shows on a phone belongs to a device-level test.

  • In a React Native project with Button.ios.tsx and Button.android.tsx, which file does a Jest test import under the preset?
    The preset's `haste` block sets `defaultPlatform: 'ios'` with the platforms `android`, `ios` and `native`, so an import of `./Button` resolves `Button.ios.tsx`. Testing the Android variant needs its own configuration, for example a second Jest project with a different default platform, or importing the Android file directly.
  • Does an Expo project use @react-native/jest-preset directly?
    Usually not. Expo documents the `jest-expo` preset, which builds a Jest configuration for Expo projects and mocks the native part of the Expo SDK. You still widen `transformIgnorePatterns` the same way when a dependency ships untranspiled code.
  • Why does the preset map image requires to an object with testUri instead of a number?
    In a Metro bundle an image `require` returns an asset registry id, but Jest has no asset registry. The preset's asset transformer replaces the file with `{ testUri: '<relative path>' }`, so the component still receives a value and snapshots record which image was requested.

The preset is a travel adapter kit for running phone code on a laptop: a plug converter for the syntax (Babel), a list of which bags get unpacked (the node_modules allowlist) and stand-in appliances for the sockets that do not exist here (core native mocks).

saying these in an interview costs you the question

  • The preset runs the tests on an iOS simulator or Android emulator
  • The preset mocks every third-party native module automatically
  • In React Native 0.87 you still write preset: 'react-native'
  • babel-jest in the preset type-checks the TypeScript tests
  • The preset renders components into a jsdom document
open as a page

In a React Native app's Jest suite, why does a calendar's untranspiled date library fail on import statements, and how do you fix it?

level: middleimportance: must knowfreq 60%

basics

~10 s

Jest skips transforming files that match transformIgnorePatterns, and the React Native preset only allowlists react-native and @react-native packages, so an ESM date library reaches Node untranspiled. Add the package to the same negative-lookahead regex.

open as a page

In a React Native TypeScript project using @react-native/jest-preset, how are .tsx tests compiled, and why don't type errors fail the run?

level: middleimportance: should knowfreq 35%

basics

~10 s

The preset sends .js, .ts and .tsx files to babel-jest, which applies the project's Babel config with @react-native/babel-preset; its TypeScript plugin strips types without checking them, so type errors need a separate tsc run.

open as a page

After upgrading a React Native app from 0.84 to 0.87, Jest cannot find the react-native preset; what changed, and what else must you recheck in the config?

level: seniorimportance: should knowfreq 28%

basics

~10 s

React Native 0.85 moved the Jest preset into @react-native/jest-preset and 0.87 requires consuming it from there. Install it at the matching version, change preset, and fix custom config that still points at react-native/jest paths.

open as a page

Why does React Native's Jest preset run tests in its Node-based react-native-env instead of jsdom, and what does that change?

level: middleimportance: nice to knowfreq 22%

basics

~20 s

React Native renders native views, not DOM nodes, so a browser DOM would give tests APIs the app never has. The preset's react-native-env extends Jest's Node environment and resolves packages with the react-native export condition.

open as a page