Opik E2E 测试失败调查指南:从红色 CI 到回归 / 抖动分类与修复提案
【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm
导读
在 Opik 项目中,当 Playwright 驱动的端到端测试(位于tests_end_to_end/e2e/)在 CI、Allure TestOps 或本地运行时变红,你需要一套可复现、有证据支撑的调查流程,而不是凭直觉改选择器。本文基于仓库中的investigate-e2e-failure命令及其背后的debugging-e2e-tests技能,完整讲解这条"只读诊断"链路:如何从四种失败入口定位证据、如何把失败判定为真实回归(regression)、抖动(flake)或环境 / 选择器漂移(environment / selector drift),以及如何输出带证据引用的修复提案。读完你将掌握一套可立即投入使用的 E2E 排障方法论,并能与writing-e2e-tests技能衔接完成修复落地。
一、命令定位:investigate-e2e-failure 是什么
在仓库的.agents/commands/comet/investigate-e2e-failure.md中定义了一个面向 AI Agent 的命令级工作流,其核心定位可以概括为三句话:
- 调查一次失败的 Opik E2E 测试并提出修复方案;
- 证据驱动:命令负责收集证据(trace、error、history),并将失败分类为真实回归、抖动或环境 / 选择器漂移;
- 只读原则:它只做诊断和提案,绝不修改测试代码。
该命令并不自包含全部逻辑,而是明确要求:
Invoke the
debugging-e2e-testsskill and follow it exactly.
也就是说,命令是入口,真正承载"调查循环"的是.agents/skills/debugging-e2e-tests/SKILL.md这份技能文档。技能里完整定义了证据来源(allure-testopsMCP、gh构件、npx playwright show-trace)、分类启发式与五步循环。本文将以这份技能为主体展开。
完成标准(Success criteria)
命令定义的验收标准正好构成一次调查的产出清单,也是你判断一次排障是否完成的检查表:
- 给出判定结论:regression / flake / environment-or-selector 三选一,并附带置信度;
- 引用证据:失败的 trace 步骤、错误信息、历史模式,以及(如果存在)相关联的代码变更;
- 给出具体的修复提案;若判定为已知抖动,则给出轮询(poll)/ 隔离(quarantine)/ 不修复(no-fix)的建议;
- 零修改:本次调查不做任何编辑,修复落地需移交给
writing-e2e-tests技能。
二、先理解证据在哪里:Opik E2E 套件的结构
要调查失败,首先要清楚"失败现场"存放在哪里。.agents/skills/debugging-e2e-tests/SKILL.md明确给出了三类证据位置,与tests_end_to_end/e2e/目录结构一一对应。
2.1 本地运行证据
本地执行 Playwright 测试时,失败现场默认保留在当前目录下:
- Playwright traces:
tests_end_to_end/e2e/test-results/(失败时保留); - Allure 结果:
tests_end_to_end/e2e/allure-results/。
这些路径由 playwright.config.ts 中的 reporter 与 use 配置决定:trace: 'retain-on-failure'、screenshot: 'only-on-failure'、video: 'retain-on-failure',同时 Allure 插件输出到allure-results目录。
2.2 CI 运行证据
CI 上每次运行会产出三个构件(保留期 7 天):
| 构件名 | 内容 |
|---|---|
test-results-v2 | Playwright traces + 视频 |
playwright-report-v2 | HTML 格式报告 |
allure-results-v2 | Allure 结果 |
下载方式(技能原文命令):
gh run download <run-id> -n test-results-v2 -D <dir>2.3 Allure TestOps
Allure TestOps(comet.testops.cloud,project id1)在 CI 期间实时接收测试结果流。launch 命名规则为Opik v2 … <tier> - <run_id>,其中:
- 尾部数字是 GitHub Actions 的 run id;
- 中间的 env 段会变化:
E2E、Post-Merge、Local、staging、production。
利用 launch 中的jobRun.url可以直接反查到对应的 GitHub Actions 运行。
2.4 套件的技术底座(佐证)
E2E 套件的运行方式对理解失败现场有帮助:Playwright 的webServer指令会自动拉起两个服务——
services/opik-sdk-driver:一个用uv运行的 FastAPI 应用,包装 Python SDK 为 TypeScript 客户端提供 seeding 路由(见 playwright.config.ts 中uv run uvicorn opik_sdk_driver.main:app --port 5175);services/mock-token-auth:Mock OAuth2 token 服务,用于动态 token 认证的 spec(OPIK-7940),封闭式设计,不依赖外部密钥。
套件还通过global-setup.ts打上每次运行的runId,global-teardown.ts负责清理本次运行创建的所有cuj-{runId}-*项目(见 tests_end_to_end/e2e/README.md)。理解这些基础设施,能帮助你在"失败是否由环境引起"这一分类维度上做出更准确的判断。
三、工具链:一张排障工具箱清单
技能文档定义了四个核心工具,调查过程基本就是这四个工具的轮流使用:
allure-testopsMCP(已配置连接)—— 信息最丰富的证据源。技能文档给出了三个验证过的调用:list_launches(projectId: 1, search: "<run_id or name fragment>", sort: ["createdDate,DESC"])或search_launches(rql: …):定位 launch;list_test_results(launchId):获取每个测试的name、fullName(spec 路径 + 行号,例如datasets/dataset-crud-smoke.spec.ts:8:7)、status、TestOps 计算的flaky标记、muted/known、tags、jobRun.url(对应 GitHub Actions 运行)以及 result 的id;可用search过滤到失败的测试;get_test_result_history(id):该测试在最近多次 launch 中的通过 / 失败时间线 —— 这是抖动(flake)判定的核心信号。
ghCLI——gh run view <run-id>定位失败 job;gh run download <run-id> -n test-results-v2 -D <dir>拉取 trace 构件。npx playwright show-trace <trace.zip>—— 在tests_end_to_end/e2e/目录下打开 trace,查看精确失败的步骤、当时的 DOM 快照以及该时刻的 console / network。git—— 对比可疑变更与失败测试的代码路径,用于相关性分析。
四、调查五步循环(核心章节)
技能的骨架是一条五步流水线,用 DOT 图表示为:
1. Resolve entry point → 2. Gather evidence → 3. Classify → 4. Diagnose → 5. Report + propose (no edits)Step 1 —— 解析入口点(Resolve the entry point)
无论失败从哪来,第一步都是把它归一化为"一个失败的测试 + 它的证据在哪里"。四种入口的归一化方式:
- 红色 CI check / Actions run:取 run id。
gh run view <run-id>找失败 job;用list_launches(projectId: 1, search: "<run-id>")找匹配 launch;trace 在test-results-v2构件中,用gh run download拉取。 - TestOps launch:直接查询
list_test_results(launchId),过滤出失败结果。 - 测试名(例如
dataset-crud-smoke):在最近的 launch 上用list_test_results加search找到 resultid,再拉取其历史。 - 本地失败:直接使用本地的
test-results/trace 和allure-results/;对于未提交的本地运行,TestOps 里可能没有对应记录,这很正常,无需强求。
Step 2 —— 收集证据(Gather evidence)
证据收集的四个要点:
- 失败断言与错误消息:来自 trace、报告或 TestOps result;
- trace:对保留 / 下载的
.zip执行npx playwright show-trace,重点读失败步骤、该时刻的 DOM 快照及其前后的 console / network; - 截图 / 视频:存在则一并使用(配置为
only-on-failure/retain-on-failure); - 测试历史:通过
get_test_result_history(id)获取,并结合 TestOps result 上的flaky标记。优雅降级:当 TestOps 不可达(例如纯本地运行)时,跳过历史收集,退回到 trace + diff 推理。
Step 3 —— 分类(Classify)
这是整个调查的核心决策点:判定为真实回归(real regression)、抖动(flake)还是环境 / 选择器漂移(environment / selector drift)。技能给出的三条启发式:
- 历史信号(优先):一条干净的连续通过记录、在某个相关变更之后立刻断裂 → 倾向 regression;间歇性通过 / 失败且无相关变更,或 TestOps
flaky: true→ 倾向 flake; - Diff 相关性:最近的变更是否触及失败断言所经过的代码路径(页面 / 组件、POM 方法、fixture)?触及 → 大概率 regression;失败区域完全未被触碰 → 大概率 flake 或环境问题;
- 默认保守:当历史呈现间歇性且不存在相关 diff 时,默认判为 "flake / uncertain"——没有证据就不要轻易扣上 regression 的帽子。
Step 4 —— 诊断(Diagnose)
在分类基础上定位根因,且必须基于引用的证据(具体 trace 步骤、错误、历史模式),而不是猜测。技能提供了四个针对 Opik 套件的诊断透镜,按优先级应用:
- 先验证测试渲染,再怪罪后端:一条 "X didn't appear" 的失败,往往不是后端回归,而是 DOM 竞态(loading spinner 还在转、最终一致性写入尚未落盘)。检查失败步骤处的 DOM 快照即可确认;
- 选择器漂移:前端改了 accessible name 或删除了
data-testid,导致 locator 无法再解析; - 最终一致性状态:异步打分 / 摄入(scoring / ingestion)需要轮询(poll)而不是固定等待;
- Fixture 种子形状不匹配:页面渲染出空 / 部分状态,是因为种子数据与断言期望的形状不一致。
这些透镜与.agents/skills/writing-e2e-tests/conventions.md中"Verify the test render before blaming the backend"的约定一脉相承——说明诊断准则与编写准则在设计上是对齐的。
Step 5 —— 报告 + 提案(Report + propose,不编辑)
输出三件套:
- 判定(Verdict):分类(regression / flake / environment-or-selector)+ 置信度;
- 证据(Evidence):trace 步骤、错误、历史模式、关联变更(如有),逐项引用;
- 修复提案(Proposed fix):必须具体。回归 → 指明要改的代码 / 选择器 / 轮询点;抖动 → 用
expect.poll替代固定等待、隔离(quarantine),或"无需改代码——已知抖动,重试"。
最后重申边界:不编辑任何东西。开发者要应用修复时,移交给writing-e2e-tests技能。
五、分类启发式背后的工程逻辑
为什么技能在分类上如此强调"证据"与"保守默认"?从仓库约定可以还原出它的工程动机:
- 失败信息密度被刻意放大:
.agents/skills/writing-e2e-tests/conventions.md强制每个 POM 方法体和测试逻辑阶段用test.step()包裹并经由回调返回。这使得 Playwright trace viewer 和 Allure timeline 可读——一次失败不再是"一堵没有叙事的操作墙",而是一个个语义化的阶段。没有这个约定,Step 2 的 trace 阅读会寸步难行。 - 选择器优先级是抖动治理的第一道防线:约定规定选择器优先级为
getByTestId>getByRole>getByLabel>getByText> CSS/XPath,并明令"结构型 CSS 选择器(如tbody > tr:nth-child(2))是抖动的主要来源"——一旦出现就应给前端组件补data-testid。这条约定直接支撑了 Step 4 中"selector drift"透镜的判断标准。 expect.soft是例外而非默认:约定指出默认应使用硬断言expect(...),让 trace 精确停在假设断裂之处;只有像workspace-roles-permissions.spec.ts这种一次性审计大量独立事实的场景才用expect.soft。这解释了为什么技能要求"失败的断言 + 精确的错误消息"作为首要证据——套件本身被设计成一次失败信息最清晰。- fixture 与 teardown 所有权清晰:teardown 归 fixture 管(无论通过、失败还是超时都会执行),destructive 测试需要 bystander 实体。这让"测试本身是否污染了环境"这类环境归因问题在调查时有章可循。
六、边界与后续衔接
6.1 只读边界
技能文档用两段话锁死了边界:
- 只读:不做测试编辑,也不为调查而重跑套件;
- 四种入口全部覆盖:CI、TestOps launch、测试名、本地失败;没有 TestOps 时优雅降级(本地失败仅靠 trace + diff)。
6.2 与 writing-e2e-tests 的分工
调查与编写是两条截然不同的流水线,技能文档明确区分:
debugging-e2e-tests解释一条红色的测试(diagnose an existing red one);writing-e2e-tests新增一条测试(author a new one),并自带"run-until-green"循环。
因此"修复落地"不是本命令的职责:调查结束后把提案移交给writing-e2e-tests(位于 .agents/skills/writing-e2e-tests/SKILL.md),由后者执行包括 POM + spec 修改、data-testid补充、tag_lint.py校验、tsc --noEmit类型检查在内的完整改动循环。二者合起来构成 Opik E2E 维护的闭环:新增测试走 writing 循环,失败测试走 investigating 循环,修复再回到 writing 循环。
七、实战速查表
| 环节 | 关键动作 / 命令 | 证据来源 |
|---|---|---|
| 定位 run | gh run view <run-id> | GitHub Actions |
| 找 launch | list_launches(projectId: 1, search: "<run-id>") | Allure TestOps |
| 查失败结果 | list_test_results(launchId),过滤 status | Allure TestOps |
| 拉历史 | get_test_result_history(id)+flaky标记 | Allure TestOps |
| 下载 trace | gh run download <run-id> -n test-results-v2 -D <dir> | CI 构件 |
| 阅读失败现场 | npx playwright show-trace <trace.zip> | Playwright |
| 相关性分析 | git diff对比失败代码路径 | git |
| 分类决策 | 历史连续断裂→regression;间歇+无相关diff→flake(默认保守) | 证据综合 |
| 诊断透镜 | 渲染竞态 → 选择器漂移 → 最终一致性 → fixture 形状 | trace DOM 快照 |
| 输出 | 判定 + 置信度 + 逐项引用证据 + 具体修复提案,零编辑 | — |
结语
Opik 的 E2E 失败调查不是"打开 trace 看运气",而是一条被明确固化的方法论:从investigate-e2e-failure命令入口进入,经由debugging-e2e-tests技能的五步循环(解析入口 → 收集证据 → 分类 → 诊断 → 报告提案),最终产出一份带证据引用、带置信度、带具体修复方向的诊断报告,且全程只读。这套流程的价值在于把"排障"从个人经验变成了可复用、可审计、可交接的工程能力——而它的根基,正是仓库中 E2E 套件本身对test.step()、选择器优先级、fixture 所有权和标签体系的一系列强制性约定。
【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考