Repository navigation
Releases
v0.15.1
Patch Changes
-
51d5899:
import * as X from 'lib'now carries every part of a component library built by esbuild or tsup with JSX preserved. The library's index re-exports a module the engine compiles, and Node read that module's names from the published file, whose JSX it could not read: the namespace held onlydefault, soX.Rootwas undefined and rendering it failed with "Element type is invalid". The engine now lists the names a module re-exports from files it compiles. No action needed. -
9def928: A snapshot of an Expo component that passes a ref as a prop, like expo-image's
Image, is stable again under the native engine. expo-modules-core'screateSnapshotFriendlyRef()is React'screateRef, so a snapshot printed the view and React's fiber tree behind each ref: thousands of lines with render timings that changed on every run. It now returns the ref jest-expo serves, which prints as"[React.ref]"and still holds its view. Runvitest -uonce to rewrite snapshots written with the old output. -
fbcebbc: Gesture Handler 3's
Touchable,RectButtonandBorderlessButtoncan be pressed from Testing Library under the native engine.userEvent.pressandfireEvent.pressnow callonPressonce, as a tap on a device does, and a disabled button takes the press without calling it. Before,userEventfound nothing to press andfireEventmissedRectButton. The engine now mocks the native button host beside the package's ownjestSetup.js, following itstestOnly_onPressconvention. Delete avi.mockthat replacedTouchablewithPressablefor this. ATouchableis found by role only withaccessible, as on iOS; pass it in your wrapper. -
21b99dd:
hangTimeoutno longer stops a run because the machine slept. On macOS, Node's timers count time asleep, so after a sleep mid-run every running test looked past its budget and the run was stopped on wake. Time the machine spends asleep now extends each limit instead, while a test stuck in synchronous code is still caught once its awake time runs out. No action needed. -
ff4dba7: Under the hot runtime on Node 22, a React Native library whose ES index is an
.mjsfile beside CommonJS files now loads. No action needed. Builds from esbuild and tsup publish this layout. vitest-native compiles the.mjsindex, and itsrequire()of a CommonJS sibling was served the ES wrapper meant for imports, which Node 22 failed to link (ERR_VM_MODULE_LINK_FAILURE: "is from a module not been linked"). Such arequire()now returns the sibling'smodule.exports, the same instance the test file's own import of it reaches, and a new one in each file. -
7569bcb: With
diagnostics: true, the hot runtime's per-file reset lines now print. No action needed. Lines such ashot reset: dropped N moduleswere written while Vitest was starting the next file, which drops console output, so they never appeared. Hot-runtime diagnostics from the worker now go to stderr. -
2f36bc5: Under the hot runtime, a library that defines a non-configurable global no longer fails every later file in the worker. No action needed. The reset before each file could not delete such a property (the
openaiSDK defines one for its provider definitions), so it threwhotRuntime state restoration failedbefore every file after the first. A property no reset can delete or replace now stays for the worker's life, as Node's own process-wide state does, anddiagnostics: truenames it. Every other global a file adds is still deleted before the next file. -
628e964:
jest.mockthrough a renamedjestfrom@jest/globalsnow applies.jestMockTransform()recognised only calls on an identifier namedjest, soimport { jest as mockJest } from '@jest/globals'followed bymockJest.mock(…)was neither hoisted nor registered, and the module stayed real. Ajestimported, required or reached as<namespace>.jestunder any name is now handled like the global. A call through a further name (const j = mockJest; j.mock(…)) fails withJEST_BINDING_NOT_FOLLOWEDinstead of being skipped. No action needed. -
63d6efa:
vitest-native migratekeeps a suite that ran the real Reanimated on the real library. A Jest setup that calls Reanimated'ssetUpTests()and mocks Reanimated nowhere ran the real library, but migrate called that setup file covered and suggested deleting it, which moved the suite onto the preset's mock, wheregetAnimatedStylereturns{}. Migrate now writespresets: { reanimated: false }for such a suite, whenreact-native-reanimatedis a declared dependency, and keeps its setup file; "delete" stays for suites that also mock Reanimated. The presets guide shows the two modes side by side (#834).Add
presets: { reanimated: false }where your Jest setup ransetUpTests()without mocking Reanimated, and keep that setup file. -
14a0b13:
vitest-native migratelists the library mocks in your own Jest setup file that the presets cover. Ajest.mock('react-native-reanimated', …), a Safe Area mock or arequire('react-native-gesture-handler/jestSetup')in asetupFilesorsetupFilesAfterEnvfile now appears under "Covered by presets — delete", as the migration guide says. A mock that keeps part of the library is listed for review instead. The report also stops callingjest-react-native, which only React Native's(jest-)?react-nativepattern produces, not installed, and lists a preset-shadowedtransformIgnorePatternsentry under "Mapped automatically" (#795, #796, #797).Delete the setup-file lines the report now lists, once the suite passes without them.
-
bca755b: Reanimated's
interpolateColorworks under the mock engine. It threwPRESET_UNAVAILABLEthere with reanimated 4.x, because its file imports React Native, which the mock engine does not transform. WheninterpolateColoris first called, the preset now compiles reanimated's own file with the project's@babel/coreand@babel/plugin-transform-modules-commonjs, which a React Native app has through its Babel preset. It returns what reanimated returns: RGB, HSV and LAB, with colour strings or numbers. A project without that Babel keeps the error, which now names the packages to install. No action needed. -
1ad8a8d: The navigation preset now has the React Navigation 7 API it lacked, so tests calling it no longer fail with "is not a function".
- Container refs gain
resetRoot,setParams,setOptions,isFocused,getId,getParent,removeListenerandemit; they anduseNavigation()gainpreload,replaceParamsandnavigateDeprecated, as mock functions. StackActions.popToandCommonActions.preload,replaceParamsandnavigateDeprecatedreturn React Navigation's action objects.StackRouter,TabRouter,DrawerRouter,NavigationProvider,createScreenFactory,createStandardNavigationFactories,NativeStackViewandcreateNativeStackScreenare exported.- Existing exports behave as before. No action needed.
- Container refs gain
-
17ab16a: A package's
.jsfile with JSX no longer stops the run with Vite's "Failed to parse source for import analysis" error under the native engine. A package that declares noreact-nativedependency or peer isn't detected, so Vite serves it uncompiled, and Vite skips JSX in.jsfiles. vitest-native now compiles JSX in such a file when Vite's parser rejects it; every file that parses is served unchanged. No action needed. A package that also ships Metro-only source, such asreact-native-calendars, still needsreactNative({ transform: ['<package>'] }), and the error now says so. -
daac3a3:
hotRuntime.freshRuntimenow works with vitest-native's presets, so it no longer declines when one that uses React is active. No action needed for vitest-native's presets. Each preset builds its mock with the Reactreact-nativeuses, the test file's own, so hooks and contexts work in every file. A preset module's factory now receives{ React }(PresetFactoryContext). Change a custom preset whose factory makes components, contexts or hooks to use it:factory: ({ React }) => …. Under the native engine, a project that resolves a second copy of React now fails withPRESET_REACT_MISMATCH. -
0b18493:
vitest-native migrateanddoctorno longer say components render the same without React Compiler. The compiler is still not needed for tests to run, but it applies to the filesprojectBabelcompiles with Babel. There a memoized child skips re-rendering, so a test that reads a value React does not track during render can see an earlier value. Other files run without it, so a test that counts renders can see more than under babel-jest (#755).Set
projectBabel: 'always'where a suite depends on React Compiler running on every file, as under babel-jest. -
705f7ae: A Reanimated derived value from a render React discards no longer keeps running, and an updater that writes a value it reads no longer recurses.
useDerivedValuestarted following its inputs during render, so a render React discarded (a Suspense throw, an error boundary) kept its updater running on every later write. It now follows them once the component commits, as Reanimated starts its mapper in an effect. An updater that wrote a value it reads overflowed the stack; the write now waits for the next change to one of its inputs. No action needed. -
ae8bfea: A cancelled run no longer waits for a stopped background build before it exits. No action needed. On Windows, a cold run cancelled with
--bailor Ctrl-C could take several more seconds to exit on a busy machine. The background process that precompiles React Native got its input on stdin, and a stop before it had read that input left ...
v0.15.0
Upgrading from 0.14
- Node 22.22.3+, 24.12+ or 26+. An older Node stops at startup with
UNSUPPORTED_NODE. - Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER. - React 19, React Native Testing Library 13 or 14, and React Native 0.86+ (Expo SDK 57+) for the
native engine. An older React or React Native stops at startup withUNSUPPORTED_PEER. - Snapshots print in Jest's format. Run
vitest -uonce to re-record existing snapshots,
then review the diff. jestMockTransform()applies Jest's manual mocks of installed packages (__mocks__/<pkg>),
as Jest does. PassjestMockTransform({ rootMocks: false })to keep the previous behaviour.- Run
npx vitest-native doctorto check all of these. Each entry below has the details.
Minor Changes
-
48fc91d:
vitest-native compare --hotshows whetherhotRuntime: 'auto'changes any test's result in your suite. It runs your Vitest config per file and hot, three times each (one warm-up and two timed runs), plus one hot run with shuffled files and one at--maxWorkers=2. It matches every test by file, name and occurrence, compares failures by kind, and checks the engine's banner, so a declined'auto'gives no verdict. It lists each test whose result differs. With no differences it prints each mode's median and range, and calls hot faster or slower only when each mode has at least two timed runs and their ranges don't overlap.--runs <n>changes the run count; 2 or fewer give no speed verdict, and--jsonrecords each run's role. See the CLI guide. No action needed. -
98c62f4: The hot runtime can run React, its renderers,
schedulerand RNTL fresh in every file (experimental). SethotRuntime: { freshRuntime: true }souseIdvalues, React's once-per-process warnings, anact()scope an earlier file left open, the scheduler's timers and RNTL's fake-timer reinstall no longer carry from one file to the next. It costs about 5 ms per file at four workers, and about 17 ms at one. It needsesmGeneration, which is on by default. -
e4473ae: A test stuck in synchronous code no longer hangs a hot-runtime run forever: the run fails and names the file and test. Vitest's
testTimeoutcan't interrupt a test that never yields, such as a loop that never ends, so such a run used to wait with nothing on screen. The newhangTimeoutoption fails a run when nothing has made progress for 60 s (or twice the longest test or hook timeout) and every running test is past its own timeout, retries included. Every module a file loads through Vite counts as progress, so a slow cold start is not taken for a hang. The report gives each file's running test and when it started, or how long ago a worker took the file, and when the last module loaded. It's on by default under the hot runtime and off otherwise. AddreactNative({ hangTimeout: <ms> })to turn it on everywhere, orhangTimeout: falseto turn it off. -
1cb74f0: Behaviour change:
jestMockTransform()applies Jest's manual mocks ofnode_modulespackages. To keep the previous behaviour, passjestMockTransform({ rootMocks: false }). A file such as__mocks__/moti.tsin a__mocks__folder under Jest'srootsnow replaces that package with nojest.mock()call, as under Jest, for imports andrequire()alike,__mocks__/react-native.jsincluded. Before, the real package ran. A setup file's or test file's ownjest.mock()orjest.unmock()still wins.migratelists each such file and carries over Jest'srootsandmodulePathIgnorePatterns.- A package a preset covers keeps its preset; the run warns that its manual mock is not applied.
-
41959da: Under jest-compat,
View.prototypehas the native methods, as React Native's Jest preset gives it.jest.spyOn(View.prototype, 'measure')now reaches everyViewref. It used to fail because React Native'sViewhas no prototype. Under the native engine, each native view name now has one host class, so everyViewref shares the methods a spy replaces.No action needed.
TextandScrollViewget no prototype. -
23275f8: jest-compat supports
jest.replaceProperty().jest.replaceProperty(Platform, 'OS', 'android')replaces the value in place, as Jest does. It used to throw. The returned handle hasreplaceValue()andrestore().jest.restoreAllMocks(), therestoreMockssetting and the end of the test file also restore it;vi.restoreAllMocks()does not. It throws Jest's errors for a getter, a function or a missing property.No action needed.
-
ece53b3: Files that need a plugin from your project's Babel config now compile with that config, as Metro and babel-jest compile them. Legacy decorators (WatermelonDB models), macros,
react-native-dotenv, the worklets plugin, custom plugins and Flow used to fail or behave differently. Remove anybabel()entry you added only to run them; setprojectBabel: 'never'for the previous behaviour.- Only a file that uses such a plugin compiles with Babel; other files keep Oxc.
migrateanddoctorlist these plugins as applied, anddoctorcalls ababel()entry that repeats one redundant.- It needs
@babel/corein the project. Without it,migrate,doctorand the mock engine's startup say so.
-
e517388: Behaviour change: snapshots of React Native trees print in Jest's format. Run
vitest -uonce to re-record existing vitest-native snapshots, then review the diff. vitest-native no longer registers its own serializer. Jest-written snapshots share the format, but ones inside adescribe, or of components Jest's preset stubs, still need one re-record (Snapshots).- No host prints
ref. A host ref, such as aTextref under the native engine or any host ref under the mock engine, is now an instance withmeasure,focusand the other native methods, where it used to be the test renderer's node ornull. vitest-native/serializerkeeps the old format for one release; it is deprecated.
- No host prints
-
a107e3a: New
vitest-native compareruns your suite under your own Jest and under Vitest and lists every test whose result differs. Use it while both runners are in place:npx vitest-native comparenames each test that passes under Jest but not under Vitest, grouped by its first error, and exits 0 only when every one of them passes andvitest runexits 0. Neither run writes snapshots or changes project files, and--json <file>writes a report without stack traces or absolute paths, for attaching to an issue. See the CLI reference. -
4271252: Under the native engine,
react-native-gesture-handlerand@shopify/flash-listrun as themselves, with thejestSetup.jseach ships before the project's setup files, as a Jest suite lists them. No action needed; to keep a preset, setpresets: { gestureHandler: true }or{ flashList: true }.- Gesture Handler 3's hook API, builder methods and test helpers work, and a
Pressablepress firesonPress. - A
FlashListrenders a window of rows, as under Jest, where the preset rendered every row. react-native-gesture-handler/Swipeableand the other modules Gesture Handler 3 does not ship no longer resolve, as under Jest.
- Gesture Handler 3's hook API, builder methods and test helpers work, and a
-
4271252: Under the native engine, a React Native library's own Jest setup and mocks get a
jestwith Jest's semantics. No action needed; a suite that importsreact-native-gesture-handler/jestSetuporreact-native-safe-area-context/jest/mockgets what Jest gave it.- Their
jest.mockreaches everyrequireof the module, andjest.requireActualand@jest/globalswork. - Implementations a library installs while building its mocks survive
vi.resetAllMocks()andmockReset: true. jest.requireActualof a package a preset shadows returns the package, as under Jest.
- Their
-
ebdda39: Breaking: vitest-native now requires Node 22.22.3+, 24.12+ or 26+, for both engines. An unsupported Node stops at startup with
UNSUPPORTED_NODE, naming the release to install;vitest-native doctorreports the same.Update Node within your major, or move from Node 20, 23 or 25 to a supported line, including CI images and
.nvmrcorenginespins. RemoveVITEST_NATIVE_LOADER_THREADfrom scripts and CI; it no longer has an effect.- Under the native engine, a runtime without
module.registerHooks(Bun) getsUNSUPPORTED_NODEtoo. - The support policy is in
docs/versioning.md.
- Under the native engine, a runtime without
-
dae3119: Native engine: a file that Vite and Node both load, with both copies in use, is now reported by name,
SOURCE_EVALUATED_TWICE, instead of silently existing twice. No action needed. To fail on it, setreactNative({ ownership: 'error' }).- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
ownership: { allow: [{ path, reason }] }. require()of a CommonJS project file a test already imported now returns that samemodule.exports.- The warning, its end-of-run summary and
vitest-native doctorlink the error reference.
- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
-
5cad255: Native engine: a new opt-in flag makes Vite and Node resolve a package to the same file, so one package is one module. Add
experimental: { ownershipModel: 'resolver' }to try it. Nothing changes without it.- Any package with separate
importandrequirebuilds, or areact-nativefield, loads one file on both sides; a JSX or Flowreact-nativefield is compiled, as Metro does. - RegExp aliases and tsconfig
pathsalso apply to Node'srequire, includingjest.requireActual.NODE_PATHapplies torequireonly, as in Node. - Not covered: an alias with a...
- Any package with separate
v0.15.0-rc.5
Upgrading from 0.14
- Node 22.22.3+, 24.12+ or 26+. An older Node stops at startup with
UNSUPPORTED_NODE. - Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER. - React 19, React Native Testing Library 13 or 14, and React Native 0.86+ (Expo SDK 57+) for the
native engine. An older React or React Native stops at startup withUNSUPPORTED_PEER. - Snapshots print in Jest's format. Run
vitest -uonce to re-record existing snapshots,
then review the diff. jestMockTransform()applies Jest's manual mocks of installed packages (__mocks__/<pkg>),
as Jest does. PassjestMockTransform({ rootMocks: false })to keep the previous behaviour.- Run
npx vitest-native doctorto check all of these. Each entry below has the details.
Minor Changes
-
48fc91d:
vitest-native compare --hotshows whetherhotRuntime: 'auto'changes any test's result in your suite. It runs your Vitest config per file and hot, three times each (one warm-up and two timed runs), plus one hot run with shuffled files and one at--maxWorkers=2. It matches every test by file, name and occurrence, compares failures by kind, and checks the engine's banner, so a declined'auto'gives no verdict. It lists each test whose result differs. With no differences it prints each mode's median and range, and calls hot faster or slower only when each mode has at least two timed runs and their ranges don't overlap.--runs <n>changes the run count; 2 or fewer give no speed verdict, and--jsonrecords each run's role. See the CLI guide. No action needed. -
98c62f4: The hot runtime can run React, its renderers,
schedulerand RNTL fresh in every file (experimental). SethotRuntime: { freshRuntime: true }souseIdvalues, React's once-per-process warnings, anact()scope an earlier file left open, the scheduler's timers and RNTL's fake-timer reinstall no longer carry from one file to the next. It costs about 5 ms per file at four workers, and about 17 ms at one. It needsesmGeneration, which is on by default. -
e4473ae: A test stuck in synchronous code no longer hangs a hot-runtime run forever: the run fails and names the file and test. Vitest's
testTimeoutcan't interrupt a test that never yields, such as a loop that never ends, so such a run used to wait with nothing on screen. The newhangTimeoutoption fails a run when nothing has made progress for 60 s (or twice the longest test or hook timeout) and every running test is past its own timeout, retries included. Every module a file loads through Vite counts as progress, so a slow cold start is not taken for a hang. The report gives each file's running test and when it started, or how long ago a worker took the file, and when the last module loaded. It's on by default under the hot runtime and off otherwise. AddreactNative({ hangTimeout: <ms> })to turn it on everywhere, orhangTimeout: falseto turn it off. -
1cb74f0: Behaviour change:
jestMockTransform()applies Jest's manual mocks ofnode_modulespackages. To keep the previous behaviour, passjestMockTransform({ rootMocks: false }). A file such as__mocks__/moti.tsin a__mocks__folder under Jest'srootsnow replaces that package with nojest.mock()call, as under Jest, for imports andrequire()alike,__mocks__/react-native.jsincluded. Before, the real package ran. A setup file's or test file's ownjest.mock()orjest.unmock()still wins.migratelists each such file and carries over Jest'srootsandmodulePathIgnorePatterns.- A package a preset covers keeps its preset; the run warns that its manual mock is not applied.
-
41959da: Under jest-compat,
View.prototypehas the native methods, as React Native's Jest preset gives it.jest.spyOn(View.prototype, 'measure')now reaches everyViewref. It used to fail because React Native'sViewhas no prototype. Under the native engine, each native view name now has one host class, so everyViewref shares the methods a spy replaces.No action needed.
TextandScrollViewget no prototype. -
23275f8: jest-compat supports
jest.replaceProperty().jest.replaceProperty(Platform, 'OS', 'android')replaces the value in place, as Jest does. It used to throw. The returned handle hasreplaceValue()andrestore().jest.restoreAllMocks(), therestoreMockssetting and the end of the test file also restore it;vi.restoreAllMocks()does not. It throws Jest's errors for a getter, a function or a missing property.No action needed.
-
ece53b3: Files that need a plugin from your project's Babel config now compile with that config, as Metro and babel-jest compile them. Legacy decorators (WatermelonDB models), macros,
react-native-dotenv, the worklets plugin, custom plugins and Flow used to fail or behave differently. Remove anybabel()entry you added only to run them; setprojectBabel: 'never'for the previous behaviour.- Only a file that uses such a plugin compiles with Babel; other files keep Oxc.
migrateanddoctorlist these plugins as applied, anddoctorcalls ababel()entry that repeats one redundant.- It needs
@babel/corein the project. Without it,migrate,doctorand the mock engine's startup say so.
-
e517388: Behaviour change: snapshots of React Native trees print in Jest's format. Run
vitest -uonce to re-record existing vitest-native snapshots, then review the diff. vitest-native no longer registers its own serializer. Jest-written snapshots share the format, but ones inside adescribe, or of components Jest's preset stubs, still need one re-record (Snapshots).- No host prints
ref. A host ref, such as aTextref under the native engine or any host ref under the mock engine, is now an instance withmeasure,focusand the other native methods, where it used to be the test renderer's node ornull. vitest-native/serializerkeeps the old format for one release; it is deprecated.
- No host prints
-
a107e3a: New
vitest-native compareruns your suite under your own Jest and under Vitest and lists every test whose result differs. Use it while both runners are in place:npx vitest-native comparenames each test that passes under Jest but not under Vitest, grouped by its first error, and exits 0 only when every one of them passes andvitest runexits 0. Neither run writes snapshots or changes project files, and--json <file>writes a report without stack traces or absolute paths, for attaching to an issue. See the CLI reference. -
4271252: Under the native engine,
react-native-gesture-handlerand@shopify/flash-listrun as themselves, with thejestSetup.jseach ships before the project's setup files, as a Jest suite lists them. No action needed; to keep a preset, setpresets: { gestureHandler: true }or{ flashList: true }.- Gesture Handler 3's hook API, builder methods and test helpers work, and a
Pressablepress firesonPress. - A
FlashListrenders a window of rows, as under Jest, where the preset rendered every row. react-native-gesture-handler/Swipeableand the other modules Gesture Handler 3 does not ship no longer resolve, as under Jest.
- Gesture Handler 3's hook API, builder methods and test helpers work, and a
-
4271252: Under the native engine, a React Native library's own Jest setup and mocks get a
jestwith Jest's semantics. No action needed; a suite that importsreact-native-gesture-handler/jestSetuporreact-native-safe-area-context/jest/mockgets what Jest gave it.- Their
jest.mockreaches everyrequireof the module, andjest.requireActualand@jest/globalswork. - Implementations a library installs while building its mocks survive
vi.resetAllMocks()andmockReset: true. jest.requireActualof a package a preset shadows returns the package, as under Jest.
- Their
-
ebdda39: Breaking: vitest-native now requires Node 22.22.3+, 24.12+ or 26+, for both engines. An unsupported Node stops at startup with
UNSUPPORTED_NODE, naming the release to install;vitest-native doctorreports the same.Update Node within your major, or move from Node 20, 23 or 25 to a supported line, including CI images and
.nvmrcorenginespins. RemoveVITEST_NATIVE_LOADER_THREADfrom scripts and CI; it no longer has an effect.- Under the native engine, a runtime without
module.registerHooks(Bun) getsUNSUPPORTED_NODEtoo. - The support policy is in
docs/versioning.md.
- Under the native engine, a runtime without
-
dae3119: Native engine: a file that Vite and Node both load, with both copies in use, is now reported by name,
SOURCE_EVALUATED_TWICE, instead of silently existing twice. No action needed. To fail on it, setreactNative({ ownership: 'error' }).- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
ownership: { allow: [{ path, reason }] }. require()of a CommonJS project file a test already imported now returns that samemodule.exports.- The warning, its end-of-run summary and
vitest-native doctorlink the error reference.
- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
-
5cad255: Native engine: a new opt-in flag makes Vite and Node resolve a package to the same file, so one package is one module. Add
experimental: { ownershipModel: 'resolver' }to try it. Nothing changes without it.- Any package with separate
importandrequirebuilds, or areact-nativefield, loads one file on both sides; a JSX or Flowreact-nativefield is compiled, as Metro does. - RegExp aliases and tsconfig
pathsalso apply to Node'srequire, includingjest.requireActual.NODE_PATHapplies torequireonly, as in Node. - Not covered: an alias with a...
- Any package with separate
v0.15.0-rc.4
Upgrading from 0.14
- Node 22.22.3+, 24.12+ or 26+. An older Node stops at startup with
UNSUPPORTED_NODE. - Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER. - React 19, React Native Testing Library 13 or 14, and React Native 0.86+ (Expo SDK 57+) for the
native engine. An older React or React Native stops at startup withUNSUPPORTED_PEER. - Snapshots print in Jest's format. Run
vitest -uonce to re-record existing snapshots,
then review the diff. jestMockTransform()applies Jest's manual mocks of installed packages (__mocks__/<pkg>),
as Jest does. PassjestMockTransform({ rootMocks: false })to keep the previous behaviour.- Run
npx vitest-native doctorto check all of these. Each entry below has the details.
Minor Changes
-
48fc91d:
vitest-native compare --hotshows whetherhotRuntime: 'auto'changes any test's result in your suite. It runs your Vitest config per file and hot, three times each (one warm-up and two timed runs), plus one hot run with shuffled files and one at--maxWorkers=2. It matches every test by file, name and occurrence, compares failures by kind, and checks the engine's banner, so a declined'auto'gives no verdict. It lists each test whose result differs. With no differences it prints each mode's median and range, and calls hot faster or slower only when each mode has at least two timed runs and their ranges don't overlap.--runs <n>changes the run count; 2 or fewer give no speed verdict, and--jsonrecords each run's role. See the CLI guide. No action needed. -
98c62f4: The hot runtime can run React, its renderers,
schedulerand RNTL fresh in every file (experimental). SethotRuntime: { freshRuntime: true }souseIdvalues, React's once-per-process warnings, anact()scope an earlier file left open, the scheduler's timers and RNTL's fake-timer reinstall no longer carry from one file to the next. It costs about 5 ms per file at four workers, and about 17 ms at one. It needsesmGeneration, which is on by default. -
e4473ae: A test stuck in synchronous code no longer hangs a hot-runtime run forever: the run fails and names the file and test. Vitest's
testTimeoutcan't interrupt a test that never yields, such as a loop that never ends, so such a run used to wait with nothing on screen. The newhangTimeoutoption fails a run when nothing has made progress for 60 s (or twice the longest test or hook timeout) and every running test is past its own timeout, retries included. Every module a file loads through Vite counts as progress, so a slow cold start is not taken for a hang. The report gives each file's running test and when it started, or how long ago a worker took the file, and when the last module loaded. It's on by default under the hot runtime and off otherwise. AddreactNative({ hangTimeout: <ms> })to turn it on everywhere, orhangTimeout: falseto turn it off. -
1cb74f0: Behaviour change:
jestMockTransform()applies Jest's manual mocks ofnode_modulespackages. To keep the previous behaviour, passjestMockTransform({ rootMocks: false }). A file such as__mocks__/moti.tsin a__mocks__folder under Jest'srootsnow replaces that package with nojest.mock()call, as under Jest, for imports andrequire()alike,__mocks__/react-native.jsincluded. Before, the real package ran. A setup file's or test file's ownjest.mock()orjest.unmock()still wins.migratelists each such file and carries over Jest'srootsandmodulePathIgnorePatterns.- A package a preset covers keeps its preset; the run warns that its manual mock is not applied.
-
41959da: Under jest-compat,
View.prototypehas the native methods, as React Native's Jest preset gives it.jest.spyOn(View.prototype, 'measure')now reaches everyViewref. It used to fail because React Native'sViewhas no prototype. Under the native engine, each native view name now has one host class, so everyViewref shares the methods a spy replaces.No action needed.
TextandScrollViewget no prototype. -
23275f8: jest-compat supports
jest.replaceProperty().jest.replaceProperty(Platform, 'OS', 'android')replaces the value in place, as Jest does. It used to throw. The returned handle hasreplaceValue()andrestore().jest.restoreAllMocks(), therestoreMockssetting and the end of the test file also restore it;vi.restoreAllMocks()does not. It throws Jest's errors for a getter, a function or a missing property.No action needed.
-
ece53b3: Files that need a plugin from your project's Babel config now compile with that config, as Metro and babel-jest compile them. Legacy decorators (WatermelonDB models), macros,
react-native-dotenv, the worklets plugin, custom plugins and Flow used to fail or behave differently. Remove anybabel()entry you added only to run them; setprojectBabel: 'never'for the previous behaviour.- Only a file that uses such a plugin compiles with Babel; other files keep Oxc.
migrateanddoctorlist these plugins as applied, anddoctorcalls ababel()entry that repeats one redundant.- It needs
@babel/corein the project. Without it,migrate,doctorand the mock engine's startup say so.
-
e517388: Behaviour change: snapshots of React Native trees print in Jest's format. Run
vitest -uonce to re-record existing vitest-native snapshots, then review the diff. vitest-native no longer registers its own serializer. Jest-written snapshots share the format, but ones inside adescribe, or of components Jest's preset stubs, still need one re-record (Snapshots).- No host prints
ref. A host ref, such as aTextref under the native engine or any host ref under the mock engine, is now an instance withmeasure,focusand the other native methods, where it used to be the test renderer's node ornull. vitest-native/serializerkeeps the old format for one release; it is deprecated.
- No host prints
-
a107e3a: New
vitest-native compareruns your suite under your own Jest and under Vitest and lists every test whose result differs. Use it while both runners are in place:npx vitest-native comparenames each test that passes under Jest but not under Vitest, grouped by its first error, and exits 0 only when every one of them passes andvitest runexits 0. Neither run writes snapshots or changes project files, and--json <file>writes a report without stack traces or absolute paths, for attaching to an issue. See the CLI reference. -
4271252: Under the native engine,
react-native-gesture-handlerand@shopify/flash-listrun as themselves, with thejestSetup.jseach ships before the project's setup files, as a Jest suite lists them. No action needed; to keep a preset, setpresets: { gestureHandler: true }or{ flashList: true }.- Gesture Handler 3's hook API, builder methods and test helpers work, and a
Pressablepress firesonPress. - A
FlashListrenders a window of rows, as under Jest, where the preset rendered every row. react-native-gesture-handler/Swipeableand the other modules Gesture Handler 3 does not ship no longer resolve, as under Jest.
- Gesture Handler 3's hook API, builder methods and test helpers work, and a
-
4271252: Under the native engine, a React Native library's own Jest setup and mocks get a
jestwith Jest's semantics. No action needed; a suite that importsreact-native-gesture-handler/jestSetuporreact-native-safe-area-context/jest/mockgets what Jest gave it.- Their
jest.mockreaches everyrequireof the module, andjest.requireActualand@jest/globalswork. - Implementations a library installs while building its mocks survive
vi.resetAllMocks()andmockReset: true. jest.requireActualof a package a preset shadows returns the package, as under Jest.
- Their
-
ebdda39: Breaking: vitest-native now requires Node 22.22.3+, 24.12+ or 26+, for both engines. An unsupported Node stops at startup with
UNSUPPORTED_NODE, naming the release to install;vitest-native doctorreports the same.Update Node within your major, or move from Node 20, 23 or 25 to a supported line, including CI images and
.nvmrcorenginespins. RemoveVITEST_NATIVE_LOADER_THREADfrom scripts and CI; it no longer has an effect.- Under the native engine, a runtime without
module.registerHooks(Bun) getsUNSUPPORTED_NODEtoo. - The support policy is in
docs/versioning.md.
- Under the native engine, a runtime without
-
dae3119: Native engine: a file that Vite and Node both load, with both copies in use, is now reported by name,
SOURCE_EVALUATED_TWICE, instead of silently existing twice. No action needed. To fail on it, setreactNative({ ownership: 'error' }).- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
ownership: { allow: [{ path, reason }] }. require()of a CommonJS project file a test already imported now returns that samemodule.exports.- The warning, its end-of-run summary and
vitest-native doctorlink the error reference.
- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
-
5cad255: Native engine: a new opt-in flag makes Vite and Node resolve a package to the same file, so one package is one module. Add
experimental: { ownershipModel: 'resolver' }to try it. Nothing changes without it.- Any package with separate
importandrequirebuilds, or areact-nativefield, loads one file on both sides; a JSX or Flowreact-nativefield is compiled, as Metro does. - RegExp aliases and tsconfig
pathsalso apply to Node'srequire, includingjest.requireActual.NODE_PATHapplies torequireonly, as in Node. - Not covered: an alias with a...
- Any package with separate
v0.15.0-rc.3
Upgrading from 0.14
- Node 22.22.3+, 24.12+ or 26+. An older Node stops at startup with
UNSUPPORTED_NODE. - Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER. - React 19, React Native Testing Library 13 or 14, and React Native 0.86+ (Expo SDK 57+) for the
native engine. An older React or React Native stops at startup withUNSUPPORTED_PEER. - Snapshots print in Jest's format. Run
vitest -uonce to re-record existing snapshots,
then review the diff. jestMockTransform()applies Jest's manual mocks of installed packages (__mocks__/<pkg>),
as Jest does. PassjestMockTransform({ rootMocks: false })to keep the previous behaviour.- Run
npx vitest-native doctorto check all of these. Each entry below has the details.
Minor Changes
-
48fc91d:
vitest-native compare --hotshows whetherhotRuntime: 'auto'changes any test's result in your suite. It runs your Vitest config per file and hot: twice each, plus one hot run with shuffled files and one at--maxWorkers=2. It matches every test by file, name and occurrence, compares failures by kind, and checks the engine's banner, so a declined'auto'gives no verdict. When nothing differs it prints the median speed-up; otherwise it lists each differing test. See the CLI guide. No action needed. -
98c62f4: The hot runtime can run React, its renderers,
schedulerand RNTL fresh in every file (experimental). SethotRuntime: { freshRuntime: true }souseIdvalues, React's once-per-process warnings, anact()scope an earlier file left open, the scheduler's timers and RNTL's fake-timer reinstall no longer carry from one file to the next. It costs about 5 ms per file at four workers, and about 17 ms at one. It needsesmGeneration, which is on by default. -
e4473ae: A test stuck in synchronous code no longer hangs a hot-runtime run forever: the run fails and names the file and test. Vitest's
testTimeoutcan't interrupt a test that never yields, such as a loop that never ends, so such a run used to wait with nothing on screen. The newhangTimeoutoption fails a run when nothing has made progress for 60 s (or twice the longest test or hook timeout) and every running test is past its own timeout, retries included. It's on by default under the hot runtime and off otherwise. AddreactNative({ hangTimeout: <ms> })to turn it on everywhere, orhangTimeout: falseto turn it off. -
1cb74f0: Behaviour change:
jestMockTransform()applies Jest's manual mocks ofnode_modulespackages. To keep the previous behaviour, passjestMockTransform({ rootMocks: false }). A file such as__mocks__/moti.tsin a__mocks__folder under Jest'srootsnow replaces that package with nojest.mock()call, as under Jest, for imports andrequire()alike,__mocks__/react-native.jsincluded. Before, the real package ran. A setup file's or test file's ownjest.mock()orjest.unmock()still wins.migratelists each such file and carries over Jest'srootsandmodulePathIgnorePatterns.- A package a preset covers keeps its preset; the run warns that its manual mock is not applied.
-
41959da: Under jest-compat,
View.prototypehas the native methods, as React Native's Jest preset gives it.jest.spyOn(View.prototype, 'measure')now reaches everyViewref. It used to fail because React Native'sViewhas no prototype. Under the native engine, each native view name now has one host class, so everyViewref shares the methods a spy replaces.No action needed.
TextandScrollViewget no prototype. -
23275f8: jest-compat supports
jest.replaceProperty().jest.replaceProperty(Platform, 'OS', 'android')replaces the value in place, as Jest does. It used to throw. The returned handle hasreplaceValue()andrestore().jest.restoreAllMocks(), therestoreMockssetting and the end of the test file also restore it;vi.restoreAllMocks()does not. It throws Jest's errors for a getter, a function or a missing property.No action needed.
-
ece53b3: Files that need a plugin from your project's Babel config now compile with that config, as Metro and babel-jest compile them. Legacy decorators (WatermelonDB models), macros,
react-native-dotenv, the worklets plugin, custom plugins and Flow used to fail or behave differently. Remove anybabel()entry you added only to run them; setprojectBabel: 'never'for the previous behaviour.- Only a file that uses such a plugin compiles with Babel; other files keep Oxc.
migrateanddoctorlist these plugins as applied, anddoctorcalls ababel()entry that repeats one redundant.- It needs
@babel/corein the project. Without it,migrate,doctorand the mock engine's startup say so.
-
e517388: Behaviour change: snapshots of React Native trees print in Jest's format. Run
vitest -uonce to re-record existing vitest-native snapshots, then review the diff. vitest-native no longer registers its own serializer. Jest-written snapshots share the format, but ones inside adescribe, or of components Jest's preset stubs, still need one re-record (Snapshots).- No host prints
ref. A host ref, such as aTextref under the native engine or any host ref under the mock engine, is now an instance withmeasure,focusand the other native methods, where it used to be the test renderer's node ornull. vitest-native/serializerkeeps the old format for one release; it is deprecated.
- No host prints
-
a107e3a: New
vitest-native compareruns your suite under your own Jest and under Vitest and lists every test whose result differs. Use it while both runners are in place:npx vitest-native comparenames each test that passes under Jest but not under Vitest, grouped by its first error, and exits 0 only when every one of them passes andvitest runexits 0. Neither run writes snapshots or changes project files, and--json <file>writes a report without stack traces or absolute paths, for attaching to an issue. See the CLI reference. -
4271252: Under the native engine,
react-native-gesture-handlerand@shopify/flash-listrun as themselves, with thejestSetup.jseach ships before the project's setup files, as a Jest suite lists them. No action needed; to keep a preset, setpresets: { gestureHandler: true }or{ flashList: true }.- Gesture Handler 3's hook API, builder methods and test helpers work, and a
Pressablepress firesonPress. - A
FlashListrenders a window of rows, as under Jest, where the preset rendered every row. react-native-gesture-handler/Swipeableand the other modules Gesture Handler 3 does not ship no longer resolve, as under Jest.
- Gesture Handler 3's hook API, builder methods and test helpers work, and a
-
4271252: Under the native engine, a React Native library's own Jest setup and mocks get a
jestwith Jest's semantics. No action needed; a suite that importsreact-native-gesture-handler/jestSetuporreact-native-safe-area-context/jest/mockgets what Jest gave it.- Their
jest.mockreaches everyrequireof the module, andjest.requireActualand@jest/globalswork. - Implementations a library installs while building its mocks survive
vi.resetAllMocks()andmockReset: true. jest.requireActualof a package a preset shadows returns the package, as under Jest.
- Their
-
ebdda39: Breaking: vitest-native now requires Node 22.22.3+, 24.12+ or 26+, for both engines. An unsupported Node stops at startup with
UNSUPPORTED_NODE, naming the release to install;vitest-native doctorreports the same.Update Node within your major, or move from Node 20, 23 or 25 to a supported line, including CI images and
.nvmrcorenginespins. RemoveVITEST_NATIVE_LOADER_THREADfrom scripts and CI; it no longer has an effect.- Under the native engine, a runtime without
module.registerHooks(Bun) getsUNSUPPORTED_NODEtoo. - The support policy is in
docs/versioning.md.
- Under the native engine, a runtime without
-
dae3119: Native engine: a file that Vite and Node both load, with both copies in use, is now reported by name,
SOURCE_EVALUATED_TWICE, instead of silently existing twice. No action needed. To fail on it, setreactNative({ ownership: 'error' }).- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
ownership: { allow: [{ path, reason }] }. require()of a CommonJS project file a test already imported now returns that samemodule.exports.- The warning, its end-of-run summary and
vitest-native doctorlink the error reference.
- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
-
5cad255: Native engine: a new opt-in flag makes Vite and Node resolve a package to the same file, so one package is one module. Add
experimental: { ownershipModel: 'resolver' }to try it. Nothing changes without it.- Any package with separate
importandrequirebuilds, or areact-nativefield, loads one file on both sides; a JSX or Flowreact-nativefield is compiled, as Metro does. - RegExp aliases and tsconfig
pathsalso apply to Node'srequire, includingjest.requireActual.NODE_PATHapplies torequireonly, as in Node. - Not covered: an alias with a custom resolver or a function replacement. It is refused at startup by name. See
experimental.
- Any package with separate
-
45154cf: Native engine:
experimental: { ownershipModel: 'resolution' }gives Node'srequireof a project file the same instance a test'simportgets, whichever loads it first. To try it, set the flag; it also turns onnodeMocks, and refusesnodeMocks: false.- A file not yet evaluated is evaluated then. A `requi...
v0.15.0-rc.2
Upgrading from 0.14
- Node 22.22.3+, 24.12+ or 26+. An older Node stops at startup with
UNSUPPORTED_NODE. - Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER. - React 19, React Native Testing Library 13 or 14, and React Native 0.86+ (Expo SDK 57+) for the
native engine. An older React or React Native stops at startup withUNSUPPORTED_PEER. - Snapshots print in Jest's format. Run
vitest -uonce to re-record existing snapshots,
then review the diff. jestMockTransform()applies Jest's manual mocks of installed packages (__mocks__/<pkg>),
as Jest does. PassjestMockTransform({ rootMocks: false })to keep the previous behaviour.- Run
npx vitest-native doctorto check all of these. Each entry below has the details.
Minor Changes
-
e4473ae: A test stuck in synchronous code no longer hangs a hot-runtime run forever: the run fails and names the file and test. Vitest's
testTimeoutcan't interrupt a test that never yields, such as a loop that never ends, so such a run used to wait with nothing on screen. The newhangTimeoutoption fails a run when nothing has made progress for 60 s (or twice the longest test or hook timeout) and every running test is past its own timeout, retries included. It's on by default under the hot runtime and off otherwise. AddreactNative({ hangTimeout: <ms> })to turn it on everywhere, orhangTimeout: falseto turn it off. -
1cb74f0: Behaviour change:
jestMockTransform()applies Jest's manual mocks ofnode_modulespackages. To keep the previous behaviour, passjestMockTransform({ rootMocks: false }). A file such as__mocks__/moti.tsin a__mocks__folder under Jest'srootsnow replaces that package with nojest.mock()call, as under Jest, for imports andrequire()alike,__mocks__/react-native.jsincluded. Before, the real package ran. A setup file's or test file's ownjest.mock()orjest.unmock()still wins.migratelists each such file and carries over Jest'srootsandmodulePathIgnorePatterns.- A package a preset covers keeps its preset; the run warns that its manual mock is not applied.
-
41959da: Under jest-compat,
View.prototypehas the native methods, as React Native's Jest preset gives it.jest.spyOn(View.prototype, 'measure')now reaches everyViewref. It used to fail because React Native'sViewhas no prototype. Under the native engine, each native view name now has one host class, so everyViewref shares the methods a spy replaces.No action needed.
TextandScrollViewget no prototype. -
23275f8: jest-compat supports
jest.replaceProperty().jest.replaceProperty(Platform, 'OS', 'android')replaces the value in place, as Jest does. It used to throw. The returned handle hasreplaceValue()andrestore().jest.restoreAllMocks(), therestoreMockssetting and the end of the test file also restore it;vi.restoreAllMocks()does not. It throws Jest's errors for a getter, a function or a missing property.No action needed.
-
ece53b3: Files that need a plugin from your project's Babel config now compile with that config, as Metro and babel-jest compile them. Legacy decorators (WatermelonDB models), macros,
react-native-dotenv, the worklets plugin, custom plugins and Flow used to fail or behave differently. Remove anybabel()entry you added only to run them; setprojectBabel: 'never'for the previous behaviour.- Only a file that uses such a plugin compiles with Babel; other files keep Oxc.
migrateanddoctorlist these plugins as applied, anddoctorcalls ababel()entry that repeats one redundant.- It needs
@babel/corein the project. Without it,migrate,doctorand the mock engine's startup say so.
-
e517388: Behaviour change: snapshots of React Native trees print in Jest's format. Run
vitest -uonce to re-record existing vitest-native snapshots, then review the diff. vitest-native no longer registers its own serializer. Jest-written snapshots share the format, but ones inside adescribe, or of components Jest's preset stubs, still need one re-record (Snapshots).- No host prints
ref. A host ref, such as aTextref under the native engine or any host ref under the mock engine, is now an instance withmeasure,focusand the other native methods, where it used to be the test renderer's node ornull. vitest-native/serializerkeeps the old format for one release; it is deprecated.
- No host prints
-
a107e3a: New
vitest-native compareruns your suite under your own Jest and under Vitest and lists every test whose result differs. Use it while both runners are in place:npx vitest-native comparenames each test that passes under Jest but not under Vitest, grouped by its first error, and exits 0 only when every one of them passes andvitest runexits 0. Neither run writes snapshots or changes project files, and--json <file>writes a report without stack traces or absolute paths, for attaching to an issue. See the CLI reference. -
4271252: Under the native engine,
react-native-gesture-handlerand@shopify/flash-listrun as themselves, with thejestSetup.jseach ships before the project's setup files, as a Jest suite lists them. No action needed; to keep a preset, setpresets: { gestureHandler: true }or{ flashList: true }.- Gesture Handler 3's hook API, builder methods and test helpers work, and a
Pressablepress firesonPress. - A
FlashListrenders a window of rows, as under Jest, where the preset rendered every row. react-native-gesture-handler/Swipeableand the other modules Gesture Handler 3 does not ship no longer resolve, as under Jest.
- Gesture Handler 3's hook API, builder methods and test helpers work, and a
-
4271252: Under the native engine, a React Native library's own Jest setup and mocks get a
jestwith Jest's semantics. No action needed; a suite that importsreact-native-gesture-handler/jestSetuporreact-native-safe-area-context/jest/mockgets what Jest gave it.- Their
jest.mockreaches everyrequireof the module, andjest.requireActualand@jest/globalswork. - Implementations a library installs while building its mocks survive
vi.resetAllMocks()andmockReset: true. jest.requireActualof a package a preset shadows returns the package, as under Jest.
- Their
-
ebdda39: Breaking: vitest-native now requires Node 22.22.3+, 24.12+ or 26+, for both engines. An unsupported Node stops at startup with
UNSUPPORTED_NODE, naming the release to install;vitest-native doctorreports the same.Update Node within your major, or move from Node 20, 23 or 25 to a supported line, including CI images and
.nvmrcorenginespins. RemoveVITEST_NATIVE_LOADER_THREADfrom scripts and CI; it no longer has an effect.- Under the native engine, a runtime without
module.registerHooks(Bun) getsUNSUPPORTED_NODEtoo. - The support policy is in
docs/versioning.md.
- Under the native engine, a runtime without
-
dae3119: Native engine: a file that Vite and Node both load, with both copies in use, is now reported by name,
SOURCE_EVALUATED_TWICE, instead of silently existing twice. No action needed. To fail on it, setreactNative({ ownership: 'error' }).- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
ownership: { allow: [{ path, reason }] }. require()of a CommonJS project file a test already imported now returns that samemodule.exports.- The warning, its end-of-run summary and
vitest-native doctorlink the error reference.
- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
-
5cad255: Native engine: a new opt-in flag makes Vite and Node resolve a package to the same file, so one package is one module. Add
experimental: { ownershipModel: 'resolver' }to try it. Nothing changes without it.- Any package with separate
importandrequirebuilds, or areact-nativefield, loads one file on both sides; a JSX or Flowreact-nativefield is compiled, as Metro does. - RegExp aliases and tsconfig
pathsalso apply to Node'srequire, includingjest.requireActual.NODE_PATHapplies torequireonly, as in Node. - Not covered: an alias with a custom resolver or a function replacement. It is refused at startup by name. See
experimental.
- Any package with separate
-
45154cf: Native engine:
experimental: { ownershipModel: 'resolution' }gives Node'srequireof a project file the same instance a test'simportgets, whichever loads it first. To try it, set the flag; it also turns onnodeMocks, and refusesnodeMocks: false.- A file not yet evaluated is evaluated then. A
requireback into a module from inside its own evaluation gets its exports so far, as in Node and Jest. - Mocks apply to what Node's
requirereaches, as to the test's imports. - What cannot be served fails by name: top-level
await, a module that throws, one still evaluating when required from elsewhere, or a mock not available synchronously (MOCK_NOT_SEEN_BY_NODE).
- A file not yet evaluated is evaluated then. A
-
4271252: Under the native engine, the worklets, safe-area-context, keyboard-controller, bottom-sheet and netinfo presets are each library's own Jest mock, as a Jest suite installs it. No action needed; snapshots of the presets' own output may change, and the mock engine keeps the hand-written presets.
- Safe-area insets are zero unless
<SafeAreaProvider initialMetrics>sets them;setInsets()still sets them untilresetAllMocks(). - Bottom-sheet's views render only their children, and netinfo reports a connected cellular network.
- Names a preset served that a mock lacks stay: bottom-sheet's
*_STATUSenums and footer components, netinfo's `useNetInfoInstan...
- Safe-area insets are zero unless
v0.15.0-rc.1
Upgrading from 0.14
- Node 22.22.3+, 24.12+ or 26+. An older Node stops at startup with
UNSUPPORTED_NODE. - Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER. - React 19, React Native Testing Library 13 or 14, and React Native 0.86+ (Expo SDK 57+) for the
native engine. An older React or React Native stops at startup withUNSUPPORTED_PEER. - Run
npx vitest-native doctorto check all of these. Each entry below has the details.
Minor Changes
-
a107e3a: New
vitest-native compareruns your suite under your own Jest and under Vitest and lists every test whose result differs. Use it while both runners are in place:npx vitest-native comparenames each test that passes under Jest but not under Vitest, grouped by its first error, and exits 0 only when every one of them passes andvitest runexits 0. Neither run writes snapshots or changes project files, and--json <file>writes a report without stack traces or absolute paths, for attaching to an issue. See the CLI reference. -
4271252: Under the native engine,
react-native-gesture-handlerand@shopify/flash-listrun as themselves, with thejestSetup.jseach ships before the project's setup files, as a Jest suite lists them. No action needed; to keep a preset, setpresets: { gestureHandler: true }or{ flashList: true }.- Gesture Handler 3's hook API, builder methods and test helpers work, and a
Pressablepress firesonPress. - A
FlashListrenders a window of rows, as under Jest, where the preset rendered every row. react-native-gesture-handler/Swipeableand the other modules Gesture Handler 3 does not ship no longer resolve, as under Jest.
- Gesture Handler 3's hook API, builder methods and test helpers work, and a
-
4271252: Under the native engine, a React Native library's own Jest setup and mocks get a
jestwith Jest's semantics. No action needed; a suite that importsreact-native-gesture-handler/jestSetuporreact-native-safe-area-context/jest/mockgets what Jest gave it.- Their
jest.mockreaches everyrequireof the module, andjest.requireActualand@jest/globalswork. - Implementations a library installs while building its mocks survive
vi.resetAllMocks()andmockReset: true. jest.requireActualof a package a preset shadows returns the package, as under Jest.
- Their
-
ebdda39: Breaking: vitest-native now requires Node 22.22.3+, 24.12+ or 26+, for both engines. An unsupported Node stops at startup with
UNSUPPORTED_NODE, naming the release to install;vitest-native doctorreports the same.Update Node within your major, or move from Node 20, 23 or 25 to a supported line, including CI images and
.nvmrcorenginespins. RemoveVITEST_NATIVE_LOADER_THREADfrom scripts and CI; it no longer has an effect.- Under the native engine, a runtime without
module.registerHooks(Bun) getsUNSUPPORTED_NODEtoo. - The support policy is in
docs/versioning.md.
- Under the native engine, a runtime without
-
dae3119: Native engine: a file that Vite and Node both load, with both copies in use, is now reported by name,
SOURCE_EVALUATED_TWICE, instead of silently existing twice. No action needed. To fail on it, setreactNative({ ownership: 'error' }).- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
ownership: { allow: [{ path, reason }] }. require()of a CommonJS project file a test already imported now returns that samemodule.exports.- The warning, its end-of-run summary and
vitest-native doctorlink the error reference.
- The report names the file, how each side loaded it, and the fix. Exempt a deliberate case with
-
5cad255: Native engine: a new opt-in flag makes Vite and Node resolve a package to the same file, so one package is one module. Add
experimental: { ownershipModel: 'resolver' }to try it. Nothing changes without it.- Any package with separate
importandrequirebuilds, or areact-nativefield, loads one file on both sides; a JSX or Flowreact-nativefield is compiled, as Metro does. - RegExp aliases and tsconfig
pathsalso apply to Node'srequire, includingjest.requireActual.NODE_PATHapplies torequireonly, as in Node. - Not covered: an alias with a custom resolver or a function replacement. It is refused at startup by name. See
experimental.
- Any package with separate
-
45154cf: Native engine:
experimental: { ownershipModel: 'resolution' }gives Node'srequireof a project file the same instance a test'simportgets, whichever loads it first. To try it, set the flag; it also turns onnodeMocks, and refusesnodeMocks: false.- A file not yet evaluated is evaluated then. A
requireback into a module from inside its own evaluation gets its exports so far, as in Node and Jest. - Mocks apply to what Node's
requirereaches, as to the test's imports. - What cannot be served fails by name: top-level
await, a module that throws, one still evaluating when required from elsewhere, or a mock not available synchronously (MOCK_NOT_SEEN_BY_NODE).
- A file not yet evaluated is evaluated then. A
-
4271252: Under the native engine, the worklets, safe-area-context, keyboard-controller, bottom-sheet and netinfo presets are each library's own Jest mock, as a Jest suite installs it. No action needed; snapshots of the presets' own output may change, and the mock engine keeps the hand-written presets.
- Safe-area insets are zero unless
<SafeAreaProvider initialMetrics>sets them;setInsets()still sets them untilresetAllMocks(). - Bottom-sheet's views render only their children, and netinfo reports a connected cellular network.
- Names a preset served that a mock lacks stay: bottom-sheet's
*_STATUSenums and footer components, netinfo'suseNetInfoInstance.
- Safe-area insets are zero unless
-
4271252: Reanimated's
interpolate,interpolateColorandclampreturn real values, and its scroll and event hooks run their handlers. No action needed; snapshots of interpolated styles may change.- Of Reanimated's own mock, only what still answers with a no-op is replaced, so a later Reanimated whose mock does better keeps its own.
- Shared values take listeners, so a Gesture Handler 3 gesture configured with a shared value works.
- Reanimated 3.17 to 4.6 get the same fixes in the hand-written preset.
-
4271252: Under the native engine, Reanimated 4.7+ (with Worklets 0.9+) is Reanimated's own test mock, as a Jest suite installs it with
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock')). No action needed;presets: { reanimated: false }turns it off, and older versions keep the hand-written preset.- The hand-written preset lacked 104 of the mock's names, among them
interpolateColor,Keyframe,useScrollOffsetand most layout animations. - Worklets is its own test mock too, so a test and Reanimated share one instance; its
runOnJSandscheduleOnRNrun a tick later, as under Jest. - A setup file that calls Reanimated's
setUpTests()keepstoHaveAnimatedStyleandtoHaveAnimatedPropsworking; keep or delete the call.
- The hand-written preset lacked 104 of the mock's names, among them
-
0a71dff: Native engine: a cold run now starts at once instead of waiting for React Native's precompiled modules to build. They compile in a low-priority background process.
To opt out, set
reactNative({ registryBuild: 'wait' })to build them before the run, as before.- Test files that start before the build lands load React Native file by file, which is slower; column numbers in React Native's stack frames can differ.
- CI runs and
hotRuntimestill wait. On close, a running build gets half ofteardownTimeoutto finish. - Not covered: on Windows, a Vitest process killed outright can leave the compiler running for about 130 s.
-
5a7f226: Breaking: vitest-native now requires React 19 and supports React Native Testing Library 13 or 14, and the native engine requires React Native 0.86+. An older React or React Native stops at startup with
UNSUPPORTED_PEER, for examplereact-native 0.85.3 is not supported: the native engine supports react-native 0.86–0.88;vitest-native doctorreports the same.Upgrade to React Native 0.86 or later (Expo SDK 57 or later) and React 19, and move from React Native Testing Library 12 to 13 or 14.
- Testing Library 14 makes
render,fireEventandactasync:await render(<App />). - The mock engine runs on any React Native.
- Testing Library outside 13–14, React Native above 0.88, or an Expo SDK other than 57 and 58, warns rather than fails.
- Testing Library 14 makes
-
25f0147: Under the native engine, a test file that imports
react-nativenow loads only the React Native modules it uses. No action needed.- Each export is read when a test uses it, as under Jest, instead of all at once on import, which loaded React Native's whole module graph.
- A change made to an export on the real
react-nativemodule is now visible throughimport { … } from "react-native"too.
-
2b764f1: Breaking: vitest-native now requires Vitest 5 and Vite 8. Vitest 4, or Vite 6 or 7, stops at startup with
UNSUPPORTED_PEER, naming the supported range;vitest-native doctorreports the same.Install
vitest@^5with matching@vitest/*packages, andvite@^8.0.5.- Vitest 5 clears mocks before every test (
clearMocks: true). A suite that asserts on calls recorded before the test started setstest.clearMocks: false. - The plugin turns on Vitest 5's
fsModuleCacheunless the config setstest.fsModuleCacheortest.experimental.fsModuleCache. - Babel plugins your tests need go through
@rolldown/plugin-babel;@vitejs/plugin-react6 removed itsbabeloption.
- Vitest 5 clears mocks before every test (
Patch Changes
- a107e3a:
vitest-native init,doctorandmigratenow refuse a flag they do not take, instead of ignoring it. A typo such asmigrate --wirteused to run a dry report without saying so; it now exits 1 with `✗ unknown option --wirte for migrate. Va...
v0.14.1
Patch Changes
-
0dd12ca: Native engine: a React Native package's required peer that your package manager installs for you (pnpm, npm 7+ and bun do), such as expo-router's
expo-linking, is now compiled. No action needed. Removetransform: ['expo-linking']if you added it for this.- Before, a required peer that no
package.jsondeclared stayed uncompiled. It then failed with "Cannot require() ES Module … not yet fully loaded" or "Cannot find module …/Linking.types". - Optional peers, and peers a package names only in its config plugin, scripts or types, are still not followed.
Thanks @AntSplash360 for reporting this (#296).
- Before, a required peer that no
-
967d3cf: Under the native engine, a relative import whose name has a dot, such as
./Linking.types, now resolves. A package that Node loads as an ES module failed with "Cannot find module …/Linking.types" because the part after the dot was read as a file extension. Only a known source or asset extension counts now, as in Metro, so./Linking.typesfindsLinking.types.js, and a platform variant such asTheme.config.native.jswins overTheme.config.js. No action needed.Thanks @AntSplash360 for reporting this (#296).
-
8ea7273:
vitest-native migratenow readsjest.config.ts,.mjs,.mtsand.cts, in Jest's own lookup order. TypeScript configs load through Node's type stripping (Node 22.18 or later). A config that still can't be loaded, such as one that relies on ts-node (an extensionless relative import, anenum), uses top-levelawaitor exports a function, is now listed under "Needs your attention" with the reason, where before the report silently left out its settings. No action needed. -
e5ff183:
vitest-native migratenow warns when the project's Babel config makes imports lazy under Jest. Withbabel-preset-expo'slazyImports,@react-native/babel-preset'slazyImportExportTransform, the CommonJS transform'slazyoption or an inline-requires plugin, Jest ran a package import only when a test first used it, while vitest-native runs every import when its file loads. A module a test never touched is then evaluated, and a partialjest.mockof something it needs can fail. The report now lists the setting under "Needs your attention". Babel plugin names under the@babel/scope are also now read the way Babel reads them.Use
jest.requireActualto give such a mock the rest of its module:jest.mock('x', () => ({ ...jest.requireActual('x'), ... })).
What's Changed
- fix(migrate): read jest.config.ts, .mjs, .mts and .cts in Jest's lookup order by @danfry1 in #512
- test: start the Babel worker before the tests that transform by @danfry1 in #514
- fix(migrate): flag Babel settings that made imports lazy under Jest by @danfry1 in #515
- docs(readme): one short README for GitHub and npm by @danfry1 in #518
- docs(site): make the getting-started snippets run under the default engine by @danfry1 in #520
- fix(native): compile a required React Native peer a compiled package loads, though nothing declares it by @danfry1 in #519
- docs(site): one Mocking page for vi.mock reach, untranspiled packages and fake timers by @danfry1 in #521
- fix(native): a relative import with a dot in its name resolves, as in Metro by @danfry1 in #509
- test(museum): pfs-hot-unawaited-act fails by name with one worker, its accepted outcome by @danfry1 in #517
- test(docs): run the README and quick-start snippets against the packed package by @danfry1 in #522
- chore(release): 0.14.1 by @danfry1 in #524
Full Changelog: v0.14.0...v0.14.1
v0.14.0-rc.14
Upgrading from 0.13
- Node 22.13 or later on Node 22, or Node 24.3 or later.
engines.nodeis
>=22.13.0 <23 || >=24.3.0(it was>=20.19.0): Node 20 reached end of life in April 2026, and
on Node 24.0–24.2jest.mock,jest.isolateModulesandjest.resetModulesdo not reach modules
Node loads.vitest-native doctorchecks the range. - Per-file isolation stays the default.
hotRuntimedefaults tofalse, as in 0.13.0: under
the native engine each test file runs in a fresh worker. The hot runtime, which reuses workers
across files and is faster on most suites, is available withhotRuntime: 'auto'. Five known
differences from per-file isolation are listed in
troubleshooting.
Early 0.14.0 release candidates defaulted to'auto'; sethotRuntime: 'auto'to keep the hot runtime. - How to tell. When the hot runtime is active, the startup banner names it, as in
(platform ios, hot runtime). With'auto', it keeps Vitest's per-file isolation whenever the run
cannot be bounded, or when you set a pool ortest.isolateyourself, and prints the reason. - Hot workers leave Node's compile cache off when they re-evaluate ES modules, so the cache no
longer grows with every test file. It costs about 15–20 ms per worker boot;
hotRuntime: { esmGeneration: false }keeps the cache on. - Hot workers no longer keep a copy of every CommonJS package each file imports, on Node
22.22.3+, 24.12+ and 26, so a suite importing large packages no longer recycles workers every few
files. hotRuntime: { mode: 'auto', memoryLimit }runs hot with your recycling options where the run
can be bounded and keeps per-file isolation where it cannot. Withoutmode, the object form still
requires the hot runtime.- A test that times out inside
act()retires its hot worker, so later files on that worker no
longer fail withUnable to find an element with text: …. - Coverage works under the native engine. With
provider: 'v8', files Node compiles, such as a
React Native workspace package, are reported against their source lines. - A project file imported and required in one test is one module. Under the native engine, with
or without jest-compat,vi.spyOn, export assignments andinstanceofreach both sides, as under
Jest. - Vite+ projects start. The Vite and Vitest versions are read from the running instances, so
Vite+ no longer fails withUNSUPPORTED_PEER. Two physical copies of Vitest stop the run at startup
withVITEST_TWIN_INSTANCE, naming both. - Expo SDK 57 and 58 are the supported SDKs. On an older or newer SDK the plugin prints one
warning per run naming them, andvitest-native doctorreports it; tests that load Expo modules
can fail there. A test that loadsexpoorexpo-modules-corefrom another SDK, for example through
a library, also warns, naming the version and path. Upgrade to Expo SDK 57 or 58. - The package is about 30% smaller and no longer ships
CHANGELOG.md; the changelog is
on GitHub. - RNTL works without jest-compat or globals.
findBy*,waitForanduserEventadvance
vi.useFakeTimers(), and RNTL's auto-cleanup runs withouttest.globals: true. A suite that relied
on trees staying mounted between tests imports@testing-library/react-native/pure. - Expo path aliases resolve. In an Expo project on Vite 8, imports through tsconfig
paths(the
template's@/…) now resolve as Metro resolves them; avite-tsconfig-pathsplugin or a hand-written
alias for them can go. - Vitest 5 keeps transformed modules on disk. The plugin turns on Vitest's
fsModuleCacheunless
your config sets it, keyed so that upgrading vitest-native or any dependency invalidates it. Set
test.fsModuleCache: falseto opt out. - react-native-mmkv 3 and later run as themselves. They detect Vitest and use their own in-memory
backend, so themmkvpreset now applies to mmkv 2 only. Tests get mmkv's real API (v4'sremove)
and change listeners instead of the preset's approximation. - jest-compat follows Jest more closely. A name a
jest.mockfactory leaves out isundefined
instead of an error,newon ajest.fnwith an arrow implementation works, and
process.env.JEST_WORKER_IDis set, so code that checks for Jest takes its test branch. hotRuntime: trueis stricter. Combined with a configured pool,test.isolate, or a conflicting
CLI flag, it now fails at startup withHOT_RUNTIME_OVERRIDDENinstead of warning and overriding.- Native modules answer as on a device. Under the native engine,
NativeModules[name]and
TurboModuleRegistry.get(name)areundefined/nullfor a module no app registers, and a React
Native module's stub has only the methods its codegen spec declares. Register a module a test needs
withmockNativeModule(name, impl);nativeModules: 'permissive'restores the earlier behaviour. - Assets are registered ids.
require('./logo.png')evaluates to the id React Native assigned
when registering the asset, as with Metro, instead of the file name. Snapshots that contained an asset's name
change; re-record them with-u. jest.mockreachesrequire(). With jest-compat, ajest.mockfactory now applies to
require(),jest.requireActual's dependencies and React Native's own requires of a mocked internal;
jest.isolateModulesandjest.isolateModulesAsyncwork. TypeScript app files that Node loads are
compiled with the project's Babel config, as babel-jest compiles them.- Unistyles and Skia are mocked automatically. The new
unistylesandskiapresets are
auto-detected. Remove Unistyles'react-native-unistyles/mockssetup file, whosejest.mock()calls
would replace the preset (vitest-native migrateremoves it), and a hand-written Skia mock, which the
preset replaces. Skia's preset loads CanvasKit before each test file, about 20–30 ms;
presets: { skia: false }turns it off. - Presets of your own are listed by path. A preset object of a project's own passed to
presets
used to shadow its packages with undefined exports; it is now refused at startup. List the module that
exports it instead:presets: { './test/presets/my-lib.ts': true }. - A deep import of a preset package loads its real file. Under the native engine,
react-native-reanimated/src/…and similar subpaths are the package's own files, as under Jest,
not the root mock; import from the package root if a test relied on the mock. The
safeAreaContextpreset's hooks read their contexts, so call them inside a component or
renderHook. - Expo SDK 57 and 58 projects run real React Native with nothing extra installed. When
@react-native/babel-presetdoes not resolve (babel-preset-expono longer depends on it), the
native engine compiles with Expo's preset, as Metro does.reactNative()used the mock engine there
before. - Expo's globals are installed before your setup files, and
fetchstays Node's. Afetchmocked
in a setup file, an MSW server, nock and undici'sMockAgentkeep working whether or not a test
importsexpo. Every test file in an Expo project now sees Expo'sURL,structuredCloneand
DOMExceptionpolyfills, as under jest-expo. - Expo's globals need
expodeclared. The native engine installs Expo's runtime (URL,
structuredCloneand the other globals jest-expo installs) only when the project, or a manifest
above it, declaresexpoor a package that depends on it, ortransformnames it. A project where
expomerely resolves, for example beside an Expo app in a hoisted workspace, no longer gets them;
declareexpoor add it totransformif it relies on them. - Your Babel config runs on its own thread. Under the native engine, Babel runs apart from the
tests, as under Jest. A Babel config or plugin sees the Babel worker'sprocess.argv,
isMainThreadisfalse, and the tests'require.cacheand globals are not visible.
process.envis shared. A transform slower than 60 s plus 15 s per MB of source fails with
TRANSFORM_FAILED. - Expo modules' own native-module mocks are served. Values that were
undefinedare the mock's
(digestStringAsyncresolves""), and a member a mock leaves out isundefinedwhere the generic
stub gave a function. - An optional native module that is not installed reads as absent.
requireOptionalNativeModule
returnsnullfor a module a package only probes for and no installed package defines, as on a
device. - Expo modules run as their installed packages. Under the native engine, the
expopreset no
longer replacesexpo-constants,expo-status-bar,expo-font,expo-asset,expo-splash-screen
andexpo-linking, so their whole API is the installed SDK's (hide(),setOptions(),
useAssets…) and their values are jest-expo's:Constants.expoConfigis{},
Linking.createURL()needs a scheme mocked intoexpo-constants, andFont.isLoaded()isfalse
until a font loads. The Minor Changes entry lists each value;presets: { expo: true }keeps the
preset while a suite moves off it.
Thank you
Thank you to @AntSplash360, @arvidtorbjoernsen, @believer, @doutatsu, @eshvatskyi, @Joozty, @OpenDeernet, @sincraianul and @swey for the issues and pull requests in this release.
Minor Changes
- 271c149: **
hotRuntime: 'auto'can take recyclin...
v0.14.0-rc.13
Upgrading from 0.13
- Node 22.13 or later on Node 22, or Node 24.3 or later.
engines.nodeis
>=22.13.0 <23 || >=24.3.0(it was>=20.19.0): Node 20 reached end of life in April 2026, and
on Node 24.0–24.2jest.mock,jest.isolateModulesandjest.resetModulesdo not reach modules
Node loads.vitest-native doctorchecks the range. - Per-file isolation stays the default.
hotRuntimedefaults tofalse, as in 0.13.0: under
the native engine each test file runs in a fresh worker. The hot runtime, which reuses workers
across files and is faster on most suites, is available withhotRuntime: 'auto'. Five known
differences from per-file isolation are listed in
troubleshooting.
Early 0.14.0 release candidates defaulted to'auto'; sethotRuntime: 'auto'to keep the hot runtime. - How to tell. When the hot runtime is active, the startup banner names it, as in
(platform ios, hot runtime). With'auto', it keeps Vitest's per-file isolation whenever the run
cannot be bounded, or when you set a pool ortest.isolateyourself, and prints the reason. - Hot workers leave Node's compile cache off when they re-evaluate ES modules, so the cache no
longer grows with every test file. It costs about 15–20 ms per worker boot;
hotRuntime: { esmGeneration: false }keeps the cache on. - Hot workers no longer keep a copy of every CommonJS package each file imports, on Node
22.22.3+, 24.12+ and 26, so a suite importing large packages no longer recycles workers every few
files. hotRuntime: { mode: 'auto', memoryLimit }runs hot with your recycling options where the run
can be bounded and keeps per-file isolation where it cannot. Withoutmode, the object form still
requires the hot runtime.- A test that times out inside
act()retires its hot worker, so later files on that worker no
longer fail withUnable to find an element with text: …. - Coverage works under the native engine. With
provider: 'v8', files Node compiles, such as a
React Native workspace package, are reported against their source lines. - A project file imported and required in one test is one module. Under the native engine, with
or without jest-compat,vi.spyOn, export assignments andinstanceofreach both sides, as under
Jest. - Vite+ projects start. The Vite and Vitest versions are read from the running instances, so
Vite+ no longer fails withUNSUPPORTED_PEER. Two physical copies of Vitest stop the run at startup
withVITEST_TWIN_INSTANCE, naming both. - Expo SDK 57 and 58 are the supported SDKs. On an older or newer SDK the plugin prints one
warning per run naming them, andvitest-native doctorreports it; tests that load Expo modules
can fail there. A test that loadsexpoorexpo-modules-corefrom another SDK, for example through
a library, also warns, naming the version and path. Upgrade to Expo SDK 57 or 58. - The package is about 30% smaller and no longer ships
CHANGELOG.md; the changelog is
on GitHub. - RNTL works without jest-compat or globals.
findBy*,waitForanduserEventadvance
vi.useFakeTimers(), and RNTL's auto-cleanup runs withouttest.globals: true. A suite that relied
on trees staying mounted between tests imports@testing-library/react-native/pure. - Expo path aliases resolve. In an Expo project on Vite 8, imports through tsconfig
paths(the
template's@/…) now resolve as Metro resolves them; avite-tsconfig-pathsplugin or a hand-written
alias for them can go. - Vitest 5 keeps transformed modules on disk. The plugin turns on Vitest's
fsModuleCacheunless
your config sets it, keyed so that upgrading vitest-native or any dependency invalidates it. Set
test.fsModuleCache: falseto opt out. - react-native-mmkv 3 and later run as themselves. They detect Vitest and use their own in-memory
backend, so themmkvpreset now applies to mmkv 2 only. Tests get mmkv's real API (v4'sremove)
and change listeners instead of the preset's approximation. - jest-compat follows Jest more closely. A name a
jest.mockfactory leaves out isundefined
instead of an error,newon ajest.fnwith an arrow implementation works, and
process.env.JEST_WORKER_IDis set, so code that checks for Jest takes its test branch. hotRuntime: trueis stricter. Combined with a configured pool,test.isolate, or a conflicting
CLI flag, it now fails at startup withHOT_RUNTIME_OVERRIDDENinstead of warning and overriding.- Native modules answer as on a device. Under the native engine,
NativeModules[name]and
TurboModuleRegistry.get(name)areundefined/nullfor a module no app registers, and a React
Native module's stub has only the methods its codegen spec declares. Register a module a test needs
withmockNativeModule(name, impl);nativeModules: 'permissive'restores the earlier behaviour. - Assets are registered ids.
require('./logo.png')evaluates to the id React Native assigned
when registering the asset, as with Metro, instead of the file name. Snapshots that contained an asset's name
change; re-record them with-u. jest.mockreachesrequire(). With jest-compat, ajest.mockfactory now applies to
require(),jest.requireActual's dependencies and React Native's own requires of a mocked internal;
jest.isolateModulesandjest.isolateModulesAsyncwork. TypeScript app files that Node loads are
compiled with the project's Babel config, as babel-jest compiles them.- Unistyles and Skia are mocked automatically. The new
unistylesandskiapresets are
auto-detected. Remove Unistyles'react-native-unistyles/mockssetup file, whosejest.mock()calls
would replace the preset (vitest-native migrateremoves it), and a hand-written Skia mock, which the
preset replaces. Skia's preset loads CanvasKit before each test file, about 20–30 ms;
presets: { skia: false }turns it off. - Presets of your own are listed by path. A preset object of a project's own passed to
presets
used to shadow its packages with undefined exports; it is now refused at startup. List the module that
exports it instead:presets: { './test/presets/my-lib.ts': true }. - A deep import of a preset package loads its real file. Under the native engine,
react-native-reanimated/src/…and similar subpaths are the package's own files, as under Jest,
not the root mock; import from the package root if a test relied on the mock. The
safeAreaContextpreset's hooks read their contexts, so call them inside a component or
renderHook. - Expo SDK 57 and 58 projects run real React Native with nothing extra installed. When
@react-native/babel-presetdoes not resolve (babel-preset-expono longer depends on it), the
native engine compiles with Expo's preset, as Metro does.reactNative()used the mock engine there
before. - Expo's globals are installed before your setup files, and
fetchstays Node's. Afetchmocked
in a setup file, an MSW server, nock and undici'sMockAgentkeep working whether or not a test
importsexpo. Every test file in an Expo project now sees Expo'sURL,structuredCloneand
DOMExceptionpolyfills, as under jest-expo. - Expo's globals need
expodeclared. The native engine installs Expo's runtime (URL,
structuredCloneand the other globals jest-expo installs) only when the project, or a manifest
above it, declaresexpoor a package that depends on it, ortransformnames it. A project where
expomerely resolves, for example beside an Expo app in a hoisted workspace, no longer gets them;
declareexpoor add it totransformif it relies on them. - Your Babel config runs on its own thread. Under the native engine, Babel runs apart from the
tests, as under Jest. A Babel config or plugin sees the Babel worker'sprocess.argv,
isMainThreadisfalse, and the tests'require.cacheand globals are not visible.
process.envis shared. A transform slower than 60 s plus 15 s per MB of source fails with
TRANSFORM_FAILED. - Expo modules' own native-module mocks are served. Values that were
undefinedare the mock's
(digestStringAsyncresolves""), and a member a mock leaves out isundefinedwhere the generic
stub gave a function. - An optional native module that is not installed reads as absent.
requireOptionalNativeModule
returnsnullfor a module a package only probes for and no installed package defines, as on a
device. - Expo modules run as their installed packages. Under the native engine, the
expopreset no
longer replacesexpo-constants,expo-status-bar,expo-font,expo-asset,expo-splash-screen
andexpo-linking, so their whole API is the installed SDK's (hide(),setOptions(),
useAssets…) and their values are jest-expo's:Constants.expoConfigis{},
Linking.createURL()needs a scheme mocked intoexpo-constants, andFont.isLoaded()isfalse
until a font loads. The Minor Changes entry lists each value;presets: { expo: true }keeps the
preset while a suite moves off it.
Thank you
Thank you to @AntSplash360, @arvidtorbjoernsen, @believer, @doutatsu, @eshvatskyi, @Joozty, @OpenDeernet, @sincraianul and @swey for the issues and pull requests in this release.
Minor Changes
- 271c149: **
hotRuntime: 'auto'can take recyclin...