让你的E2E测试更稳定

2024-11-03   出处: checklyhq  作/译者:Nočnica Mellifera/溜的一比

在使用 Playwright 进行端到端网站测试和监控时,选择合适的定位器至关重要。正确的定位器有助于创建更可靠、稳定性更强的测试。让我们来探讨面向用户的定位器,以及如何筛选定位器以增强测试的稳健性。

示例场景

考虑一个包含标题、按钮和状态更新框的简单网页。点击按钮后,状态会更新并触发彩纸动画。我们将通过这个场景来展示如何测试。

为什么不使用 CSS 选择器查找页面元素?

如果你习惯了使用一些老旧的自动化和页面操作系统,比如 JQuery,你可能会倾向于使用 CSS 选择器。如果我们检查这个页面,确实可以看到按钮应用了一个类,我们可以通过它来选择页面上的这个按钮。

在测试中,我们可以用类似 await page.locator("button.button-frontpage-style").click()​ 这样的代码点击这个按钮,虽然这能奏效,但并不推荐。

这种方法有什么问题?

  • 用户查看页面时会寻找按钮,而不会去看 CSS 类,因此我们的测试不再模仿用户的操作路径。
  • 如果前端工程师为了样式原因将类更改为 button-hero-panel-style​,那么我们的测试会出现假阳性:报告出错但实际并无问题。
  • 如果按钮文本来自内容管理系统(CMS),而文本发生故障,按钮文本可能会变为 "HEROBUTTON_TXT",此时我们的测试依然会通过,但用户界面对用户来说已经损坏了,这是一个假阴性。 基于以上原因,Playwright 项目建议不要使用 CSS 定位器,遵循项目中设定的标准是个好主意!

替代 CSS 选择器的做法:使用面向用户的定位器

Playwright 提供了一些基于页面角色的定位器,这比通过 CSS 或 HTML 查找更加功能化。使用内置的定位器,比如 getByRole​、getByText​ 和 getByLabel​,这些定位器的工作方式与用户的操作一致,即使用户使用的是不寻常的浏览器版本、移动设备,甚至是屏幕阅读器。

面向用户的定位器的应用

让我们将 page.locator​ 替换为 getByRole​,通过按钮的角色和可访问名称来定位按钮:

await page.getByRole('button', { name: 'click me' }).click();

使用 Chrome DevTools 检查元素,查看它们的可访问角色和名称。

这种方法可以确保即使类名或 HTML 结构发生变化,测试依然稳定。

一个额外的好处是,Playwright 的名称匹配是不区分大小写的,并且可以通过子字符串匹配。例如你可以将选择器改为 { name: 'click' }​,即使营销团队将按钮文本改为 "Click me now!",测试依然会通过,不会失败。

这个改变意味着,如果按钮标签变为类似 "HEROBUTTON_TXT" 的文本,测试会如预期那样失败。

getByRole​ 和 getByLabel​ 在你的页面上不起作用时该怎么办?

我支持使用面向用户的定位器的原因之一是,当你发现这些选择器在页面上不起作用时,它提示你页面可能存在严重的可访问性问题。如果很多页面元素没有设置角色和标签,或者所有页面元素的标签和角色都一样,这意味着页面的可访问性存在问题。毕竟,如果没有独特的标签,屏幕阅读器和键盘导航工具将无法正常工作,许多用户将无法导航你的页面。这应该引发开发者和 QA 人员之间关于如何改进页面结构的讨论,这将不仅改善测试,也改善所有用户的体验。

短期来看,可以查看 Playwright 的所有定位器,肯定有办法能找到页面上的任何元素,但我鼓励你将此作为未来讨论技术债务的起点。

处理多个匹配元素

如果定位器匹配了多个元素,Playwright 的严格模式将失败。例如,使用 getByRole('button')​ 可能会匹配多个按钮。你会收到类似这样的错误:

Error: locator.click: Error: strict mode violation: getByRole('button', { name: 'click' }) resolved to 2 elements:

请注意,即使第一个结果或所有结果通过了测试,严格模式下这个测试仍会失败。要解决这个问题,可以通过指定位置或筛选元素来处理。

基于位置的选择

当我们第一次遇到这个错误时,最简单的解决方案是指定列表中的某个位置。最简单的方法是选择第一个结果:

await page.getByRole('button').first().click();

我经常遇到上述错误,因此几乎每次写定位器时我都会养成在定位器中添加 first()​ 的习惯。😅

如果你想更具体地指定列表中的位置,可以使用:

await page.getByRole('button').nth(3).click();

.nth()​ 方法是从零开始的,因此 .nth(3)​ 将选择结果中的第四个元素。位置选择器可以工作,但如果页面内容是动态的,选择除第一个结果外的任何项都可能产生假阳性。为了更确保我们在动态列表中指向正确的元素,可以进行元素筛选。

Playwright 中的元素筛选

假设我们有一个电商界面,显示多个商品结果,但其中只有一些是可用的,使用位置选择器进行测试可能并不可靠。

如果我们检查页面,可以看到这些是列表项,因此可以使用一个选择器来确保商品是可用的,然后再检查按钮,代码如下:

const button = page.getByRole('listitem')
.filter({ hasText: 'available' })
.getByRole('button', { name: 'buy' });
await button.click();

现在,当用户看到的商品全部售罄时,这个测试将会在合适的时候失败。

定位器策略的最佳实践

没有一种通用的定位器解决方案可以适用于所有情况。这里有一些提示:

  • 避免依赖实现细节:使用反映用户操作的定位器,而不是 HTML 结构。
  • 使用内置定位器getByRole​、getByText​ 等定位器可以提高测试的稳定性和可维护性。
  • 使用数据测试 ID:对于复杂的场景,使用数据测试 ID 可以简化定位器并提高测试的可靠性。任何仅用于调试的页面内容都应谨慎使用。

结论

选择正确的定位器是创建稳定且可维护的 Playwright 测试的关键。面向用户的定位器减少了测试的不稳定性,并鼓励良好的开发实践。如果你有兴趣加入 Playwright 开发者社区,欢迎加入 Checkly 的 Slack 频道。如果你使用 Playwright 进行端到端测试,考虑使用 Checkly 监控你的生产网站,我们有一个关于“监控即代码”的精彩故事,可以赋能你的开发者。


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
149° /1491 人阅读/0 条评论 发表评论

登录 后发表评论