Previous
Day 25 · Weekly Review 5: A Sustainably Running Test Suite
Next
Day 27 · Accessibility and User-Behavior Testing
进阶掌握
Day 2660-120 minutesPlaywright QA hands-on drill

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 动态区域。

实操步骤

为一个稳定页面添加截图对比测试:

  1. 首次生成 baseline。
  2. 修改页面或尺寸触发失败。
  3. 查看 diff。
  4. 尝试 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 当基线。
  • 像素级全页对比,任何一行文案改动都全红。

今日产出

  • 一个视觉测试示例。
  • 一份视觉测试适用场景清单。

今日问题

  1. 视觉测试和功能测试有什么区别?
  2. 哪些页面适合截图对比?
  3. 为什么动态内容会导致误报?
  4. baseline 应该如何维护?
  5. 视觉测试是否应该放在 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 方案,补充遗漏的动态区域。

自检清单

Previous
Day 25 · Weekly Review 5: A Sustainably Running Test Suite
Next
Day 27 · Accessibility and User-Behavior Testing