Testing with React Native – Jest

React Native is like React, but it uses native components instead of web components as building blocks. Testing front-end component has never been easy. Front-end testing requires to test user events, their responses and what not. But React has it all clean and organized. To set up a testing environment in react-native, we need the following:

  1. Test Runner: A tool to pick and run tests and log the results into a file. There are many test runners for JavaScript like Mocha, Jest, Karma.
  2. Mocks: Mocking react components and their underlying dependencies.

We will be using Jest (recommended by Facebook) with Enzyme.

Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components’ output.

Setting it up: Running react-native init has a default setup including Jest from react-native 0.38. So your package.json already has this bit:

"scripts": {
"test": "jest"
},"jest": {
"preset": "react-native"
},

To test this, run npm test and Jest is up and running. To install Jest run: 

npm i --save-dev jest

npm i --save-dev jest-cli

This automatically creates a __tests__ folder and a file Intro-test.js

Now, Lets install Enzyme with: 

npm i --save-dev enzyme

In addition to Enzyme, few more dependencies are required:

npm i --save-dev react-addons-test-utils
npm i --save-dev react-dom

We will add sample code and its corresponding test in __tests__ folder. FYI, Jest looks in __tests__ folder for test files.

average.js

function average(a, b) {
return (a + b)/2;
}
module.exports = average;

__tests__/averageSpecs.js

Jest.unmock('../average');  // to use the actual implementation of average
describe('average', () => {
it('average of 3 + 5 to equal 4', () => {
const avergae = require('../average');
expect(average(3, 5)).toBe(4);
});
});

Run npm test

Output:

Snapshot Testing: Snapshot testing is another concept introduced by Facebook. When a test is run, Jest creates a snapshot of the current component and keeps it to compare with the rendered output in subsequent runs. If 2 screenshots don’t match, there is either an unexpected change or an updated implementation. This comes in handy if we review snapshots while merging a PR, as one can quickly tell which test/view has been modified.

Let’s try testing a view component now. Taking a simple component for reference here:

components/SimpleComponent.js


import React, {Component} from 'react';
import {
StyleSheet,
Text
} from 'react-native';
export default class SimpleComponent extends Component {
render() {
return (
<Text style = {styles.instructions}>
Always write tests for your code :)
</Text>
);
}
}
const styles = StyleSheet.create({
instructions: {
fontSize: 20,
textAlign: 'center',
margin: 10
}
});

__tests__/SimpleComponentSpecs.js


import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import SimpleComponent from '../components/SimpleComponent';
import { shallow } from 'enzyme';
describe('Simple Component', function() {
it('renders correctly', () => {
const tree = shallow(<SimpleComponent />)
expect(tree).toMatchSnapshot();
});
it('has length 3', function() {
const tree = shallow(<SimpleComponent />)
expect(tree.length).toBe(3);
});
});

Snapshot is stored in parallel to the component. It looks like this:

Output:

Test fails! Since our component tree does not have the mentioned length. Replacing 3 with 1 fixes it.

Output:

PS: npm test — -u is used to remove obsolete snapshots. 

Happy Testing 🙂

 

FacebookTwitterGoogle+Share

Tagged under: , , ,

Back to top