Learning to test React Native with Jest — part 1

It’s a snap!(shot)

Adding Jest to our project

In React Native versions 0.38 and greater, Jest is included when creating a project via react-native init, so the following setup may be already done for you. Same goes if you’ve read the documentation from Jest on setting up testing with React Native

1. Installing packages

For our initial setup, we installed three libraries: jest, babel-jest, and react-test-renderer. Be sure to install these as devDependencies using either npm i --save-dev or yarn add -dev.

2. Just a few more lines before we can get testing…

// Add this to your package.json
"scripts": {
"test": "jest"
},
"jest": {
"preset": "react-native"
}
// Add this to your .babelrc
{
"presets": ["react-native"]
}

3. Creating our first test

Our first test was pretty humble, creating a snapshot of the render output for our Login component.

Doing more with Snapshots (enter: Enzyme)

As we started writing more tests, we quickly found for our more complex components the react-test-renderer was just not getting it done, so we transitioned to utilizing an awesome library from the folks at AirbnbEng: Enzyme.

"jest": {
"preset": "react-native",
"snapshotSerializers": [
"./node_modules/jest-serializer-enzyme"
]
},

Test rendering connected components

Our application utilizes react-redux to store much of our local information, and most of our components are wrapped in a connect statement like this:

export default connect(mapStateToProps)(CameraSettings);

An okay way… (avoid the state)

Early on, we worked around this issue by simply adding an export for the component class and importing it with curly brackets in our test:

// components/menu/CameraSettings.js
export class CameraSettings extends Component { ... }
// __tests__/components/menu/CameraSettings.test.js
import { CameraSettings } from 'components/menu/CameraSettings';

The better way (mock the state!)

Instead of manually adding props, it feels much more natural to mock the state so that we can avoid duplicating code, plus we have the the added bonus of testing our mapStateToProps function at the same time.

Having a mocked state allows us to test the functionality of mapStateToProps rather than duplicating its logic in our test file.

To mock our state, we utilize the redux-mock-store library.

  1. In order to put those in a mock store our test can use, we first create our initialState object (providing only the values required by our component’s mapStateToProps function), then pass that object into the mockStore function from redux-mock-store.
  2. Next, we pass the mocked store to our connected component adding a second argument to the shallow function:
    { context: { store: mockStore() } }.
  3. Finally, to render the snapshot of our connected component we use wrapper.dive() to access the actual render output of our component for the snapshot (otherwise wrapper will represent the connect function).

We’ve only dipped our toes in the water so far

This is the first of many posts detailing lessons I’ve learned implementing Jest testing on our React Native app. I hope you might find them helpful, I spent many hours spinning my wheels on things that seem simple now. Looking back, I wished I’d had a simple walkthrough that would make it easier to get things rolling.

  • Understanding test coverage reports
  • Mocking responses from API requests for testing
  • Testing component functions using spies
  • Creating a setup file with global mocks
  • Best practices when mocking libraries
  • Testing functionality for touchable elements (TouchableHighlights, Switches, etc.)

More in this series:

Part 2Part 3Part 4

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jason Gaare

Mobile developer at @CompanyCam. Husband, father, follower of Christ.