Together with my tech lead, we implemented this method:
def get_visible_locator(self, selector):
locators = self.page.query_selector_all(selector)
for locator in locators:
if locator.is_visible():
return locator
else:
raise Exception('Can not find visible object with given selector:'
f' {selector}')
Calling the method sometimes fails:
self.get_visible_locator('text="Select All"').click(timeout=1000)
One workaround is using sleep of 2 seconds before calling the method, but my tech lead doesn't like this.
How to return the first visible and clickable / enabled element?
The misconception here seems to be that visible == clickable
. That is not the case. In fact the docs explain what exact actionability checks are performed that determines whether the element is clickable
For example, for page.click(selector, **kwargs), Playwright will ensure that:
element is Attached to the DOM
element is Visible
element is Stable, as in not animating or completed animation
element Receives Events, as in not obscured by other elements
element is Enabled
Functionality to check whether all this is True for any element is currently not exposed in playwright (specifically, for checking whether the element is stable and reactive). The best you can do is change if locator.is_visible()
to if locator.is_visible() and locator.is_enabled()
to additionally check whether it is enabled as well (which would be done as part of the actionability checks later).
You can track the relevant issue here