I got this working in the end using the evaluateAll method. Example code:
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}`)
}
Update for 2023:
There are new methods available which can now be used for this purpose:
toHaveCount() e.g.
await expect(yourLocator).toHaveCount(0);
poll() e.g.
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);
Answer from bee-anchor on Stack OverflowAnyone annoyed by locator strictness in playwright?
[Question] Is there way to iterate the Locator elements?
How do I use the all() method to iterate over multiple elements in Playwright?
How to deal with multiple elements found error?
Videos
I got this working in the end using the evaluateAll method. Example code:
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}`)
}
Update for 2023:
There are new methods available which can now be used for this purpose:
toHaveCount() e.g.
await expect(yourLocator).toHaveCount(0);
poll() e.g.
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);
Spinner or an "..loading" text element's presence cannot be verified for sure as it may or may not appear during page load depending on page performance .
However , it's eventual disappearance can be verified.
Use toHaveCount() (Added in: v1.20)
await expect(locator).toHaveCount(0,{timeout:5000});
Timeout: To avoid infinite loops timeout can be configured globally or passed as an parameter in the function call.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
expect: {
timeout: 5000
},
});
Tip: Its better to keep local timeouts lower than global timeout to avoid any race conditions if both exist.
Reference: https://github.com/microsoft/playwright/issues/11988
https://stackoverflow.com/a/74209034/1831456
How can I assert that an element is NOT on the page in playwright?
I came from selenium where i would constantly use findelements then foreach thru the results to assert against many elements in a loop rather than doing 1 at a time. I realize that you can get multiple elements with a locator in playwright but the result isn’t enumerable so i have to jump thru more hoops to loop over multiple elements. Im also not sure how to disable strictness, but pretty sure it wouldn’t makw a difference. Am i missing something?
I am switching from Selenium to Playwright and I am creating python behave POM framework.
MY problem is that the page tested has multiple elements (doing exactly the same) with absolutely nothing unique and devs refuse to help me. So I need to collect all found elements and say to use one of them. Here is the function in base class:
def find_element(self, locator):
elements = self.context.page.locator(locator).all()
if elements:
if len(elements) == 1:
return elements[0]
else:
return elements[1]
else:
raise Exception(f'No elements found with locator {locator}!')
However, using this function in page classes, does not benefit from Playwright auto waiting for elements and my tests fail with the exception, unless I manually put sleeps in the code.
Is there any way I can keep the workaround for dealing with no unique elements but still benefit from auto waiting?