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

Jest测试中如何验证指定Promise在超时时间内无resolve无reject

1. 自定义.not.toComplete匹配器实现方案

Jest的expect.extend扩展机制完全支持实现这类自定义匹配器,核心逻辑是将待校验的Promise与指定时长的超时定时器对比,判断目标Promise是否在指定时间内完成。

匹配器扩展代码

expect.extend({
  // 校验Promise是否在指定毫秒数内完成(支持.not取反)
  async toCompleteWithin(targetPromise, timeoutMs) {
    let isCompleted = false;
    let completeType, completeValue;

    // 监听目标Promise的完成状态
    const wrappedTarget = Promise.resolve(targetPromise)
      .then(res => {
        isCompleted = true;
        completeType = 'resolve';
        completeValue = res;
      })
      .catch(err => {
        isCompleted = true;
        completeType = 'reject';
        completeValue = err;
      });

    // 等待超时时长
    await new Promise(resolve => setTimeout(resolve, timeoutMs));

    if (isCompleted) {
      return {
        pass: false,
        message: () => `预期Promise不会在${timeoutMs}ms内完成,但实际已${completeType},返回值为:${JSON.stringify(completeValue)}`
      };
    }
    return {
      pass: true,
      message: () => `预期Promise会在${timeoutMs}ms内完成,但实际未触发任何完成状态`
    };
  }
});

使用示例

// 校验8000ms内Promise不会resolve或reject,阈值可根据测试超时时间自行调整
await expect(eventually("projects/1/userInfo/xyz", o => !!o, 800)).not.toCompleteWithin(8000);

如果需要避免目标Promise后续运行产生的副作用,可以给eventually方法增加取消逻辑(比如传入AbortSignal),匹配器返回时触发取消信号即可。


2. 测试即将超时的触发器实现方案

Jest当前未提供原生的「超时前触发」钩子,其内部超时逻辑执行后会直接标记测试失败,不会提前暴露回调入口。你可以通过自定义定时器模拟该能力:设置一个比测试超时时间短100~500ms的定时器,触发后执行你需要的自定义逻辑。

示例代码

test ('User information is not distributed to a project where the user is not a member', async () => {
  await collection("userInfo").doc("xyz").set({ displayName: "blah", photoURL: "https://no-such.png" });
  const targetProm = eventually("projects/1/userInfo/xyz", o => !!o, 800);

  let isTestPassed = false;
  // 测试超时设为9999ms,提前500ms触发自定义逻辑
  const preTimeoutTrigger = setTimeout(() => {
    // 此处编写超时前的自定义逻辑,判断符合条件则标记测试通过
    isTestPassed = true;
  }, 9500);

  // 目标Promise提前完成则抛出错误
  targetProm.finally(() => {
    clearTimeout(preTimeoutTrigger);
    if (!isTestPassed) throw new Error('目标Promise在超时前意外完成');
  });

  // 等待测试状态确认
  await new Promise(resolve => {
    const checkStatus = () => isTestPassed ? resolve() : setTimeout(checkStatus, 50);
    checkStatus();
  });
}, 9999);

如果需要原生支持该能力,确实可以向Jest提交功能请求,目前官方没有提供对应的公开API。


补充说明

由于JS原生Promise不支持外部取消,所有方案都需要你在eventually的内部实现中兼容超时/取消逻辑,比如通过AbortSignal接收外部取消信号,终止内部的轮询等操作,避免产生无意义的后续执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 20:24:03