提前阅读
视觉测试 Visual Testing
主要是有能力检查用户界面的图像是否正确,视觉测试也是E2E测试的一种测试手段。之前接触到自动化测试框架,基本都是核对文本来做校验,或者是类文本的对比,那么视觉测试就是可以校验图片,或者是二进制文件。
视觉比较 Visual Comparisons
Playwright新版支持了快照(Snapshots)比较的断言:
- await expect(page).toHaveScreenshot();
- expect(await page.screenshot()).toMatchSnapshot('my-page.png');
所以比较截图的快照就能进行自动化视觉测试了,但Playwright也有一些与众不同的设计。
页面截图比较
先看一个最典型的例子
// example.spec.ts
import { test, expect } from '@playwright/test';
test('example test', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveScreenshot();
});
await expect(page).toHaveScreenshot()
这个断言就是先对page进行截图,然后与设定好的快照截图进行比较。默认没有任何参数就是:
- 首先截图是默认截取当前页面可视区域,可能不是整个页面
- 然后快照是读取默认位置默认名称的快照。
- 默认位置在spec文件同一级的目录,比如
example.spec.ts-snapshots
,spec文件名加上-snapshots
后缀的目录,也就是testInfo.snapshotDir
- 默认名称是当前测试的title,加上浏览器名,再加上系统名。比如
example-test-1-chromium-darwin.png
。之所以这样是因为不同的浏览器和操作系统的字体可能不同,这样相同的页面渲染的图像界面也可能不同,为了保障像素级别的比较有意义,快照必须针对不同的系统和浏览器进行严格匹配。如果不想用title作为名称前缀,可以指定参数自定义名称:
- 默认位置在spec文件同一级的目录,比如
await expect(page).toHaveScreenshot('my-snapshot-name.png');
到这里一定会有一个疑问,快照文件从哪来?如何产生快照文件?
Playwright自动产生快照文件
对于截图的快照,Playwright是支持自动产生的:
- 第一次运行测试的时候,大概是开发阶段,playwright如果发现没有快照文件,会自动生成对应的快照文件到对应的位置,当然此刻的测试肯定是failed。
- 一旦快照产生后,后面的测试运行就可以进行比较了。所以还需要把快照文件夹
example.spec.ts-snapshots
提交到git仓库才行,以支持后续的运行。注意不同的环境文件名会不同,所以开发的时候如果你的本地是Windows,回归测试的在服务端用的是Linux,那么此时测试快照其实是缺失的,需要想办法对应到。比如可以使用虚拟机在本地运行一次并提交对应的快照到git仓库 - playwright还提供一种方式,相当于重置所有快照。产生后也记得提交到git仓库。
npx playwright test --update-snapshots
容错对比
Playwright支持截图对比的时候,不一定要求100%匹配,可以通过参数允许一定量的不匹配。
await expect(page).toHaveScreenshot({
maxDiffPixelRatio: 0.1,
maxDiffPixels: 100
});
这里有两个参数,使用一种即可:
maxDiffPixelRatio
0-1之间,0.1就是允许10%的不匹配像素,否则失败maxDiffPixels
像素的数量,100就是允许100个不匹配像素,否则失败
例如,在错误日志里可以看到像素的不匹配信息
Error: Screenshot comparison failed:
4510 pixels (ratio 0.01 of all image pixels) are different.
Call log:
- expect.toHaveScreenshot with timeout 5000ms
- verifying given screenshot expectation
- taking page screenshot
- disabled all CSS animations
- 4510 pixels (ratio 0.01 of all image pixels) are different.
- waiting 100ms before taking screenshot
- taking page screenshot
- disabled all CSS animations
- captured a stable screenshot
- 4510 pixels (ratio 0.01 of all image pixels) are different.
Expected: /monocart-reporter/image-comparison-Desktop-Chromium/my-snapshot-name-1-expected.png
Received: /monocart-reporter/image-comparison-Desktop-Chromium/my-snapshot-name-1-actual.png
Diff: /monocart-reporter/image-comparison-Desktop-Chromium/my-snapshot-name-1-diff.png
这里有4510 pixels,也就是1% (0.01)的像素不匹配,可以根据情况调整容错参数。同时还可以设置全局的容错参数,这样不用每个方法都添加:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
expect: {
toHaveScreenshot: {
maxDiffPixels: 100
}
}
});
视觉测试报告
除了从控制台错误日志看到比较的报告,还可以从官方的html
报告更好的查看对比报告
也可以从第三方报告比如monocart-reporter更直观的查看对比报告
范围对比
最开始的例子是对比页面可视区域,可以通过fullPage
参数对比完整的页面(也就是页面滚动条所有的区域)
await expect(page).toHaveScreenshot('my-snapshot-name.png', {
fullPage: true
});
toHaveScreenshot
断言除了支持page
也支持到了locator
,所以也可以对比页面上某个元素,比如一个按钮,一个div等等,直接使用locator的API定位选择即可
const locator = page.getByRole('button');
await expect(locator).toHaveScreenshot();
蒙版比较
如果想在截图中排除一些区域不比较,通过蒙版参数mask
可以实现:
await expect(page).toHaveScreenshot('my-snapshot-name.png', {
fullPage: true,
mask: [page.getTestId('name')]
});
这里假设页面有一个table,其中有一列是name,但并不想比较name这一列,即使它可能会不同,那么可以使用mask
进行排除,这样截图里面就变成洋红区域,也就忽略了不同的比较,因为大家都是一片洋红。
注意mask
参数是数组,所以就可以排除任意多个你想要排除的区域,就比较一个UI的外边框也是一样可以实现。如果不喜欢洋红色可以使用maskColor
参数自定义遮罩颜色。
非图片快照比较
和截图比较是一样的,设置对应的快照名称即可,比如想要比较页面的一处的文本
expect(await page.textContent('.some-content')).toMatchSnapshot('my-content.txt');