WebDriver’s implicit wait and deleting elements

WebDriver has introduced implicit waits on functions like find_element. That means that when WebDriver cannot find an element, it will automatically wait for a defined amount of time for it to appear. 10 seconds is the default duration.

This is very useful behaviour and makes dealing with ambiguous page load events and dynamic elements far more tolerable; where it seems obvious to a human that the test should wait briefly then WebDriver does exactly that. Tests are now more patient and durable throughout tests on dynamic webpages.

However with Selenium RC and Selenium IDE we became quite used to using methods like is_element_present and wait_for_element_present to deal with Ajax and page loading events. With WebDriver we have to write them ourselves.

Checking an element is not present
When dealing with Ajax or javascript we might want to wait until an element is not present, when an element is being deleted, for example. Trying to find an element after it has been deleted will cause WebDriver to implicitly wait for the element to appear. This is not WebDriver’s fault. It’s doing the right thing, but we need to tell it not to implicitly wait just for this moment otherwise we will waste time waiting when we don’t need to. This time can really add up if you check a few times in each test.

The Web QA team has written its own is_element_present method for WebDriver:

def is_element_present(self, *locator):
    self.selenium.implicitly_wait(0)
    try:
        self.selenium.find_element(*locator)
        return True
    except NoSuchElementException:
        return False
    finally:
        # set back to where you once belonged
        self.selenium.implicitly_wait(default_implicit_wait)

There are 4 important things going on here. In order:

  1. Setting implicity_wait to 0 so that WebDriver does not implicitly wait.
  2. Returning True when the element is found.
  3. Catching the NoSuchElementException and returning False when we discover that the element is not present instead of stopping the test with an exception.
  4. Setting implicitly_wait back to 10 after the action is complete so that WebDriver will implicitly wait in future.

(Note that we have previously stored the default implicit wait value in the default_implicit_wait variable)

You may use this in logic but we mostly use this in WebDriverWait. It is important for bypassing WebDriverWait’s catching of the ElementNotFoundException:
WebDriverWait(self.selenium, 10).until(lambda s: not self.is_element_present((By.ID, ‘delete-me’)))

This method works well and most importantly the implicit wait is not triggered meaning your test does not needlessly wait!

6 comments on “WebDriver’s implicit wait and deleting elements”

Post a comment

  1. Titus wrote on

    Couldn’t you do the same thing with-

    def is_element_present(self, *locator):
    self.selenium.find_elements(*locator).length > 0

    You wouldn’t need to change the implicit wait or catch any exceptions

    Reply

    1. zcampbell wrote on

      Hi Titus, you certainly could do that but find_elements does implicitly wait aswell.

      Reply

      1. Titus wrote on

        Excellent, I didn’t realize that. Thanks!

        Reply

    2. Smithe850 wrote on

      Wow, fantastic blog layout! How long have you been blogging for? you made blogging look easy. The overall look of your web site is wonderful, let alone the content! kfbddedkccaakgdc

      Reply

  2. mam-p wrote on

    Don’t you find a need to call is_element_present() sometimes when waiting is needed? I’m contemplating a Boolean second argument named “wait” for this purpose but would like to hear how Mozilla handled this….

    Reply

    1. Zac Campbell wrote on

      Hi mam-p, by calling find_element and checking an attribute you do the same thing as `is_element_present()`.

      We prefer to keep `is_present` and `wait_for` methods separate as they are often used in different circumstances.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *