用完整Playwright失败现场驱动代理修复
文章建议向编码代理提供原始断言错误、堆栈、失败路由、追踪文件路径和运行命令,避免只描述测试失败现象。作者通过结账端到端测试案例,展示了请求单文件补丁并解释脆弱定位器的工作流。
AI 深度解读
一次 checkout 端到端测试在 main 上失败,作者和同事先把 CI 截图发进 Slack,3 个人猜了 20 分钟。后来,作者把完整 Playwright 报错交给 agent,要求只修一个文件,10 分钟后拿到了补丁和定位器脆弱的原因说明。
这篇经验分享的重点,是怎样让 AI 修测试时有证据、有边界、有验收。对已经用 agent 辅助开发的团队,最值得借用的不是提示词措辞,而是先分清产品故障、测试漂移和基础设施偶发失败,再决定改哪里。
报错原文为什么比一句故障描述管用
「提交按钮不能用了」会把问题压缩得只剩结论。真正有助于定位的,是断言期望什么、实际收到什么、等待多久超时,以及堆栈指向哪个测试文件的哪一行。
作者要求同时提供失败时的页面 URL 或路由、CI 上传的 trace 与截图路径,以及实际执行的命令。例如 pnpm test:e2e --grep checkout,能交代这次运行筛选了哪些测试。Playwright 默认 reporter 已经输出了其中大部分信息,直接复制失败块即可。
下面这个模板解决的是交接信息缺失的问题:
## Playwright failure (paste raw)
Command: pnpm exec playwright test e2e/checkout.spec.ts --project=chromium
CI job: main / e2e / #4821
<<< paste the failure block here, including Expected/Received and stack >>>
Trace zip (if any): artifacts/trace-checkout.zip
Goal: smallest fix in the test OR one related page object — do not rewrite the suite
Out of scope: changing product behavior, deleting assertions "to make green"
重点看最后两行:既限定修改范围,也明确不能修改产品行为、不能删除断言来换取通过。否则,agent 很容易把「修复失败」理解成「让测试变绿」。
Slack 适合讨论是否回滚、是否属于真实回归。作者观察到,截图经常丢失选择器和超时数字,讨论又容易被猜测带偏。因此,他会在形成方案后再发一句结论,说明哪个定位器发生变化、补丁在哪个 PR。
修改之前,先让 agent 判断该不该改测试
作者给失败分了三类:
- A:产品回归。保留失败测试,说明应该检查应用的什么行为。
- B:测试漂移。文案、定位器或时序发生变化,提出最小测试修复。
- C:基础设施偶发失败。提出基于状态的等待方案,例如原文列出的
network idle / attached,避免固定休眠。
这里的「测试漂移」,就是测试还按旧页面找元素,页面却已经变了。但页面发生变化,也可能正是产品缺陷,不能看到定位失败就直接归入 B。
先判断失败属于哪一类,再允许 agent 修改测试。
作者建议先要假设,再看补丁。例如先解释「按钮文案从 Pay 改成了 Place order」,再更新定位器。合格输出至少包含一句根因、限制在失败路径内的 diff,以及没有改变含义的断言。结账测试修完后,仍然应检查用户能否下单。
A 和 B 不应混在一个 PR。否则,测试调整可能掩盖产品回归,审查者也难以判断绿色 CI 究竟证明了什么。
怎样把一次修复限制在可审查的范围内
作者的流程从复现开始:如果怀疑 CI 偶发失败,就用相同 project 在本地跑一次,必要时启用有界面模式。如果只有负载较高时才失败,也要写进提示词。
接着提供失败日志和测试路径;堆栈涉及页面对象(page object)时,再附相关文件。修改范围限制为一个测试文件,加上最多一个页面对象,保留断言意图,优先使用 getByRole、getByLabel。
这段约束进一步堵住了几条常见捷径:
You are fixing ONE Playwright failure. Do not expand coverage.
Rules:
- Prefer getByRole / getByLabel over CSS / XPath
- Do not remove waits by deleting the assertion
- Do not add `waitForTimeout`
- If the app copy changed, update the locator and note the copy change in the PR body
- If the failure looks like a real product bug, STOP and say so — do not paper over it in the test
最关键的是最后一行:发现真实产品问题就停下,报告问题。waitForTimeout(2000) 也被作者明确列为不应接受的修复方式,固定睡两秒并没有解释测试究竟在等什么。
拿到补丁后,要重跑单个测试,把通过或仍然失败的输出交回 agent。作者会拒绝只写「更新了选择器」的说明,也会丢弃顺手重构三个无关 spec 的补丁。
trace 用来补证据即可,不必把完整 JSON 塞进对话。提供失败动作名称、小体积快照 HTML 路径,或 CI artifact 地址及失败步骤标题就够了。比如「点击 Pay 后等待订单确认,等待 #confirmation 超时」,但仍须附断言原文。
我的判断
这套方法最扎实的地方,是把 AI 修复变成一项可以审查的工程任务:有原始输入,有根因假设,有修改边界,最后还有运行结果。相比只发截图让人猜,信息确实更完整;相比直接让 agent「修好 CI」,验收标准也更清楚。
不过,3 人讨论 20 分钟、agent 10 分钟给出补丁,只是作者的一次经历。原文没有对照实验,也没有长期通过率、误修率等数据,不能据此认定 agent 一定更快,或这套流程已经解决了 flaky test。
「一个测试文件加最多一个页面对象」适合作为初始约束,未必适合共享组件、公共 fixture 引发的大面积失败。分类也允许暂时不确定,证据不足时应继续查。
另外,原文将 network idle / attached 列为稳定等待的候选,却没有说明具体适用条件。审查时仍要追问:元素挂载、网络安静,是否足以证明当前业务步骤完成?等待条件需要对应断言,而不是机械替换固定休眠。
能拿来做什么
- 给前端仓库准备一份失败交接模板,固定收集执行命令、断言原文、堆栈、失败路由和 artifact 路径,减少人工转述造成的信息损失。
- 在日常 AI 编程中,要求 agent 先提交失败分类和一句根因假设,再生成 diff;涉及文案变化时,在 PR 描述中明确记录。
- 审查 Playwright 修复时,重点检查断言是否保留原有含义、是否新增
waitForTimeout、是否修改无关 spec,并附上单测重跑结果。 - 在 Slack 中同步判断和处理方案,把完整日志与修复过程保留在可追踪的任务或 PR 中,让讨论围绕证据推进。