0

https://www.testim.io/blog/how-to-wait-for-a-page-to-load-in-selenium/

I want to understand how "Explicit Wait" is implemented under selenium. Can you show some example python code to demonstrate how selenium's "Explicit Wait" is implemented without using selenium?

Is the logic just wait for some time, then test for if an element is available, if not wait more time, check again, ..., until the element is available?

user1424739
  • 11,937
  • 17
  • 63
  • 152
  • 1
    Check out the [documentation](https://selenium-python.readthedocs.io/waits.html) as well. "By default, WebDriverWait calls the ExpectedCondition every 500 milliseconds until it returns success . . . An implicit wait tells WebDriver to poll the DOM for a certain amount of time when trying to find any element (or elements) not immediately available." – It_is_Chris Dec 15 '22 at 19:37
  • The `WebDriverWait` [source code](https://github.com/SeleniumHQ/selenium/blob/trunk/py/selenium/webdriver/support/wait.py) is pretty straight forward and may be helpful to understanding how it works. – It_is_Chris Dec 15 '22 at 19:47

1 Answers1

0

To understand explicit waits better, I found I needed to understand what's happening in the following:

  1. The expected condition function.
  2. The WebdriverWait.until method

The simplest expected condition is presence_of_element_located. It is just a wrapper around driver.find_element()

def presence_of_element_located(locator):
    def _predicate(driver):
        return driver.find_element(*locator)
    return _predicate

Other expected conditions will check the element for certain conditions but I'll keep this example simple.

The result of presence_of_element_located is passed into WebDriverWait.until, typically examples will look like this:

wait = WebDriverWait(driver, timeout=30)
element = wait.until(ec.presence_of_element_located((By.ID, "my_id")))

When I break down what's happening in the above it starts to become a little more clear.

a_callable_method = ec.presence_of_element_located((By.ID, "my_id"))

wait = WebDriverWait(driver, timeout=30)
element = wait.until(a_callable_method)

WebDriverWait.until is simply a while loop calling a_callable_method you passed in. The method/function we are passing in always takes driver as an argument.

    def until(self, method, message: str = ""):
        """Calls the method provided with the driver as an argument until the \
        return value does not evaluate to ``False``.

        :param method: callable(WebDriver)
        :param message: optional message for :exc:`TimeoutException`
        :returns: the result of the last call to `method`
        :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs
        """
        screen = None
        stacktrace = None

        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.monotonic() > end_time:
                break
        raise TimeoutException(message, screen, stacktrace)

In other words, explicit waiting is just a retry loop until a certain condition is met, or the timer runs out. In our example it's trying to find the element with id="my_id". If/when the element is found, it will be returned, otherwise a TimeoutException will be raised.


The real power of explicit wait starts to shine when looking at some of the other expected conditions:

def visibility_of(element):
    def _predicate(_):
        return _element_if_visible(element)
    return _predicate

def _element_if_visible(element, visibility=True):
    return element if element.is_displayed() == visibility else False

Using visibility_of will look for the element but then also check to see if the element has the condition consistent with being visible.

Marcel Wilson
  • 3,842
  • 1
  • 26
  • 55
  • In that sense, I can just use loop and implicit waiting which will achieve the exact result as explicit wait? In this sense, the interface to the explicit wait is more like a syntactic glue without offering something fundamentally new? – user1424739 Dec 15 '22 at 20:14
  • Are you looking for a reason _why_ you would want to use explicit waits? – Marcel Wilson Dec 15 '22 at 20:22
  • Unfortunately, trying to loop over implicit waiting doesn't work (at least not how you are expecting). I think https://stackoverflow.com/a/28067495/2532408 is a decent explanation. – Marcel Wilson Dec 15 '22 at 20:31
  • The differences mentioned there do not make sense to me. For example, It seems that everything, whether explicit or implicit waiting, run in the local code. But it says Explicit wait "runs in the local part of selenium", Implicit wait "runs in the remote part of selenium". – user1424739 Dec 15 '22 at 20:47
  • `Are you looking ...`: Yes. I want to use code that I know exactly what is going on. It looks to me they are just the same in terms of the underlying operations. But the Explicit wait's code is more bloated and harder to understand (e.g., people have to understand several classes involved, that is just extra burden to programmers). – user1424739 Dec 15 '22 at 20:49
  • implicit waits happen in the driver and have the possibility of changing which would require you to alter your tests. It's also global, so if you set the timeout to 30, you'll be waiting 30 seconds for ALL of your calls to `find_element`. – Marcel Wilson Dec 15 '22 at 20:53
  • I don't get it. What "driver"? Webdriver? I don't see webdriver allow such a test. – user1424739 Dec 15 '22 at 20:55
  • "harder to understand" is a little subjective. I personally don't think you're wrong there, but experience has shown that in the long run it's worth the extra effort. There are some ways to cut down on the bloated code and still use explicit waits. It's the balance between maintainable vs readable. – Marcel Wilson Dec 15 '22 at 20:57
  • Yes, `driver` == `WebDriver`. So in this case the implementation for implicit wait in Chrome could be different from Firefox or Edge. – Marcel Wilson Dec 15 '22 at 20:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/250446/discussion-between-marcel-wilson-and-user1424739). – Marcel Wilson Dec 15 '22 at 21:01