deflake 是一个针对“不稳定测试”的修复技能。所谓不稳定测试(flaky test),是指在一个 deflake 类型的问题中,已经被观察到在同一提交上先失败、重跑又通过——这是确定性的不稳定信号。该技能的目标是让这个测试变得确定,同时不改变它验证的内容。
【用途】 处理已被明确指出的单个 flaky 测试。问题描述中会携带测试身份(所在文件与测试名称)以及观察到的失败特征,例如“Test timed out in 5000ms”“Timed out waiting for …”、依赖顺序的断言、依赖真实时钟或随机数的值。使用者需要阅读该测试、在脑中复现其不确定性机制,然后从允许的修复集合中选择并应用最小修复。
【主要能力(仅允许的四类修复)】
- 提高超时或轮询预算:例如在 CI 资源竞争下触发 vitest 默认超时的测试(全 mock 或 I/O 密集,而非性能测试),可以给它一个更宽松的单个测试 testTimeout(it 的第三个参数),或把内部轮询循环从固定迭代次数改为真实的墙钟预算(固定次数的 setImmediate 只消耗毫秒级时间,会与真实 I/O 竞争)。
- 稳定时序与等待:把裸 setTimeout 或固定睡眠替换为对真实条件的显式等待(vi.waitFor、已解决的 promise、某个事件);或在 beforeAll 中预热惰性加载(例如 WASM 运行时),使每个测试的耗时不再包含首次加载成本。
- 使随机与时间确定化:给随机数生成器设定种子、使用 vi.useFakeTimers() 或 mock Date.now,或固定输入,使依赖真实时钟或 Math.random 的值无法漂移。
- 隔离或串行化干扰:对在共享资源上冲突的测试(同名临时目录、固定端口、全局单例)分配唯一的每测试资源,或将它们串行化。
【使用方式】
- 先读取问题中给出的测试身份与失败特征,理解其不确定性来源。
- 从上述四类修复中选择最小、最贴合本地场景的一种并实施。
- 保持差异最小且局限于被点名的测试(及其所在文件的辅助代码),不重构无关代码。
- 完整保留每一个断言和每一份输入:提高超时只改变上限;确定化修复只改变不确定性的来源。
- 优先选择按测试或按文件的改动,而非全局配置改动;除非同一类问题确实横跨整个包,此时可在该包的 vitest.config.ts 中设置 testTimeout(它只提高上限,不弱化任何断言)。
【硬性规则】
- 绝不删除测试、跳过(skip/todo)测试、放宽断言、扩大期望范围、添加 blanket try/catch,也不在断言外加重试包装。这些做法只是掩盖不稳定,而非修复,还可能隐藏真实缺陷。
- 如果四类修复都不适用,或失败看起来是真实的产品间歇性缺陷(而非测试不确定性),就写入 <workdir>/failure.md 说明发现并停止,交由人工处理。
【验证】
- 多次运行被点名测试所在的文件(在正确的包中执行 npx vitest run <file> 并重复),必须每次都通过。
- 然后运行标准校验关卡(构建 / 类型检查 / lint / 被修改的测试)。
- 如果无法让它稳定通过,写入 <workdir>/failure.md 并停止。
- 之后按照 .qwen/skills/prepare-pr/SKILL.md 准备 PR 描述,并依据 Shared Rules 写入双语 <workdir>/e2e-report.md,说明:不稳定的机制、应用了四类修复中的哪一类及原因、以及重复运行证明其现已确定的证据。
【适用场景与限制】 适用于已被明确定位为测试不确定性(而非产品缺陷)的 flaky 测试修复。限制在于:只能使用上述四类修复;必须保留全部断言与输入;改动范围应尽量小且本地化;遇到疑似真实产品间歇性缺陷时应停止而非强行修复。关于该技能的具体安装命令、收费方式、平台支持等细节,资料中暂未提供。