我正在用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`.
所以在我看来,使用本机代码的模块不能简单地通过自动模拟来实现。
所以我尝试手动模拟它。在我的根项目中与__mocks__
相邻的文件夹node_modules
中,我创建了一个名为react-native-firebase.ts
的文件,如下所示:
const firebase = {
messaging: jest.fn(() => ({
hasPermission: jest.fn(() => new Promise(resolve => resolve(true)))
}))
};
export default firebase;
但是此代码也失败了,因为据称firebase.messaging
未定义。
一个人将如何测试这些东西?
答案 0 :(得分:1)
这是一种测试取决于react-native-firebase
的代码的方法
仅通过在__mocks__/react-native-firebase.js
中添加一个空文件来创建手动模拟, mocks 文件夹应与node_modules
处于同一级别,如in jest docs所述< strong>模拟节点模块部分。
借助此手动模拟功能,您可以避免错误
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();
});
});
希望对您有帮助!