Introduction
It was all so easy. Simply run the react-native init
command, set the preset in your Jest config as 'react-native'
, and voila, npm test
works like a charm. But, things aren't as rosy when you want to publish npm libraries and Jest is your chosen test suite.
While we all love the modern ESM import from
and export default
syntax, Jest - not so much. It is very much still in love with CommonJS syntax. This along with the fact that react-native code uses Flow, made my life not-so-easy when trying to publish my npm library. It wasn't just me experiencing these issues. Based on these discussions - Issue 152, Issue 10111 - many of my fellow devs were facing similar roadblocks.
To introduce some order to all the above chaos, here are some steps to get Jest working with your ESM-based npm library for React Native:
Setting up your package.json
{
{
"name": "my-react-native-library",
"version": "1.0.1",
"description": "A useful library",
"main": "dist/index.js",
"scripts": {
"test": "jest",
"prepare": "npm run build",
"build": "BABEL_ENV=production babel <folder-path-with-your-code> --out-dir dist",
},
"keywords": [
"useful"
],
"author": "Ronil Mehta",
"license": "ISC",
"dependencies": {
"@react-native-async-storage/async-storage": "~1.15.0",
"react-native-get-random-values": "~1.7.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/cli": "^7.18.9",
"@babel/core": "^7.18.9",
"@babel/preset-env": "^7.18.9",
"@babel/preset-flow": "^7.18.6",
"jest": "^27.5.1",
"jsdoc-to-markdown": "^7.1.1"
}
}
}
Setting up your babel.config.js
module.exports = {
presets: [
"@babel/preset-env",
"@babel/preset-flow"
],
env: {
production: {
ignore: [
"<folder-path-with-your-code>/**/*.test.js"
]
}
}
}
It's important to know that babel runs the presets
array from right to left. Meaning, it will first run @babel/preset-flow
and then @babel/preset-env
. @babel/preset-flow
first converts any Flow syntax in react-native to ESM. @babel/preset-env
then converts this ESM code to CommonJS, which is then used by Jest.
Note: Jest had issues when the babel configs were in .babelrc
or in package.json
. Please make sure to write your babel config in babel.config.js
.
Setting up your jest.config.js
Run npx jest --init
in the project root directory to begin the config file generator wizard. The following are the inputs you should provide:
$ npx jest --init
The following questions will help Jest to create a suitable configuration for your project
✔ Would you like to use Typescript for the configuration file? … no
✔ Choose the test environment that will be used for testing › jsdom (browser-like)
✔ Do you want Jest to add coverage reports? … yes
✔ Which provider should be used to instrument code for coverage? › babel
✔ Automatically clear mock calls, instances and results before every test? … yes
Once the config is generated, set preset: 'react-native'
.
By default, Jest ignores libraries in node_modules
when transforming code using babel. But since react-native contains Flow
code that needs to be transpiled, a special regex needs to be added to transformIgnorePatterns
in the config. One of the most important things preset: 'react-native' does is force Jest to transform the react-native libraries in
node_modulesto a form Jest can understand. It does this by presetting the value of
transformIgnorePatternsin
jest.config.js`.
Running Jest
Now that you have carefully followed the above instructions and set up the configs, it is time to run some unit tests:
Execute npm test
and hopefully, you see a whole lot of green text!