异步函数中Mock函数未被调用的React测试问题
异步逻辑下Mock函数调用断言失败的解决办法
问题核心是异步代码的执行时机:修改后handleSubmit变为异步函数,点击按钮后isUserLoggedIn()是异步调用(返回Promise),测试代码在fireEvent.click后立刻执行断言,此时await还未完成,searchFunctionMock还没被调用,导致断言失败。而isUserLoggedInSpy的断言能通过,是因为该函数在点击后立刻被触发执行,只是其返回的Promise还未resolve。
解决方案
针对Testing Library的场景,有两种常用处理方式:
方式1:使用waitFor等待断言条件满足
waitFor会重复执行传入的断言,直到断言通过或超时(默认1000ms),适配异步操作后的断言需求:
// Updated SearchButton.test.js import "@testing-library/jest-dom"; import { render, fireEvent, waitFor } from "@testing-library/react"; import { SearchButton } from "./SearchButton.js"; import * as utils from "./utils.js"; describe("SearchButtonTest", () => { it("should call search function on submit", async () => { const searchFunctionMock = jest.fn(); const isUserLoggedInSpy = jest .spyOn(utils, "isUserLoggedIn") .mockResolvedValue(true); const { getByTestId } = render( <SearchButton searchFunction={searchFunctionMock} /> ); fireEvent.click(getByTestId("search-button-submit")); // 修正testid不匹配问题 expect(isUserLoggedInSpy).toHaveBeenCalled(); // 用waitFor包裹断言,等待异步逻辑完成 await waitFor(() => { expect(searchFunctionMock).toHaveBeenCalled(); }); }); });
方式2:直接等待Mock函数的Promise完成
因为isUserLoggedInSpy使用mockResolvedValue,可以直接await它的调用结果,确保异步流程走完:
// Updated SearchButton.test.js import "@testing-library/jest-dom"; import { render, fireEvent } from "@testing-library/react"; import { SearchButton } from "./SearchButton.js"; import * as utils from "./utils.js"; describe("SearchButtonTest", () => { it("should call search function on submit", async () => { const searchFunctionMock = jest.fn(); const isUserLoggedInSpy = jest .spyOn(utils, "isUserLoggedIn") .mockResolvedValue(true); const { getByTestId } = render( <SearchButton searchFunction={searchFunctionMock} /> ); fireEvent.click(getByTestId("search-button-submit")); // 等待isUserLoggedIn的Promise resolve await isUserLoggedInSpy.mock.results[0].value; expect(isUserLoggedInSpy).toHaveBeenCalled(); expect(searchFunctionMock).toHaveBeenCalled(); }); });
其他测试框架的通用思路
无论是Enzyme(mount)还是react-test-renderer,核心都是等待异步操作完成后再执行断言:
- Enzyme可结合
async/await与wrapper.update(),或使用官方提供的wait工具函数; - react-test-renderer需等待Promise resolve后,再调用
root.findBy*方法或执行断言。
额外注意:测试代码中存在testid不匹配问题——组件内button的testid是search-button-submit,但原测试中写的是search-icon-submit,这也会导致点击未触发正确元素,建议优先修正。
内容的提问来源于stack exchange,提问作者thdDross347
相关产品推荐
相关产品推荐

