剧作家选择带有 text= 或 hastext 完全匹配的元素

Mac*_*tyn 10 playwright

我正在使用剧作家nodejs。我自己编写了一个动态选择器函数来选择数据表上的页码按钮。

pageNumberButton(page, table_id, page_number) {
   page.locator(`[aria-controls=${table_id}]`, {hasText: page_number});
}
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

pageNumberButton(page, table_id, page_number) {
   page.locator(`[aria-controls=${table_id}] text=${page_number}`);
}
Run Code Online (Sandbox Code Playgroud)

但是,我似乎无法使其完全匹配。

假设我的数据表有 13 页:

显示上一个、1、2、3、4、5、...、13、下一个按钮的 dataTable 按钮控件

我希望单击第 1 页。因此我发出以下命令:await pageNumberButton(page, "resultsTable", "1").click();

但我收到严格模式错误,因为有两个结果:1 和 13。

动态创建这个小选择器以便我可以对按钮进行精确匹配的最佳或好的方法是什么?

Mac*_*tyn 10

我找到了一个选择。创建一个正则表达式对象并将其传递给 hasText。

pageNumberButton(page, table_id, page_number) { 
    const regexNumber = new RegExp(`^${page_number}$`); 
    page.locator(`[aria-controls=${table_id}]`, {hasText: regexNumber});
}`  
Run Code Online (Sandbox Code Playgroud)


小智 8

文本正文可以使用单引号或双引号进行转义,以搜索具有确切内容的文本节点

    pageNumberButton(page, table_id, page_number) {
       page.locator(`[aria-controls=${table_id}]`)
           .filter({ has: page.locator(`text="${page_number}"`) });
    }
Run Code Online (Sandbox Code Playgroud)


ggo*_*len 5

可以使用 进行精确匹配{exact: true}请参阅文档中的示例:

await expect(page.getByText('Welcome, John', { exact: true })).toBeVisible();
Run Code Online (Sandbox Code Playgroud)

请注意,这确实规范化空白,这可能是大多数情况下所需的行为,因此它并不像广告中那样“精确”。

适用于您的案例:

page
  .locator(`[aria-controls="${tableId}"]`)
  .getByText(pageNumber, {exact: true});
Run Code Online (Sandbox Code Playgroud)

只要将 CSS 和定位器分成两个调用并在选择器内使用引号,就可以text=像您尝试的那样在定位器中使用语法。应用于您的示例:text=text=""

page
  .locator(`[aria-controls="${table_id}"]`)
  .locator(`text="${page_number}"`);
Run Code Online (Sandbox Code Playgroud)

这是一个完整的、可运行的演示:

import {expect, test} from "@playwright/test"; // ^1.39.0

const html = `<!DOCTYPE html><html><body>
<div aria-controls="foo">1</div>
<div aria-controls="foo">13</div>
</body>
</html>`;

const pageNumberButton = (page, tableId, pageNumber) => {
  return page
    .locator(`[aria-controls="${tableId}"]`)
    .locator(`text="${pageNumber}"`);
};

test("aria-controls='foo' with text '1' is visible", async ({page}) => {
  await page.setContent(html);
  await expect(pageNumberButton(page, "foo", 1)).toBeVisible();
});
Run Code Online (Sandbox Code Playgroud)

忘记text=""语法中的引号是一个微妙的问题,这就是为什么我更喜欢更明确的getByText("...", {exact: true}).

[aria-controls="..."]在CSS 选择器和选择器上使用引号text=""

不要忘记函数return中的定位器pageNumberButton


另一种方法是:text-is("")伪选择器,它“将最小元素与精确文本匹配。精确匹配区分大小写,修剪空格并搜索完整字符串”,根据文档

page.locator(`[aria-controls="${tableId}"]:text-is("${pageNumber}")`);
Run Code Online (Sandbox Code Playgroud)

进一步说明:

  • 正则表达式是可能的,但如果可能的话我会避免这种情况,因为很容易忘记正则表达式特殊字符(如.被区别对待)并最终出现微妙的错误。
  • 一般来说,.filter()应尽可能避免。语法不如单个定位器链清晰。
  • CSS 属性不被认为是测试中的最佳实践,因此您可以考虑使用测试 id,或者更好的是,基于用户可见的属性进行定位。

  • 它并不能解决实际问题。该元素必须由 CSS select 和确切的文本找到。 (2认同)
  • 这不是 XY 问题 - 您正在寻找页面上唯一带有“1”的元素。“1”在页面中的元素中可能不是唯一的。例如,所需要的只是第二个分页控件,而现在有两个。aria-controls 细化是限制这种情况并保持选择器独特的好方法。我添加了一个“更简单、有效和直接”的答案,实际上解决了OP的问题。你的答案应该存在,但是“因此应该是被接受的答案”,当答案不能很好地解决原始问题时,奇怪的是它被投票了 5 次,这是错误的。 (2认同)