进阶掌握
Day 26 - Visual Testing and Screenshot Comparison
今日目标
- 了解 Playwright 的 screenshot assertion。
- 能判断视觉测试适合哪些场景。
学习时间安排(60–120 分钟)
| 时间 | 模块 | 做什么 |
|---|---|---|
| 0-20 分钟 | 核心概念与词汇 | 读概念表,重点理解 baseline 和 mask 的作用。 |
| 20-45 分钟 | 官方文档阅读 | 读 Visual comparisons 文档的 toHaveScreenshot 部分。 |
| 45-75 分钟 | 实操练习 | 为稳定页面添加截图对比测试,体验失败与更新流程。 |
| 75-105 分钟 | 示例代码改写 | 尝试 mask 动态区域,减少误报。 |
| 105-120 分钟 | 复盘与作业 | 完成视觉测试适用场景清单,完成今日问题。 |
核心概念与词汇
| English | 中文 | 场景用法 |
|---|---|---|
toHaveScreenshot() | 截图对比断言 | Use it when you compare the page or element against a baseline image. |
| baseline | 基线截图 | Use it when the first run stores the reference image to compare against. |
| diff | 差异图 | Use it when you inspect which pixels changed between runs. |
mask | 掩码 | Use it when you exclude dynamic areas like ads, clocks, or animations. |
| pixel comparison | 像素对比 | Use it when you explain how screenshots are compared. |
| visual regression | 视觉回归 | Use it when you catch unintended layout or styling changes. |
| anti-aliasing | 抗锯齿 | Use it when font rendering differences cause false positives. |
| deterministic rendering | 确定性渲染 | Use it when CI needs identical rendering for stable comparisons. |
| snapshot update | 基线更新 | Use it when --update-snapshots refreshes baselines after intended changes. |
| false positive | 误报 | Use it when a visual diff appears without a real bug. |
学习材料
- 必读:[Visual comparisons](https://playwright.dev/docs/test-snapshots)
- 必读:[toHaveScreenshot 文档](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1)
- 选读:[Screenshots](https://playwright.dev/docs/screenshots)(普通截图 vs 对比截图)
重点理解
示例:
await expect(page).toHaveScreenshot();
await expect(page.getByRole('main')).toHaveScreenshot('main-section.png');
注意:
- 视觉测试容易受字体、系统、浏览器版本影响。
- 更适合关键页面、组件、布局回归。
- 不适合频繁变化的动态内容。
- CI 环境应固定浏览器版本和渲染环境。
- 需要合理 mask 动态区域。
实操步骤
为一个稳定页面添加截图对比测试:
- 首次生成 baseline。
- 修改页面或尺寸触发失败。
- 查看 diff。
- 尝试 mask 动态区域。
示例代码
import { test, expect } from '@playwright/test';
test('homepage layout is stable', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png', {
// 屏蔽动态区域:广告位、时间、随机推荐
mask: [
page.getByRole('banner').locator('.ads'),
page.locator('.recommendation-list'),
],
maxDiffPixels: 100,
});
});
# 首次生成基线
npx playwright test tests/visual.spec.ts --update-snapshots
# 后续对比失败后查看 diff,确认是有意改动再更新
npx playwright test tests/visual.spec.ts
常见坑
- 动态内容(时间、广告、推荐流)不 mask,每次跑都误报。
- 本地 macOS 和 CI Linux 字体渲染不同,基线两边不一致。
- 把视觉测试铺到所有页面,维护成本爆炸。
- 基线更新太随意:不先看 diff 就
--update-snapshots,把 bug 当基线。 - 像素级全页对比,任何一行文案改动都全红。
今日产出
- 一个视觉测试示例。
- 一份视觉测试适用场景清单。
今日问题
- 视觉测试和功能测试有什么区别?
- 哪些页面适合截图对比?
- 为什么动态内容会导致误报?
- baseline 应该如何维护?
- 视觉测试是否应该放在 PR 阶段?
复盘要点
- 视觉测试抓的是“长坏了”而不是“不能用了”:布局、样式、渲染回归。
- 选页面要克制:关键页、组件级、变化少,三条标准缺一不可。
- baseline 是契约:更新前必须看 diff,确认是有意改动。
AI 时代扩展:AI 辅助 Playwright 测试
新增概念
| English | 中文 |
|---|---|
| visual diff triage | 视觉差异分类 |
| dynamic masking | 动态区域掩码 |
| visual acceptance | 视觉验收 |
适用场景
让 AI 根据页面描述建议哪些区域需要 mask,或者根据 diff 描述判断改动是否属于预期。AI 看不了图片时,可以让它基于你提供的 diff 文本/尺寸信息辅助判断。
可复用表达 / 提示词
我的首页有轮播图、实时时间、推荐流三块动态内容,请设计 toHaveScreenshot 的 mask 方案并说明理由。
视觉测试失败,diff 显示页头按钮组整体右移 20px,请分析最可能的 3 个原因。
追问加练
- AI 建议 mask 掉整个页头,代价是什么?
- diff 判定“有意改动”和“意外回归”的标准由谁定?
- 视觉测试的误报率如何度量?
今日作业
- 完成 1 个页面级 + 1 个组件级视觉测试并跑通。
- 完成视觉测试适用场景清单:至少 5 条选择标准。
- 让 AI 审查你的 mask 方案,补充遗漏的动态区域。