Dom*_*ino 6 javascript css-selectors e2e-testing playwright
我是开发新手,在创建一个 e2e 测试时面临着一个真正的问题。
基本上,我有一个包含 2 行或更多行的表格,每行有 5 列(标题、x、y、z 按钮)。如何使用标题单击正确行上的按钮?(这是为了证明这个表的删除过程有效的测试)。我正在测试的应用程序是用 React 框架编写的,因此所有表都会频繁更改,我需要一种信任代码并且没有任何错误的方法。
我需要单击此元素,但它始终不在同一位置
超文本标记语言
<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>
Run Code Online (Sandbox Code Playgroud)
这是我遇到的解决方案
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"
);
Run Code Online (Sandbox Code Playgroud)
期望的行为
我的代码似乎没有遵循最佳实践,我需要一个将其分为两部分的解决方案。
1 - 将正确的行保存到变量中
2 - 单击已保存行中包含的按钮
小智 11
使用以下选择器组合可以可靠地单击右侧按钮。
const row = await page.waitForSelector('*css=tr >> text=Some title');
const button = await row.$('button');
await button.click();
Run Code Online (Sandbox Code Playgroud)
Playwright 是一个很棒的工具,可能是迄今为止最好的网络自动化工具之一。但需要正确使用。
const row = await page.waitForSelector('*css=tr >> text=Some title');
Run Code Online (Sandbox Code Playgroud)
tr该行指示 Playwright在页面中查找包含文本内容与字符串匹配的元素的元素Some title。
该表达式由两个单独的选择器组成,即css=tr和text=Some title。
第一个将使用css选择器引擎并且仅针对所有tr元素。第二个使用text引擎来匹配文本内容。
指示>>Playwright 将两个选择器合并为一个。这是通过首先评估来实现的css=tr。在第一个选择器的每个匹配元素上应用第二个选择器。
通常,组合选择器返回最右边选择器的结果:
tr >> text=Some title将为您提供 element <td>Some Title</td>。但是可以用 标记所需的选择器*(同时仍然使用所有组合选择器缩小结果范围)。
注意:星号强制*要求显式指定选择器引擎 ( css=),否则 Playwright 会猜测错误的引擎。
const button = await row.$('button');
Run Code Online (Sandbox Code Playgroud)
一旦我们找到了正确的行,在这种情况下选择按钮就更容易了。一个简单的查询选择器 ( $) 就足够了,因为它是一行中存在的唯一按钮元素。
调用$on row(而不是page)将仅匹配 DOM 子树中的元素row。这与组合匹配器的工作原理完全相同。
下一节将解释为什么步骤 1 必须使用waitForSelector().
就像你的例子一样,许多网站都是动态的。这意味着当使用自动脚本在页面中查找内容时,您将遇到计时问题:当 Playwright 搜索所需内容时,表格可能尚未呈现。更糟糕的是,如果它在您的计算机上运行,则可能会在几周后在另一台计算机上失败。
这就是为什么查看与网页交互的每一行并确定是否存在需要考虑的时间问题很重要。
一些 Playwright 方法将定期探测选择器以进行匹配,并且仅在特定超时后失败。其他人不会等待并立即失败。
有时,方法会在其名称中指示它们是否正在等待(例如page.waitForSelector())。但情况并非总是如此(例如elementHandle.click()实际上正在等待)。
因此,必须仔细查看API 参考并阅读说明。
现在回到示例:
在步骤 1 中,我们必须使用等待方法,因为我们不知道动态表何时实际呈现到页面。在步骤 2 中,不需要使用等待方法,因为我们可以确定步骤 1 成功后该表存在于页面中。