如何正确模拟使用本机代码的 React Native 模块?
How to correctly mock a React Native module that utilizes native code?
我正在使用 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
未定义。
如何测试这些东西?
这是一种测试依赖于 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
的代码隔离在小函数上,然后监视那些添加已知结果的代码。
比如这个依赖于react-native-firebase的verifyPhone函数
// ./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();
});
});
希望对您有所帮助!
我正在使用 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
未定义。
如何测试这些东西?
这是一种测试依赖于 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
的代码隔离在小函数上,然后监视那些添加已知结果的代码。
比如这个依赖于react-native-firebase的verifyPhone函数
// ./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();
});
});
希望对您有所帮助!