《刚刚问世》系列初窥篇-Java+Playwright自动化测试-6- 元素基础定位方式-上篇 (详细教程)
1.简介
从这篇文章开始,就开始要介绍UI自动化核心的内容,也是最困难的部分了,就是:定位元素,并去对定位到的元素进行一系列相关的操作。想要对元素进行操作,第一步,也是最重要的一步,就是要找到这个元素,如果连元素都定位不到,后续什么操作都是无用功,都是扯淡,因此宏哥建议小伙伴或者同学们从这里开始就要跟紧宏哥的脚步,一步一个脚印的将基础打结实,不要到后期了要定位操作元素了,到处找人问到处碰壁。说到元素定位,小伙伴或者童鞋们肯定会首先想到 selenium 的八大元素定位大法。同理Playwright也有自己的元素定位的方法。今天就给小伙伴或者童鞋们讲解和分享一下Playwright的元素定位方法。其实在Python+Playwright自动化测试系列文章中也介绍过元素定位,宏哥看一下Java和Python的几乎是大同小异,只不过是Java和Python语法格式的区别,其他的大差不差。但是为了这一系列文字的完整和连贯,宏哥还是将其讲解和分享一下。
2.什么是定位?
宏哥这里说的定位和我们平时说的不一样,Playwright能够模拟用户去浏览器页面上执行对应(输入,点击,清除,提交)等操作,它是凭什么方式去寻找到页面的元素?Playwright没有视觉、听觉等。Selenium通过在页面上寻找元素位置,找到元素后,然后对元素进行相应的操作,Playwright寻找元素位置的方法,称之为定位。
3.定位器(Locator)
官网是这样对定位器进行定义的:定位器(Locator)是 Playwright 的自动等待和重试能力的核心部分。简而言之,定位器是一种随时在网页上查找元素的方法。
4.内置定位器
这些是 Playwright 推荐的内置定位器。
- Page.getByRole()
通过显式和隐式可访问性属性进行定位。 - Page.getByText()
按文本内容定位。 - Page.getByLabel()
通过关联标签的文本来定位表单控件。 - Page.getByPlaceholder()
按占位符查找输入。 - Page.getByAltText()
通过其文本替代来定位元素,通常是图像。 - Page.getByTitle()
通过其 title 属性定位元素。 - Page.getByTestId()
根据元素的属性定位元素(可以配置其他属性)。
5.元素基础定位方式
Playwright 带有多个内置定位器。为了使测试具有弹性,我们建议优先考虑面向用户的属性和显式契约,例如 Page.getByRole()。例如:以下 DOM 结构。
按名称为“Sign in”的角色找到元素:
button 。
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Sign in")).click();
使用代码生成器生成定位器,然后根据需要进行编辑。
每次将定位器用于操作时,页面中都会找到最新的 DOM 元素。在下面的代码片段中,底层 DOM 元素将定位两次,一次在每次操作之前。这意味着,如果 DOM 在两次调用之间由于重新渲染而发生变化,则将使用与定位器对应的新元素。
Locator locator =page.getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Sign in"))
locator.hover();
locator.click();
请注意,创建定位器的所有方法(如 Page.getByLabel())也可用于 Locator 和 FrameLocator 类,因此您可以链接它们并迭代缩小定位器的范围。
Locator locator =page
.frameLocator("#my-frame")
.getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Sign in"));
locator.click();
5.1按角色定位
Page.getByRole()定位器反映了用户和辅助技术如何感知页面,例如,某个元素是按钮还是复选框。按角色定位时,通常还应传递可访问的名称,以便定位器精确定位确切的元素。例如:以下 DOM 结构。
您可以根据其隐式角色来定位每个元素:
assertThat(page
.getByRole(AriaRole.HEADING,new Page.GetByRoleOptions().setName("Sign up")))
.isVisible();
page.getByRole(AriaRole.CHECKBOX,new Page.GetByRoleOptions().setName("Subscribe"))
.check();
page.getByRole(AriaRole.BUTTON,newPage.GetByRoleOptions().setName(
Pattern.compile("submit", Pattern.CASE_INSENSITIVE)))
.click();
角色定位器包括按钮、复选框、标题、链接、列表、表格等,并遵循 W3C 对 ARIA 角色、ARIA 属性和可访问名称的规范。请注意,许多 html 元素(例如)都有一个隐式定义的角色,该角色定位器可以识别该角色:
<button>
请注意,角色定位器
不会取代可访问性审核和一致性测试,而是提供有关 ARIA 指南的早期反馈。
建议优先使用角色定位器来定位元素,因为这是最接近用户和辅助技术感知页面的方式。
5.2按标签定位
大多数表单控件通常都有专用标签,可以方便地使用这些标签与表单进行交互。在这种情况下,您可以使用 Page.getByLabel() 通过其关联标签来定位控件。例如:以下 DOM 结构。
您可以通过标签文本找到输入后填充输入:
page.getByLabel("Password").fill("secret");
敲黑板!!!注意:何时使用标签定位器:官网建议在查找表单字段时,请使用此定位器。
5.3按占位符定位
输入可能具有占位符属性,以提示用户应输入什么值。您可以使用 Page.getByPlaceholder()找到此类输入。例如:以下 DOM 结构。
您可以通过占位符文本找到输入后填充输入:
page.getByPlaceholder("name@example.com").fill("playwright@microsoft.com");
敲黑板!!!注意:何时使用占位符定位器:官网建议在查找没有标签但具有占位符文本的表单元素时,请使用此定位器。
5.4按文本定位
通过它包含的文本找到一个元素。使用 Page.getByText()时,您可以通过子字符串、精确字符串或正则表达式进行匹配。例如:以下 DOM 结构。
您可以通过它包含的文本找到该元素:
assertThat(page.getByText("Welcome, John")).isVisible();
设置完全匹配:
assertThat(page
.getByText("Welcome, John", new Page.GetByTextOptions().setExact(true)))
.isVisible();
与正则表达式匹配:
assertThat(page
.getByText(Pattern.compile("welcome, john$", Pattern.CASE_INSENSITIVE)))
.isVisible();
敲黑板!!!注意:
(1)按文本匹配始终会使空格归一化,即使完全匹配也是如此。例如,它将多个空格转换为一个空格,将换行符转换为空格,并忽略前导和尾随空格。
(2)何时使用文本定位器:官网建议建议使用文本定位器来查找非交互式元素,如div、span、p 等。对于交互式元素(如button、a、input 等),请使用角色定位器。
您还可以按文本进行筛选,这在尝试查找列表中的特定项目时非常有用。
5.5通过替代文本定位
所有图像都应具有描述图像的属性alt。您可以使用 Page.getByAltText() 根据替代文本定位图像。例如:以下 DOM 结构。
您可以通过文本替代找到图像后单击图像:
page.getByAltText("playwright logo").click();
敲黑板!!!注意,何时使用 ALT 定位器:官网建议当您的元素支持 alt 文本(如 img 和 area)时,请使用此定位器。
5.6按标题定位
使用 Page.getByTitle()找到具有匹配 title 属性的元素。例如:以下 DOM 结构。
您可以通过标题文本找到问题后检查问题计数:
assertThat(page.getByTitle("Issues count")).hasText("25 issues");
敲黑板!!!注意,何时使用标题定位器:官网建议当元素具有title属性时,请使用此定位器。
5.7按测试ID定位
通过测试 ID 进行测试是最具弹性的测试方式,因为即使您的文本或属性角色发生变化,测试仍将通过。 QA 和开发人员应定义显式测试 ID 并使用 Page.getByTestId() 查询它们。但是,通过测试 ID 进行测试不是面向用户的。如果角色或文本值对您很重要,请考虑使用面向用户的定位器,例如角色和文本定位器。例如:以下 DOM 结构。
您可以通过其测试 ID 找到该元素:
page.getByTestId("directions").click();
敲黑板!!!注意,何时使用 TESTID 定位器:官网建议当您选择使用测试 ID 方法时,或者当您无法按角色或文本进行定位时,也可以使用测试 ID。
5.7.1设置自定义的测试ID
默认情况下,Page.getByTestId()将根据属性data-testid定位元素,但您可以在测试配置中或通过调用 Selectors.setTestIdAttribute()来配置它。
将测试 ID 设置为对测试使用自定义数据属性。
playwright.selectors().setTestIdAttribute("data-pw");
在您的 html 中,您现在可以用data-pw作您的测试 ID,而不是默认的data-testid。然后像往常一样找到该元素:
page.getByTestId("directions").click();
5.8通过CSS或者Xpath定位
如果您绝对必须使用 CSS 或 XPath 定位器,则可以使用 Page.locator()创建一个定位器,该定位器采用描述如何在页面中查找元素的选择器。Playwright 支持 CSS 和 XPath 选择器,如果您省略或添加前缀css=或xpath=,则会自动检测它们。
page.locator("css=button").click();
page.locator("xpath=//button").click();
page.locator("button").click();
page.locator("//button").click();
XPath 和 CSS 选择器可以绑定到 DOM 结构或实现。当 DOM 结构发生变化时,这些选择器可能会中断。下面的长 CSS 或 XPath 链是导致测试不稳定的
不良做法的一个示例:
page.locator("#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input").click();
page.locator("//*[@id='tsf']/div[2]/div[1]/div[1]/div/div[2]/input").click();
敲黑板!!!注意,何时使用此工具:官网不建议使用 CSS 和 XPath,因为 DOM 经常会更改,从而导致无法恢复的测试。取而代之的是,尝试提出一个接近用户感知页面方式的定位器,例如角色定位器,或者使用测试 ID 定义明确的测试合同。
6.阴影定位-Shadow DOM
在做web自动化的时候,一些元素在shadow-root的节点下,使得playwright中无法通过xpath来定位
上面所看到的shadow-root标签其实就是一个shadowDOM,那么什么是shadowDOM呢?
他是前端的一种页面封装技术,可以将shadowDOM视为“DOM中的DOM”(可以看成一个隐藏的DOM)
他是一个独立的DOM树,具有自己的元素和样式,与原始文档DOM完全隔离。
shadowDOM必须附在一个HTML元素中,存放shadowDOM的元素,我们可以把它称为宿主元素。在HTML5中有很多的标签样式都是通过shadowDOM来实现的。
比如:日期选择框,音频播放标签,视频播放标签都自带了样式;(这种封装对于前端开发来说虽好,但是我们测试人员在做web自动给的时候就会遇到一些问题,shadowDOM中的标签无法定位。)
默认情况下,Playwright 中的所有定位器都使用 Shadow DOM 中的元素。例外情况是:
- 通过 XPath 定位不会刺穿阴影根部。
- 不支持闭合模式影子根。
例如:以下自定义 Web 组件示例:
<x-detailsrole=buttonaria-expanded=truearia-controls=inner-details> <div>Title</div>#shadow-root<divid=inner-details>Details</div> </x-details>
您可以采用与影子根根本不存在相同的方式进行定位。
要单击 :
<div>Details</div>
page.getByText("Details").click();
<x-detailsrole=buttonaria-expanded=truearia-controls=inner-details> <div>Title</div>#shadow-root<divid=inner-details>Details</div> </x-details>
点击 :
<x-details>
page.locator("x-details", new Page.LocatorOptions().setHasText("Details"))
.click();
<x-detailsrole=buttonaria-expanded=truearia-controls=inner-details> <div>Title</div>#shadow-root<divid=inner-details>Details</div> </x-details>
要确保包含文本“详细信息”,请执行以下操作:
<x-details>
assertThat(page.locator("x-details")).containsText("Details");
7.小结
今天这一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方法的理论基础知识以及在什么情况下推荐使用,当然了这不是一成不变的,希望大家在使用中可以灵活多变的应用,一种不行就换另一种说不定就可以了,不要太较真死活就要用它,一棵树上吊死。
好了,今天时间也不早了,宏哥就讲解和分享到这里,感谢您耐心的阅读,希望对您有所帮助。