- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下剩下部分的基础定位方式.
例如以下 DOM 结构,我们要在其中单击第二个产品卡的购买按钮。我们有几个选项来过滤定位器以获得正确的定位器.
定位器可以使用 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();
通过没有文本进行筛选:
// 5 in-stock items assertThat(page.getByRole(AriaRole.LISTITEM) .filter(new Locator.FilterOptions().setHasNotText("Out of stock"))) .hasCount(5);
定位器支持一个选项,即仅选择具有或没有与另一个定位器匹配的后代的元素的元素。因此,您可以按任何其他定位器进行过滤,例如 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);
我们也可以通过内部没有匹配的元素来过滤.
assertThat(page .getByRole(AriaRole.LISTITEM) .filter(new Locator.FilterOptions().setHasNot(page.getByText("Product 2"))) .hasCount(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();
方法 Locator.and()通过匹配其他定位器来缩小现有定位器的范围。例如,您可以将 Page.getByRole() 和 Page.getByTitle() 组合在一起,以按角色和标题进行匹配.
Locator button = page.getByRole(AriaRole.BUTTON).and(page.getByTitle("Subscribe"));
如果您想定位两个或多个元素中的一个,但不知道会是哪一个,请使用 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();
敲黑板!!!注意:
通常,找到一种更可靠的方法来唯一标识元素,而不是检查可见性.
考虑一个有两个按钮的页面,第一个不可见,第二个可见.
<button style='display: none'>Invisible</button> <button>Visible</button>
这将找到两个按钮并抛出严格性违规错误:
page.locator("button").click();
这只会找到第二个按钮,因为它是可见的,然后单击它.
page.locator("button").locator("visible=true").click();
可以断言定位器以对列表中的项目进行计数。例如:以下DOM结构 。
使用count断言确保列表包含 3 个项目.
assertThat(page.getByRole(AriaRole.LISTITEM).hasCount(3);
可以断言定位器以查找列表中的所有文本。例如:以下DOM结构 。
使用 assertThat(locator).hasText() 确保列表包含文本“apple”、“banana”和“orange”.
assertThat(page .getByRole(AriaRole.LISTITEM)) .hasText(new String[] { "apple", "banana", "orange" });
有许多方法可以在列表中定位特定项目.
使用 Page.getByText()方法通过文本内容在列表中查找元素,然后单击它。例如:以下DOM结构 。
通过文本内容找到项目并单击它.
page.getByText("orange").click();
使用 locator.filter() 在列表中查找特定项目。例如:以下DOM结构 。
按“listitem”的角色找到一个项目,然后按“orange”的文本进行筛选,然后单击它.
page.getByRole(AriaRole.LISTITEM) .filter(new Locator.FilterOptions().setHasText("orange")) .click();
使用 Page.getByTestId()方法在列表中查找元素。如果您还没有测试 ID,则可能需要修改 html 并添加测试 ID.
通过测试 ID “orange”找到一个项目,然后单击它.
page.getByTestId("orange").click();
如果您有一个相同元素的列表,并且区分它们的唯一方法是顺序,则可以使用 Locator.first()、Locator.last() 或 Locator.nth() 从列表中选择特定元素.
Locator banana = page.getByRole(AriaRole.LISTITEM).nth(1);
但是,请谨慎使用此方法。通常,页面可能会发生变化,定位器将指向与您预期的完全不同的元素。取而代之的是,尝试提出一个独特的定位器,该定位器将通过严格的标准.
当您有各种相似性的元素时,可以使用 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”文件.
迭代元素 。
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());
locator.evaluate_all()中的代码在页面中运行,您可以在那里调用任何 DOM API.
Locator rows = page.getByRole(AriaRole.LISTITEM); Object texts = rows.evaluateAll( "list => list.map(element => element.textContent)");
定位器是非常严格。这意味着,如果多个元素匹配,则对定位器执行暗示某些目标 DOM 元素的所有操作都将引发异常。例如,如果 DOM 中有多个按钮,则会引发以下调用:
page.getByRole(AriaRole.BUTTON).click();
另一方面,Playwright 了解何时执行多元素操作,因此当定位器解析为多个元素时,以下调用工作正常.
page.getByRole(AriaRole.BUTTON).count();
您可以通过 locator.first、locator.last 和 locator.nth() 告诉 Playwright 在多个元素匹配时使用哪个元素来明确选择退出严格性检查。不建议使用这些方法,因为当您的页面更改时,Playwright 可能会单击您不想要的元素。相反,请按照上述最佳实践创建唯一标识目标元素的定位器.
对于不太常用的定位器,请查看官网的其他定位器指南。由于时间关系,宏哥就不在这里对其进行展开介绍和讲解了。好了时间不早了,关于元素基础定位方式今天就分享到这里!!!仅供大家学习参考,感谢您耐心的阅读.
最后此篇关于《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇(详细教程)的文章就讲到这里了,如果你想了解更多关于《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇(详细教程)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!