E2E 测试报告从"没人打开"到"直接开修":Playwright 报告重做 + 2 个专项测试实战
【免费下载链接】notepad--一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。项目地址: https://gitcode.com/GitHub_Trending/no/notepad--
CI 一晚上跑完 200 条 Playwright 测试,早上打开 E2E 测试报告,你大概率和我一样:扫一眼红绿数字,然后关掉页面。报告没被看,通常不是同事懒,而是它压根没回答"我接下来该干什么"。这篇文章只讲三件事:怎么把报告从陈列柜改成能直接分配的工单,怎么把 Flaky 从失败堆里剥出来单独治理,以及 Web3 钱包连接和链上交易这两个最容易翻车的场景怎么测才稳。
CI 测试报告设计的第一刀:把一行统计改成四态表格
多数报告的头部长这样:总数、通过数、失败数,完事。问题出在"失败"这一个桶里至少混着两种完全不同的东西——一种是确定性失败,页面真坏了;另一种是时过时不过,多半是网络抖动或等待不足。同事看到"失败 12 条",第一反应是"有 12 个 bug 要修",结果修到第三条发现一半是环境问题,下次对这份报告的信任也就没了。
所以头部统计必须把四种状态分开摆,别偷懒:
| 状态 | 含义 | 看到它之后该干什么 |
|---|---|---|
| Total | 本轮总条数 | 和上一版对比,明显缩水说明用例被误删或批量跳过 |
| Passed | 稳定通过,附占比 | 扫一眼即可 |
| Failed | 确定性失败,指向真实缺陷 | 进缺陷队列,当天认领 |
| Flaky | 时过时不过 | 单列出来,走隔离流程 |
| Skipped | 被条件跳过 | 核对是不是覆盖率在悄悄缩水 |
表格本身不新鲜,新鲜的是 Flaky 单独占了一行。为什么这件事权重最高,下面专门说。
Flaky 单列,是 flaky test 隔离能跑起来的前提
说实话,我最初也把 Flaky 混在失败里,理由很朴素:失败不就是失败吗。结果每次复盘失败列表,一半时间在确认"这条是真是假",真正的新缺陷被噪音淹没,没人愿意认领一个"可能是 flaky"的失败。
单列之后,变化发生在两个地方。第一,Flaky 变成了一个独立的治理数字:它在涨,说明你的隔离手段——把反复失败的用例挪进隔离区、不阻塞主管线、定期复查——已经追不上新引入的不稳定用例了;它在降,说明隔离区的清理在起作用。第二,Failed 桶变纯了,剩下的每一条都值得当天处理。换句话说,报告里的这个分桶,本质上是给隔离治理开的接口:你不先把它单列出来,后面谈"隔离区""定期复查"全是空中楼阁。
失败用例四要素:让每一条失败都能直接开工单 🎫
报告列失败用例时,最没用的写法是"用例名 + 一句断言报错"。我现在的硬性规定是每个失败条目必须带四样东西:
- 位置:文件和行号,例如 tests/e2e/ 下的
wallet.spec.ts:45。只给文件不给行号,等于让人先重跑一遍定位; - 错误信息:保留断言原文,能直接粘进工单标题;
- 截图路径:相对路径指向 artifacts/ 里的失败现场,例如
artifacts/wallet-connect-123.png,不用跑用例就能看到当时页面长什么样; - Recommended Fix:一句话写最可能的原因,比如"选择器变了,DOM 结构更新过"。
四样凑齐,报告里的每个条目就是一张可以直接分配的工单,接手的工程师不需要先复现一遍。两个常见坑:别把整段堆栈塞进报告,保留断言附近三五行加失败时的页面 URL 就够;截图路径一定要写成相对路径,CI 清完工作区之后,图还能找得回来。
产物归档定死目录:截图、视频、Trace 各归各位
报告会被关闭,产物不能跟着被忘掉。我的目录约定很简单,四类产物对应四个固定位置:
- HTML 报告:
playwright-report/index.html,给人看的入口; - 截图:
artifacts/*.png,每张和一条失败用例一一对应; - 视频:
artifacts/videos/*.webm,回放整个操作序列,专治"我本地明明没问题"; - Trace:
artifacts/*.zip,丢进 trace viewer 可以逐帧回放,连网络请求和 DOM 变化都看得到。
为什么写死?因为工单里会说"截图在 artifacts/xx.png",目录要是随心情变,这条信息第二天就废了。目录按"用例名 + 时间戳"生成,两轮构建互不覆盖。另外 trace 平时别默认全开,体积太吓人,留给失败用例和专项场景就行。
给钱包打桩:Web3 钱包 mock 的 addInitScript 写法
先说清这事为什么麻烦:MetaMask 这类插件,CI 环境里装不了,你没法让一个无头浏览器真的弹出插件再点"连接"。解法是把"钱包"整个换掉——在页面里任何 JS 跑起来之前,往window.ethereum上挂一个假实现,应用检测到的就一直是这个假对象。
Playwright 里干这事靠 addInitScript 注入:context.addInitScript给浏览器上下文注册一段脚本,之后该上下文里每加载一个新文档,这段脚本都会先于页面代码执行。时序上这意味着:应用还没读window.ethereum,你的假 Provider 已经坐在那了。
test('连接钱包', async ({ page, context }) => { // 先于页面脚本执行:假 Provider 提前挂上 window.ethereum await context.addInitScript(() => { window.ethereum = { isMetaMask: true, request: async ({ method }) => { // 只响应测试路径会用到的 method if (method === 'eth_requestAccounts') return ['0x1234567890123456789012345678901234567890'] if (method === 'eth_chainId') return '0x1' } } }) await page.goto('/') await page.locator('[data-testid="connect-wallet"]').click() // 只断言地址前缀,不和完整地址绑死 await expect(page.locator('[data-testid="wallet-address"]')).toContainText('0x1234') })两个决策值得说透。第一,mock 只实现了eth_requestAccounts和eth_chainId两个方法。多出来的方法就是多出来的维护成本:测试路径用不到的接口一概不写,写了就是伪造的契约,哪天它和真插件行为不一致,这种用例是最难排查的。第二,断言只匹配0x1234这个前缀。返回的地址是写死的,若断言把 42 位全写进去,以后改 mock 地址就得满文件搜断言,前缀弱匹配正好拆掉这层耦合。
链上交易测试的三条保命规则 ⏳
别笑,我见过有人把"真下单"的 E2E 用例挂在生产环境上,靠的是祈祷。链上交易测试的风险不在断言写没写对,在于它真的会花钱。规则就三条:
第一,生产环境直接跳过。一行test.skip,把"真金白银"从测试变量里剔除,省得哪天有人手滑改了环境变量就出事。第二,先验证预览再点确认。金额填1.0本身不可怕,可怕的是预览区算出来是 100;预览断言过了,再谈成交。第三,给链上结果留足等待时间。交易确认要走链上流程,节奏不由你的代码定,默认超时大概率不够。用waitForResponse盯/api/trade返回 200,显式给到 30 秒,比无脑 sleep 强——后者只是让每条用例多花 30 秒,前者等的是真实事件。
test('下单成交', async ({ page }) => { // 涉及真实资金的环境一律跳过 test.skip(process.env.NODE_ENV === 'production', '生产环境跳过') await page.goto('/markets/test-market') await page.locator('[data-testid="position-yes"]').click() await page.locator('[data-testid="trade-amount"]').fill('1.0') // 先确认预览数量对得上,再往下走 const preview = page.locator('[data-testid="trade-preview"]') await expect(preview).toContainText('1.0') // 点确认后等接口真实返回;链上确认慢,超时给足 30 秒 await page.locator('[data-testid="confirm-trade"]').click() await page.waitForResponse( resp => resp.url().includes('/api/trade') && resp.status() === 200, { timeout: 30000 } ) await expect(page.locator('[data-testid="trade-success"]')).toBeVisible() })如果只能做一件事,先把现有报告改成四态统计加四要素,一个下午就够,当天就能看到有人开始认领失败。然后把 Flaky 清单挪进隔离区,定个每周清理的节奏;钱包和链上这两个场景按上面的 mock 与跳过策略落下去,再给 Playwright 测试加上"失败必产截图和 trace"的约定——到那一步,这份报告才配当发布前的门禁,而不是一堆没人看的红点。
【免费下载链接】notepad--一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。项目地址: https://gitcode.com/GitHub_Trending/no/notepad--
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考