Playwright 中有没有办法在动态表格中选择特定按钮?

时间:2021-01-12 18:19:06

标签: javascript css-selectors e2e-testing playwright

我是开发新手,我在创建一个 e2e 测试时遇到了真正的问题。
基本上,我有一个包含 2 行或更多行的表格,每行有 5 列(标题、x、y、z 按钮)。 如何使用标题单击正确行上的按钮? (这是为了证明这个表的删除过程有效的测试)。 我正在测试的应用程序是用 React 框架编写的,因此所有表都经常更改,我需要一种方法来信任代码并且没有任何错误。 I need to click this element but it is not ever in the same position

HTML

<table>
    <tr>
     <td>Some Title</td>
     <td>x</td>
     <td>y</td>
     <td>
       <button>I need to click this</button>
    </td>
    </tr>
    <!--other rows--!>
</table>  

这是我遇到的解决方案

const rows = await page.$$eval("tr", (row) =>
    row.map((e) => e.textContent)
);
const correctRowIndex = rows.findIndex((e) => e.includes(TITLE_I_KNOW));
await page.click(
    "//tr[normalize-space(.)='" + rows[correctRowIndex] + "']/td/button"
);

期望的行为

我的代码似乎没有遵循最佳实践,我需要一个解决方案,将这件事分成两部分。
1 - 将正确的行保存到变量中
2 - 单击已保存行中包含的按钮

1 个答案:

答案 0 :(得分:1)

快速回答

使用以下选择器组合来可靠地单击右键。

const row = await page.waitForSelector('*css=tr >> text=Some title');
const button = await row.$('button');
await button.click();

深入讲解

Playwright 是一个很棒的工具,可能是迄今为止最好的网络自动化工具之一。但需要正确使用。

1.选择正确的行

const row = await page.waitForSelector('*css=tr >> text=Some title');

此行指示 Playwright 在页面中查找包含文本内容与字符串 tr 匹配的元素的 Some title 元素。

该表达式由两个独立的选择器组成,即 css=trtext=Some title

第一个将使用 css 选择器引擎并且只针对所有 tr 元素。第二个使用 text 引擎从而匹配文本内容。

>> 指示 Playwright 将两个选择器合二为一。这是通过评估第一个 css=tr 来工作的。在第一个选择器的每个匹配元素上应用第二个选择器。

通常组合选择器返回最右边选择器的结果: tr >> text=Some title 会给你元素 <td>Some Title</td>。 但是可以使用 * 标记所需的选择器(同时仍然使用所有组合选择器缩小结果范围)。

注意:星号 * 强制要求明确指定选择器引擎 (css=),否则 Playwright 会猜错引擎。

Here you can read more about Playwright selectors.

2.选择按钮

const button = await row.$('button');

一旦我们有了正确的行,在这种情况下选择按钮就更容易了。一个简单的查询选择器 ($) 就足够了,因为它是一行中唯一存在的按钮元素。

$ 上调用 row(而不是 page)将仅匹配 row 的 DOM 子树中的元素。这与组合匹配器完全一样。

下一部分解释为什么第 1 步必须使用 waitForSelector()


合适的时机

就像您的示例一样,许多网站都是动态的。这意味着在使用自动脚本查找页面中的内容时会遇到计时问题:当 Playwright 搜索所需内容时,表格可能尚未呈现。更糟糕的是,如果它在您的计算机上运行,​​它可能会在数周后在另一台计算机上失败。

这就是为什么查看与网页交互的每一行并确定是否存在需要考虑的时间问题很重要的原因。

某些 Playwright 方法会定期探测选择器是否匹配,并且只会在特定超时后失败。其他人不会等待并立即失败。

有时方法会在它们的名称中指明它们是否在等待(例如 page.waitForSelector())。但情况并非总是如此(例如,elementHandle.click() 实际上在等待)。

因此必须查看 API reference 并仔细阅读说明。

现在回到例子:
在步骤 1 中,我们不得不使用等待方法,因为我们不知道动态表何时真正呈现到页面上。在第 2 步中不需要使用等待方法,因为我们可以确定在第 1 步成功后该表存在于页面中。