Sam
Sam

Reputation: 654

Selenium: Expected conditions for explicit waiting using WebElement

Selenium offers explicit wait functionality to handle situations (for example) when you want to execute a click() operation on an element which is not yet clickable.

The syntax is as follows:

WebDriverWait(self._driver, 20).until(EC.element_to_be_clickable(BY.ID, 'some-id')).click()

This tells the program to wait until some element (located by its ID) is clickable.

Under the hood, EC.element_to_be_clickable() calls an internal _find_element() function reading in the parameters specified by element_to_be_clickable().. In this case, it searches the DOM for elements corresponding with the ID: some-id.

I cant however, directly pass in a WebElement object into the element_to_be_clickable() function because it fails in the internal _find_element() call.

Is there a way I can use these explicit waits (or any alternatives) while working with the WebElements themselves?

My initial thought is I can download the code and add functionality to bypass the _find_element() under certain conditions but wondering if anyone else has had this issue.

Thanks in advance.

Upvotes: 1

Views: 444

Answers (1)

Todor Minakov
Todor Minakov

Reputation: 20067

You could, stretching the WebDriverWait operations a bit - by passing to it not a driver object, but the element itself, and a lambda function to the until().

As you've seen in its code, the "meat" of WebDriverWait's until() is to call the passed function with an argument the passed object, and return the outcome:

value = method(self._driver)
if value:
    return value

So in theory, you could pass the element itself, and as a function to have an expression that returns the element if all checks are matching, or False if not.
The original element_to_be_clickable expects two things out of the element (apart from it to be present) - is_displayed() and is_enabled(). Thus the expression, inside a lambda, would be:

lambda x: x if x.is_displayed() and x.is_enabled() else False

And the whole call would he:

WebDriverWait(self.your_webelemt_object, 20).until(lambda x: x if x.is_displayed() and x.is_enabled() else False).click()

I said "in theory", causes I'm typing this on mobile :), and I haven't checked it in practice (but the theoery is solid ;). What could go wrong? An exception to be raised, that is different from what WebDriverWait normally handles (it handles during the waits just NoSuchElementException, by default). If that's the case, you have to pass those additional exceptions to its constructor:

WebDriverWait(self.your_webelemt_object, 20, ignored_exceptions=[NoSuchElementException, the_other_exceptions]).  # the rest omitted for brevity

Upvotes: 1

Related Questions