《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇 (详细教程)
软件测试微信群:https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入
1.简介
上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下剩下部分的基础定位方式。
2.过滤器定位
例如以下 DOM 结构,我们要在其中单击第二个产品卡的购买按钮。我们有几个选项来过滤定位器以获得正确的定位器。

2.1按文本过滤
定位器可以使用 locator.filter()方法按文本进行过滤。它将搜索元素内某处的特定字符串,可能在后代元素中,不区分大小写。您还可以传递正则表达式。
1.使用文本
page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHasText("Product 2")).getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Add to cart")).click();
2.使用正则表达式
page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHasText(Pattern.compile("Product 2"))).getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Add to cart")).click();
2.2按没有文本进行筛选
通过没有文本进行筛选:
// 5 in-stock items
assertThat(page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHasNotText("Out of stock"))).hasCount(5);
2.3子项/后代过滤
定位器支持一个选项,即仅选择具有或没有与另一个定位器匹配的后代的元素的元素。因此,您可以按任何其他定位器进行过滤,例如 Locator.getByRole()、Locator.getByTestId()、Locator.getByText() 等。

page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHas(page.GetByRole(AriaRole.HEADING, new Page.GetByRoleOptions().setName("Product 2")))).getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Add to cart")).click()
我们还可以断言产品卡,以确保只有一个:
assertThat(page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHas(page.GetByRole(AriaRole.HEADING,new Page.GetByRoleOptions().setName("Product 2")))).hasCount(1);
过滤定位器必须相对于原始定位器进行查询,并且从原始定位器匹配项开始进行查询,而不是从文档根开始进行查询。因此,以下操作将不起作用,因为过滤定位器从列表元素开始匹配,该列表元素位于原始定位器匹配的列表项之外:<ul><li>
// ✖ WRONG
assertThat(page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHas(page.GetByRole(AriaRole.LIST).GetByRole(AriaRole.HEADING,new Page.GetByRoleOptions().setName("Product 2")))).hasCount(1);
2.4按没有子项/后代过滤
我们也可以通过内部没有匹配的元素来过滤。
assertThat(page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHasNot(page.getByText("Product 2"))).hasCount(1);
敲黑板!!!!请注意,内部定位器是从外部定位符开始匹配的,而不是从文档根目录开始匹配的。
3.定位器操作员
3.1定位器内部匹配
您可以链接创建定位器的方法,例如 Page.getByText() 或 Locator.getByRole(),以将搜索范围缩小到页面的特定部分。
在此示例中,我们首先通过定位其角色listitem来创建一个名为 product 的定位器。然后,我们按文本进行过滤。我们可以再次使用产品定位器来获取按钮的角色并单击它,然后使用断言来确保只有一个文本为“产品 2”的产品。
Locator product = page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHasText("Product 2"));product.getByRole(AriaRole.BUTTON,new Locator.GetByRoleOptions().setName("Add to cart")).click();
您还可以将两个定位器链接在一起,例如,在特定对话框中查找“保存”按钮:
Locator saveButton = page.getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Save"));
// ...
Locator dialog = page.getByTestId("settings-dialog");
dialog.locator(saveButton).click();
3.2同时匹配两个定位器
方法 Locator.and()通过匹配其他定位器来缩小现有定位器的范围。例如,您可以将 Page.getByRole() 和 Page.getByTitle() 组合在一起,以按角色和标题进行匹配。
Locator button = page.getByRole(AriaRole.BUTTON).and(page.getByTitle("Subscribe"));
3.3匹配两个备选定位器之一
如果您想定位两个或多个元素中的一个,但不知道会是哪一个,请使用 Locator.or() 创建一个与所有备选项匹配的定位器。
例如,考虑这样一种情况:您想单击“新电子邮件”按钮,但有时会出现安全设置对话框。在这种情况下,您可以等待“新电子邮件”按钮或对话框,然后采取相应措施。
敲黑板!!!注意:
如果屏幕上同时出现“新建电子邮件”按钮和安全对话框,则“或”定位器将匹配它们,从而可能引发“严格模式违规”错误。在这种情况下,您可以使用 Locator.first() 仅匹配其中一个。
Locator newEmail = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("New"));
Locator dialog = page.getByText("Confirm security settings");
assertThat(newEmail.or(dialog).first()).isVisible();
if (dialog.isVisible())page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Dismiss")).click();
newEmail.click();
3.4仅匹配可见元素
敲黑板!!!注意:
通常,找到一种更可靠的方法来唯一标识元素,而不是检查可见性。
考虑一个有两个按钮的页面,第一个不可见,第二个可见。
<button style='display: none'>Invisible</button> <button>Visible</button>
这将找到两个按钮并抛出严格性违规错误:
page.locator("button").click();
这只会找到第二个按钮,因为它是可见的,然后单击它。
page.locator("button").locator("visible=true").click();
4.列表
4.1对列表中的项目进行计数
可以断言定位器以对列表中的项目进行计数。例如:以下DOM结构

使用count断言确保列表包含 3 个项目。
assertThat(page.getByRole(AriaRole.LISTITEM).hasCount(3);
4.2断言列表中所有文本
可以断言定位器以查找列表中的所有文本。例如:以下DOM结构

使用 assertThat(locator).hasText() 确保列表包含文本“apple”、“banana”和“orange”。
assertThat(page.getByRole(AriaRole.LISTITEM)).hasText(new String[] { "apple", "banana", "orange" });
4.3定位特定项目
有许多方法可以在列表中定位特定项目。
4.3.1通过文本定位
使用 Page.getByText()方法通过文本内容在列表中查找元素,然后单击它。例如:以下DOM结构

通过文本内容找到项目并单击它。
page.getByText("orange").click();
4.3.2通过文本过滤定位
使用 locator.filter() 在列表中查找特定项目。例如:以下DOM结构

按“listitem”的角色找到一个项目,然后按“orange”的文本进行筛选,然后单击它。
page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHasText("orange")).click();
4.3.3通过测试id定位
使用 Page.getByTestId()方法在列表中查找元素。如果您还没有测试 ID,则可能需要修改 html 并添加测试 ID。

通过测试 ID “orange”找到一个项目,然后单击它。
page.getByTestId("orange").click();
4.3.4通过第n项定位
如果您有一个相同元素的列表,并且区分它们的唯一方法是顺序,则可以使用 Locator.first()、Locator.last() 或 Locator.nth() 从列表中选择特定元素。
Locator banana = page.getByRole(AriaRole.LISTITEM).nth(1);
但是,请谨慎使用此方法。通常,页面可能会发生变化,定位器将指向与您预期的完全不同的元素。取而代之的是,尝试提出一个独特的定位器,该定位器将通过严格的标准。
4.4链接过滤器
当您有各种相似性的元素时,可以使用 locator.filter()方法选择正确的元素。您还可以链接多个筛选器以缩小选择范围。

要截取带有“Mary”和“Say goodbye”的行的屏幕截图,请执行以下操作:
Locator rowLocator = page.getByRole(AriaRole.LISTITEM);rowLocator.filter(new Locator.FilterOptions().setHasText("Mary")).filter(new Locator.FilterOptions().setHas(page.getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Say goodbye")))).screenshot(new Page.ScreenshotOptions().setPath("screenshot.png"));
现在,您应该在项目的根目录中有一个“screenshot.png”文件。
4.5罕见例子
4.5.1对列表中每个元素执行某些操作
迭代元素
for (Locator row : page.getByRole(AriaRole.LISTITEM).all())System.out.println(row.textContent());
使用常规 for 循环进行迭代:
Locator rows = page.getByRole(AriaRole.LISTITEM); int count = rows.count(); for (int i = 0; i < count; ++i)System.out.println(rows.nth(i).textContent());
4.5.2在页面中评估
locator.evaluate_all()中的代码在页面中运行,您可以在那里调用任何 DOM API。
Locator rows = page.getByRole(AriaRole.LISTITEM);
Object texts = rows.evaluateAll("list => list.map(element => element.textContent)");
5.小结
定位器是非常严格。这意味着,如果多个元素匹配,则对定位器执行暗示某些目标 DOM 元素的所有操作都将引发异常。例如,如果 DOM 中有多个按钮,则会引发以下调用:
如果有多个button,则引发错误
page.getByRole(AriaRole.BUTTON).click();
另一方面,Playwright 了解何时执行多元素操作,因此当定位器解析为多个元素时,以下调用工作正常。
适用于多个元素
page.getByRole(AriaRole.BUTTON).count();
您可以通过 locator.first、locator.last 和 locator.nth() 告诉 Playwright 在多个元素匹配时使用哪个元素来明确选择退出严格性检查。不建议使用这些方法,因为当您的页面更改时,Playwright 可能会单击您不想要的元素。相反,请按照上述最佳实践创建唯一标识目标元素的定位器。
5.1其他定位器
对于不太常用的定位器,请查看官网的其他定位器指南。由于时间关系,宏哥就不在这里对其进行展开介绍和讲解了。好了时间不早了,关于元素基础定位方式今天就分享到这里!!!仅供大家学习参考,感谢您耐心的阅读。
每天学习一点,今后必成大神-
往期推荐(由于跳转参数丢失了,所有建议选中要访问的右键,在新标签页中打开链接即可访问)或者微信搜索: 北京宏哥 公众号提前解锁更多干货。
Appium自动化系列,耗时80天打造的从搭建环境到实际应用精品教程测试
Python接口自动化测试教程,熬夜87天整理出这一份上万字的超全学习指南
Python+Selenium自动化系列,通宵700天从无到有搭建一个自动化测试框架
Java+Selenium自动化系列,仿照Python趁热打铁呕心沥血317天搭建价值好几K的自动化测试框架
Jmeter工具从基础->进阶->高级,费时2年多整理出这一份全网超详细的入门到精通教程
其他定位器
Pycharm工具基础使用教程
相关文章:
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇 (详细教程)
软件测试微信群:https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下剩下部分的基…...
[Day 44] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
生成对抗网络(Generative Adversarial Networks,GANs)是一种由Ian Goodfellow等人在2014年提出的深度学习模型,广泛用于图像生成、图像超分辨率、图像修复等领域。GAN由一个生成器(Generator)和一个判别器&…...
【Redis】 Redis 列表指令指南
这是我父亲 日记里的文字 这是他的生命 留下留下来的散文诗 几十年后 我看着泪流不止 可我的父亲已经 老得像一个影子 🎵 许飞《父亲写的散文诗》 Redis 是一个开源的内存数据库,支持多种数据结构,其中列表(…...
设计测试用例的具体方法
一.等价类 等价类分为: 1.有效等价类 [6~15] 2.无效等价类 :小于6位,大于15位(不在数据范围内) 组合规则: 有效等价类组合的时候,尽可能一条测试用例尽可能多的覆盖有效等价类 无效等价类组合的时候,一条测试点,之恶能覆盖一个无效等价类 二.边界值 1.上点,离点,内点 上…...
GPT-4o mini(假设模型)概览
开篇背景: 近年来,随着计算能力的提升和大数据的积累,大型语言模型(LLMs)如GPT系列取得了显著进展。这些模型不仅能够理解复杂的自然语言文本,还能生成流畅、连贯的回复,甚至展现出一定程度的创…...
抽象代数精解【9】
文章目录 置换密码密码体制加解密过程置换置换运算定义置换运算的例子集合与置换置换规则两行表示法轮换表示法置换运算的结果置换的性质注意事项 分组加解密 理论基础1. 准备工作2. 置换过程3. 置换密码的具体实现方式4. 安全性分析5. 置换密码的应用代换密码代换密码的工作原…...
熟悉简单测试面经
SQL语句中增、删、查、改的关键字 MySQL中SQL语句删除语句有哪些?区别是啥。 “”和equals的区别 “String s "1"”与“String s new String("1")”中的s一样吗? StringBuilder与StringBuffer的区别 洗牌问题 HTTP、HTTPS、U…...
IoTDB 入门教程 实战篇④——C#示例(开源)
文章目录 一、前文二、新建C#项目三、NuGet安装四、示例源码五、查询数据六、参考 一、前文 IoTDB入门教程——导读 本文详细阐述了如何通过一个C#项目成功连接到IoTDB时序数据库,进而展示了如何向该数据库高效地写入数据以及执行精确的数据查询操作。 此示例旨在为…...
STL-vector容器
目录 一、常见接口 1.1 构造函数 1.2 访问与遍历 1.3 容量操作 1.4 增删查改 二、模拟实现 2.1 迭代器失效 2.2 源代码 一、常见接口 vector数据结构实际上是顺序表 详细解释与使用请参见官方网站:vector - C Reference (cplusplus.com) 1.1 构造函数 函…...
python字符串与变量名互相转换,字典,list操作
locals是python的内置函数,他可以以字典的方式去访问局部和全局变量 vars()本函数是实现返回对象object的属性和属性值的字典对象 eval()将字符串str当成有效的表达式来求值并返回计算结果 #!/usr/bin/python3 #-*- coding uft-8 -*- guo 666 str1 "guo&qu…...
企业及园区电力能源管理系统方案
概述 面对中小型的用能集团、园区能耗监测分析等场景需求,拓扑未来公司推出标准化的企业及园区电力能源管理系统方案,力求高效高质地为目标客户提供高效部署、轻松运维的本地化能源管理解决方案。 本方案以软硬件一体的方式,集成了标准电力监…...
5.3 需求分析
需求分析 软件需求定义分类练习题 需求工程需求获取练习题 需求分析状态转化图数据流图DFD顶层数据流图0层数据流图1层数据流图 练习题 需求规约需求定义方法 需求验证需求管理版本控制需求跟踪变更控制练习题 考试大概3分 软件需求 定义 软件需求:是指用户对目标…...
【C++】list介绍以及模拟实现(超级详细)
欢迎来到我的Blog,点击关注哦💕 list的介绍和模拟实现 前言list介绍标准库容器 std::list 与 std::vector 的优缺点缺点 list的基本操作构造函数list iteratorlist capcacitylist modify list模拟实现存贮结构(双向带头循环)itera…...
从艺术创作到作物生长,农业AI迎来“GPT“时刻
(于景鑫 国家农业信息化工程技术研究中心)"GPT"一词早已不再神秘,其在文本、图像生成领域掀起的风暴正以摧枯拉朽之势席卷全球。人们惊叹于ChatGPT对话之智能、思维之敏捷,更对Stable Diffusion、Midjourney创作的艺术画作赞叹不已。而大语言模…...
前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线
本章响应小伙伴的反馈,除了算法自动画连接线(仍需优化完善),实现了可以手动绘制直线、折线连接线功能。 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,欢迎来提 Issue 哟~ github源码 gitee…...
C#:通用方法总结—第15集
大家好,今天继续分享我们的通用方法系列。 下面是今天的通用方法: (1)这个通用方法为用文件流写数据 /// <summary> /// 用文件流写数据 /// </summary> /// <param name"data"></param> //…...
LoadRunner12 添加事务并添加检查点
1、先要添加事务开始函数lr_start_transaction("登陆事务");,在接口上方右击点击-插入-开始事务。输入事务名称; 2、在某个接口想法 右击点击-插入-结束事务,输入事务名称,与开始事务名称要保持一致,lr_end_…...
python中的文件
绝对路径和相对路径 一般情况下绝对路径就是从根目录开始描述的路径 相对路径就是相对于当前目录 . 没错,就是一个点,表示的是当前文件夹;.. 两个点表示的是上一层文件夹 os模块与os.path os 和 os.path 是两个非常重要的标准库模块,它们分别用于操作系统相关的功能操…...
Powerdesigner连接mysql数据库,逆向工程生成ER图 (保姆级教程:下载->连接->配置)看这一篇就够了
一、下载powerdesigner 下载的教程请看如下链接,我太懒了,直接借鉴! 把别大佬的博客搬过来了嘿嘿~我真聪明!ㄟ( ▔, ▔ )ㄏ 操作到完成汉化就好!!第5步不看了,别按那个走,因为新手…...
商家转账到零钱分销返佣申请方案及驳回处理办法
分销返佣场景是商家申请最多的场景,因而申请被驳回也是最多的,根据我们上万次成功开通商家转账到零钱的经验,当商家转账到零钱的分销返佣场景被驳回时,按照以下步骤,商家都可以快速过审: 一、分析驳回原因 …...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
