How to test a React Native component that imports

2019-04-21 00:02发布

问题:

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.

回答1:

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() } 
  });
  ...
});


回答2:

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);
        })
      }
    }
  }
});


回答3:

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



回答4:

#__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'


回答5:

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.