使用Jest测试React Native应用程序
Testing React Native apps with Jest
我一直在努力让Jest使用我的react原生项目,但运气不佳。似乎大多数线程都是被黑客入侵的解决方案,以使事情正常运行,而我似乎无法克服我面临的最后一个障碍。
问题
我在尝试运行以下代码时遇到以下错误。如果我在jessupport/env.js文件中模拟反应,我可以克服错误,但显然我不能使用任何结构(如AsyncStorage)来实际测试我的代码(因为我只有模拟的功能)。
问题
有人对如何解决这个问题有什么建议吗?
在这个阶段,我愿意尝试任何事情,包括放弃所有与测试相关的东西,然后再试一次。如果是这样的话,我需要一些指导方针来遵循,因为React Native文档中关于Jest的内容已经过时了,而且我对React场景还比较陌生。
错误
Runtime Error
Error: Cannot find module 'ReactNative' from 'react-native.js'
at Runtime._resolveNodeModule (/Users/Yulfy/Downloads/COMPANY-Mobile/node_modules/jest-cli/src/Runtime/Runtime.js:451:11)
at Object.<anonymous> (/Users/Yulfy/Downloads/COMPANY-Mobile/node_modules/react-native/Libraries/react-native/react-native.js:181:25)
at Object.<anonymous> (/Users/Yulfy/Downloads/COMPANY-Mobile/network/connections.js:8:18)
测试代码
jest.unmock('../network/connections');
import Authorisation from '../network/connections';
describe('connections', () => {
it('Should store and retrieve a mocked user object', () => {
Auth = new Authorisation();
const TEST_STRING = "CONNECTION TEST PASS";
var userObj = {
test_string: TEST_STRING
};
Auth._localStore(userObj, (storeRes) => {
Auth._localRetrieve((retRes) => {
expect(retRes.test_string).toEqual(TEST_STRING);
});
});
});
});
connection.js
/*
* All returns should give the following structure:
* {isSuccess: boolean, data: object}
*/
import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
const Firebase = require('firebase');
const FIREBASE_URL = 'https://COMPANY-test.firebaseio.com';
const STORAGE_KEY = 'USER_DATA';
class Authorisation{
_ref = null;
user = null;
constructor(){
}
getOne(){return 1;}
_setSystemUser(userObj, authObj, callback){
var ref = this.connect();
if(ref === null){
callback({isSuccess:false, data:{message:"Could not connect to the server"}});
}
ref = ref.child('users').child(authObj.uid);
ref.once("value", function(snapshot){
if(snapshot.exists()){
callback({isSuccess:false, data:{message:"Email is currently in use"}});
return;
}
ref.set(userObj, function(error){
if(error){
callback({isSuccess:false, data:error});
}else{
callback({isSuccess:true, data:authObj});
}
});
});
}
_localStore(userObj, callback){
AsyncStorage.setItem(STORAGE_KEY, userObj, (error) => {
console.log("_localStore::setItem -> ", error);
if(error){
callback({
isSuccess:false,
data:'Failed to store user object in storage.'
});
}else{
callback({
isSuccess:true,
data: userObj
});
}
});
}
_localRetrieve(callback){
AsyncStorage.getItem(STORAGE_KEY, (error, res) => {
console.log("_localStore::getItem:error -> ", error);
console.log("_localStore::getItem:result -> ", res);
if(error){
callback({
isSuccess:false,
data:error
});
}else{
callback({
isSuccess: true,
data: res
});
}
});
}
connect(){
if(this._ref === null){
_ref = new Firebase(FIREBASE_URL);
}
return _ref;
}
getUser(){
}
isLoggedIn(){
}
registerUser(userObj, callback){
var ref = this.connect();
if(ref === null){
callback({isSuccess:false, data:{message:"Could not connect to the server"}});
}
var that = this;
ref.createUser({
email: userObj.username,
password: userObj.password
}, function(error, userData){
if(error){
callback({isSuccess:false, data:error});
return;
}
var parseObj = {
email: userObj.username,
fullName: userObj.fullName
};
that.loginUser(parseObj, function(res){
if(res.isSuccess){
that._setSystemUser(parseObj, res.data, callback);
}else{
callback(res);//Fail
}
});
});
}
loginUser(userObj, callback){
var ref = this.connect();
if(ref === null){
callback({isSuccess:false, data:{message:"Could not connect to the server"}});
}
ref.authWithPassword({
email: userObj.email,
password: userObj.password
}, function(error, authData){
if(error){
callback({isSuccess:false, data:error.message});
}else{
callback({isSuccess:true, data:authData});
}
});
}
}
export default Authorisation;
如果你已经读到这里了,谢谢你抽出时间!
-Yulfy
TL;DR
我在这个GitHub Repo中有一个使用最新版本React Native(v0.28.0
)运行Jest的工作示例。
-
在调查了这个问题很长一段时间后,我终于找到了解决办法。
有一些React Native应用程序与Jest集成的在线示例,但不幸的是,您不能简单地将代码复制并粘贴到代码库中,然后期望它能够工作。这是因为RN版本不同。
React Native在v0.20.0
之前的版本在打包程序(node_modules/react-native/packager/react-packager/.babelrc
)中包含一个.babelrc
文件,一些在线示例直接将其包含在其package.json
中。然而,v0.20.0
及以上版本已更改为不再包含此文件,这意味着您不能再尝试包含它。因此,我建议您使用自己的.babelrc
文件,并定义自己的预设和插件。
我不知道你的package.json
文件是什么样子的,但它对解决这个问题非常重要。
{
"name": "ReactNativeJest",
"version": "0.0.1",
"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"unmockedModulePathPatterns": [
"node_modules"
],
"verbose": true,
"collectCoverage": true
},
"scripts": {
"test": "jest"
},
"dependencies": {
"react": "^15.1.0",
"react-native": "^0.27.2"
},
"devDependencies": {
"babel-core": "^6.4.5",
"babel-jest": "^12.1.0",
"babel-plugin-transform-regenerator": "^6.0.18",
"babel-polyfill": "^6.0.16",
"babel-preset-react-native": "^1.9.0",
"babel-types": "^6.1.2",
"chai": "^3.5.0",
"enzyme": "^2.3.0",
"jest-cli": "^12.1.1",
"react-addons-test-utils": "^15.1.0",
"react-dom": "^15.1.0"
}
}
另一个重要的部分是嘲讽React Native。我创建了一个__mocks__/react-native.js
文件,如下所示:
'use strict';
var React = require('react');
var ReactNative = React;
ReactNative.StyleSheet = {
create: function(styles) {
return styles;
}
};
class View extends React.Component {}
class Text extends React.Component {}
class TouchableHighlight extends React.Component {}
// Continue to patch other components as you need them
ReactNative.View = View;
ReactNative.Text = Text;
ReactNative.TouchableHighlight = TouchableHighlight;
module.exports = ReactNative;
通过像这样对React Native函数进行猴子补丁,您可以成功避免在尝试运行测试时出现奇怪的Jest错误。
最后,确保在项目的根目录中创建一个.babelrc
文件,该文件至少包含以下行:
{
"presets": ["react-native"],
"plugins": [
"transform-regenerator"
]
}
这个文件将用于告诉babel如何正确地转换ES6代码。
完成此设置后,您应该可以使用React Native运行Jest。我相信React Native的未来版本将使这两个框架更容易集成在一起,但这项技术将完全适用于当前版本:)
编辑
不需要手动模拟__mocks__/react-native.js
文件中的ReactNative元素,您可以使用ReactNative模拟库为您进行模拟(确保将库添加到package.json
文件中):
// __mocks__/react-native.js
module.exports = require('react-native-mock');
我更新了我的GitHub Repo示例来演示这种方法。
您是否尝试过在测试文件内部模拟本地react?
它适用于我的测试用例:
jest.dontMock(`../my-module-that-uses React-native.AsyncStorage`);
jest.setMock(`react-native`, {
AsyncStorage: {
multiGet: jest.fn(),
},
});
const ReactNative = require(`react-native`);
const {AsyncStorage, } = ReactNative;
const myModule = require(`../my-module-that-uses React-native.AsyncStorage`);
// Do some tests and assert ReactNative.AsyncStorage.multiGet calls
- 使用Jest测试React Native应用程序
- 使用react native检测应用程序终止
- 可以在React Native中制作一个自哈希应用程序
- IFRAME和谷歌应用程序脚本中的NATIVE模式
- React Native - Android应用程序在调试上工作,在发布时崩溃
- 如何将Crashlytics与React Native应用程序集成
- React Native JS没有'应用程序处于后台时无法执行
- 我如何确定我的React Native应用程序是从JavaScript代码中调试还是发布的
- React Native静态图像don'脱机捆绑时不会显示在应用程序中
- 是否可以在React Native中设置整个应用程序的背景
- 如何在react native上创建具有多个页面的应用程序
- 在Redux和React Native应用程序中访问Store
- React-Native:关闭应用程序时刷新后台应用程序
- 在javascript应用程序中使用Google Native Client (NACL)进行I/O的预期加速
- 关闭应用程序后,React Native进度条百分比不保持不变
- 如何在React Native中完全关闭应用程序后保持应用程序的内存
- 在 React.js 和 React Native 应用程序之间重用代码
- 当模态打开时,停止新闻事件的传播/防止React Native应用程序冒泡
- 如何将函数/文件导入到react native应用程序中?
- 如何在React Native应用程序中显示超链接