HomeGuidesReferenceLearn
ArchiveExpo SnackDiscord and ForumsNewsletter

Unit testing

Learn how to set up and configure the jest-expo package to write unit tests and snapshot tests for a project.


Jest is the most widely used JavaScript unit testing framework. In this guide, you'll learn how to set up Jest in your project, write a unit test, write a snapshot test, and best practices for structuring your tests when using Jest with React Native.

You'll also use the jest-expo package, which is a Jest preset and mocks the native part of the Expo SDK and handles most of the configuration.

Installation

To install jest-expo in your project, run the following command:

Terminal
- npx expo install jest-expo jest
If you are using TypeScript, then also install @types/jest as a dev dependency.

Then, update package.json to add a script for running tests and add the preset for using the base configuration from jest-expo:

package.json
"scripts": {
  %%placeholder-start%%... %%placeholder-end%%
  "test": "jest"
},
%%placeholder-start%%... %%placeholder-end%%
"jest": {
  "preset": "jest-expo"
}

Configuration

A starting configuration you can use is to make sure any modules you are using within the node_modules directory are transpiled when running Jest. This can be done by including the transformIgnorePatterns property that takes a regex pattern as its value:

package.json
"jest": {
  "preset": "jest-expo",
  "transformIgnorePatterns": [
    "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)"
  ]
}
package.json
"jest": {
  "preset": "jest-expo",
  "transformIgnorePatterns": [
    "node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg))"
  ]
}

Jest has various configuration options. The above configuration covers the majority of your needs. However, you can always add to this pattern list. For more details, see Configuring Jest.

Unit test

A unit test is used to check the smallest unit of code, usually a function.

To write your first unit test, start by writing a simple test for App.js. Create a test file for it and call it App.test.js. Jest identifies a file with the .test.js extension as a test and includes it in the tests queue. There are also other ways to structure a test.

The test will expect the state of the <App /> component to have one child element:

App.test.js
import React from 'react';
import renderer from 'react-test-renderer';

import App from './App';

describe('<App />', () => {
  it('has 1 child', () => {
    const tree = renderer.create(<App />).toJSON();
    expect(tree.children.length).toBe(1);
  });
});
If you are using TypeScript, use .ts or .tsx file extension.

To run the test:

Terminal
- npm run test

If everything goes well, you should see the one test passed. For more information, see expect and conditional matchers.

Structure your tests

Right now, you have a single test file in the project directory. Adding more test files can make it hard to organize your project directory. The easiest way to avoid this is to create a __tests__ directory and put all your tests inside it.

An example structure is shown below:

__tests__
 components
  button.test.js
 navigation
  mainstack.test.js
 screens
  home.test.js
src
 components
  button.js
 navigation
  mainstack.js
 screens
  home.js

However, this approach causes a lot of long import paths, such as ../../src/components/button.

Alternatively, you can have multiple __tests__ sub-directories for different areas of your project. For example, create a separate test directory for components, navigation, and so on:

src
 components
  button.js
  __tests__
   button.test.js

Now, if you move __tests__ within the components directory, the import path of <Button> in the the button.test.js will be ../button.

Another option for test/file structure:

src
 components
  button.js
  button.style.js
  button.test.js

It's all about preferences and up to you to decide how you want to organize your project directory.

Snapshot test

A snapshot test is used to make sure that UI stays consistent, especially when a project is working with global styles that are potentially shared across components. For more information, see snapshot testing.

To add a snapshot test for <App />, add the following code snippet in the describe() in App.test.js:

App.test.js
it('renders correctly', () => {
  const tree = renderer.create(<App />).toJSON();
  expect(tree).toMatchSnapshot();
});

Run npm run test command, and if everything goes well, you should see a snapshot created and two tests passed.

Code coverage reports

Code coverage reports can help you understand how much of your code is tested.

If you'd like to see code coverage report in your project using the HTML format, add the following to the package.json:

package.json
"jest": {
  ...
  "collectCoverage": true,
  "collectCoverageFrom": [
    "**/*.{js,jsx}",
    "!**/coverage/**",
    "!**/node_modules/**",
    "!**/babel.config.js",
    "!**/jest.setup.js"
  ]
}

Adding the above snippet allows Jest to collect coverage of all .js and .jsx files that are not inside the coverage or node_modules directories. It also excludes the babel.config.js and jest.setup.js files. You can add or remove more to this list to match your needs.

Run npm run test. You should see a coverage directory created in your project. Find the index.html file within this directory and double-click to open it up in a browser to see the coverage report.

Usually, we don't recommend uploading index.html file to git. To prevent it from being tracked, you can add coverage/**/* in the .gitignore file.

Optional: Jest flows

You can also use different flows to run your tests. Below are a few example scripts that you can try:

package.json
"scripts": {
  ...
  // active development of tests, watch files for changes and re-runs all tests
  "test": "jest --watch --coverage=false --changedSince=origin/main",

  // debug, console.logs and only re-runs the file that was changed
  "testDebug": "jest -o --watch --coverage=false",

  // displays code coverage in cli and updates the code coverage html
  "testFinal": "jest",

  // when a screen/component is updated, the test snapshots will throw an error, this updates them
  "updateSnapshots": "jest -u --coverage=false"
}

For more information, see CLI Options in Jest documentation.

More

React Native Testing library

You can also use React Native Testing Library that provides testing utilities that encourage good testing practices and works with Jest.

Testing configuration for Expo Router

Learn how to create integration tests for your app when using Expo Router.