How to create a custom expected condition

First , We need to understand how an existing expected condition works.

A example when we use an explicitly wait as below:

wait = WebDriverWait(self.driver, timeout)
element = wait.until(EC.visibility_of_element_located(tuple_selector))

Let’s take a look on a expected condition already existed in Selenium API:


class visibility_of_element_located(object):

    def __init__(self, locator):
        self.locator = locator

    def __call__(self, driver):
        try:
              return _element_if_visible(_find_element(driver, self.locator))
       except StaleElementReferenceException:
             return False


def until(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is not False."""
screen = None
stacktrace = None

end_time = time.time() + 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.time() > end_time:
        break
    raise TimeoutException(message, screen, stacktrace)

You see that an expected condition above needs both magic methods __init__ and __call__.

Firstly , when we call: EC.visibility_of_element_located(tuple_selector) , it will create a instance of Class visibility_of_element_located , this is when __init__(self, selector) is executed. object variable self.locator = locator. 

And in until method, each time the method is called (value = method(self._driver)) , it actually executes the code in __call__(self, driver) of Class visibility_of_element_located.

So , when understand it , we can create a new expected condition as below. You need pass all needed arguments in __init__ like by, locator, attribute, attribute value.

class ElementAttributeToBe(object):
    def __init__(self, tuple_selector, attribute, value):
        self.by = tuple_selector[0]
        self.locator = tuple_selector[1]
        self.attribute = attribute
        self.value = value

    def __call__(self, driver):
        web_element = driver.find_element(self.by, self.locator)
        if web_element.get_attribute(self.attribute) == self.value:
            return web_element
        return False

 

Leave a comment