1--- 2title: Unit testing 3description: Learn how to set up and configure the jest-expo package to write unit tests and snapshot tests for a project. 4--- 5 6import { Terminal } from '~/ui/components/Snippet'; 7import { BoxLink } from '~/ui/components/BoxLink'; 8import { FileTree } from '~/ui/components/FileTree'; 9import { Tabs, Tab } from '~/ui/components/Tabs'; 10 11[Jest](https://jestjs.io) 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. 12 13You'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. 14 15## Installation 16 17To install `jest-expo` in your project, run the following command: 18 19<Terminal cmd={['$ npx expo install jest-expo jest']} /> 20 21> **info** If you are using TypeScript, then also install `@types/jest` as a dev dependency. 22 23Then, update **package.json** to add a script for running tests and add the preset for using the base configuration from `jest-expo`: 24 25{/* prettier-ignore */} 26```json package.json 27"scripts": { 28 /* @hide ... */ /* @end */ 29 "test": "jest" 30}, 31/* @hide ... */ /* @end */ 32"jest": { 33 "preset": "jest-expo" 34} 35``` 36 37## Configuration 38 39A 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`](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring) property that takes a regex pattern as its value: 40 41<Tabs> 42 43<Tab label="npm/Yarn"> 44 45```json package.json 46"jest": { 47 "preset": "jest-expo", 48 "transformIgnorePatterns": [ 49 "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)" 50 ] 51} 52``` 53 54</Tab> 55 56<Tab label="pnpm"> 57 58```json package.json 59"jest": { 60 "preset": "jest-expo", 61 "transformIgnorePatterns": [ 62 "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))" 63 ] 64} 65``` 66 67</Tab> 68 69</Tabs> 70 71Jest 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](https://jestjs.io/docs/configuration). 72 73## Unit test 74 75A unit test is used to check the smallest unit of code, usually a function. 76 77To 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](#structure-your-tests). 78 79The test will expect the state of the `<App />` component to have one child element: 80 81```js App.test.js 82import React from 'react'; 83import renderer from 'react-test-renderer'; 84 85import App from './App'; 86 87describe('<App />', () => { 88 it('has 1 child', () => { 89 const tree = renderer.create(<App />).toJSON(); 90 expect(tree.children.length).toBe(1); 91 }); 92}); 93``` 94 95> **info** If you are using TypeScript, use **.ts** or **.tsx** file extension. 96 97To run the test: 98 99<Terminal cmd={['$ npm run test']} /> 100 101If everything goes well, you should see the one test passed. For more information, see [expect and conditional matchers](https://jestjs.io/docs/en/expect). 102 103## Structure your tests 104 105Right 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. 106 107An example structure is shown below: 108 109<FileTree 110 files={[ 111 '__tests__/components/button.test.js', 112 '__tests__/navigation/mainstack.test.js', 113 '__tests__/screens/home.test.js', 114 'src/components/button.js', 115 'src/navigation/mainstack.js', 116 'src/screens/home.js', 117 ]} 118/> 119 120However, this approach causes a lot of long import paths, such as `../../src/components/button`. 121 122Alternatively, 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: 123 124<FileTree files={['src/components/button.js', 'src/components/__tests__/button.test.js']} /> 125 126Now, if you move **\_\_tests\_\_** within the **components** directory, the import path of `<Button>` in the the **button.test.js** will be `../button`. 127 128Another option for test/file structure: 129 130<FileTree 131 files={[ 132 'src/components/button.js', 133 'src/components/button.style.js', 134 'src/components/button.test.js', 135 ]} 136/> 137 138It's all about preferences and up to you to decide how you want to organize your project directory. 139 140## Snapshot test 141 142A 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](https://jestjs.io/docs/en/snapshot-testing). 143 144To add a snapshot test for `<App />`, add the following code snippet in the `describe()` in **App.test.js**: 145 146```js App.test.js 147it('renders correctly', () => { 148 const tree = renderer.create(<App />).toJSON(); 149 expect(tree).toMatchSnapshot(); 150}); 151``` 152 153Run `npm run test` command, and if everything goes well, you should see a snapshot created and two tests passed. 154 155## Code coverage reports 156 157Code coverage reports can help you understand how much of your code is tested. 158 159If you'd like to see code coverage report in your project using the HTML format, add the following to the **package.json**: 160 161```json package.json 162"jest": { 163 ... 164 "collectCoverage": true, 165 "collectCoverageFrom": [ 166 "**/*.{js,jsx}", 167 "!**/coverage/**", 168 "!**/node_modules/**", 169 "!**/babel.config.js", 170 "!**/jest.setup.js" 171 ] 172} 173``` 174 175Adding 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. 176 177Run `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. 178 179> 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. 180 181## Optional: Jest flows 182 183You can also use different flows to run your tests. Below are a few example scripts that you can try: 184 185```json package.json 186"scripts": { 187 ... 188 // active development of tests, watch files for changes and re-runs all tests 189 "test": "jest --watch --coverage=false --changedSince=origin/main", 190 191 // debug, console.logs and only re-runs the file that was changed 192 "testDebug": "jest -o --watch --coverage=false", 193 194 // displays code coverage in cli and updates the code coverage html 195 "testFinal": "jest", 196 197 // when a screen/component is updated, the test snapshots will throw an error, this updates them 198 "updateSnapshots": "jest -u --coverage=false" 199} 200``` 201 202For more information, see [CLI Options](https://jestjs.io/docs/en/cli) in Jest documentation. 203 204## Next step 205 206<BoxLink 207 title="React Native Testing library" 208 description="You can also use React Native Testing Library which provides testing utilities that encourage good testing practices and works with Jest." 209 href="https://github.com/callstack/react-native-testing-library" 210/> 211