《最新出炉》系列初窥篇-Python+Playwright自动化测试-5-元素定位大法-上篇

发布时间 2023-06-30 15:37:40作者: 北京-宏哥

1.简介

说到元素定位,小伙伴或者童鞋们肯定会首先想到 selenium 的八大元素定位大法。同理Playwright也有自己的元素定位的方法。今天就给小伙伴或者童鞋们讲解和分享一下Playwright的元素定位方法。

宏哥对UI自动化的理解:定位元素--->操作元素---->断言。

2.定位器

定位器(Locator)是 Playwright 的自动等待和重试能力的核心部分。定位器是一种随时在网页上查找元素的方法,用于在元素上执行诸如 .click、.fill 之类的操作。可以使用 page.locator(selector, **kwargs) 方法创建自定义定位器。

选择器(Selector)是用于创建定位器的字符串。Playwright 支持许多不同的选择器,比如 Text、CSS、XPath 等。阅读 in-depth guide 文档,了解更多关于可用的选择器以及如何进行选择的信息。

3.内置定位器

这些是 playwright 推荐的内置定位器。

  • page.get_by_role()通过显式和隐式可访问性属性进行定位。
  • page.get_by_text()通过文本内容定位。
  • page.get_by_label()通过关联标签的文本定位表单控件。
  • page.get_by_placeholder()按占位符定位输入。
  • page.get_by_alt_text()通过替代文本定位元素,通常是图像。
  • page.get_by_title()通过标题属性定位元素。
  • page.get_by_test_id()根据data-testid属性定位元素(可以配置其他属性)。

当然除了这些,还有其他定位方法,selenium的8种by元素定位,id、xpath、css等都可使用,还有W3C标准规定的webDriver协议为5种定位方式CSS、Link text、Partial link text、Tag name、XPath

playwright把这些定位归类成3种,分别是:css、xpath、text。

如:

page.locator("xpath=//h2")
page.locator("text=文本输入") 
page.locator("#s-usersetting-top")
page.locator("input[name=\"wd\"]").click()
page.get_by_role("button", name="百度一下").click()
page2.get_by_placeholder("唱片名、表演者、条码、ISRC").click()
page2.get_by_text("或者,亲自来帮豆瓣添加:").click()

官方文档给出一个登录系统的使用示例如下:

page.get_by_label("User Name").fill("John")

page.get_by_label("Password").fill("secret-password")

page.get_by_role("button", name="Sign in").click()

expect(page.get_by_text("Welcome, John!")).to_be_visible()

3.1角色定位-page.get_by_role()

Playwright带有多个内置定位器。为了使测试具有弹性,我们建议优先考虑面向用户的属性和显式协定,例如page.get_by_role()。例如:以下 DOM 结构。

button通过名称为“登录”的角色定位元素。

page.get_by_role("button", name="Sign in").click()

每次将定位器用于操作时,都会在页面中找到一个最新的 DOM 元素。在下面的代码片段中,底层 DOM 元素将被定位两次,一次在每个动作之前。这意味着如果 DOM 由于重新渲染而在调用之间发生变化,则将使用与定位器对应的新元素。

locator = page.get_by_role("button", name="Sign in")

locator.hover()
locator.click()

请注意,所有创建定位器的方法(例如page.get_by_label() )也可用于Locator和FrameLocator类,因此您可以将它们链接起来并迭代地缩小定位器的范围。

locator = page.frame_locator("my-frame").get_by_role("button", name="Sign in")

locator.click()

page.get_by_role ()定位器反映了用户和辅助技术如何感知页面,例如某个元素是按钮还是复选框。按角色定位时,通常还应传递可访问的名称,以便定位器准确定位元素。

例如,考虑以下 DOM 结构。

 您可以通过其隐式角色定位每个元素:

expect(page.get_by_role("heading", name="Sign up")).to_be_visible()

page.get_by_role("checkbox", name="Subscribe").check()

page.get_by_role("button", name=re.compile("submit", re.IGNORECASE)).click()

角色定位器包括按钮、复选框、标题、链接、列表、表格等,并遵循ARIA 角色、ARIA 属性和可访问名称的 W3C 规范。

请注意:许多html元素如:<button>都有一个隐式定义的角色,该角色可被角色定位器识别。

请注意,角色定位器不会取代可访问性审核和一致性测试,而是提供有关 ARIA 指南的早期反馈。

3.1.1何时使用角色定位器

我们建议优先使用角色定位器来定位元素,因为这是最接近用户和辅助技术感知页面的方式。

3.2标签定位-page.get_by_label()

大多数表单控件通常都有专用标签,可以方便地用于与表单交互。在这种情况下,您可以使用page.get_by_label()通过其关联标签定位控件。例如:以下 DOM 结构。

您可以在通过标签文本定位后填写输入:

page.get_by_label("Password").fill("secret")
3.2.1何时使用标签定位器

定位表单区域时,使用标签定位器。

3.3占位符定位-page.get_by_placeholder()

输入可能具有占位符属性,以向用户提示应输入的值。您可以使用page.get_by_placeholder()定位此类输入。例如:以下 DOM 结构。

 您可以在通过占位符文本定位后填充输入:

page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")
3.3.1何时使用占位符定位器

在定位没有标签但具有占位符文本的表单元素时,使用此定位器。

3.4文本定位-page.get_by_text()

根据元素包含的文本查找元素。使用page.get_by_text()时,您可以通过子字符串、精确字符串或正则表达式进行匹配。例如:以下 DOM 结构。

 您可以通过元素包含的文本来查找该元素:

expect(page.get_by_text("Welcome, John")).to_be_visible()

设置完全匹配:

expect(page.get_by_text("Welcome, John", exact=True)).to_be_visible()

与正则表达式匹配:

expect(page
    .get_by_text(re.compile("welcome, john", re.IGNORECASE)))
    .to_be_visible()
注意:按文本匹配始终规范化空格,即使完全匹配也是如此。例如,它将多个空格转换为一个空格,将换行符转换为空格,并忽略前导和尾随空格。
3.4.1何时使用文本定位器

建议使用文本定位器来查找非交互式元素,如div, span, p 等。对于交互式元素,如请button, a, input, 使用角色定位器。

您还可以按文本进行筛选,这在尝试在列表中定位特定项目时很有用。

3.5替代文本定位-page.get_by_alt_text()

所有图像都应该有一个alt描述图像的属性。您可以使用page.get_by_alt_text()根据替代文本定位图像。例如:以下 DOM 结构。

 可以在通过替代文本选项找到图像后单击它:

page.get_by_alt_text("playwright logo").click()
3.5.1何时使用替代文本定位器
当您的元素支持替代文本(例如img和area元素)时使用此定位器。

3.6标题定位-page.get_by_title()

使用page.get_by_title()找到具有匹配 title 属性的元素。例如:以下 DOM 结构。

 您可以在通过标题文本找到它后检查问题数:

expect(page.get_by_title("Issues count")).to_have_text("25 issues")
3.6.1何时使用标题定位器

当您的元素具有该title属性时使用此定位器。

3.7测试id定位-page.get_by_test_id()

通过测试 ID 进行测试是最具弹性的测试方式,因为即使您的文本或属性角色发生变化,测试仍会通过。QA 和开发人员应该定义明确的测试 ID 并使用page.get_by_test_id()查询它们。但是,通过测试 ID 进行的测试不是面向用户的。如果角色或文本值对您很重要,那么请考虑使用面向用户的定位器,例如角色定位器和文本定位器。例如:以下 DOM 结构。

 您可以通过它的测试 ID 定位到该元素:

page.get_by_test_id("directions").click()
3.7.1何时使用测试id定位器

当你选择使用测试id的方法,或者角色、文本无法定位时,你也可以使用测试id进行定位。

3.7.2设置自定义测试id属性

默认情况下,page.get_by_test_id()将根据data-testid属性定位元素,但您可以在测试配置中或通过调用selectors.set_test_id_attribute()对其进行配置。

设置测试 ID 以使用自定义数据属性进行测试。

playwright.selectors.set_test_id_attribute("data-pw")

在您的 html 中,您现在可以使用data-pwtest id 而不是 default data-testid。

 然后像往常一样定位元素:

page.get_by_test_id("directions").click()

4.CSS或Xpath定位

如果必须使用 CSS 或 XPath 定位器,则可以使用 page.locator()创建一个定位器,该定位器采用描述如何在页面中定位元素的选择器。Playwright 支持 CSS 和 XPath 选择器,并在省略前缀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()

4.1何时使用CSS或Xpath定位器

不建议使用 CSS 和 XPath,因为 DOM 经常会发生变化,从而导致无弹性测试。相反,请尝试提出一个接近用户感知页面的定位器,例如角色定位器,或使用测试 ID 定义显式测试协定。

5.文本选择器定位-text()

文本选择器是一个非常实用的定位方式,根据页面上看到的text文本就可以定位了,比如我们经常使用xpath 的文本选择器定位。

  • 完全匹配文本 //*[text()="北京-宏哥"]
  • 包含某个文本 //*[contains(text(),"北京-宏哥")

playwright 封装了text文本定位的方式,也可以支持2种文本定位方式

page.click("text=北京-宏哥")
page.click("text='北京-宏哥'")

text=北京-宏哥和text='北京-宏哥'的区别:

  • text=北京-宏哥 没有加引号(单引号或者双引号),模糊匹配,对大小写不敏感
  • text='北京-宏哥' 有引号,精确匹配,对大小写敏感

text文本除了可以定位a标签,还可以定位 button 按钮,input标签的button 按钮,有value="百度一下" 文本值

<input type=button value="百度一下">

或者是button 标签的按钮

<button>百度一下</button>

6.HTML属性选择器定位

HTML 属性选择器, 根据html元素的id 定位

page.fill("id=kw", "北京-宏哥")

7.select选择器组合定位

定位目标元素,我们有时候可以使用>>(两个大于号)连接不同的selector可组合使用,例如:我们定位百度首页的登录

#id 属性+ css
page.fill('form >> [name="username"]', "北京-宏哥")
page.fill('form >> #TANGRAM__PSP_11__password', "aa123456")
page.click("text=登录")

form >> [name="username"] 定位方式等价于

#page.fill('form >> [name="username"]', "北京-宏哥")
page.locator("form").locator('[name="username"]').fill("北京-宏哥")

相当于是根据父元素找到子元素了

登录按钮的值是value="登录 > ",可以用text文本定位的方式,模糊匹配到,这种人性化的设计提高了定位的效率。

<input id="TANGRAM__PSP_11__submit" type="submit" value="登录" class="pass-button pass-button-submit">

8.小结

今天这一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的定位方法的理论基础知识以及在什么情况下推荐使用,当然了这不是一成不变的,希望大家在使用中可以灵活的应用。

好了,今天时间也不早了,宏哥就讲解和分享到这里,感谢您耐心的阅读,希望对您有所帮助。