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

Jest测试中如何带延迟模拟返回值并测试未决Promise?

Jest测试未决Promise的正确实现方案

原代码中的核心问题

  1. API调用错误:mockResolvedValue接收的是直接resolved值,而非返回Promise的函数。要返回延迟resolve的Promise,需用mockImplementation或mockReturnValue。
  2. 拼写错误:flushpromises应为flushPromises,toHavebeencalled应为toHaveBeenCalled(遵循驼峰命名规范)。
  3. 逻辑偏差:原测试意图是验证callout返回的Promise未决,但断言方向错误,误判callout是否被调用而非Promise状态。

假计时器方案修正代码

import callout from "../callout";

jest.mock("../callout", () => ({
  default: jest.fn(),
}), { virtual: true });

const { setImmediate } = require("timers");

function flushPromises() {
  return new Promise((resolve) => setImmediate(resolve));
}

it("测试延迟Promise在推进部分时间后仍处于未决状态", async () => {
  jest.useFakeTimers();
  // 模拟callout返回一个2秒后才resolve的Promise
  callout.mockImplementation(() => 
    new Promise(resolve => setTimeout(() => resolve("done"), 2000))
  );

  // 调用callout并获取返回的Promise
  const pendingPromise = callout();

  // 推进20ms,远未达到resolve所需时间
  jest.advanceTimersByTime(20);
  await flushPromises();

  // 通过标志位验证Promise仍未决
  let isResolved = false;
  pendingPromise.then(() => isResolved = true);
  expect(isResolved).toBe(false);

  // 推进足够时间触发Promise resolve
  jest.advanceTimersByTime(2000);
  await flushPromises();

  expect(isResolved).toBe(true);
  expect(callout).toHaveBeenCalled();

  // 恢复真实计时器,避免影响其他测试
  jest.useRealTimers();
});

两种方案的完整实现

方案1:返回永久未决的空Promise

适合无需后续状态切换,仅需验证未决状态的场景:

it("测试空Promise的永久未决状态", async () => {
  // 返回一个永远不resolve/reject的空Promise
  callout.mockReturnValue(new Promise(() => {}));

  const pendingPromise = callout();
  await flushPromises();

  let isSettled = false;
  // 无论resolve还是reject都会标记为已完成
  pendingPromise.then(() => isSettled = true).catch(() => isSettled = true);
  expect(isSettled).toBe(false);
});

方案2:假计时器控制的延迟Promise

如修正后的代码所示,核心是通过模拟计时器控制Promise的resolve时机,实现"未决→已决"的状态切换验证,适合需要测试状态变化的场景。

关键注意事项

  • 使用假计时器后,必须调用jest.useRealTimers()恢复真实计时器,防止影响其他测试用例。
  • 无法直接断言Promise对象的状态,需通过then/catch回调设置标志位间接判断是否已决议。
  • flushPromises通过setImmediate清空微任务队列,确保同步代码执行完毕后再检查Promise状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:40:36