如何测试使用 Jest 导入自定义本机模块的 React Native 组件?

How to test a React Native component that imports a custom native module with Jest?

这是我尝试使用 React Native 0.39 和 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);

这是 TestModule 及其 test 方法:

// ios/TestProject/TestModule.m

#import "TestModule.h"

@implementation TestModule

RCT_EXPORT_MODULE();

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

@end

以下测试失败并出现错误 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 />
  );
});

我已经阅读了关于如何 Mock native modules using jest.mock 的 Jest 文档,但我仍然不清楚如何扩展 Jest 的 NativeModules 模拟以包含我上面的 TestModule class。

Jest 是一个 JavaScript 测试工具,它不会 运行 您在本机模块中 Objective C/Swift/Java 编写的代码。您可以模拟本机模块的功能,以便您可以通过链接到的方法从 JavaScript 调用它。例如

jest.mock('NetInfo', () => {
  return {
    isConnected: {
      fetch: () => {
        return new Promise((accept, resolve) => {
          accept(true);
        })
      }
    }
  }
});

您只需在本机模块所在的位置添加模拟即可:

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

describe('TestProject', () => {
  beforeEach(() => {
    NativeModules.TestModule = { test: jest.fn() } 
  });
  ...
});
#__mocks__/react-native-modules

const ReactNative = require('react-native')

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

module.exports = ReactNative

然后

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

这样,你将嘲笑一次(在开玩笑之前)

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

不要忘记模拟 YourNativeBridge

中所有可能的函数和属性

这对我来说也失败了(react-native 0.57.5,jest 23.6.0)。我能够找到一个解决方案,但它与这里完全不同(在我的情况下,一个更优雅的修复)。

查看 the ticket I filed 了解更多详情。

本质上,我必须通过作为第二个参数传递给 jest.mock() and put this is in a script run at the beginning of each test using Jest's setupFiles 配置选项的函数来充实 NativeModules。