# vitest-native > Run your React Native tests under Vitest, against real React Native — the same JavaScript that ships in your app, mocking only the native-module boundary. That's the zero-config default. A fast pure-JS mock engine is available as an opt-in for RN-free unit tests. One plugin gives you both. Maintained successor to vitest-community/vitest-react-native, rebuilt for Vitest 5. ## Core idea Two engines behind one plugin (`reactNative()`), so you choose the fidelity each suite needs: - `engine: 'native'` (what the default `auto` resolves to in any RN or Expo app): runs real React Native JS, mocking only the thin native boundary: native modules and native host components. Jest's React Native preset mocks more than that (it also swaps View, Text, ScrollView, Image and Modal for stand-ins; both replace TextInput), so the real component JavaScript runs here. Needs `@react-native/babel-preset` (or, without it, Expo's preset) + `@babel/core` (present in any RN or Expo app). Highest fidelity. - `engine: 'mock'`: a fast, zero-dependency pure-JS reimplementation of React Native. No Babel. For pure-logic suites, environment control, maximum determinism. Covers 100% of RN's stable public API. - `engine: 'auto'` (the default): native when babel deps present, else mock. A CI-gated behavioral cross-check runs the same assertions against both the mock and real RN across RN 0.86–0.88, keeping the mock honest. ## Evidence rules Package capability and fidelity are defined only by package-owned conformance tests, behavioral crosschecks, packed consumer fixtures, version matrices, and the exact-version API compatibility check. Pinned external apps are observational tripwires only: they include custom migration configuration, dependency pins, snapshots, Jest-era mocks, fake timers, and other shims. Never infer that vitest-native regressed, a behavior is unsupported, or a migration is impossible from a bakeoff result alone. First reduce the behavior into a minimal package-owned test. See https://vitest-native.danfry.dev/guide/validation-model. ## Setup Install: `npm install -D vitest vite vitest-native @testing-library/react-native` (vitest and vite are peers; RNTL is optional). `npx vitest-native init` writes the config; `npx vitest-native doctor` checks the setup. vitest.config.ts: ```ts import { defineConfig } from 'vitest/config' import { reactNative } from 'vitest-native' export default defineConfig({ plugins: [reactNative()] }) ``` Requirements: Node 22.22.3+ (on 22), 24.12+ (on 24) or 26+, Vitest 5.x, Vite ^8.0.5, React 19, React Native 0.86–0.88 (native engine), Expo SDK 57 and 58. RNTL (@testing-library/react-native) 13–14 is an optional peer; auto-configured when installed. RNTL 14 makes render, fireEvent and act async: always `await render(...)` (a no-op on 13). ## Plugin options `reactNative({ engine, platform, diagnostics, presets, mocks, assetExts, transform, hotRuntime, nativeModules, metroConfig })` - engine: 'native' | 'mock' | 'auto' (default 'auto') - platform: 'ios' | 'android' (default 'ios') - presets: third-party library presets. Omit to auto-detect from installed deps; an array replaces auto-detection (`[]` disables all); an object such as `{ navigation: false }` switches presets off; a string inside either form is a path to your own preset module (`{ './my-preset.ts': true }` adds one) - mocks: mock engine only (a non-empty value under native is a config error). JSON-serializable values only; each replaces that export whole. For components or functions use `vi.mock('react-native', ...)` in a setup file - assetExts: extra asset extensions (loaded as Metro does: a registered asset id) - transform: extra node_modules to transform (native engine; like Jest's transformIgnorePatterns) - hotRuntime: false (default, fresh worker per file) | 'auto' | true | options object. Opt-in, experimental: reuses workers across files; measure whether it is faster on your suite - nativeModules: native engine only. 'device' (default; unregistered native modules are absent, as on a device) | 'permissive' - metroConfig: experimental; use the project's Metro source-extension order and asset list ## Presets (auto-detected; most apply under both engines) The full list, with the exact packages each preset shadows, is at https://vitest-native.danfry.dev/guide/presets#available-presets. Coming from Jest, delete a manual native-library mock only when a preset shadows that exact package. Under the native engine the `expo` preset is off unless enabled (`presets: { expo: true }` or listed in an array): Expo modules run their own JavaScript, as under jest-expo. ## Test helpers (`vitest-native/helpers`) setDimensions, setColorScheme, setInsets, mockNativeModule, extendPresetMock, resetAllMocks (both engines). setPlatform is mock engine only (it throws under native; set `platform` in config). The mock engine's Keyboard/AppState also expose `_show`/`_hide`/`_setState`; native has no such methods. ## jest-compat (`vitest-native/jest-compat`) For migrating existing Jest suites: jestCompatSetup (jest global backed by vi), jestMockTransform() (hoists top-level jest.mock), jestCompatAliases() (@jest/globals shim + jest-native no-op). Clears mechanical Jest-API coupling; per-suite cleanup (snapshots, suite-specific mocks) still required. ## Docs - Guide: https://vitest-native.danfry.dev/guide/ - Choosing an engine: https://vitest-native.danfry.dev/guide/engines - Presets: https://vitest-native.danfry.dev/guide/presets - API coverage: https://vitest-native.danfry.dev/api/coverage - Validation model: https://vitest-native.danfry.dev/guide/validation-model - Migrating from Jest: https://vitest-native.danfry.dev/migration/from-jest - Migrating from vitest-react-native: https://vitest-native.danfry.dev/migration/from-vitest-react-native - Repo: https://github.com/danfry1/vitest-native - npm: https://www.npmjs.com/package/vitest-native