You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步函数中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 07:54:18