如何在JavaScript中Mock含Promise的函数?解决loginCognito只读报错
问题:测试时修改
loginCognito报错"loginCognito is read-only" 我有一个AWS Cognito登录的辅助函数(路径:src/utils/calls/aws.js):
export const loginCognito = (cognitoUser, authenticationDetails) => { cognitoUser.authenticateUser(authenticationDetails, { onSuccess: function (result) { return result; }, onFailure: function (error) { return error; }, }); };
在测试文件中尝试mock这个函数时,报错"loginCognito is read-only",测试代码如下:
import { loginCognito } from "../../../utils"; describe("Test LoginPage", () => { it("Can press button without userEvent", async () => { loginCognito = jest.fn().mockResolvedValue({accessToken: "a2b3"}); renderWithProviders(<LoginPage />); const inputUsername = screen.getByLabelText(/username/i); fireEvent.change(inputUsername, { target: { value: "info@example.com", }, }); const inputPassword = screen.getByLabelText(/password/i); fireEvent.change(inputPassword, { target: { value: "thisIsASecretPassword", }, }); const loginButton = screen.getByRole("button", { name: /login/i }); fireEvent.click(loginButton); await waitFor(() => { expect(localStorage.getItem(LOCALSTORAGE_ACCESS_TOKEN)).toEqual( accessToken ); }); }); });
我需要跳过loginCognito的真实实现,直接返回指定值,求解决方案。
解决方案1:使用Jest模块Mock(无需修改源文件)
ES模块导出的是只读引用,直接赋值会报错,需要用Jest的jest.mock替换整个模块的导出:
修改测试文件的导入和Mock部分:
// 先Mock整个utils模块,保留其他未Mock的函数,仅替换loginCognito jest.mock('../../../utils', () => ({ ...jest.requireActual('../../../utils'), loginCognito: jest.fn().mockResolvedValue({accessToken: "a2b3"}) })); // 导入Mock后的函数 import { loginCognito } from "../../../utils"; describe("Test LoginPage", () => { it("Can press button without userEvent", async () => { // 可根据测试需求临时调整返回值,比如用mockResolvedValueOnce // loginCognito.mockResolvedValueOnce({accessToken: "test-token"}); renderWithProviders(<LoginPage />); // 以下测试逻辑保持不变 const inputUsername = screen.getByLabelText(/username/i); fireEvent.change(inputUsername, { target: { value: "info@example.com", }, }); const inputPassword = screen.getByLabelText(/password/i); fireEvent.change(inputPassword, { target: { value: "thisIsASecretPassword", }, }); const loginButton = screen.getByRole("button", { name: /login/i }); fireEvent.click(loginButton); await waitFor(() => { // 注意期望值要和Mock返回的accessToken一致 expect(localStorage.getItem(LOCALSTORAGE_ACCESS_TOKEN)).toEqual("a2b3"); }); }); });
解决方案2:调整源文件导出结构(允许修改源文件时使用)
把函数包装在对象中导出,这样可以修改对象属性实现Mock:
修改src/utils/calls/aws.js:
export const authUtils = { loginCognito: (cognitoUser, authenticationDetails) => { cognitoUser.authenticateUser(authenticationDetails, { onSuccess: function (result) { return result; }, onFailure: function (error) { return error; }, }); } };
测试文件中修改导入和Mock:
import { authUtils } from "../../../utils"; describe("Test LoginPage", () => { it("Can press button without userEvent", async () => { // 直接Mock对象中的方法 authUtils.loginCognito = jest.fn().mockResolvedValue({accessToken: "a2b3"}); renderWithProviders(<LoginPage />); // 以下测试逻辑保持不变 }); });
内容的提问来源于stack exchange,提问作者sineverba
相关产品推荐
相关产品推荐

