CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-selenium

Python bindings for Selenium WebDriver providing automated browser control for multiple browsers including Chrome, Firefox, Edge, Safari, and Internet Explorer

Pending
Overview
Eval results
Files

waits-conditions.mddocs/

WebDriverWait and Expected Conditions

This document covers WebDriverWait and Expected Conditions in Python Selenium WebDriver, which provide mechanisms for handling dynamic web content by waiting for specific conditions to be met before proceeding with test execution.

WebDriverWait Class

{ .api }

from selenium.webdriver.support.ui import WebDriverWait

class WebDriverWait(Generic[D]):
    def __init__(
        self,
        driver: Union[WebDriver, WebElement],
        timeout: float,
        poll_frequency: float = 0.5,
        ignored_exceptions: Optional[WaitExcTypes] = None,
    )

Description: WebDriverWait implements explicit waits that pause execution until a certain condition is met or a timeout occurs.

Parameters:

  • driver: Instance of WebDriver (Chrome, Firefox, etc.) or a WebElement
  • timeout: Number of seconds before timing out
  • poll_frequency: Sleep interval between calls (default: 0.5 seconds)
  • ignored_exceptions: Iterable of exception classes to ignore during calls (default: NoSuchElementException)

Default Values:

  • POLL_FREQUENCY: 0.5 seconds
  • IGNORED_EXCEPTIONS: (NoSuchElementException,)

Example:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# Basic wait setup
wait = WebDriverWait(driver, 10)

# Wait with custom poll frequency
fast_wait = WebDriverWait(driver, 5, poll_frequency=0.1)

# Wait with custom ignored exceptions
from selenium.common.exceptions import ElementNotVisibleException
custom_wait = WebDriverWait(
    driver, 
    10, 
    ignored_exceptions=(ElementNotVisibleException, NoSuchElementException)
)

WebDriverWait Methods

until() Method

{ .api }

def until(
    self,
    method: Callable[[D], Union[Literal[False], T]],
    message: str = ""
) -> T

Description: Waits until the method returns a value that is not False.

Parameters:

  • method: A callable that takes a WebDriver instance and returns a truthy value when the condition is met
  • message: Optional message for TimeoutException

Returns: The result of the last call to method

Raises:

  • TimeoutException: If 'method' does not return a truthy value within the timeout

Example:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Wait for element to be visible
wait = WebDriverWait(driver, 10)
element = wait.until(
    EC.visibility_of_element_located((By.ID, "myElement"))
)

# Wait with custom message
element = wait.until(
    EC.element_to_be_clickable((By.ID, "submit-btn")),
    "Submit button did not become clickable"
)

until_not() Method

{ .api }

def until_not(
    self,
    method: Callable[[D], T],
    message: str = ""
) -> Union[T, Literal[True]]

Description: Waits until the method returns a value that evaluates to False.

Parameters:

  • method: A callable that takes a WebDriver instance as an argument
  • message: Optional message for TimeoutException

Returns: The result of the last call to method or True if an ignored exception occurred

Raises:

  • TimeoutException: If 'method' does not return False within the timeout

Example:

# Wait for element to disappear
wait = WebDriverWait(driver, 10)
is_disappeared = wait.until_not(
    EC.visibility_of_element_located((By.ID, "loading-spinner"))
)

# Wait for element to become stale
old_element = driver.find_element(By.ID, "dynamic-content")
# Trigger page refresh or DOM change
refresh_button.click()
wait.until_not(EC.staleness_of(old_element))

Expected Conditions Module

Expected Conditions provide pre-built condition functions for common waiting scenarios.

from selenium.webdriver.support import expected_conditions as EC

Page and URL Conditions

Title Conditions

{ .api }

def title_is(title: str) -> Callable[[WebDriver], bool]

Description: An expectation for checking the title of a page.

Parameters:

  • title: The expected title (exact match)

Returns: True if the title matches, False otherwise

{ .api }

def title_contains(title: str) -> Callable[[WebDriver], bool]

Description: An expectation for checking that the title contains a case-sensitive substring.

Parameters:

  • title: The fragment of title expected

Returns: True when the title contains the substring, False otherwise

Example:

# Wait for exact title
wait.until(EC.title_is("Welcome to My Site"))

# Wait for title to contain text
wait.until(EC.title_contains("Dashboard"))

URL Conditions

{ .api }

def url_contains(url: str) -> Callable[[WebDriver], bool]

Description: An expectation for checking that the current URL contains a case-sensitive substring.

Parameters:

  • url: The fragment of URL expected

Returns: True when the URL contains the substring, False otherwise

{ .api }

def url_matches(pattern: str) -> Callable[[WebDriver], bool]

Description: An expectation for checking that the current URL matches a regular expression pattern.

Parameters:

  • pattern: The regex pattern to match

Returns: True when the URL matches the pattern, False otherwise

{ .api }

def url_to_be(url: str) -> Callable[[WebDriver], bool]

Description: An expectation for checking the current URL.

Parameters:

  • url: The expected URL (exact match)

Returns: True if the URL matches, False otherwise

{ .api }

def url_changes(url: str) -> Callable[[WebDriver], bool]

Description: An expectation for checking that the current URL does not match the given URL.

Parameters:

  • url: The URL to compare against

Returns: True if current URL is different, False otherwise

Example:

# Wait for URL to contain specific path
wait.until(EC.url_contains("/dashboard"))

# Wait for URL to match pattern
wait.until(EC.url_matches(r"https://.*\.example\.com/user/\d+"))

# Wait for navigation to complete
current_url = driver.current_url
login_button.click()
wait.until(EC.url_changes(current_url))

Element Presence and Visibility

Element Presence

{ .api }

def presence_of_element_located(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], WebElement]

Description: An expectation for checking that an element is present on the DOM. This does not necessarily mean that the element is visible.

Parameters:

  • locator: Used to find the element (By strategy, value)

Returns: The WebElement once it is located

{ .api }

def presence_of_all_elements_located(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], List[WebElement]]

Description: An expectation for checking that there is at least one element present on a web page.

Parameters:

  • locator: Used to find the elements

Returns: List of WebElements once they are located

Example:

# Wait for single element to be present in DOM
element = wait.until(
    EC.presence_of_element_located((By.ID, "content"))
)

# Wait for multiple elements to be present
elements = wait.until(
    EC.presence_of_all_elements_located((By.CLASS_NAME, "item"))
)

Element Visibility

{ .api }

def visibility_of_element_located(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], WebElement]

Description: An expectation for checking that an element is present on the DOM and visible. Visibility means that the element is not only displayed but also has a height and width greater than 0.

Parameters:

  • locator: Used to find the element

Returns: The WebElement once it is located and visible

{ .api }

def visibility_of(element: WebElement) -> Callable[[Any], Union[Literal[False], WebElement]]

Description: An expectation for checking that an element, known to be present on the DOM, is visible.

Parameters:

  • element: The WebElement to check

Returns: The WebElement if visible, False otherwise

{ .api }

def visibility_of_all_elements_located(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], List[WebElement]]

Description: An expectation for checking that all elements are present on the DOM and visible.

Parameters:

  • locator: Used to find the elements

Returns: List of WebElements once they are located and visible

{ .api }

def visibility_of_any_elements_located(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], List[WebElement]]

Description: An expectation for checking that there is at least one element visible on a web page.

Parameters:

  • locator: Used to find the elements

Returns: List of visible WebElements

Example:

# Wait for element to be visible
visible_element = wait.until(
    EC.visibility_of_element_located((By.ID, "modal"))
)

# Wait for existing element to become visible
element = driver.find_element(By.ID, "hidden-content")
visible_element = wait.until(EC.visibility_of(element))

# Wait for all matching elements to be visible
all_visible = wait.until(
    EC.visibility_of_all_elements_located((By.CLASS_NAME, "menu-item"))
)

# Wait for any matching elements to be visible
any_visible = wait.until(
    EC.visibility_of_any_elements_located((By.TAG_NAME, "button"))
)

Element Invisibility

{ .api }

def invisibility_of_element_located(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], Union[WebElement, bool]]

Description: An expectation for checking that an element is either invisible or not present on the DOM.

Parameters:

  • locator: Used to find the element

Returns: WebElement if invisible, True if not present

{ .api }

def invisibility_of_element(
    element: WebElement
) -> Callable[[Any], Union[WebElement, bool]]

Description: An expectation for checking that an element is either invisible or not present on the DOM.

Parameters:

  • element: The WebElement to check

Returns: WebElement if invisible, True if not present

Example:

# Wait for loading spinner to disappear
wait.until(
    EC.invisibility_of_element_located((By.ID, "loading-spinner"))
)

# Wait for specific element to become invisible
modal = driver.find_element(By.ID, "error-modal")
close_button.click()
wait.until(EC.invisibility_of_element(modal))

Element Interaction Conditions

Clickability

{ .api }

def element_to_be_clickable(
    mark: Union[WebElement, Tuple[str, str]]
) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]

Description: An expectation for checking an element is visible and enabled such that you can click it.

Parameters:

  • mark: WebElement or locator tuple (By strategy, value)

Returns: The WebElement once it is clickable, False otherwise

Example:

# Wait for button to be clickable
clickable_button = wait.until(
    EC.element_to_be_clickable((By.ID, "submit-btn"))
)
clickable_button.click()

# Wait for existing element to be clickable
button = driver.find_element(By.ID, "action-btn")
wait.until(EC.element_to_be_clickable(button))

Element Selection State

{ .api }

def element_to_be_selected(element: WebElement) -> Callable[[Any], bool]

Description: An expectation for checking that an element is selected.

Parameters:

  • element: The WebElement to check

Returns: True if the element is selected, False otherwise

{ .api }

def element_located_to_be_selected(
    locator: Tuple[str, str]
) -> Callable[[WebDriverOrWebElement], bool]

Description: An expectation for the element to be located and selected.

Parameters:

  • locator: Used to find the element

Returns: True if the element is selected, False otherwise

{ .api }

def element_selection_state_to_be(
    element: WebElement,
    is_selected: bool
) -> Callable[[Any], bool]

Description: An expectation for checking if the given element's selection state matches the expected state.

Parameters:

  • element: The WebElement to check
  • is_selected: Expected selection state

Returns: True if the element's selection state matches, False otherwise

{ .api }

def element_located_selection_state_to_be(
    locator: Tuple[str, str],
    is_selected: bool
) -> Callable[[WebDriverOrWebElement], bool]

Description: An expectation to locate an element and check if its selection state matches the expected state.

Parameters:

  • locator: Used to find the element
  • is_selected: Expected selection state

Returns: True if the element's selection state matches, False otherwise

Example:

# Wait for checkbox to be selected
checkbox = driver.find_element(By.ID, "agree-terms")
wait.until(EC.element_to_be_selected(checkbox))

# Wait for element to be found and selected
wait.until(
    EC.element_located_to_be_selected((By.ID, "default-option"))
)

# Wait for specific selection state
wait.until(
    EC.element_selection_state_to_be(checkbox, True)
)

# Wait for located element to have specific selection state
wait.until(
    EC.element_located_selection_state_to_be((By.ID, "toggle"), False)
)

Text and Attribute Conditions

Text Presence

{ .api }

def text_to_be_present_in_element(
    locator: Tuple[str, str],
    text_: str
) -> Callable[[WebDriverOrWebElement], bool]

Description: An expectation for checking if the given text is present in the specified element.

Parameters:

  • locator: Used to find the element
  • text_: The text to check for

Returns: True if text is present, False otherwise

{ .api }

def text_to_be_present_in_element_value(
    locator: Tuple[str, str],
    text_: str
) -> Callable[[WebDriverOrWebElement], bool]

Description: An expectation for checking if the given text is present in the element's value attribute.

Parameters:

  • locator: Used to find the element
  • text_: The text to check for in the value attribute

Returns: True if text is present in value, False otherwise

{ .api }

def text_to_be_present_in_element_attribute(
    locator: Tuple[str, str],
    attribute_: str,
    text_: str
) -> Callable[[WebDriverOrWebElement], bool]

Description: An expectation for checking if the given text is present in the element's specified attribute.

Parameters:

  • locator: Used to find the element
  • attribute_: The attribute to check
  • text_: The text to check for in the attribute

Returns: True if text is present in attribute, False otherwise

Example:

# Wait for text to appear in element
wait.until(
    EC.text_to_be_present_in_element(
        (By.ID, "status"), "Operation completed"
    )
)

# Wait for text in input value
wait.until(
    EC.text_to_be_present_in_element_value(
        (By.ID, "search-box"), "selenium"
    )
)

# Wait for text in custom attribute
wait.until(
    EC.text_to_be_present_in_element_attribute(
        (By.ID, "progress"), "data-status", "finished"
    )
)

Attribute Conditions

{ .api }

def element_attribute_to_include(
    locator: Tuple[str, str],
    attribute_: str
) -> Callable[[WebDriverOrWebElement], bool]

Description: An expectation for checking if the element has a particular attribute.

Parameters:

  • locator: Used to find the element
  • attribute_: The attribute to check for

Returns: True if the attribute is present, False otherwise

Example:

# Wait for element to have specific attribute
wait.until(
    EC.element_attribute_to_include(
        (By.ID, "upload-btn"), "disabled"
    )
)

Advanced Conditions

Staleness

{ .api }

def staleness_of(element: WebElement) -> Callable[[Any], bool]

Description: Wait until an element is no longer attached to the DOM.

Parameters:

  • element: The element to wait for

Returns: False if the element is still attached, True otherwise

Example:

# Store reference to element before DOM change
old_element = driver.find_element(By.ID, "dynamic-content")

# Trigger page refresh or dynamic update
refresh_button.click()

# Wait for old element to become stale
wait.until(EC.staleness_of(old_element))

# Now safe to find the new element
new_element = driver.find_element(By.ID, "dynamic-content")

Frame Switching

{ .api }

def frame_to_be_available_and_switch_to_it(
    locator: Union[Tuple[str, str], str]
) -> Callable[[WebDriver], bool]

Description: An expectation for checking whether the given frame is available to switch to. If the frame is available, it switches to it.

Parameters:

  • locator: Either a frame name/id (string) or a locator tuple

Returns: True if the frame was switched to, False otherwise

Example:

# Wait for frame to be available and switch to it
wait.until(
    EC.frame_to_be_available_and_switch_to_it("payment-frame")
)

# Or using locator
wait.until(
    EC.frame_to_be_available_and_switch_to_it(
        (By.ID, "checkout-iframe")
    )
)

# Interact with frame content
frame_button = driver.find_element(By.ID, "pay-now")
frame_button.click()

# Switch back to default content
driver.switch_to.default_content()

Window Management

{ .api }

def number_of_windows_to_be(num_windows: int) -> Callable[[WebDriver], bool]

Description: An expectation for the number of windows to be a certain value.

Parameters:

  • num_windows: The expected number of windows

Returns: True when the number of windows matches, False otherwise

{ .api }

def new_window_is_opened(current_handles: List[str]) -> Callable[[WebDriver], bool]

Description: An expectation that a new window will be opened and have the number of windows handles increase.

Parameters:

  • current_handles: List of current window handles

Returns: True when a new window is opened, False otherwise

Example:

# Store current window handles
current_handles = driver.window_handles

# Click link that opens new window
external_link.click()

# Wait for new window to open
wait.until(EC.new_window_is_opened(current_handles))

# Switch to new window
new_handles = driver.window_handles
new_window = [h for h in new_handles if h not in current_handles][0]
driver.switch_to.window(new_window)

# Wait for specific number of windows
wait.until(EC.number_of_windows_to_be(3))

Alert Handling

{ .api }

def alert_is_present() -> Callable[[WebDriver], Union[Alert, Literal[False]]]

Description: An expectation for checking that an alert is present.

Returns: Alert object if present, False otherwise

Example:

# Trigger alert
delete_button.click()

# Wait for alert and handle it
alert = wait.until(EC.alert_is_present())
alert_text = alert.text
alert.accept()  # or alert.dismiss()

Logical Conditions

any_of()

{ .api }

def any_of(*expected_conditions: Callable[[D], T]) -> Callable[[D], Union[Literal[False], T]]

Description: An expectation that any of multiple expected conditions is true. Equivalent to a logical OR.

Parameters:

  • *expected_conditions: Variable number of expected condition functions

Returns: The result of the first condition that evaluates to True, False if none do

Example:

# Wait for either success or error message
result = wait.until(
    EC.any_of(
        EC.visibility_of_element_located((By.ID, "success-message")),
        EC.visibility_of_element_located((By.ID, "error-message"))
    )
)

# Check which condition was met
if result.get_attribute("id") == "success-message":
    print("Operation succeeded")
else:
    print("Operation failed")

all_of() (Custom Implementation)

While not built into Selenium, you can create an all_of condition:

def all_of(*expected_conditions):
    """Wait for all conditions to be true"""
    def _predicate(driver):
        results = []
        for condition in expected_conditions:
            result = condition(driver)
            if not result:
                return False
            results.append(result)
        return results
    return _predicate

# Usage
wait.until(
    all_of(
        EC.visibility_of_element_located((By.ID, "form")),
        EC.element_to_be_clickable((By.ID, "submit")),
        EC.text_to_be_present_in_element((By.ID, "status"), "Ready")
    )
)

Custom Expected Conditions

You can create custom expected conditions by following the same pattern:

def element_has_css_class(locator, css_class):
    """Wait for element to have a specific CSS class"""
    def _predicate(driver):
        try:
            element = driver.find_element(*locator)
            classes = element.get_attribute("class")
            return css_class in classes.split() if classes else False
        except:
            return False
    return _predicate

def page_source_contains(text):
    """Wait for page source to contain specific text"""
    def _predicate(driver):
        return text in driver.page_source
    return _predicate

def element_count_to_be(locator, count):
    """Wait for specific number of elements"""
    def _predicate(driver):
        elements = driver.find_elements(*locator)
        return len(elements) == count
    return _predicate

# Usage
wait.until(element_has_css_class((By.ID, "status"), "active"))
wait.until(page_source_contains("Welcome"))
wait.until(element_count_to_be((By.CLASS_NAME, "item"), 5))

Best Practices and Examples

1. Combine Multiple Conditions

def wait_for_form_ready(driver):
    """Wait for form to be completely ready for interaction"""
    wait = WebDriverWait(driver, 10)
    
    # Wait for form to be visible
    form = wait.until(
        EC.visibility_of_element_located((By.ID, "registration-form"))
    )
    
    # Wait for all required fields to be present
    wait.until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, "input[required]"))
    )
    
    # Wait for submit button to be clickable
    wait.until(
        EC.element_to_be_clickable((By.ID, "submit-btn"))
    )
    
    return form

2. Handle Dynamic Content

def wait_for_search_results(driver, search_term):
    """Wait for search results to load and contain expected content"""
    wait = WebDriverWait(driver, 15)
    
    # Wait for loading to disappear
    wait.until(
        EC.invisibility_of_element_located((By.ID, "search-loading"))
    )
    
    # Wait for results container to be visible
    results_container = wait.until(
        EC.visibility_of_element_located((By.ID, "search-results"))
    )
    
    # Wait for at least one result or no-results message
    wait.until(
        EC.any_of(
            EC.presence_of_element_located((By.CLASS_NAME, "result-item")),
            EC.text_to_be_present_in_element(
                (By.ID, "search-results"), "No results found"
            )
        )
    )
    
    return results_container

3. Error Handling with Waits

def safe_wait_and_click(driver, locator, timeout=10):
    """Safely wait for element and click with error handling"""
    try:
        wait = WebDriverWait(driver, timeout)
        element = wait.until(EC.element_to_be_clickable(locator))
        element.click()
        return True
    except TimeoutException:
        print(f"Element {locator} not clickable within {timeout} seconds")
        return False
    except Exception as e:
        print(f"Error clicking element {locator}: {e}")
        return False

# Usage
if safe_wait_and_click(driver, (By.ID, "submit-btn")):
    print("Successfully clicked submit button")
else:
    print("Failed to click submit button")

4. Polling with Custom Logic

def wait_for_api_response(driver, timeout=30):
    """Wait for API response to be displayed"""
    wait = WebDriverWait(driver, timeout, poll_frequency=0.5)
    
    def api_response_ready(driver):
        try:
            status = driver.find_element(By.ID, "api-status")
            response = driver.find_element(By.ID, "api-response")
            
            # Check if API call is complete
            if status.text == "Complete":
                # Check if response has content
                if response.text and response.text != "Loading...":
                    return {"status": status.text, "response": response.text}
            return False
        except:
            return False
    
    return wait.until(api_response_ready)

# Usage
result = wait_for_api_response(driver)
print(f"API Status: {result['status']}")
print(f"Response: {result['response']}")

5. Fluent Wait Pattern

from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException

class FluentWait:
    def __init__(self, driver, timeout=10, poll_frequency=0.5):
        self.driver = driver
        self.timeout = timeout
        self.poll_frequency = poll_frequency
        self.ignored_exceptions = []
    
    def ignoring(self, *exceptions):
        """Add exceptions to ignore"""
        self.ignored_exceptions.extend(exceptions)
        return self
    
    def until(self, condition, message=None):
        """Wait until condition is met"""
        wait = WebDriverWait(
            self.driver,
            self.timeout,
            self.poll_frequency,
            tuple(self.ignored_exceptions) if self.ignored_exceptions else None
        )
        return wait.until(condition, message)

# Usage
from selenium.common.exceptions import StaleElementReferenceException

result = FluentWait(driver, timeout=15, poll_frequency=0.2)\
    .ignoring(StaleElementReferenceException)\
    .until(EC.element_to_be_clickable((By.ID, "dynamic-btn")))

This comprehensive guide covers all aspects of WebDriverWait and Expected Conditions, providing you with the tools to handle any dynamic web content scenario in your Selenium automation.

Install with Tessl CLI

npx tessl i tessl/pypi-selenium

docs

action-chains.md

browser-configuration.md

element-interaction.md

index.md

waits-conditions.md

webdriver-classes.md

tile.json