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

Posted

技术标签:

【中文标题】如何使用 Jest 测试导入自定义原生模块的 React Native 组件?【英文标题】:How to test a React Native component that imports a custom native module with Jest? 【发布时间】:2017-05-11 10:26:27 【问题描述】:

这是我尝试使用 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 类。

【问题讨论】:

【参考方案1】:

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

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

本质上,我必须通过作为第二个参数传递给 jest.mock() 的函数来充实 NativeModules,并将其放在使用 Jest 的 setupFiles 配置选项在每次测试开始时运行的脚本中。

【讨论】:

【参考方案2】:

这样,您将模拟一次(在开玩笑开始之前)

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中所有可能的函数、属性

【讨论】:

有人写过这些属性的完整列表吗?我不确定我需要哪些,所以我想他们都会做【参考方案3】:
#__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'

【讨论】:

这失败了:“无法设置属性 NativeModules of # 它只有一个 getter”【参考方案4】:

你可以简单地在你的原生模块应该是的地方添加一个模拟:

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

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

【讨论】:

谢谢!传递给beforeEach 的函数缺少一个右花括号,但在其他方面就像一个魅力。我还选择使用beforeAll,因为这个设置只需要运行一次,而不是在每个规范之前运行。 太好了,我添加了缺少的花括号。 现在失败(0.57),因为您无法将属性添加到只读对象【参考方案5】:

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

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

【讨论】:

我认为这误解了我也有的问题。 OP 询问您如何模拟从react-native 导入的NativeModules.TestModule。我被困住了,因为react-native 需要导入,而不是模拟,react-test-renderer 覆盖才能工作。 @rgoldfinger 是正确的。我不是在尝试测试本机模块本身,而是尝试模拟 NativeModules.TestModule 以测试 index.ios.js 有没有办法测试原生模块?

以上是关于如何使用 Jest 测试导入自定义原生模块的 React Native 组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jest 测试中使用我的 webpack 的 html-loader 导入?

使用 Jest 在 VueJS 组件中模拟自定义模块

如何在 Jest 的自定义测试环境文件中使用 TypeScript?

如何使用 JEST、Enzyme 在 React 中测试自定义钩子?

Jest 无法从 npm 链接模块转换导入

笑话:节点模块依赖使用导入语句并导致测试崩溃