Search code examples
pythonplaywrightplaywright-python

Waiting for a visible locator returns a non-clickable element


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?


Solution

  • 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