mcpField
C
condition-based-waiting

condition-based-waiting

github.com/bobmatnyc测试与质量78332 次安装15 周前更新
代码仓库

关于 condition-based-waiting

一种测试技能,以等待可观察条件取代猜测式延时,帮助开发者减少异步操作、负载或并行执行引发的不稳定测试。

主要功能

  1. 01等待条件而非固定延时
  2. 02等待事件、状态、数量或文件
  3. 03为复合条件编写等待逻辑
  4. 04使用特定领域的事件辅助函数

适用场景

  1. 01替换测试中的任意休眠调用
  2. 02稳定在高负载下失败的测试
  3. 03等待异步操作完成
  4. 04避免并行测试运行时超时

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill condition-based-waiting

安装后在 Claude Code 中输入/condition-based-waiting确认已加载。

附带文件metadata.jsonreferences/patterns-and-implementation.md

详细介绍

基于条件的等待

概述

不稳定的测试常常依赖任意延迟来猜测时机。这会导致竞态条件:测试在速度较快的机器上能通过,但在负载较高或 CI 环境中却会失败。

核心原则: 等待你关心的实际条件,而不是猜测需要多长时间。

适用场景

digraph when_to_use {
    "Test uses setTimeout/sleep?" [shape=diamond];
    "Testing timing behavior?" [shape=diamond];
    "Document WHY timeout needed" [shape=box];
    "Use condition-based waiting" [shape=box];

    "Test uses setTimeout/sleep?" -> "Testing timing behavior?" [label="yes"];
    "Testing timing behavior?" -> "Document WHY timeout needed" [label="yes"];
    "Testing timing behavior?" -> "Use condition-based waiting" [label="no"];
}

适用情况:

  • 测试中存在任意延迟(setTimeout、sleep、time.sleep())
  • 测试不稳定(有时通过,有时在负载下失败)
  • 测试并行运行时超时
  • 等待异步操作完成

不适用情况:

  • 测试实际的时序行为(防抖、节流间隔)
  • 如果使用任意超时,始终说明原因

核心模式

// ❌ BEFORE: Guessing at timing
await new Promise(r => setTimeout(r, 50));
const result = getResult();
expect(result).toBeDefined();

// ✅ AFTER: Waiting for condition
await waitFor(() => getResult() !== undefined);
const result = getResult();
expect(result).toBeDefined();

快速模式

场景模式
等待事件waitFor(() => events.find(e => e.type === 'DONE'))
等待状态waitFor(() => machine.state === 'ready')
等待数量waitFor(() => items.length >= 5)
等待文件waitFor(() => fs.existsSync(path))
复杂条件waitFor(() => obj.ready && obj.value > 10)

实现

通用轮询函数:

async function waitFor<T>(
  condition: () => T | undefined | null | false,
  description: string,
  timeoutMs = 5000
): Promise<T> {
  const startTime = Date.now();

  while (true) {
    const result = condition();
    if (result) return result;

    if (Date.now() - startTime > timeoutMs) {
      throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`);
    }

    await new Promise(r => setTimeout(r, 10)); // Poll every 10ms
  }
}

完整实现及特定领域的辅助函数(waitForEvent、waitForEventCount、waitForEventMatch)请参阅 @example.ts。

有关详细模式、实现指南和常见错误,请参阅 @references/patterns-and-implementation.md

实际效果

来自调试会话(2025-10-03):

  • 修复了 3 个文件中的 15 个不稳定测试
  • 通过率:60% → 100%
  • 执行时间:缩短了 40%
  • 不再出现竞态条件

评论

支持 Markdown