Ken
Ken

Reputation: 4887

How to test React Native component with NavigationEvents in jest

How can I write a jest unit test for a react native component which contains a NavigationEvents subcomponent.

I've tried the solutions offered in questions here and here without success.

The error I am getting is

    console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9215
      The above error occurred in the <Context.Consumer> component:
          in withNavigation(NavigationEvents) (created by MyComponent)
          in View (created by View)
          in View (created by MyComponent)
          in MyComponent

      Consider adding an error boundary to your tree to customize error handling behavior.

  ● MyComponent test › renders

    Invariant Violation: withNavigation can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.

Below is a minimal example that causes the error.

import 'react-native';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
import React from 'react';
import renderer from 'react-test-renderer';

class MyComponent extends React.Component {

    constructor(props) {
      super(props);
    }

    render() {
        return (
          <View>
            <NavigationEvents/>
          </View>
        );}
  }

describe('MyComponent test', () => {
    it('renders', () => {

        jest.mock('react-navigation', () =>({
            NavigationEvents: 'mockNavigationEvents',
            withNavigation: component => component
          }));
        const navigation = { navigate: jest.fn() };

        renderer.create(<MyComponent navigation={navigation}/>);
    });
});

Edit

As requested in comments added package.json below:


{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "eject": "expo eject",
    "test": "node ./node_modules/jest/bin/jest.js --watchAll"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/samples": "2.1.1",
    "@expo/vector-icons": "^10.0.0",
    "expo": "^35.0.0",
    "expo-camera": "~7.0.0",
    "expo-sqlite": "^7.0.0",
    "moment": "^2.24.0",
    "react": "16.8.3",
    "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
    "react-native-action-button": "^2.8.5",
    "react-native-calendar-picker": "^6.0.0",
    "react-native-dialog": "^5.6.0",
    "react-native-dotenv": "^0.2.0",
    "react-native-dynamic-search-bar": "^0.1.11",
    "react-native-elements": "^1.1.0",
    "react-native-gesture-handler": "~1.3.0",
    "react-native-keyboard-aware-scroll-view": "^0.9.1",
    "react-native-modal-datetime-picker": "^7.4.0",
    "react-native-paper": "^2.15.2",
    "react-native-progress-circle": "^2.1.0",
    "react-native-search-bar": "^3.4.2",
    "react-native-vector-icons": "^6.4.2",
    "react-navigation": "^3.0.9",
    "expo-constants": "~7.0.0",
    "expo-file-system": "~7.0.0"
  },
  "devDependencies": {
    "babel-preset-expo": "^7.0.0",
    "jest-expo": "^35.0.0"
  },
  "private": true
}

expo-cli version

$ expo-cli -V
3.13.1

Upvotes: 1

Views: 2804

Answers (1)

Christos Lytras
Christos Lytras

Reputation: 37318

The problem is that jest.mock has to be outside of describe and it functions. You don't need to manually mock navigation object since you're mocking the withNavigation HOC function:

// Setup mocks outside describe and it functions
jest.mock('react-navigation', () =>({
  NavigationEvents: 'mockNavigationEvents',
  withNavigation: component => component
}));

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View>
        <NavigationEvents/>
      </View>
    );
  }
}

describe('MyComponent test', () => {
  it('renders', () => {
    renderer.create(<MyComponent/>);
  });
});

And the renders test passes:

Jest test renders

I suggest you have all those mocks inside a file and set setupFilesAfterEnv in package.json:

package.json > jest:

"jest": {
  "preset": "jest-expo"
  "setupFilesAfterEnv": ["./path/to/jestInit.js"]
},

jestInit.js:

jest.mock('react-navigation', () =>({
  NavigationEvents: 'mockNavigationEvents',
  withNavigation: component => component
}));

This way, you'll have those mocks for every Jest test file without having to include the mocks inside each test file.

Upvotes: 4

Related Questions