React Native mocks for testing. It is the same as the internal Jest-based mocks but is more straightforward, faster, and decoupled from the Jest dependency.
Testing on React Native is not such a trivial task, mainly because some modules and components communicate directly to native code (iOS, Android, etc.) However, in a testing environment like Node.js, the native code is unavailable. Also, React Native code is not delivered in a distributable manner -- most of the code in Flow, and some modules need to go through a haste map resolver (modules with .ios.js
and .android.js
prefix, required without the prefix).
React Native solves this problem through Jest, providing Jest mocks for native modules. Jest transpiles the code before running it, so there's also a Flow preset in the configuration and some settings to solve the haste map. React Native then exports this configuration as a Jest preset for developers to use with their Jest configuration.
But what if you don't want to use Jest as your testing framework? What if you don't need Babel because you already have TypeScript, and your test can run on ts-node? Is it even possible to test React Native code without Jest? This package aims to solve this problem by providing mocks the same way as React Native does but without Jest dependency in the middle. It solves the "haste map" modules and transforms Flow code on the fly, caching the result so subsequent executions are 6x faster. Overall, the package makes it possible to test React Native in other frameworks, like Mocha.js.
- Fast and simple. It transforms just what it needs when it needs it.
- 6x faster before cache.
- 12x faster after cache.
- Compatible with @testing-library/react-native renderer.
- Extensive range of compatibility by imitating React Native's original mocks.
- Testing framework agnostic.
- Easy to use and set up.
- It provides a function to add behaviors to the native methods of Native Components.
- Node.js: >=18
- react: >=18.2.0
- react-native: ">=0.73.2
With NPM:
npm i --save-dev react-native-testing-mocks
With Yarn:
yarn add --dev react-native-testing-mocks
To register the testing mocks, load the effect in a file that runs before all tests:
// setup.ts
import "react-native-testing-mocks/register";
// ...rest of your setup code
Ideally, Vitest should be able to replace Babel when it comes to resolving and transforming the React Native code. However, so much more goes on in @react-native/babel-preset that replacing this module with Vite is not only a hard task but also increases the risk of something going wrong. So, until React Native delivers their code in a more conventional format (CommonJS/ESM), is my opinion that it's safer to keep using Babel to transform React Native's code with Vitest.
That being said, this package also provides a Vite Plugin you can add to your vitest.config.ts
configuration file:
import { reactNativeVitestPlugin } from "react-native-testing-mocks/vitest";
import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [reactNativeVitestPlugin()],
test: {
include: ["test/**/*.test.ts?(x)"],
setupFiles: "./test/setup.ts",
},
});
Some frameworks like Mocha provide a mechanism to require modules during the Node.js execution. For instance, you can use the --require
CLI option:
mocha --require react-native-testing-mocks/register
Or you can add it to the .mocharc.json
file:
{
"$schema": "https://json.schemastore.org/mocharc",
"exit": true,
"extension": ["ts", "tsx"],
"recursive": true,
"require": [
"ts-node/register",
"react-native-testing-mocks/register",
"./test/setup.ts"
],
"spec": ["test/**/*.test.ts?(x)"]
}
Native components like View
, ScrollView
, or TextInput
have specific instance methods that help communicate between JS and native code. Because there's no native code on tests, we must mock these native methods somehow. By default, the methods mocks are just a "no-operation" function, meaning nothing happens whenever a component invokes them in a test environment.
However, your components may be using these methods in their implementation, and it'd be good to be able to test that as well. React Native Testing Mocks provides the mockNative
function that allows you to change the default native methods mocks on native components. Let's say your component uses the .measure
instance method of a <View>
component. Before you run your test, you can change the mocked behavior of .measure
like so:
mockNative("View", { measure: callback => { callback(10, 10, 100, 100) } });
Now, whenever a test invokes the .measure
method of any View
instance, it will use your implementation instead. Remember that mocks persist until the program finishes, but you can restore the original behavior called restoreNativeMocks()
. You can add the method to a before hook to ensure restoration after each test:
afterEach(() => {
restoreNativeMocks();
});
Suggestions are always welcome! Please create an issue describing the request, feature, or bug. Opening meaningful issues is as helpful as opening Pull Requests.
Pull Requests are very welcome as well! Please fork this repository and open your PR against the main
branch.