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

setTimeout内Mock的console.error未被调用的Jest测试问题

解决Jest中setTimeout异步回调内console.error断言失败的问题

问题根源

测试失败的核心原因是:setTimeout的回调是异步函数,jest.runAllTimers()只会同步执行回调的起始部分,而回调内await fetch的异步逻辑会被放入微任务队列。此时直接断言console.error,断言代码会早于微任务执行,导致断言时console.error还未被调用。

另外测试代码还有两个无效/错误点:

  • jest.spyOn(global, "setTimeout").mockReturnValueOnce;语法错误,未调用mockReturnValueOnce方法,属于无效代码
  • 断言时重新调用jest.spyOn(console, "error")会创建新的mock实例,和beforeEach中创建的mock不是同一个,导致断言失效

修复方案

1. 保存console.error的Spy引用

在beforeEach中保存spy的引用,避免每次断言时重新创建新的mock:

describe("persist store", () => {
  let store: any;
  let state: RootState;
  let consoleErrorSpy: jest.SpyInstance; // 保存spy引用

  beforeEach(() => {
    jest.clearAllMocks();
    store = makeStore();
    state = store.getState();
    global.fetch = jest.fn();
    // 保存spy到变量
    consoleErrorSpy = jest.spyOn(global.console, "error").mockImplementation(() => {});
    jest.useFakeTimers();
  });

  afterEach(() => {
    consoleErrorSpy.mockRestore(); // 用保存的引用恢复
    jest.restoreAllMocks();
  });

2. 使用异步定时器API等待异步逻辑完成

Jest 27+提供了jest.runAllTimersAsync(),可自动等待定时器回调内的异步操作完成:

it("should throw error if state cannot be stored in", async () => {
  const sessionId = cookieMock.body.sessionId;

  (global.fetch as jest.Mock).mockResolvedValueOnce({
    ok: false,
    status: 500,
    statusText: "Session ID is required",
  });

  store.dispatch(setSessionId(sessionId));
  await jest.runAllTimersAsync(); // 改用异步版本,等待所有异步逻辑完成

  expect(setTimeout).toHaveBeenCalledTimes(1);
  expect(consoleErrorSpy).toHaveBeenCalled(); // 用保存的spy断言
});

3. 兼容旧版Jest的替代方案

如果你的Jest版本低于27,可以手动等待微任务队列清空:

it("should throw error if state cannot be stored in", async () => {
  // ... 其他代码不变

  store.dispatch(setSessionId(sessionId));
  jest.runAllTimers();
  await Promise.resolve(); // 等待微任务队列执行完成

  expect(setTimeout).toHaveBeenCalledTimes(1);
  expect(consoleErrorSpy).toHaveBeenCalled();
});

额外说明

  • 移除无效的jest.spyOn(global, "setTimeout").mockReturnValueOnce;代码,避免干扰测试
  • 确保delayTime是确定值,防止定时器未被正确触发

内容的提问来源于stack exchange,提问作者RasMason

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:18:19