Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›Selenium›Explicit Waits — WebDriverWait and Expected Conditions

Waits and Timing

Explicit Waits — WebDriverWait and Expected Conditions

Explicit waits are a mechanism to pause test execution until a specific condition is met by the browser state. They are essential because they prevent race conditions caused by the asynchronous nature of modern web pages. You should use them whenever you need to ensure an element is interactable or present before performing an action.

The Philosophy of WebDriverWait

WebDriverWait acts as a synchronization bridge between your test script and the browser's current rendering state. Unlike rigid static pauses which waste time, explicit waits allow the script to poll the DOM at defined intervals until a specific predicate returns true or a timeout occurs. The reasoning here is that modern applications load parts of the UI dynamically via JavaScript. If your script searches for an element before the browser has finished executing the rendering logic, the script will crash. WebDriverWait handles this by creating an instance that binds a driver to a maximum duration. By defining a polling interval—typically every 500 milliseconds—the driver constantly re-evaluates the condition without developer intervention. This approach is superior because it minimizes wait times, resulting in tests that pass as soon as the condition is satisfied, thus significantly increasing the reliability and speed of your automated suite in diverse network environments.

from selenium.webdriver.support.ui import WebDriverWait

# Initialize wait object for a 10-second maximum duration
# The driver will check every 500ms by default
wait = WebDriverWait(driver, timeout=10)

# The wait will throw a TimeoutException if conditions aren't met in 10s

Condition: visibility_of_element_located

The visibility of an element is a distinct state from its mere existence in the DOM structure. Many developers make the mistake of checking if an element exists when they actually need to interact with it, such as clicking a button or typing into a field. An element might be present in the HTML but hidden behind a CSS style like 'display: none' or 'visibility: hidden'. Using the 'visibility_of_element_located' condition is the robust choice because it forces the driver to verify that the element has both height and width greater than zero, and its CSS properties are not masking it from the user. This is crucial for user-interface interactions, as it prevents attempts to interact with non-clickable elements which would otherwise trigger an ElementNotInteractableException. By forcing this check, you mirror actual user behavior, ensuring that the element is not only available for the browser's parser but also genuinely usable by a human.

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

# Wait until the submit button is rendered and visible on screen
submit_btn = wait.until(EC.visibility_of_element_located((By.ID, 'submit-button')))
submit_btn.click()

Condition: element_to_be_clickable

When dealing with buttons or input forms, visibility is sometimes insufficient. An element may appear on the page while the underlying JavaScript event listeners are still being initialized, or it might be temporarily disabled due to a pending background process. The 'element_to_be_clickable' condition is a higher-order check that confirms both visibility and the enabled state of the target web element. If the element is disabled, the condition will continue to wait until the application logic flips its state to enabled. This is particularly relevant in single-page applications where form submissions might keep a button disabled until all required fields are populated correctly. Relying on this specific condition saves you from writing complex custom polling logic, as it intrinsically handles the nuance of functional readiness. It ensures that when your script proceeds, the browser is fully prepared to receive the mouse click or keyboard event without rejection.

from selenium.webdriver.support import expected_conditions as EC

# Ensures the login button is both visible and enabled
# before attempting to perform the click operation
login_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button.login')))
login_btn.click()

Handling StaleElementReferenceException

A frequent hurdle in dynamic web environments is the StaleElementReferenceException. This occurs when an element you have previously located is removed or replaced by a new node during a DOM update, even if it appears visually identical. To handle this, explicit waits allow you to define custom logic. Rather than just catching the error and failing, you can wrap your interaction in a logic loop that re-locates the element. By re-invoking the 'find_element' method inside the wait condition, you ensure that you are referencing the current, active version of the element rather than a stale memory pointer. This pattern demonstrates the power of the 'until' method, which accepts a callable object. By passing a function that attempts to find and return the element, the wait mechanism automatically retries the operation if the initial attempt fails due to a stale reference or temporary instability, effectively healing the interaction attempt.

# Using a lambda to retry finding the element if it becomes stale
# This ensures we get the fresh DOM reference
fresh_element = wait.until(lambda d: d.find_element(By.ID, 'dynamic-field'))
fresh_element.send_keys('Data processed')

Inverting Logic with invisibility_of_element

There are scenarios where you must wait for a process to finish rather than start. A common example is the disappearance of a loading spinner or a modal overlay that blocks interaction with the main page content. The 'invisibility_of_element_located' condition is the primary tool for this requirement. It operates by polling the browser until the target element is no longer visible in the DOM or is hidden. This logic is vital for test reliability, as attempting to click an element while a loading overlay is still present will lead to failures, as the overlay might catch the click event instead of the intended target. By waiting for the invisibility condition to resolve, you effectively guarantee that the page has finished its internal transition and is now in a clean, idle state, ready for the next phase of your testing scenario.

from selenium.webdriver.support import expected_conditions as EC

# Wait for the loading spinner to vanish before proceeding
# Ensures the page is no longer in a transient state
wait.until(EC.invisibility_of_element_located((By.ID, 'loading-spinner')))
print('Overlay removed, safe to interact.')

Key points

  • Explicit waits prevent test flakiness by synchronizing actions with the browser's actual state.
  • The WebDriverWait class provides a mechanism to poll the DOM at regular intervals until a condition is met.
  • Visibility checks are more reliable than presence checks because they confirm the element can actually be interacted with.
  • Using element_to_be_clickable ensures an element is both visible and not disabled by the application logic.
  • StaleElementReferenceException occurs when the DOM structure updates and invalidates previously located elements.
  • Custom wait conditions can be defined using lambda functions to handle complex synchronization scenarios.
  • Waiting for the invisibility of loading elements is essential for ensuring the page is ready for further input.
  • Explicit waits are superior to static sleeps because they allow the test to resume immediately upon completion of the awaited condition.

Common mistakes

  • Mistake: Using implicit waits and explicit waits together. Why it's wrong: It causes unpredictable polling intervals and timeouts. Fix: Use only explicit waits for element-specific synchronization.
  • Mistake: Creating a new WebDriverWait instance inside a loop for every element. Why it's wrong: It is inefficient and creates unnecessary object overhead. Fix: Reuse a single WebDriverWait instance for the duration of the test.
  • Mistake: Passing a WebElement directly to ExpectedConditions that require a locator. Why it's wrong: Many expected conditions are designed to wait for the element's presence in the DOM before locating it. Fix: Pass By locators to conditions like visibilityOfElementLocated.
  • Mistake: Ignoring the default 500ms polling interval. Why it's wrong: Sometimes a faster or slower poll is needed for performance or timing-sensitive animations. Fix: Configure the polling interval using the .pollingEvery() method on the wait instance.
  • Mistake: Failing to handle TimeoutException. Why it's wrong: When an element doesn't appear within the allotted time, the script crashes, preventing cleanup tasks. Fix: Wrap the wait logic in a try-catch block to handle the exception gracefully.

Interview questions

What is an Explicit Wait in Selenium and why do we use it?

An Explicit Wait in Selenium is a command that tells the web driver to wait for a certain condition to occur before proceeding to the next step in the code. We use it instead of Thread.sleep because it is dynamic; it polls the DOM at set intervals, meaning if the element appears in one second, the test continues immediately rather than waiting for a hard-coded duration, which improves performance and stability.

How do you implement a basic WebDriverWait in Selenium?

To implement an Explicit Wait, you must instantiate the WebDriverWait class, passing the driver instance and a timeout duration in seconds to its constructor. You then call the 'until' method on this object, passing in an ExpectedCondition. For example, 'wait.until(ExpectedConditions.visibilityOfElementLocated(By.id('submit')))' tells Selenium to actively monitor the page until that specific element becomes visible to the user, preventing common ElementNotVisible exceptions during test execution.

What is the difference between ExpectedConditions and basic polling?

ExpectedConditions is a built-in library provided by Selenium that contains pre-defined methods to handle common synchronization scenarios like element visibility, clickability, or text presence. Basic polling involves writing a custom loop to check for element properties manually. ExpectedConditions is preferred because it is thoroughly tested, handles edge cases regarding DOM staleness automatically, and makes the test code significantly more readable and maintainable for other automation engineers on the team.

Compare Implicit Waits and Explicit Waits in Selenium; when should you choose one over the other?

An Implicit Wait is a global setting applied to the entire life of the driver instance, telling it to poll the DOM for any element for a set time before throwing an exception. An Explicit Wait is targeted at a specific element for a specific condition. You should choose Explicit Waits for most scenarios because they provide granular control. Never mix Implicit and Explicit Waits in the same project, as this can cause unpredictable wait times and unintended timeout delays.

How does the 'StaleElementReferenceException' relate to Explicit Waits?

A StaleElementReferenceException occurs when an element is no longer attached to the DOM, often because the page refreshed or the DOM structure updated. While Explicit Waits cannot always prevent this, using 'ExpectedConditions.refreshed' or re-locating the element inside a custom wait condition can solve it. By wrapping the logic in an Explicit Wait, we can ensure the driver waits for the DOM to settle or for the specific element to be re-rendered before interacting with it again.

Can you explain how to create a custom ExpectedCondition if the built-in ones are insufficient?

If built-in conditions aren't enough, you can create a custom condition by implementing the ExpectedCondition interface. You must override the 'apply' method, which takes the driver as an argument and returns the desired object type. For example, you could write a condition that returns a boolean based on whether a JavaScript variable on the page has changed. The 'until' method will keep calling your 'apply' logic until it returns true or a non-null object, providing total flexibility for complex UI scenarios.

All Selenium interview questions →

Check yourself

1. When should you prefer an Explicit Wait over an Implicit Wait in a Selenium project?

  • A.When you want the driver to wait globally for all elements to be present
  • B.When you need to wait for a specific condition, such as an element becoming clickable or a text change
  • C.When you want to increase the speed of the script execution globally
  • D.When you want to avoid using the WebDriverWait class entirely
Show answer

B. When you need to wait for a specific condition, such as an element becoming clickable or a text change
Explicit waits allow you to define conditions for specific elements, which is more robust. Implicit waits are global and can cause unintended delays. Options 1 and 3 describe global settings, and option 4 ignores the primary tool for explicit synchronization.

2. What happens if an ExpectedCondition is not met within the timeout period defined in WebDriverWait?

  • A.The driver returns null
  • B.The driver moves to the next line of code
  • C.A TimeoutException is thrown
  • D.The driver automatically retries the action indefinitely
Show answer

C. A TimeoutException is thrown
WebDriverWait is designed to throw a TimeoutException when the condition fails, allowing you to catch it. It does not return null, skip lines, or retry indefinitely, as that would hang the test suite.

3. Why is 'elementToBeClickable' often a better choice than 'visibilityOfElementLocated' for button interactions?

  • A.It checks if the element is present in the DOM, whereas visibility only checks for style
  • B.It verifies both visibility and the enabled state, ensuring the element can actually receive a click
  • C.It is faster than checking for visibility
  • D.It forces the driver to click the element automatically
Show answer

B. It verifies both visibility and the enabled state, ensuring the element can actually receive a click
An element might be visible but disabled; 'elementToBeClickable' confirms both visibility and enabled status. Visibility only checks if the element is rendered, and it doesn't perform automatic clicks.

4. What is the primary function of the polling interval in a WebDriverWait instance?

  • A.It dictates how long the driver waits before starting to look for the element
  • B.It defines the frequency at which the driver re-evaluates the ExpectedCondition
  • C.It limits the maximum number of times the driver can refresh the page
  • D.It sets the default wait time for all elements in the script
Show answer

B. It defines the frequency at which the driver re-evaluates the ExpectedCondition
The polling interval defines how often the driver checks if the condition has been met during the timeout period. The other options refer to timeout durations or page interactions, not the polling mechanism.

5. If you are waiting for a specific text to appear in an element, which approach is most efficient?

  • A.Use thread.sleep to wait for a fixed amount of time
  • B.Use an implicit wait and then manually loop through the text
  • C.Use WebDriverWait with textToBePresentInElementLocated
  • D.Wait for the element to be present, then use an if-statement to check the text
Show answer

C. Use WebDriverWait with textToBePresentInElementLocated
textToBePresentInElementLocated is a built-in ExpectedCondition specifically optimized for this scenario. Thread.sleep is unstable and slow, manual looping is redundant, and an if-statement lacks the necessary synchronization logic to wait for the DOM to update.

Take the full Selenium quiz →

← PreviousImplicit WaitsNext →Fluent Waits

Selenium

18 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app