Skip to content

Choosing an Engine

vitest-native ships two engines behind one plugin, so you choose the fidelity each suite needs. This is the core idea of the project — pick real-RN fidelity or a fast mock per suite, without changing test runners.

The two engines

ts
reactNative()                      // default — real React Native (native), when its babel deps are present
reactNative({ engine: 'native' })  // force real React Native; mock only the native boundary
reactNative({ engine: 'mock' })    // opt in to the fast pure-JS mock
reactNative({ engine: 'auto' })    // the default — native when available, else mock (with a one-line notice)

reactNative() with no options resolves to native whenever @react-native/babel-preset and @babel/core are present (i.e. any real RN app), falling back to mock only when they're absent.

engine: 'native' — real React Native

Runs real React Native JavaScript — the same code that ships in your app — and mocks only the thin native boundary (native modules, UIManager, and the native host-component registry; the View/Text/ScrollView component JS runs for real). Jest's preset mocks a superset of this — see where the boundary sits.

Reach for it when you want:

  • Fidelity — accessibility behavior, RN-API semantics, and component internals that a mock can drift away from.
  • Integration confidence — testing how your components actually compose with real RN.
  • No mock drift — you're testing RN itself, not a reimplementation of it.

It Flow-strips real React Native through your project's Babel preset — the toolchain RN already uses — so it needs @react-native/babel-preset + @babel/core (present in every RN app).

engine: 'mock' — fast pure-JS

A fast, zero-dependency pure-JS reimplementation of React Native. Mocks all of React Native.

Reach for it when you want:

  • Pure-logic suites — testing reducers, hooks, and view logic where you don't need real RN.
  • Environment control — full control over platform, dimensions, color scheme, and native modules.
  • Maximum determinism — no real RN internals, no Babel, just Vite.

The mock engine covers 100% of React Native's stable public API and needs no Babel.

Side by side

engine: 'native' (default)engine: 'mock'
What runsReal React Native JSFast pure-JS reimplementation
MocksOnly the native boundaryAll of React Native
FidelityHighestHigh, but a reimplementation
Babel@react-native/babel-preset + @babel/coreNone
Best forFidelity, integration, accessibilityPure logic, environment control, determinism
Test APIRNTL, helpers, presetsRNTL, helpers, presets

Both engines share the same test API. You can mix them across suites in the same project.

Keeping the mock honest

Because the mock is a reimplementation, it could drift from real RN behavior. A CI-gated behavioral cross-check runs the same assertions against both the mock and real RN across React Native 0.81–0.85, so divergences are caught before release. See Comparison with Jest for how that trust mechanism works.

Hot runtime (experimental)

For large suites under the native engine, an opt-in hot runtime keeps React Native warm across files while resetting app/test modules and common process-wide pollution between files:

ts
reactNative({ hotRuntime: true })

It uses Vitest's custom worker APIs and remains experimental. Leave it off unless you're testing it.

Next: How It Works explains what the plugin does under the hood.

Released under the MIT License.