w3resource

Testing React Native Apps


This tutorial covers the steps to take if you want to test React Native applications using Jest.

Setup

As from react-native version 0.38, you will have a jest setup included by default when you run react-native init. Below is the configuration that will be added to your package.json file automatically:

// package.json
  "scripts": {
    "test": "jest"
  },
  "jest": {
    "preset": "react-native"
  }

It should be noted that when you are upgrading your react-native application and you previously used jest-react-native preset, you will need to remove the dependency from your package.json file and then change the preset to react-native instead.

All you need to do to run tests in Jest is to run yarn test.

Snapshot Test

We will be creating a snapshot test for a small intro component that has a few views and text components and some styles:

// Intro.js
import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    flex: 1,
    justifyContent: 'center',
  },
  instructions: {
    color: '#333333',
    marginBottom: 5,
    textAlign: 'center',
  },
  welcome: {
    fontSize: 20,
    margin: 10,
    textAlign: 'center',
  },
});

export default class Intro extends Component {
  render() {
    return (
     <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>
          This is a React Native snapshot test.
        </Text>
      </View>
    );
  }
}

We will now use React's test renderer and Jest's snapshot failure to interact with the component and capture the rendered output and then create snapshot file:

// __tests__/Intro-test.js
import React from 'react';
import Intro from '../Intro';

import renderer from 'react-test-renderer';

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

If you run yarn test or you run jest, it will produce an output file like this:

// __tests__/__snapshots__/Intro-test.js.snap
exports[`Intro renders correctly 1`] = `
<View
  style={
    Object {
      "alignItems": "center",
      "backgroundColor": "#F5FCFF",
      "flex": 1,
      "justifyContent": "center",
    }
  }>
  <Text
    style={
      Object {
        "fontSize": 20,
        "margin": 10,
        "textAlign": "center",
      }
    }>
    Hello React Native!
  </Text>
  <Text
    style={
      Object {
        "color": "#333333",
        "marginBottom": 5,
        "textAlign": "center",
      }
    }>
     A snapshot test for React Native.
  </Text>
</View>
`;

The next time that you run the tests, the rendered output is compared to the previously created snapshot. The snapshot has to be committed along code changes. if a snapshot test fails, you will need to inspect whether it is an intended or unintended change. In the case where the change is expected you can invoke Jest with jest -u to overwrite the existing snapshot.

Preset configuration

The preset will set up the environment and is it very opinionated. All of the configuration options can be overwritten and they can also be customized when no preset is used.

Environment

react-native has Jest as its preset, so the jest.preset field of your package.json has to point to react-native. The preset will be a node environment that mimics the environment of a React Native app. Because it does not load any DOM or browser APIs, it will greatly improve Jest's startup time.

transformIgnorePatterns customization

The transformIgnorePatterns option may be used to whitelist or blacklist files that you don't want to be transformed with Babel. Unfortunately, many react-native npm modules don't pre-compile their source code before publishing.

The jest-react-native preset only processes the project's own source files and react-native by default. In the case where you have npm dependencies that have to be transformed you can customize this configuration option by whitelisting modules other than react-native:

"transformIgnorePatterns": [
  "node_modules/(?!(react-native|my-project|react-native-button)/)"
]

setupFiles

If you want to provide additional configuration for every test file, you can specify setup scripts using the specify setup scripts

moduleNameMapper

You can use the moduleNameMapper to map a module path to a different module. By default, the preset will map all images to an image stub module. However, if a module cannot be found this configuration option can help:

"moduleNameMapper": {
  "my-module.js": "<rootDir>/path/to/my-module.js"
}

Tips

Mock native modules using jest.mock

The Jest preset built into react-native comes with a few default mocks which are applied on a react-native repository. However, some react-native components or third party components rely on native code to be rendered. For such cases, Jest's manual mocking system will help to mock out the underlying implementation.

For instance, when your code depends on a third party native video component called react-native-video you might want to stub it out with a manual mock as shown below:

jest.mock('react-native-video', () => 'Video');

This renders the component as <Video {...props} /> with all of its props in the snapshot output.

There are also times when you need to provide a more complex manual mock. For instance, if you want to forward the prop types or static fields of a native component to a mock, you may return a different React component from a mock through this helper from jest-react-native:

jest.mock('path/to/MyNativeComponent', () => {
  const mockComponent = require('react-native/jest/mockComponent');
  return mockComponent('path/to/MyNativeComponent');
});

Also if you want to create your own manual mock, you can do this:

jest.mock('Text', () => {
  const RealComponent = jest.requireActual('Text');
  const React = require('React');
  class Text extends React.Component {
    render() {
      return React.createElement('Text', this.props, this.props.children);
    }
  }
  Text.propTypes = RealComponent.propTypes;
  return Text;
});

In other cases, you may like to mock a native module that is not a React component. You can also apply the same technique. We recommend that you inspect the native module's source code and log the module when you are running a react native app on a real device and then you model a manual mock after the real module.

In the case where you end up mocking the same modules over and over we recommend that you define these mocks in a separate file and then add it to the list of setupFiles.



Inviting useful, relevant, well-written and unique guest posts