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

测试包含Promise与setTimeout的函数时Jest超时的原因是什么?

问题产生原因
  • 核心逻辑顺序错误:你启用了Jest的假定时器jest.useFakeTimers(),但在代码中先执行了await sleep(+SLEEP_DURATION),后调用jest.runAllTimers()。sleep函数内部的Promise依赖setTimeout的回调触发resolve,在假定时器模式下,你不主动调用跑定时器的方法,setTimeout的回调永远不会执行,导致sleep函数的Promise持续处于pending状态,测试阻塞,无论你把超时阈值设多大都会触发超时错误。
  • 额外的错误点:
    • 你没有给sleep函数创建Spy,直接调用expect(sleep).toHaveBeenCalledWith会抛出断言错误,因为Jest没有监听过sleep的调用行为,且该断言属于冗余逻辑——你主动调用的sleep不需要额外校验调用行为。
    • setTimeout的入参断言顺序错误:setTimeout第一个参数是要执行的回调函数,第二个参数才是等待时长,你的断言传入的参数顺序和实际入参不匹配。
修复方案

调整执行顺序,保证定时器在Promise等待前被触发,同时修复错误的断言逻辑即可,修复后的测试代码如下:

import { sleep } from "../../helpers/utils";

console.log = jest.fn();
jest.useFakeTimers();

test("calls sleep with correct argument and calls console.log", async () => {
  const NODE_ENV = "test";
  const SLEEP_DURATION = 100;

  process.env = { ...process.env, NODE_ENV };

  const timeoutSpy = jest.spyOn(global, "setTimeout");
  // 调用sleep但不立即await
  const sleepPromise = sleep(SLEEP_DURATION);
  // 执行所有定时器回调
  jest.runAllTimers();
  // 等待Promise队列清空,sleep执行完成
  await sleepPromise;

  // 校验setTimeout调用参数
  expect(timeoutSpy).toHaveBeenCalledWith(expect.any(Function), SLEEP_DURATION);
  // 校验console.log调用
  expect(console.log).toHaveBeenCalledWith("sleep end");
});

如果你使用的是新版Jest的modern假定时器配置,可以把jest.runAllTimers()替换为await jest.runAllTimersAsync(),兼容性更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:54:03