提问人:bee-anchor 提问时间:1/29/2022 更新时间:11/18/2023 访问量:21261
剧作家如何等待匹配多个元素的定位器不可见
Playwright how to wait for locator that matches multiple elements to not be visible
问:
我正在尝试等待一个元素,该元素指示页面仍在加载中,并且多次存在于页面上,不可见(想想带有加载数据占位符的表)。
Playwright 文档建议使用定位器是最佳实践,因此我最初尝试通过以下方式实现这一点:
locator.waitFor({state: "hidden")
但是,由于定位器很严格并且只允许匹配一个元素而导致的错误。
我现在使用以下代码来执行此操作:
page.waitForSelector(".foo .bar", {state: "hidden"})
由于以下几个原因,这是不理想的:
- 我将页面元素存储为页面对象模型中的定位器,您似乎无法访问定位器的选择器,这意味着选择器在代码中是重复的
- 我相信page.waitForSelector将使用不鼓励的ElementHandle
有没有办法关闭定位器上的严格约束?或者使用定位器实现此目的的方法。我知道您可以在匹配多个元素的定位器上执行此操作,但我还没有找到一种很好的方法将其与等待计数为 0 相结合。.count
答:
2赞
Oleksandr Pelykh
1/29/2022
#1
希望它会起作用
每次下一个元素消失时,此代码都会检查下一个元素
while (await page.locator('.foo .bar').first().isVisible()) { //do nothing }
评论
1赞
bee-anchor
1/31/2022
如果它们永远不会停止可见,这可能会让你陷入无限循环。我现在有一个使用函数的工作解决方案。evaluateAll
0赞
Vishal Aggarwal
3/27/2023
此解决方案也有效,为了避免在函数调用中传递无限循环超时。
0赞
bee-anchor
3/28/2023
@VishalAggarwal 在哪个函数调用中?
0赞
Vishal Aggarwal
3/31/2023
@bee锚点 while(await expect(page.locator(locator)).not.toBeVisible({timeout: 2000 })) { }
0赞
ggorlen
11/17/2023
在剧作家的断言中不需要循环。这里的循环基本上是一个令人困惑的空操作,因为如果定位器断言抛出,循环将不会重复。断言不是可以在这样的条件下测试的布尔值 - 如果它们失败,它们就会抛出。while
2赞
bee-anchor
1/31/2022
#2
我最终使用该方法将其工作。示例代码:evaluateAll
async waitForAllHidden(locator: Locator, timeout: number = 10000) {
const start = Date.now()
const elementsVisible = async () => (
await locator.evaluateAll(elements =>
elements.map(element => element.hidden))
).includes(false)
while (await elementsVisible()) {
if (start + timeout < Date.now()) {
throw (`Timeout waiting for all elements to be hidden.
Locator: ${locator}. Timeout: ${timeout}ms`);
}
}
console.log(`All elements hidden: ${locator}`)
}
2023 年更新:
现在有一些新的方法可用于此目的:
await expect(yourLocator).toHaveCount(0);
poll() 例如
await expect.poll(async () => {
for (const e of await yourLocator.all()) {
if (await e.isVisible()) return false
}
return true
}, {
message: 'youLocator is still visible', // optional custom error message
intervals: [1_000, 2_000, 10_000], // optional polling overrides
timeout: 10000, // optional timeout override
}).toBe(true);
评论
1赞
Vishal Aggarwal
3/27/2023
对于一个更简单的问题,这是一个有点复杂的解决方案。
1赞
bee-anchor
3/28/2023
同意,但当时没有更好的解决方案
1赞
ggorlen
11/17/2023
这不是推荐的解决方案。如果您正确使用其 API,则无需在 Playwright 中编写自定义超时或循环,例如 或 ,即使不可用。我建议将复选标记移到此答案并考虑删除。poll()
toPass()
toHaveCount()
0赞
bee-anchor
11/18/2023
poll()
(在 v1.21.0 中添加)和(在 v1.29.0 中添加)在我写这个问题时也不可用。请记住,Playwright 中现在可用的功能并不总是存在。我已经用当前的方法更新了答案。toPass()
3赞
Vishal Aggarwal
3/27/2023
#3
微调器或“..loading“文本元素是否存在无法验证 可以肯定的是,它可能会在页面加载期间出现,也可能不会出现,具体取决于 页面性能。
然而,它最终的消失是可以验证的。
使用 toHaveCount() (新增于: v1.20)
await expect(locator).toHaveCount(0,{timeout:5000});
超时: 为了避免无限循环,超时可以全局配置,也可以作为函数调用中的参数传递。
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
expect: {
timeout: 5000
},
});
提示:最好将本地超时保持在低于全局超时的水平,以避免任何竞争条件(如果两者都存在)。
参考: https://github.com/microsoft/playwright/issues/11988
评论