Opik 端到端测试标签体系:用 Playwright 标签构建可验证的覆盖率地图 Opik 端到端测试标签体系用 Playwright 标签构建可验证的覆盖率地图【免费下载链接】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导读本文以 tests_end_to_end/TESTING-TAGS.md 为骨架系统讲解 Opik 仓库端到端测试Playwright 功能测试 视觉回归测试的标签语法tag grammar、分层执行策略与覆盖率治理机制。读完本文你将掌握t1-smoke、t2-cuj、t3-nightly、area:、cap:、vcap:六类标签各自的语义与组合规则理解标签如何被 CI 中的tag_lint.py强制校验、如何被 Allure 报表消费以及如何为新增测试区域与能力制定符合规范的分层方案。一、标签是覆盖率地图而不是装饰在 Opik 的端到端测试体系中标签承担着一个核心职责它是测试覆盖率的唯一事实来源。正如文档开篇所强调的没有人维护一张哪些测试覆盖了 prompts的电子表格——spec 本身就是地图覆盖率构建器coverage builder直接读取这些标签。这句话有两层含义声明即覆盖一条能力capability被标记为已覆盖依据是存在一条携带其cap:标签的测试而非人工填写的台账。语法必须成立grammar holds既然覆盖率完全依赖标签的机器可读性标签语法就必须被 CI 强制执行否则地图就会失真。这套机制的**作用域Scope**被严格限定为两个目录tests_end_to_end/e2ePlaywright 功能测试functionaltests_end_to_end/visual-testsPlaywright 视觉回归测试visual除此之外的任何测试例如仓库中 tests_load 目录下的压测脚本都不在这套标签体系内这在后面覆盖率维度一节会再展开。二、四类标签tier / suite / area / cap标签只允许出现在 Playwright 的tag选项里绝不能写进测试标题。一个典型的标签声明如下test.describe(Prompt Library — smoke, { tag: [t1-smoke, area:prompts, cap:prompts.list-prompts], }, () { /* ... */ });四类标签按回答什么问题划分类别Kind基数Cardinality示例回答的问题tier恰好 1 个t1-smoke跑多深 / 多久跑一次suite0 或多个t1-stsaas除了分层阶梯还要在哪里跑area恰好 1 个area:prompts属于哪个产品区域cap1 个或多个cap:prompts.list-prompts覆盖了哪些能力这种设计把跑得多深和在哪里跑这两个正交维度拆开而不是用一个扁平枚举混在一起——这是理解整套体系的钥匙。2.1 tier——深度与频率标签运行时机成本要求t1-smoke合并后post-merge 生产环境每天 3 次必须廉价且稳定t2-cuj每夜作为 t3 的一部分真实用户旅程Critical User Journeyt3-nightly每夜在 staging 上最慢、最彻底tier 是累积的test:t2会跑 t1t2test:t3会跑 t1t2t3。这一规则在 tests_end_to_end/e2e/package.json 的 npm scripts 中得到了精确实现test:t1: playwright test --grep t1-smoke, test:t2: playwright test --grep \t1-smoke|t2-cuj\, test:t3: playwright test --grep \t1-smoke|t2-cuj|t3-nightly\,因此选择 tier 的依据是**它应该多频繁地运行**而不是它有多重要。一个重要但昂贵的测试应当属于 t3 而非 t1——把它放进 t1 只会拖慢高频回归并制造不稳定。2.2 suite——决定在哪里而不是有多深文档特别强调suite 与 tier 正交这是最容易搞错的部分。一个 suite 标签表示也把我包含进这次运行与测试深度无关。一条 spec 可以同时是t2-cuj和t1-stsaas——拥有 t2 的深度同时被纳入 STSaaS 的客户环境 sanity 集合。标签含义t1-stsaas纳入 STSaaS 客户环境 sanity 运行test:t1-stsaasprovider-sanityLLM 提供商矩阵自有节奏不阻塞部署文档给出的实战案例是 optimization-studio/optimization-studio.spec.tstest.describe(Optimization Studio — core, { tag: [t2-cuj, t1-stsaas, area:optimization-studio] }, () { test(the new-run form renders its sections and enables Optimize only once valid, { tag: [cap:optimization-studio.new-run-form-validation] }, async ({ /* ... */ }) { // ... }); });选择t2-cuj是因为它是一条完整的用户旅程选择t1-stsaas是因为 Optimization Studio 在客户环境上历史上不稳定必须在那里验证不选t1-smoke是因为每次运行都会消耗真实的 LLM 预算而 t1 每天跑 3 次。同样合法的情况是一条 spec只携带 suite 标签而没有 tier——这是刻意退出分层阶梯opt-out。例如 playground/playground-providers.spec.ts 就只带provider-sanity它按自己的节奏运行不参与 t1/t2/t3 阶梯。2.3 area 与 cap——覆盖率本体area:表示该 spec断言的能力所属的产品区域。关键约束区域名要从coverage/taxonomy.yaml读取而不是从 spec 所在的目录名推断详见五、spec 放哪里。cap:的格式必须是area.capability且两半都必须在 taxonomy 文件中存在。目前只有cap:与area:的匹配关系由tag_lint.py强制检查。一个来自 datasets/dataset-items.spec.ts 的完整例子test.describe(Dataset items — direct coverage, { tag: [area:datasets] }, () { test(Editing an item field commits as a new version and round-trips to the SDK, { tag: [t2-cuj, cap:datasets.edit-item-versions], }, async ({ dataset, project, backendClient, page }) { // ... }); });为 spec 实际断言的每一条能力添加cap:而不仅仅是最显眼的那一条同时只为自己真正断言的能力添加。覆盖率的口径是只要存在携带该标签的测试能力即视为已覆盖测试的健康状况绿/不稳定/红被单独跟踪和报告。这带来两个方向上的纪律未列出unlisted的断言是不可见的覆盖如果测试断言了某个行为但没有对应cap:覆盖率地图对此完全盲区列了却没断言listed but not asserted则是永久的假绿permanent false green标签声明了覆盖实际没有任何测试在守护它。2.4 Visual specs——独立的vcap:体系视觉测试携带vcap:且不带 tier——它们作为一个整体套件运行。参考 visual-tests/tests/empty-states.spec.ts{ tag: [vcap:datasets.datasets-empty] }视觉能力是**页面/状态形态page/state-shaped**的而非行为形态一张截图断言整个页面渲染正确。它们位于每个区域的visual:块中且每个都必须声明一个state:取值限定为default | empty | loading | error四种枚举值。在 taxonomy.yaml 中可以看到视觉能力的实际组织方式例如 traces 区域下的visual: logs-traces-view: { covered: true, state: default, spec: visual-comparison.spec.ts 02 } logs-traces-empty: { covered: true, state: empty, spec: empty-states.spec.ts E01 } trace-sidebar-messages: { covered: true, state: default, spec: trace-sidebar.spec.ts S01 }三、标签放哪里describe 与 test把共享标签放在describe上单测特有标签放在test上。覆盖率构建器会做并集操作unions因此每个 test 自动继承其外层 describe 的全部标签。test.describe(Dataset items, { tag: [area:datasets] }, () { test(editing commits a version, { tag: [t2-cuj, cap:datasets.edit-item-versions], }, async () { /* ... */ }); test(bulk delete commits a version, { tag: [t3-nightly, cap:datasets.bulk-delete-items], }, async () { /* ... */ }); });一个文件可以包含多个处于不同 tier 的 describe——ollie/ollie-agentic.spec.ts 就有三个这完全合法且往往是正确的组织方式。代价是 tier 的基数cardinality检查因此无法在文件级做具体见八、CI 强制。四、命名规范标签kebab-case 小写。cap:为area.capability两侧都保持 kebab-case。测试标题capability: behavior的语义——描述什么必须为真而不是点了什么按钮。文档给出了正反例// good —— 说明必须成立的不变式 test(Editing an item field commits as a new version and round-trips to the SDK) // bad —— 描述的是点击动作而非保证 test(click edit then save then check)这一规范在 dataset-items.spec.ts 中落地得相当彻底Editing an item field commits as a new version and round-trips to the SDK、Bulk-deleting selected items commits as a new version and round-trips to the SDK、Searching filters the items table to matching rows——每条标题都在陈述产品承诺而不是 UI 操作序列。五、spec 放哪里区域不来自目录area:不能从目录名推导。必须读取 taxonomy 中该区域的spec_dir字段——目录以产品表面命名而一个目录可以承载多个区域。当前仓库就有两个真实案例目录承载的区域原因trace-explore/area:traces、area:threads两个区域都声明spec_dir: trace-exploreUI 把这块表面称为 Logsprompts/area:prompts、area:playground四条 prompt→playground 旅程 spec 按所演练的流程而非区域分组这一点在 taxonomy.yaml 中可以看到直接的代码级证据traces区域声明spec_dir: trace-explorethreads区域也声明spec_dir: trace-exploreprompts区域的specs:列表里则出现了prompts/prompt-playground-new-prompt.spec.ts等跨区域文件这些 spec 的cap:前缀是 playground但文件躺在 prompts 目录下。所以同一个目录中出现两个不同的area:值是常态不是错误跨区域的旅程 spec 放在它所演练的流程的邻居之间。新增 spec 时的操作顺序是把文件放在其流程邻居所在处用它断言的区域打area:标签把它加入该区域的specs:列表保持排序插入见第八节。六、test.step()把失败定位到阶段用test.step()包裹每个阶段。失败时 Allure 会以失败步骤命名报告从而把测试坏了细化为播种成功但对 version 2 的断言失败了const dataset await test.step(Seed a dataset via the SDK, async () { /* ... */ }); await test.step(Edit an item field and commit, async () { /* ... */ }); await test.step(Verify the edit round-trips to the SDK, async () { /* ... */ });这是仓库既有的事实风格24 条功能 spec 中有 22 条、21 个 page object 中有 16 个在使用它。test.step()支持返回值和模板字符串标题——dataset-items.spec.ts 中const items await test.step(Open the dataset items page, async () { ... })正是步骤返回值的用法返回值被后续步骤复用。七、Allure 集成标签自动到达报表Playwright 标签会自动流入 Allure无需任何allure.label()调用。Allure 会去掉开头的因此cap:prompts.list-prompts可以按如下方式查询tag cap:prompts.list-prompts复合查询同样可用这正是覆盖率构建器所依赖的能力tag area:traces and status passed这一机制在 tests_end_to_end/e2e/playwright.config.ts 中由allure-playwrightreporter 配置支撑reporter: [ [line], [html, { outputFolder: playwright-report, open: never }], [json, { outputFile: test-results/results.json }], [allure-playwright, { outputFolder: process.env.ALLURE_RESULTS || allure-results, detail: true, suiteTitle: true, }], ],所有结果上报到project 1Opik 与 EM 共用因此需要按 launch name 或标签分段查看绝不能按 project id 区分。八、CI 强制tag_lint.py 与 GitHub Actions.github/workflows/tag_lint.yml在每次触碰tests_end_to_end/的 PR 上运行硬失败而非警告。硬失败的原因很现实一条未打标签的 spec 对--grep不可见会静默地永远不运行——而 package.json 中的test脚本使用了--pass-with-no-tests即使零测试被匹配也会通过。这就是这套 lint 要防住的失败模式。8.1 本地复现 CI 校验与 CI 完全一致的方式在仓库根目录运行pip install pyyaml python3 tests_end_to_end/coverage/tag_lint.py \ --taxonomy tests_end_to_end/coverage/taxonomy.yaml \ --estate tests_end_to_endlint 产出的 findings 是**行锚定line-anchored**的因此在 CI 中使用--format github时问题会直接出现在 PR 的 Files-changed 视图中对应代码行上。8.2 强制项清单每条非豁免的 e2e spec 必须有 tier或 suite 豁免且恰好一个area:每条非视觉 spec 至少声明一个cap:area:/cap:/vcap:都必须在 taxonomy 中可解析cap:必须位于该 spec 声明的 area 之下视觉 spec 携带vcap:且不带 tiertaxonomy 中每个视觉能力都必须有枚举内的state:不允许出现无法识别的标签。8.3 明确不强制的事项tier 基数cardinality不在强制范围内。恰好一个 tier约束的是单条测试——即 describe 继承之后的状态而 linter 只读取字符串字面量不解析 TS AST它无法区分同一文件里多个 describe 的 tier 各不相同合法有 4 条 spec 这么做与一条测试携带两个 tier错误。这一条要靠人来维持正确。8.4 计算型标签的陷阱计算得到的标签是不可见的tag: [variant.cap]能通过 lint但对覆盖率毫无贡献——因为 lint 和覆盖率构建器都只匹配tag: [...]内的引号字符串字面量。因此如果在循环里生成测试且每次迭代覆盖不同能力必须改写为带字面量标签的独立test()调用——prompt-library-smoke.spec.ts 就是正确做法的范例。8.5 豁免目录与旧标签迁移豁免rules.exempt_dirs只有_seedharness 自测。遗留裸区域标签如旧式的datasets和退役标签会得到明确指出替换方案的报错信息而不是一句笼统的 unrecognised。九、taxonomy.yaml定义100%的评审文件coverage/taxonomy.yaml 是整套覆盖率的根基这个文件定义了100%。每个区域的覆盖率 拥有至少 1 条近期通过测试的能力数 ÷ 该区域总能力数。因此向 taxonomy 中添加能力会改变分母并降低覆盖率直到测试落地——这是刻意设计让已知缺口显性化而不是静默缺席。9.1 新增区域或能力的三步流程在coverage/taxonomy.yaml中添加区域或能力标记covered: false提交评审——这是 QA 拥有的决策不是实现细节随着覆盖落地用新cap:给 spec 打标签并翻转covered: true。9.2 能力粒度的把握能力的海拔建议为每区域 5–15 条每条都是测试可合理断言的用户可见行为✅ Create a prompt 是一条能力❌ Click the save button 不是Tab 通常应该是独立能力。9.3 区域重命名重命名区域时把旧名字加入tag_aliases:保证历史 Allure 结果仍可解析。如果旧标签已无法映射到唯一区域则加入retired_tags:并按 spec 逐一解析——trace-explore拆分进traces与threads就是这一场景taxonomy 中记录了完整的拆分理由retired_tags: trace-explore: reason: split into traces and threads — resolve per spec, not by rename replaced_by: [traces, threads]此外taxonomy 还记录了现实世界中另一个别名场景annotation-queues区域带tag_aliases: [annotation-queue]——这是历史上单复数不一致的遗留lint 在报错时会提示 canonical 名称。9.4 三个覆盖率维度taxonomy 将覆盖率拆成三个独立维度绝不混合成一个数字functionalcap:源自tests_end_to_end/e2e适用性为all——每条能力都应正常工作visualvcap:源自tests_end_to_end/visual-tests适用性为opt_in——只有声明了visual: {...}的能力才计入分母避免把空态截图虚增成功能覆盖loadlcap:源自仓库外的tests_load当前状态为planned——压测报告到 JUnit XML 而非 Allure因此对 Allure 构建器不可见v1 构建器必须跳过它。applicability是防止 load 列数据失真的关键大部分 UI 能力不承担负载把它们算作负载覆盖 0%会凭空捏造一个无人打算填补的 180 条缺口。同样taxonomy 中的cloud_only: true能力如diagnostics、ollie依赖仓库外的 comet 前端插件被排除出自托管覆盖率视图但计入云版本视图。十、从源码验证lint 的实现细节tag_lint.py 是这套语法的执行者其实现印证了文档中的全部声明正则而非 TS AST第 27–30 行注释被 lint 的标签永远是tag: [...]数组中的字符串字面量可可靠 grep测试标题不在此列3 条 spec 传变量、5 条用模板字符串覆盖率构建器改用playwright test --list解析运行时标题。TAG_BLOCK 与 TAG_LITERAL 两个正则分别匹配tag:\s*\[(.*?)\]和其中的引号包裹标签支持单行与多行数组。视觉 spec 分支无vcap:报错携带 tier 则报visual spec must not carry a tier tag。suite 豁免if not tiers and not suites_present时才算缺 tier——证实了只带 suite 标签合法的规则。区域归属检查cap:的.前缀必须等于声明的area:否则报cap:... does not belong to declared area area:...。taxonomy 自身也受检每个visual:能力必须有枚举内state:且每个区域的specs:列表必须保持排序——这是为了并发场景追加会把所有并发新增压在同一行导致 git 冲突排序插入让它们落在不同行taxonomy 头部注释记载该文件一度是 QA 队列中冲突最频繁的文件。退出码非零即失败且只读Read-only; never edits specs。结语让标签成为一种工程纪律Opik 的这套标签体系把三件事绑定在了一起声明tag、执行grep 选择、度量Allure 查询与覆盖率构建。tier 决定频率、suite 决定场所、area/cap 决定覆盖声明、vcap 决定视觉断言——而 CI 的硬校验保证了语法不会腐烂。对新加入的 spec 作者来说核心心法是三句话按该多频繁运行选 tiersuite 与 tier 正交为每条真实断言都声明cap:且只为真实断言声明。【免费下载链接】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),仅供参考