如何用 Playwright 做截图测试
使用视觉基准、浏览器项目、稳定等待、差异阈值和更新审查,构建 Playwright 截图测试。

Playwright 截图测试用于在 UI 变化发布前发现问题。测试会打开页面、等待稳定状态、截图,再与已批准的基准图比较。这正是普通自动截图与视觉回归测试的区别。
本文示例使用 Shotomatic 功能页 https://www.shotomatic.com/features 作为公开目标。同样的模式在自己的应用中更有价值,因为你可以控制数据、登录状态、动画和测试选择器。
如果只需要从一组 URL 生成图片文件,请先阅读普通 Playwright 自动截图。本文讲的是测试版本:基准图、截图对比、浏览器项目和审查。
何时值得使用截图测试
如果视觉错误很容易被普通断言漏掉,截图测试就很有用。
适合的对象:
- 主视觉区、价格区或注册区很重要的营销页面;
- 有多种状态的设计系统组件;
- 版式很重要的结账、引导或仪表盘界面;
- 经常在移动宽度下出错的响应式页面;
- CSS 变化可能悄悄移动或隐藏内容的页面。
不太适合的对象:
- 信息流、广告、时间戳或用户内容不断变化的页面;
- 视觉细节并不重要的页面;
- 已经由更可靠的文字、角色或行为断言覆盖的流程;
- 没有审查流程,却包含数百个不稳定页面的整站。
从少量重要界面开始。让截图测试监视所有内容,很快就会产生大量噪声。
安装 Playwright Test
在新的或现有 Node 项目中,Playwright 官方安装器可以创建测试运行器、配置文件、示例测试和浏览器安装步骤:
$ npm init playwright@latest
安装器会询问使用 TypeScript 还是 JavaScript、测试文件放在哪里、是否添加 GitHub Actions 工作流,以及是否安装浏览器。设置完成后运行测试:
$ npx playwright test
本文示例使用 tests/ 目录中的 TypeScript 文件。
创建第一个截图测试
创建 tests/features-page.spec.ts:
import { expect, test } from "@playwright/test";
test("features page has a stable desktop layout", async ({ page }) => {
await page.goto("https://www.shotomatic.com/features");
await expect(
page.getByRole("heading", {
name: /Shotomatic Features/i,
}),
).toBeVisible();
await expect(page).toHaveScreenshot("features-page-desktop.png", {
fullPage: true,
});
});
与 page.screenshot() 的关键区别是断言。Playwright Test 的 toHaveScreenshot() 会创建基准图,或与现有基准比较。第一次运行会写入缺失的基准;之后运行则比较当前截图和已保存图片。
运行测试:
$ npx playwright test tests/features-page.spec.ts
首次运行时,由于基准图尚不存在,Playwright 会写入一张新的预期图片。提交前先检查它。基准图是测试预期,不是随手生成的产物。
测试页面的一小部分
全页截图能发现大范围版式偏移,但也更容易因为页面下方无关变化而失败。对许多团队来说,维护区块或组件基准更轻松。
import { expect, test } from "@playwright/test";
test("features comparison cards stay aligned", async ({ page }) => {
await page.goto("https://www.shotomatic.com/features");
const comparisonHeading = page.getByRole("heading", {
name: /Choose a workflow/i,
});
const comparisonSection = page.locator("section").filter({
has: comparisonHeading,
});
await expect(comparisonHeading).toBeVisible();
await expect(comparisonSection).toHaveScreenshot("features-comparison-section.png");
});
如果审查问题只涉及局部——“这个区块看起来还正常吗?”——就用定位器截图。需要检查整页版式时,再用页面截图。
添加浏览器和设备项目
Playwright 测试运行器可以在多个命名项目中运行同一测试。截图测试由此不同于简单的捕获脚本:浏览器、设备、视口和快照名称都会成为测试矩阵的一部分。
playwright.config.ts 示例:
import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./tests",
use: {
baseURL: "https://www.shotomatic.com",
trace: "on-first-retry",
},
projects: [
{
name: "desktop-chromium",
use: {
...devices["Desktop Chrome"],
viewport: { width: 1440, height: 1000 },
},
},
{
name: "mobile-safari",
use: {
...devices["iPhone 13"],
},
},
],
});
随后在测试中使用相对 URL:
import { expect, test } from "@playwright/test";
test("features page visual baseline", async ({ page }) => {
await page.goto("/features");
await expect(page.getByRole("main")).toBeVisible();
await expect(page).toHaveScreenshot("features-page.png", {
fullPage: true,
});
});
Playwright 会为不同项目保存不同快照,因此桌面与移动基准可以并列存在,不必假装两者应该相同。当问题是 UI 是否适配不同设备尺寸时,这比只截一个视口更合适。
让页面状态保持稳定
许多无意义的截图失败都来自不稳定页面状态。Playwright 默认会在截图断言期间禁用 CSS 动画和过渡,但变化中的数据、延迟内容、广告和用户专属元素仍会移动像素。
截图前等待一个具体条件:
await page.goto("/features");
await expect(page.getByRole("main")).toBeVisible();
await expect(page.getByText("Hands-Free Capture")).toBeVisible();
不要把固定超时当作主要等待规则。如果页面必须等某张卡片、标题、表格或图片加载完才算就绪,就直接等待该条件。
如果全页截图包含延迟加载内容,先滚动页面:
await page.evaluate(async () => {
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const viewportHeight = window.innerHeight;
for (let y = 0; y < document.body.scrollHeight; y += viewportHeight) {
window.scrollTo(0, y);
await delay(100);
}
window.scrollTo(0, 0);
});
页面确实需要时,这类辅助函数没有问题。把它放在测试附近,让以后维护的人知道为什么要滚动。
隐藏或遮罩易变元素
页面的某些部分不应参加视觉比较,例如时间戳、头像、广告、用户名称、加载指示器或视频缩略图。
常用方法有两种。
遮罩指定定位器:
await expect(page).toHaveScreenshot("features-page.png", {
fullPage: true,
mask: [page.locator("[data-testid='release-date']")],
});
或在截图时应用样式表:
await expect(page).toHaveScreenshot("features-page.png", {
fullPage: true,
stylePath: "./tests/screenshot.css",
});
tests/screenshot.css 示例:
[data-testid="release-date"],
[data-testid="animated-cursor"] {
visibility: hidden !important;
}
不要为了让测试通过而隐藏真正的产品 UI。遮罩只用于不属于视觉问题、却会产生噪声的内容。
谨慎设置差异阈值
Playwright 可以允许少量像素差异:
await expect(page).toHaveScreenshot("features-page.png", {
fullPage: true,
maxDiffPixels: 100,
});
这能容忍细小渲染差异,但也可能藏住真正的回归。阈值要低,并记录存在原因。放宽对比前,优先让页面更确定。
还可以在 playwright.config.ts 中共享截图断言默认值:
import { defineConfig } from "@playwright/test";
export default defineConfig({
expect: {
toHaveScreenshot: {
maxDiffPixels: 100,
},
},
});
审查并更新基准
截图测试失败时,问题不是“怎样让它变绿”,而是“这次视觉变化是否符合预期”。
如果变化是 Bug,就修复 UI 后重新运行。如果变化是有意的,再更新基准:
$ npx playwright test --update-snapshots
然后在拉取请求中检查新的基准图。像对待代码改动一样对待快照更新:应有人理解改了什么、为什么改。
在 CI 中运行截图测试
截图比较对环境很敏感。字体、操作系统、浏览器版本、硬件和无头模式都可能影响像素。要得到稳定结果,请在相同环境中生成和比较基准。
实践中通常意味着:
- 提交在 CI 或匹配本地容器中生成的基准快照;
- 在拉取请求上运行截图项目;
- 除非本来就接受差异,否则不要用 macOS 生成的基准与 Linux CI 比较;
- 有计划地更新 Playwright 及其浏览器二进制文件;
- 接受变化前先审查更改的快照。
失败难以理解时,使用 Playwright HTML 报告或 trace viewer。截图测试失败需要比“构建变红”更多的审查语境。
普通自动截图仍适用的场景
截图测试用于检查代码所控制的 UI 质量,不等于为审阅、报告、归档或内容流程收集截图。
需要从 URL 获取输出文件时,使用普通 Playwright 自动截图。
需要一个专注 Chrome 的小脚本,并且不需要 Playwright Test 时,使用 Puppeteer 自动截图。
任务是无需代码的 URL 列表捕获时,使用 Shotomatic Website Capture:添加 URL、调整捕获选项、检查结果并导出截图,无需维护测试套件。团队手动检查响应式截图时,这可能已经足够;需要自动判断通过/失败时,请继续使用 Playwright Test。
常见错误
- 测试页面范围太大:先为重要区块创建基准,再考虑整页。
- 捕获不稳定数据:对每次运行都会变化的内容使用固定测试数据、遮罩或样式。
- 不经检查就更新快照:只有审查视觉差异后才更新基准。
- 在一台机器生成基准、到另一台比较:保持渲染环境一致。
- 把视觉测试当行为测试:截图之外,还要对文字、角色、导航和交互使用普通断言。
常见问题
Playwright 能做截图测试吗?
能。Playwright Test 通过 expect(page).toHaveScreenshot() 和 expect(locator).toHaveScreenshot() 提供截图断言。
截图测试和保存截图有什么区别?
保存截图只会创建图片文件。截图测试会把新截图与已批准的基准图比较,差异超过允许阈值时测试失败。
Playwright 把截图基准存在哪里?
默认情况下,Playwright 将基准保存在以测试文件命名、带 -snapshots 后缀的目录中。可以在 Playwright 配置中用 snapshotPathTemplate 自定义路径。
如何更新 Playwright 截图基准?
确认视觉变化符合预期后,使用 --update-snapshots 运行 Playwright Test。
每个页面都应该使用 Playwright 截图测试吗?
不应该。截图测试适合重要且稳定的 UI 状态。行为应使用普通断言;视觉基准只用于版式变化很重要的页面或组件。
参考资料
以上示例按照当前官方文档检查:
- Playwright 的安装指南:设置 Playwright Test;
- Playwright 的视觉对比指南:
toHaveScreenshot()、基准、更新流程和比较选项; - Playwright 的
PageAssertions.toHaveScreenshot()API:fullPage、mask、stylePath、maxDiffPixels、threshold等选项; - Playwright 的断言指南:自动重试的网页断言;
- Playwright 的运行和调试测试指南与 trace viewer 指南:审查失败测试。
相关文章
查看更多文章如何用 Playwright 自动截取网站截图
使用 Playwright 和 JavaScript 自动截取网站截图,包括单页、整页、移动端视图,以及带重试机制的 URL 批量截图。




无需编写代码,自动截取网页
Website Capture 可以截取 URL 列表,为每个页面设置选项,检查结果并导出,不需要维护脚本。