引言
使用带有模拟数据的
Playwright快照可以显著提高UI回归
测试的速度。它能够快速自动化检查三大主流浏览器(Chromium、Firefox、Webkit)中的 UI 元素。你可以将多个断言绑定到一个快照上,这极大地提高了 UI 测试的效率。在 GUI 应用快速扩展的背景下,这种效率至关重要。
Playwright 是一个功能强大的
自动化测试库,广泛应用于回归测试。它在基于 Web 的测试方面表现出色,即导航到链接并执行各种用户流程,这些流程的行为始终应保持一致。通常会自动化用户流程测试以验证事物的运行方式,但事物的外观又该如何呢?

问题所在
主要挑战是创建一个仪表板,显示预测空气质量与实时测量值之间的差异。主页面相对简单,因为它使用了 ag-grid,因此我们可以模拟并断言每个单元格中的值。然而,对于类似图表的元素来说,情况就没那么简单了。我们需要测试这些图表中的数据是否正确地以默认模拟数据进行了可视化,然后,我们还需要测试各种 UI 交互是否会按预期改变图表。
完整背景信息请参阅此案例研究。
上图展示了一个包含六个不同图表的 UI,这些图表显示了预测的和现场测量的污染物数据。第一个大问题是数据是非静态的。我们通过 Playwright Mock API 来模拟数据解决了这个问题。这样一来,我们的回归测试就可以专注于数据的功能以及数据所经历的各种转换。第二个问题是,我们如何知道实际数据是否被正确地可视化了呢?这就是 Playwright 快照的用武之地。
Playwright 快照详解
Playwright 会启动每个浏览器,并完成各种操作,例如按钮点击、滚动、数据输入。在执行完操作后,将捕获 DOM 元素(或多个元素)状态的截图。然后,它会依次检查每个像素,并查看其 RGBA 值是否与代码库中创建的比较图像相匹配。
借助 Playwright 快照,我们可以轻松断言页面元素应有的外观。如果代码库中没有比较图像,那么我们起初运行 `npx playwright test` 时,它将为我们创建一个比较图像。接下来,我们需要调整测试步骤,直到对 Playwright 创建的快照感到满意。一旦满意,我们再次运行相同的命令,并添加 `--update-snapshots` 标志,这将把快照保存为我们参考的黄金标准图像。此后,每次运行测试时,我们都会将其与该图像进行比较。
可以到我的个人号:atstudy-js,这里有10W+ 热情踊跃的测试小伙伴们, 一起交流行业热点、测试技术各种干货, 一起共享面试经验、跳槽求职各种好用的。 欢迎加入-> 多行业测试学习交流群,内含直播课+实战+面试资料。 【AI测试、 车载测试、自动化测试、银行、金融、游戏、AIGC...】
请注意,对于我们启用的每个浏览器,都会创建一个比较图像。因此,如果我运行 `toMatchSnapshot('Image.png')`,那么它将分别为 Chrome、Firefox 和 Webkit 创建单独的图像。
示例代码片段
如果没有额外参数,只要有一个像素不同,比较就会失败。此选项可实现最大精度。
javascript
test('Verify so2 graph updates correctly when sites are removed', async ({
cityPage,
}) => {
//移除一个空气质量监测站点的操作
await cityPage.siteRemover('Centro')
//捕获硫化氢图表的快照
const chartShot = await cityPage.captureChartScreenshot(cityPage.so2Chart)
//将其与我们保存在代码库中的参考图像进行比较
expect(chartShot).toMatchSnapshot('rio-so2-graph-without-centro.png')
})
在这里,我们在页面对象模型中创建了一个方法,该方法接受我们希望在测试结束时截取屏幕快照以供比较的图表/图形。
测试中针对 Chrome 浏览器的元素尺寸为 600x400 像素,这意味着如果 1/240000 个像素不匹配,测试就会失败。然而,我们可以通过提供额外参数来放宽一些限制,例如:
· 进行视觉回归测试时,允许的最大像素差异值。
.toMatchSnapshot("in-situ-AQI-is-4-at-00:00-due-to-PM2.5.png",{ maxDiffPixels: 27 }
如果 27/240000 个像素不同,测试将通过。28/240000 个不同的像素将导致测试失败。
进行视觉回归测试时,允许的最大像素比差异阈值。
.toMatchSnapshot("in-situ-AQI-is-4-at-00:00-due-to-PM2.5.png",{ maxDiffPixelRatio: 27 }
这是一个百分比检查。如果最多有 27% 的像素不匹配,测试仍将通过。通过运行 Playwright CLI 命令进行测试后,测试结束时会生成一份报告。这将向我们展示图像中的不同之处。
失败是什么样子的?
通过 CLI 运行测试后,默认情况下会在 localhost:9323 上生成一份报告。
然后,用户可以选择失败的快照测试,并能够看到各种比较选项。如下面所示,有多个选项可供选择,以进一步调查失败原因。我们可以查看预期图像、实际图像,但最重要的是查看差异。这是最有用的视图,因为它会突出显示所有未能与我们的比较图像匹配的像素。
预期:
实际:
差异:
使用示例
通过结合模拟数据和快照视觉测试,可以轻松发现系统功能的明显回归。在回归测试中测试多个图表会迅速变得单调乏味且耗时。特别是对于我们的 UI,图表可能有多种形式。
以下是城市页面上的一个传感器选择功能:
图中的每条不同颜色的线代表一个不同的传感器,可以切换。我们可以通过选择标签页禁用传感器,或者通过双击实际图表上的线条来禁用传感器。然后,图表将重新调整自身,以便更好地呈现数据。
示例测试流程:
1. 使用模拟数据对默认图表进行快照。
2. 移除一个站点。
3. 现在创建一个新快照,显示更新后的图表形状。
然后,我们可以有一些测试来移除不同的站点,并断言图表的新预期形状。
下面展示的是主要的 AQI 图表。蓝色的现场线会根据启用的传感器动态变化。这是通过前端对每个时间点的每个点进行平均来完成的。然后绘制出最高的平均值为蓝色。
测试流程:我们希望测试蓝色线是否根据启用的站点准确绘制。因此,我们移除站点,然后手动检查新的绘制是否正确。一旦满意,我们就可以重复步骤,创建一个我们刚刚修改的图表的新快照。最后,我们的测试将简单地导航到页面,移除一个站点,并断言图表与我们刚刚捕获的快照匹配。
这解决了什么问题?
它解决了尝试断言许多不同元素的问题,这些元素可能相当繁琐,需要逐个定位和断言。
这个页面使用 echarts 库来渲染图表。
- 它就像一双额外的眼睛。如果我们对数据应有的外观有很好的了解,那么它将使 UI 回归测试更加高效。
- 除了由于数据可视化不正确而导致的失败外,我们还可以捕捉到许多其他无意的更改,例如填充或边距的变化。
- 节省了一些繁琐的手动工作。如上所示,我们可能需要手动检查并点击 6 个不同的图表,如果按工单进行回归测试,这将非常耗时。
- 有时你可以期望元素可见,但实际内容可能被错误表示或损坏。
- 我们可以快速测试元素的数据在多个浏览器/视口中的正确呈现。这将进一步减少多平台应用的工作量。
维护和变更
快照测试需要团队之间密切协调。当进行新更改时,作为测试人员,了解或调查需要更新哪些快照非常重要。然后,这将需要与开发人员合作,以确保新的快照与任何新实现保持一致。为了提高效率,我们最终作为团队达成一致,在工单的开发分支或单独的分支上更新这些快照。这意味着新的实现将与更新的快照一起合并到主分支中,以减少回归运行中的许多失败。
使用 `-–update-snapshots` 标志更新快照相当轻松。
示例快照更新
一个新实现的更新快照。之前背景颜色分级的最大值为八百。现在更新为没有上限。
命名规范
为快照命名也很重要。这使得团队中的任何人都更容易理解它们的用途。这也使得调试变得更容易。
- “graph-image.png” 与 “graph-is–bristol-air-quality”。使用类似后者的内容,你将更清楚哪些功能失败了。
有用的函数
javascript
async siteRemover(location: string) {
await this.siteForm.waitFor({ state: 'visible' })
await this.siteForm.scrollIntoViewIfNeeded()
const siteDeselect = this.page.getByLabel(`Remove ${location}`)
await siteDeselect.click()
}
有许多不同的问题可能导致你的屏幕截图测试变得不稳定。像其他 Playwright 测试一样,确保使用诸如 `waitFor({ state: visible })` 和 `scrollIntoViewIfNeeded()` 之类的函数。这将确保你每次都能准确地捕获屏幕截图。
我们还可以在表示加载状态的元素上使用 `waitFor({ state: hidden })`。
在我们的项目中,我们还实现了一种网络轮询方法,这将确保在为某些元素拍摄屏幕截图之前,所有网络活动都已停止。在某些情况下,由于元素处于加载状态,屏幕截图可能不准确,这被证明是非常有用的。
使用 Playwright 高效模拟数据
模拟数据是拼图的另一个重要部分。
最初,我们只是简单地提取一个 JSON 对象,然后从一个辅助文件中导出它。这在实际代码方面相当繁琐(有时一个测试项的模拟数据代码会达到四千行)。
然后,我们通过使用重写接口减少了不必要的代码。
javascript
interface forecastAPIResponse {
base_time: string
valid_time: string
location_type: string
location_name: string
location: { longitude: number; latitude: number }
overall_aqi_level: number
no2: { aqi_level: number; value: number }
o3: { aqi_level: number; value: number }
pm2_5: { aqi_level: number; value: number }
pm10: { aqi_level: number; value: number }
so2: { aqi_level: number; value: number }
}
这意味着我们现在可以有默认的模拟值,并且只在实际测试场景中更改我们需要的内容。
javascript
export function createForecastAPIResponseData(
overrides: Partial<forecastAPIResponse> = {},
): forecastAPIResponse {
const defaultForecastResponse = {
base_time: '2024-07-08T00:00:00Z',
valid_time: '2024-07-08T00:00:00Z',
location_type: 'city',
location_name: 'Los Angeles',
location: { longitude: -22.90642, latitude: -43.18223 },
overall_aqi_level: 3,
no2: { aqi_level: CaseAQI3.aqiLevel, value: CaseAQI3.no2 },
o3: { aqi_level: CaseAQI3.aqiLevel, value: CaseAQI3.o3 },
pm2_5: { aqi_level: CaseAQI3.aqiLevel, value: CaseAQI3.pm2_5 },
pm10: { aqi_level: CaseAQI3.aqiLevel, value: CaseAQI3.pm10 },
so2: { aqi_level: CaseAQI3.aqiLevel, value: CaseAQI3.so2 },
}
return { ...defaultForecastResponse, ...overrides }
}
现在来看一个测试设置的使用示例。我们希望保持其他所有内容不变,只更改四个值。
javascript
test.describe('City graph snapshots', () => {
test.beforeEach(async ({ cityPage, page, banner }) => {
const mockedForecastResponse = [
createForecastAPIResponseData({
base_time: '2024-07-01T00:00:00Z',
valid_time: '2024-07-01T00:00:00Z',
location_name: 'Rio de Janeiro',
overall_aqi_level: 1,
})
]
// 满足模拟并开始测试步骤
})
})
这使我们无需为使用不同端点的测试模拟许多对象。因此,减少了大量代码,使测试更容易遵循和维护。
结论
Playwright 快照测试易于设置,甚至 API 模拟也非常简单。但应谨慎使用。团队必须紧密合作,确保在需要时适当维护和更新快照。特别是如果这些快照测试是 CI/CD 回归管道的一部分。你还应该清楚正在测试的确切范围,因为 Playwright 中的模拟数据可能会无意中绕过任何 API 功能。这就是为什么它主要用于面向前端的 UI 功能,而不是完整的端到端流程。它是一个快速扩展的 GUI 应用程序的绝佳补充,因为它在任何测试阶段都能节省大量时间。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70034708/viewspace-3080386/
,如需转载,请注明出处,否则将追究法律责任。