如何正确模拟使用本机代码的 React Native 模块?
Posted
技术标签:
【中文标题】如何正确模拟使用本机代码的 React Native 模块?【英文标题】:How to correctly mock a React Native module that utilizes native code? 【发布时间】:2019-03-19 20:03:09 【问题描述】:我正在使用 TypeScript 构建一个 React Native 应用程序。我正在为我的通知使用 react-native-firebase。我还在使用 Jest 和 Enzyme 进行单元测试。
我有以下包装函数来检查用户权限:
export const checkPermissions = (): Promise<boolean> =>
new Promise((resolve, reject) =>
firebase
.messaging()
.hasPermission()
.then(enabled =>
if (enabled)
resolve(enabled);
else
firebase
.messaging()
.requestPermission()
.then(resolve)
.catch(reject);
);
);
现在我想测试函数是否被调用。
这是我写的测试:
import * as firebase from "react-native-firebase";
import checkPermissions from "./notificationHelpers";
jest.mock("react-native-firebase");
describe("checkPermissions", () =>
beforeEach(async done =>
jest.resetAllMocks();
await checkPermissions();
done();
);
it("should call firebase.messaging().hasPermission()", () =>
expect(firebase.messaging().hasPermission).toHaveBeenCalledTimes(1);
);
);
这会引发错误:
FAIL app/services/utils/core/notificationHelpers/notificationHelpers.test.ts
● Test suite failed to run
RNFirebase core module was not found natively on ios, ensure you have correctly included the RNFirebase pod in your projects `Podfile` and have run `podinstall`.
See http://invertase.link/ios for the ios setup guide.
Error: RNFirebase core module was not found natively on iOS, ensure you have correctly included the RNFirebase pod in your projects `Podfile` and haverun `pod install`.
所以在我看来,使用本机代码的模块不能简单地通过自动模拟。
所以我尝试手动模拟它。在与node_modules
相邻的根项目中的文件夹__mocks__
中,我创建了一个名为react-native-firebase.ts
的文件,如下所示:
const firebase =
messaging: jest.fn(() => (
hasPermission: jest.fn(() => new Promise(resolve => resolve(true)))
))
;
export default firebase;
但是这段代码也失败了,因为 firebase.messaging
据称是未定义的。
如何测试这些东西? ????
编辑:哇,mocking seems to be completely broken in RN 0.57.x :(
【问题讨论】:
【参考方案1】:这是一种测试依赖于react-native-firebase
的代码的方法
只需在__mocks__/react-native-firebase.js
中添加一个空文件即可创建手动模拟,mocks 文件夹应与node_modules
处于同一级别,如in jest docs 特别说明模拟节点模块 部分。
使用此手动模拟可以避免错误
RNFirebase core module was not found natively on iOS, ensure you have correctly included the RNFirebase pod in your projects `Podfile` and have run `pod install`.
那么你不需要jest.mock("react-native-firebase");
你也不需要
测试expect(firebase.messaging().hasPermission).toHaveBeenCalledTimes(1);
您可以做的是将依赖于react-native-firebase
的代码隔离在小函数上,然后监视那些添加已知结果的代码。
例如,这个 verifyPhone 函数依赖于 react-native-firebase。
// ./lib/verifyPhoneNumber.ts
import firebase from "react-native-firebase";
const verifyPhoneNumber = (phoneNumber: string) =>
return new Promise((resolve, reject) =>
firebase
.auth()
.verifyPhoneNumber(phoneNumber)
.on("state_changed", phoneAuthSnapshot =>
resolve(phoneAuthSnapshot.state);
);
);
;
export default verifyPhoneNumber;
要测试依赖于verifyPhoneNumber
函数的代码,你可以监视它并像这样替换它的实现。
jest.mock("react-native-firebase");
import signInWithPhone from "../actions";
import verifyPhoneNumberEpic from "./verifyPhoneNumberEpic";
import ActionsObservable from "redux-observable";
// Note "import * as" is needed to use jest.spyOn(verifyPhoneNumber, "default");
import * as verifyPhoneNumber from "./lib/verifyPhoneNumber";
describe("Epic: verifyPhoneNumberEpic", () =>
test('On Request "[Auth] Verify Phone Number Request" executes the promise', done =>
// Create the spy
const verifyPhoneNumberMock = jest.spyOn(verifyPhoneNumber, "default");
// For this test I simulate the promise resolves with CODE_SENT
verifyPhoneNumberMock.mockImplementation(async () => "CODE_SENT");
// the rest of the code is very specific for testing Epics (redux-observable)
// But all you need to know is that internally my epic verifyPhoneNumberEpic
// calls verifyPhoneNumber but the implication will be replaced with the spy
const requestAction = signInWithPhone.request(
phoneNumber: "+40111222333"
);
const action$ = ActionsObservable.of(requestAction);
verifyPhoneNumberEpic(action$, null, null).subscribe((action: any) =>
expect(action.payload.code).toBe("CODE_SENT");
expect(action.type).toBe(signInWithPhone.success.toString());
done();
);
);
希望对你有帮助!
【讨论】:
以上是关于如何正确模拟使用本机代码的 React Native 模块?的主要内容,如果未能解决你的问题,请参考以下文章