《刚刚问世》系列初窥篇-Java+Playwright自动化测试-6- 元素基础定位方式-上篇 (详细教程)

devtools/2024/10/24 12:28:55/

软件测试微信群:https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 

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,new Page.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-details role=button aria-expanded=true aria-controls=inner-details><div>Title</div>#shadow-root<div id=inner-details>Details</div>
</x-details>

您可以采用与影子根根本不存在相同的方式进行定位。

要单击 :<div>Details</div>

page.getByText("Details").click();
<x-details role=button aria-expanded=true aria-controls=inner-details><div>Title</div>#shadow-root<div id=inner-details>Details</div>
</x-details>

点击 :<x-details>

page.locator("x-details", new Page.LocatorOptions().setHasText("Details")).click();
<x-details role=button aria-expanded=true aria-controls=inner-details><div>Title</div>#shadow-root<div id=inner-details>Details</div>
</x-details>

要确保包含文本“详细信息”,请执行以下操作:<x-details>

assertThat(page.locator("x-details")).containsText("Details");

7.小结

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

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

 每天学习一点,今后必成大神-

往期推荐(由于跳转参数丢失了,所有建议选中要访问的右键,在新标签页中打开链接即可访问)或者微信搜索: 北京宏哥  公众号提前解锁更多干货。

Appium自动化系列,耗时80天打造的从搭建环境到实际应用精品教程测试

Python接口自动化测试教程,熬夜87天整理出这一份上万字的超全学习指南

Python+Selenium自动化系列,通宵700天从无到有搭建一个自动化测试框架

Java+Selenium自动化系列,仿照Python趁热打铁呕心沥血317天搭建价值好几K的自动化测试框架

Jmeter工具从基础->进阶->高级,费时2年多整理出这一份全网超详细的入门到精通教程

Fiddler工具从基础->进阶->高级,费时100多天吐血整理出这一份全网超详细的入门到精通教程

Pycharm工具基础使用教程


http://www.ppmy.cn/devtools/89033.html

相关文章

【jvm】类加载分几步

目录 1. 加载&#xff08;Loading&#xff09;2. 链接&#xff08;Linking&#xff09;2.1 验证&#xff08;Verification&#xff09;2.2 准备&#xff08;Preparation&#xff09;2.3 解析&#xff08;Resolution&#xff09; 3. 初始化&#xff08;Initialization&#xff0…

Spring Boot常用注解

一&#xff0c;核心注解 1&#xff0c; SpringBootApplication 用途&#xff1a;标注一个主程序类&#xff0c;表明是一个SpringBoot应用程序的入口。 功能&#xff1a;这是一个复合注解&#xff0c;组合了ComponentScan&#xff0c;EnableAutoConfiguration&#xff0c;Spr…

【Material-UI】Autocomplete 组件中的虚拟化功能(Virtualization)详解

文章目录 一、虚拟化概述二、实现虚拟化的步骤1. 引入依赖2. 自定义 Popper 组件和 Listbox 组件3. 代码详解4. 性能优化 三、实际应用场景1. 大规模数据列表2. 高性能需求的应用 四、总结 在现代 Web 开发中&#xff0c;处理大量数据时&#xff0c;性能优化显得尤为重要。Mate…

Vue3 + js-echarts 实现前端大屏可视化

1、前言 此文章作为本人大屏可视化项目的入门学习笔记&#xff0c;以此作为记录&#xff0c;记录一下我的大屏适配解决方案&#xff0c;本项目是基于vite Vue3 js less 实现的&#xff0c;首先看ui&#xff0c;ui是网上随便找的&#xff0c;代码是自己实现的&#xff0c;后面…

Java02 Java程序结构

程序的主结构&#xff1a; 一个完整的Java程序&#xff0c;它的基本结构包括&#xff1a;class类、main方法、输出语句、注释。 命名规范和代码书写 新建项目命名 项目命名时可用数字&#xff0c;字母&#xff0c;下划线&#xff0c;$来命名。&#xff08;注意&#xff1a;命名…

堆内存申请 - 华为OD统一考试(D卷)

OD统一考试(D卷) 分值: 100分 题解: Java / Python / C++ 题目描述 有一个总空间为100字节的堆,现要从中新申请一块内存,内存分配原则为: 优先分配紧接着前一块已使用的内存,分配空间足够时分配最接近申请大小的空闲内存。 输入描述 第1行是1个整数,表示期望申请的…

【JVM基础11】——垃圾回收-说一下JVM的分代回收?

目录 1- 引言&#xff1a;分代回收1-1 什么是分代回收&#xff08;What&#xff09;1-2 为什么要用分代回收&#xff1f;&#xff08;Why&#xff09; 2- ⭐核心&#xff1a;分代回收工作机制2-1 工作机制2-2 MinorGC、Mixed GC、FullGC的区别是什么 3- 总结3-1 说一下 JVM 的分…

C++标准模板(STL)- 类型支持 (类型属性,检查类型是否为 final 类类型,std::is_final)

类型特性 类型特性定义一个编译时基于模板的结构&#xff0c;以查询或修改类型的属性。 试图特化定义于 <type_traits> 头文件的模板导致未定义行为&#xff0c;除了 std::common_type 可依照其所描述特化。 定义于<type_traits>头文件的模板可以用不完整类型实例…