10680b787SAman Mittal--- 20680b787SAman Mittaltitle: Unit testing 30680b787SAman Mittaldescription: Learn how to set up and configure the jest-expo package to write unit tests and snapshot tests for a project. 40680b787SAman Mittal--- 50680b787SAman Mittal 60680b787SAman Mittalimport { Terminal } from '~/ui/components/Snippet'; 70680b787SAman Mittalimport { BoxLink } from '~/ui/components/BoxLink'; 8*d3ed20bfSAman Mittalimport { FileTree } from '~/ui/components/FileTree'; 9*d3ed20bfSAman Mittalimport { Tabs, Tab } from '~/ui/components/Tabs'; 100680b787SAman Mittal 110680b787SAman Mittal[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. 120680b787SAman Mittal 130680b787SAman MittalYou'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. 140680b787SAman Mittal 150680b787SAman Mittal## Installation 160680b787SAman Mittal 17*d3ed20bfSAman MittalTo install `jest-expo` in your project, run the following command: 180680b787SAman Mittal 190680b787SAman Mittal<Terminal cmd={['$ npx expo install jest-expo jest']} /> 200680b787SAman Mittal 21*d3ed20bfSAman Mittal> **info** If you are using TypeScript, then also install `@types/jest` as a dev dependency. 220680b787SAman Mittal 23*d3ed20bfSAman MittalThen, update **package.json** to add a script for running tests and add the preset for using the base configuration from `jest-expo`: 24*d3ed20bfSAman Mittal 25*d3ed20bfSAman Mittal{/* prettier-ignore */} 260680b787SAman Mittal```json package.json 270680b787SAman Mittal"scripts": { 28*d3ed20bfSAman Mittal /* @hide ... */ /* @end */ 290680b787SAman Mittal "test": "jest" 300680b787SAman Mittal}, 31*d3ed20bfSAman Mittal/* @hide ... */ /* @end */ 320680b787SAman Mittal"jest": { 330680b787SAman Mittal "preset": "jest-expo" 340680b787SAman Mittal} 350680b787SAman Mittal``` 360680b787SAman Mittal 370680b787SAman Mittal## Configuration 380680b787SAman Mittal 390680b787SAman MittalA 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: 400680b787SAman Mittal 41*d3ed20bfSAman Mittal<Tabs> 42*d3ed20bfSAman Mittal 43*d3ed20bfSAman Mittal<Tab label="npm/Yarn"> 44*d3ed20bfSAman Mittal 450680b787SAman Mittal```json package.json 460680b787SAman Mittal"jest": { 470680b787SAman Mittal "preset": "jest-expo", 480680b787SAman Mittal "transformIgnorePatterns": [ 490680b787SAman Mittal "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)" 500680b787SAman Mittal ] 510680b787SAman Mittal} 520680b787SAman Mittal``` 530680b787SAman Mittal 54*d3ed20bfSAman Mittal</Tab> 550680b787SAman Mittal 56*d3ed20bfSAman Mittal<Tab label="pnpm"> 57*d3ed20bfSAman Mittal 58*d3ed20bfSAman Mittal```json package.json 59*d3ed20bfSAman Mittal"jest": { 60*d3ed20bfSAman Mittal "preset": "jest-expo", 61*d3ed20bfSAman Mittal "transformIgnorePatterns": [ 62*d3ed20bfSAman Mittal "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*d3ed20bfSAman Mittal ] 64*d3ed20bfSAman Mittal} 65*d3ed20bfSAman Mittal``` 66*d3ed20bfSAman Mittal 67*d3ed20bfSAman Mittal</Tab> 68*d3ed20bfSAman Mittal 69*d3ed20bfSAman Mittal</Tabs> 70*d3ed20bfSAman Mittal 71*d3ed20bfSAman MittalJest 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). 720680b787SAman Mittal 730680b787SAman Mittal## Unit test 740680b787SAman Mittal 750680b787SAman MittalA unit test is used to check the smallest unit of code, usually a function. 760680b787SAman Mittal 770680b787SAman MittalTo 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). 780680b787SAman Mittal 790680b787SAman MittalThe test will expect the state of the `<App />` component to have one child element: 800680b787SAman Mittal 810680b787SAman Mittal```js App.test.js 820680b787SAman Mittalimport React from 'react'; 830680b787SAman Mittalimport renderer from 'react-test-renderer'; 840680b787SAman Mittal 850680b787SAman Mittalimport App from './App'; 860680b787SAman Mittal 870680b787SAman Mittaldescribe('<App />', () => { 880680b787SAman Mittal it('has 1 child', () => { 890680b787SAman Mittal const tree = renderer.create(<App />).toJSON(); 900680b787SAman Mittal expect(tree.children.length).toBe(1); 910680b787SAman Mittal }); 920680b787SAman Mittal}); 930680b787SAman Mittal``` 940680b787SAman Mittal 95*d3ed20bfSAman Mittal> **info** If you are using TypeScript, use **.ts** or **.tsx** file extension. 96*d3ed20bfSAman Mittal 970680b787SAman MittalTo run the test: 980680b787SAman Mittal 990680b787SAman Mittal<Terminal cmd={['$ npm run test']} /> 1000680b787SAman Mittal 1010680b787SAman MittalIf everything goes well, you should see the one test passed. For more information, see [expect and conditional matchers](https://jestjs.io/docs/en/expect). 1020680b787SAman Mittal 1030680b787SAman Mittal## Structure your tests 1040680b787SAman Mittal 1050680b787SAman MittalRight 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. 1060680b787SAman Mittal 1070680b787SAman MittalAn example structure is shown below: 1080680b787SAman Mittal 109*d3ed20bfSAman Mittal<FileTree 110*d3ed20bfSAman Mittal files={[ 111c7504584SBartosz Kaszubowski '__tests__/components/button.test.js', 112c7504584SBartosz Kaszubowski '__tests__/navigation/mainstack.test.js', 113c7504584SBartosz Kaszubowski '__tests__/screens/home.test.js', 114c7504584SBartosz Kaszubowski 'src/components/button.js', 115c7504584SBartosz Kaszubowski 'src/navigation/mainstack.js', 116*d3ed20bfSAman Mittal 'src/screens/home.js', 117*d3ed20bfSAman Mittal ]} 118*d3ed20bfSAman Mittal/> 1190680b787SAman Mittal 1200680b787SAman MittalHowever, this approach causes a lot of long import paths, such as `../../src/components/button`. 1210680b787SAman Mittal 1220680b787SAman MittalAlternatively, 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: 1230680b787SAman Mittal 124*d3ed20bfSAman Mittal<FileTree files={['src/components/button.js', 'src/components/__tests__/button.test.js']} /> 1250680b787SAman Mittal 1260680b787SAman MittalNow, if you move **\_\_tests\_\_** within the **components** directory, the import path of `<Button>` in the the **button.test.js** will be `../button`. 1270680b787SAman Mittal 1280680b787SAman MittalAnother option for test/file structure: 1290680b787SAman Mittal 130*d3ed20bfSAman Mittal<FileTree 131*d3ed20bfSAman Mittal files={[ 132c7504584SBartosz Kaszubowski 'src/components/button.js', 133c7504584SBartosz Kaszubowski 'src/components/button.style.js', 134c7504584SBartosz Kaszubowski 'src/components/button.test.js', 135*d3ed20bfSAman Mittal ]} 136*d3ed20bfSAman Mittal/> 1370680b787SAman Mittal 1380680b787SAman MittalIt's all about preferences and up to you to decide how you want to organize your project directory. 1390680b787SAman Mittal 1400680b787SAman Mittal## Snapshot test 1410680b787SAman Mittal 1420680b787SAman MittalA 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). 1430680b787SAman Mittal 1440680b787SAman MittalTo add a snapshot test for `<App />`, add the following code snippet in the `describe()` in **App.test.js**: 1450680b787SAman Mittal 1460680b787SAman Mittal```js App.test.js 1470680b787SAman Mittalit('renders correctly', () => { 1480680b787SAman Mittal const tree = renderer.create(<App />).toJSON(); 1490680b787SAman Mittal expect(tree).toMatchSnapshot(); 1500680b787SAman Mittal}); 1510680b787SAman Mittal``` 1520680b787SAman Mittal 1530680b787SAman MittalRun `npm run test` command, and if everything goes well, you should see a snapshot created and two tests passed. 1540680b787SAman Mittal 1550680b787SAman Mittal## Code coverage reports 1560680b787SAman Mittal 1570680b787SAman MittalCode coverage reports can help you understand how much of your code is tested. 1580680b787SAman Mittal 1590680b787SAman MittalIf you'd like to see code coverage report in your project using the HTML format, add the following to the **package.json**: 1600680b787SAman Mittal 1610680b787SAman Mittal```json package.json 1620680b787SAman Mittal"jest": { 1630680b787SAman Mittal ... 1640680b787SAman Mittal "collectCoverage": true, 1650680b787SAman Mittal "collectCoverageFrom": [ 1660680b787SAman Mittal "**/*.{js,jsx}", 1670680b787SAman Mittal "!**/coverage/**", 1680680b787SAman Mittal "!**/node_modules/**", 1690680b787SAman Mittal "!**/babel.config.js", 1700680b787SAman Mittal "!**/jest.setup.js" 1710680b787SAman Mittal ] 1720680b787SAman Mittal} 1730680b787SAman Mittal``` 1740680b787SAman Mittal 1750680b787SAman MittalAdding 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. 1760680b787SAman Mittal 1770680b787SAman MittalRun `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. 1780680b787SAman Mittal 1790680b787SAman Mittal> 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. 1800680b787SAman Mittal 1810680b787SAman Mittal## Optional: Jest flows 1820680b787SAman Mittal 1830680b787SAman MittalYou can also use different flows to run your tests. Below are a few example scripts that you can try: 1840680b787SAman Mittal 1850680b787SAman Mittal```json package.json 1860680b787SAman Mittal"scripts": { 1870680b787SAman Mittal ... 1880680b787SAman Mittal // active development of tests, watch files for changes and re-runs all tests 1890680b787SAman Mittal "test": "jest --watch --coverage=false --changedSince=origin/main", 1900680b787SAman Mittal 1910680b787SAman Mittal // debug, console.logs and only re-runs the file that was changed 1920680b787SAman Mittal "testDebug": "jest -o --watch --coverage=false", 1930680b787SAman Mittal 1940680b787SAman Mittal // displays code coverage in cli and updates the code coverage html 1950680b787SAman Mittal "testFinal": "jest", 1960680b787SAman Mittal 1970680b787SAman Mittal // when a screen/component is updated, the test snapshots will throw an error, this updates them 1980680b787SAman Mittal "updateSnapshots": "jest -u --coverage=false" 1990680b787SAman Mittal} 2000680b787SAman Mittal``` 2010680b787SAman Mittal 2020680b787SAman MittalFor more information, see [CLI Options](https://jestjs.io/docs/en/cli) in Jest documentation. 2030680b787SAman Mittal 2040680b787SAman Mittal## Next step 2050680b787SAman Mittal 2060680b787SAman Mittal<BoxLink 2070680b787SAman Mittal title="React Native Testing library" 2080680b787SAman Mittal description="You can also use React Native Testing Library which provides testing utilities that encourage good testing practices and works with Jest." 2090680b787SAman Mittal href="https://github.com/callstack/react-native-testing-library" 2100680b787SAman Mittal/> 211