24
votes

Here is a simple component that I am trying to test using React Native 0.39 and Jest 18:

// index.ios.js

import React, { Component } from 'react';
import { AppRegistry, NativeModules, View } from 'react-native';

export default class TestProject extends Component {
  componentDidMount() {
    NativeModules.TestModule.test();
  }

  render() {
    return <View style={{ flex: 1 }} />;
  }
}

AppRegistry.registerComponent('TestProject', () => TestProject);

Here is TestModule and its test method:

// ios/TestProject/TestModule.m

#import "TestModule.h"

@implementation TestModule

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(test){
  NSLog(@"This is a test");
}

@end

The following test fails with the error TypeError: Cannot read property 'test' of undefined:

// __tests__/index.ios.js

import 'react-native';
import renderer from 'react-test-renderer';
import React from 'react';
import Index from '../index.ios.js';

it('renders correctly', () => {
  const tree = renderer.create(
    <Index />
  );
});

I have read the Jest docs on how to Mock native modules using jest.mock, but am still unclear as to how to extend Jest's mock of NativeModules to include my TestModule class above.

5

5 Answers

24
votes

You can simply add a mock where your native module should be:

import {
  NativeModules,
} from 'react-native';
import React from 'react';
import renderer from 'react-test-renderer';

describe('TestProject', () => {
  beforeEach(() => {
    NativeModules.TestModule = { test: jest.fn() } 
  });
  ...
});
8
votes

This way, you will mock it once (before jest starts)

jest.config.js

module.exports = {
  preset: 'react-native',
  setupFiles: ['./__mocks__/your-native-bridge.js']
};

__mocks__/your-native-bridge.js

import {NativeModules} from 'react-native';

NativeModules.YourNativeBridge = {
  property: jest.fn()
};

Don't forget to mock all possible functions, properties in YourNativeBridge

2
votes

Jest is a JavaScript testing tool, it won't run code that you have written in Objective C/Swift/Java in a native module. You can mock the functionality of a native module so that you can call it from JavaScript by the approach you linked to. eg.

jest.mock('NetInfo', () => {
  return {
    isConnected: {
      fetch: () => {
        return new Promise((accept, resolve) => {
          accept(true);
        })
      }
    }
  }
});
0
votes
#__mocks__/react-native-modules

const ReactNative = require('react-native')

ReactNative.NativeModules = {
  Defaults: {
    RU: {
      publicKey: '',
      privateKey: '',
    },
  },
}

module.exports = ReactNative

and then

# in test file
jest.mock('react-native-modules')
import 'react-native-modules'
0
votes

This failed for me, too (react-native 0.57.5, jest 23.6.0). I was able to find a solution, but it was totally different (and in my case, a more elegant fix) than here.

Check out the ticket I filed for more details.

Essentially, I had to have NativeModules fleshed out by a function passed as the second parameter to jest.mock() and put this is in a script run at the beginning of each test using Jest's setupFiles config option.