关于 condition-based-waiting
一种测试技能,以等待可观察条件取代猜测式延时,帮助开发者减少异步操作、负载或并行执行引发的不稳定测试。
主要功能
- 01等待条件而非固定延时
- 02等待事件、状态、数量或文件
- 03为复合条件编写等待逻辑
- 04使用特定领域的事件辅助函数
适用场景
- 01替换测试中的任意休眠调用
- 02稳定在高负载下失败的测试
- 03等待异步操作完成
- 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