Explicit Waits
Learn to use explicit waits in Selenium to handle dynamic content and avoid flaky tests.
Selenium 3 & 4 Stable
Explicit waits are the most reliable way to synchronize your tests with the application. They wait for a specific condition to be true before proceeding, with a configurable timeout.
Why Use Explicit Waits?
Modern web applications are dynamic. Elements may:
- Load asynchronously via AJAX
- Appear after animations complete
- Become clickable after JavaScript initialization
Without proper waits, tests become flaky and unreliable.
Basic WebDriverWait
Basic Explicit Wait
Selenium 4 Stable
import org.openqa.selenium.support.ui.WebDriverWait;import org.openqa.selenium.support.ui.ExpectedConditions;import java.time.Duration;
// Create a wait with 10 second timeoutWebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Wait for element to be visibleWebElement element = wait.until( ExpectedConditions.visibilityOfElementLocated(By.id("result")));from selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import By
# Create a wait with 10 second timeoutwait = WebDriverWait(driver, 10)
# Wait for element to be visibleelement = wait.until( EC.visibility_of_element_located((By.ID, "result")))const { until } = require('selenium-webdriver');
// Wait for element to be located (10 second timeout)const element = await driver.wait( until.elementLocated(By.id('result')), 10000);
// Wait for element to be visibleawait driver.wait(until.elementIsVisible(element), 10000);using OpenQA.Selenium.Support.UI;using SeleniumExtras.WaitHelpers;
// Create a wait with 10 second timeoutWebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Wait for element to be visibleIWebElement element = wait.Until( ExpectedConditions.ElementIsVisible(By.Id("result")));Common Expected Conditions
Visibility
Visibility Conditions
Selenium 3 & 4 Stable
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Wait for element to be visiblewait.until(ExpectedConditions.visibilityOfElementLocated(By.id("modal")));
// Wait for element to be invisible (e.g., loading spinner)wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("spinner")));
// Wait for text to be presentwait.until(ExpectedConditions.textToBePresentInElementLocated( By.id("status"), "Complete"));wait = WebDriverWait(driver, 10)
# Wait for element to be visiblewait.until(EC.visibility_of_element_located((By.ID, "modal")))
# Wait for element to be invisible (e.g., loading spinner)wait.until(EC.invisibility_of_element_located((By.ID, "spinner")))
# Wait for text to be presentwait.until(EC.text_to_be_present_in_element( (By.ID, "status"), "Complete"))// Wait for element visibilityconst element = await driver.wait( until.elementLocated(By.id('modal')), 10000);await driver.wait(until.elementIsVisible(element), 10000);
// Wait for element to become invisibleawait driver.wait(until.elementIsNotVisible(element), 10000);WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Wait for element to be visiblewait.Until(ExpectedConditions.ElementIsVisible(By.Id("modal")));
// Wait for element to be invisible (e.g., loading spinner)wait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.Id("spinner")));
// Wait for text to be presentwait.Until(ExpectedConditions.TextToBePresentInElementLocated( By.Id("status"), "Complete"));Clickability
Clickable Element
Selenium 3 & 4 Stable
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Wait for element to be clickable, then clickWebElement button = wait.until( ExpectedConditions.elementToBeClickable(By.id("submit")));button.click();wait = WebDriverWait(driver, 10)
# Wait for element to be clickable, then clickbutton = wait.until( EC.element_to_be_clickable((By.ID, "submit")))button.click()// Wait for element to be enabled and clickconst button = await driver.wait( until.elementLocated(By.id('submit')), 10000);await driver.wait(until.elementIsEnabled(button), 10000);await button.click();WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Wait for element to be clickable, then clickIWebElement button = wait.Until( ExpectedConditions.ElementToBeClickable(By.Id("submit")));button.Click();Presence vs Visibility
| Condition | Description |
|---|---|
presenceOfElementLocated | Element exists in DOM (may be hidden) |
visibilityOfElementLocated | Element is visible on page |
elementToBeClickable | Element is visible and enabled |
Expected Conditions Reference
| Condition | Use Case |
|---|---|
visibilityOfElementLocated | Wait for element to be visible |
invisibilityOfElementLocated | Wait for spinner/overlay to disappear |
elementToBeClickable | Before clicking buttons |
presenceOfElementLocated | Element in DOM (may not be visible) |
textToBePresentInElement | Wait for specific text |
titleIs / titleContains | Page title verification |
urlToBe / urlContains | URL verification |
alertIsPresent | Wait for JavaScript alert |
frameToBeAvailableAndSwitchToIt | Wait for iframe |
numberOfElementsToBe | Wait for specific count |
stalenessOf | Wait for element to become stale |
Custom Wait Conditions
Custom Condition
Selenium 3 & 4 Stable
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Custom condition using lambdaBoolean result = wait.until(driver -> { WebElement element = driver.findElement(By.id("status")); return element.getText().equals("Ready") && element.isDisplayed();});
// Wait for attribute valuewait.until(driver -> { String value = driver.findElement(By.id("progress")) .getAttribute("data-complete"); return "true".equals(value);});wait = WebDriverWait(driver, 10)
# Custom condition using lambdaresult = wait.until(lambda d: d.find_element(By.ID, "status").text == "Ready")
# Wait for attribute valuewait.until(lambda d: d.find_element(By.ID, "progress").get_attribute("data-complete") == "true")// Custom condition with functionawait driver.wait(async function() { const element = await driver.findElement(By.id('status')); const text = await element.getText(); return text === 'Ready';}, 10000);
// Wait for attribute valueawait driver.wait(async function() { const element = await driver.findElement(By.id('progress')); const value = await element.getAttribute('data-complete'); return value === 'true';}, 10000);WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Custom condition using lambdawait.Until(d => { var element = d.FindElement(By.Id("status")); return element.Text == "Ready" && element.Displayed;});
// Wait for attribute valuewait.Until(d => { var value = d.FindElement(By.Id("progress")) .GetAttribute("data-complete"); return value == "true";});Configuring Wait Behavior
Wait Configuration
Selenium 3 & 4 Stable
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Set polling interval (default is 500ms)wait.pollingEvery(Duration.ofMillis(100));
// Ignore specific exceptions during waitwait.ignoring(StaleElementReferenceException.class);
// Custom message on timeoutwait.withMessage("Element did not become visible within timeout");wait = WebDriverWait( driver, timeout=10, poll_frequency=0.1, # Check every 100ms ignored_exceptions=[StaleElementReferenceException])
# The wait will throw TimeoutException with default message on failure// Polling is automatic, use timeout for configurationawait driver.wait( until.elementLocated(By.id('result')), 10000, // timeout in ms 'Element did not appear' // custom error message);WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Set polling intervalwait.PollingInterval = TimeSpan.FromMilliseconds(100);
// Ignore specific exceptionswait.IgnoreExceptionTypes(typeof(StaleElementReferenceException));
// Custom messagewait.Message = "Element did not become visible within timeout";Best Practices
- Use explicit waits over implicit waits: More control and predictable behavior
- Wait for the right condition: Use
elementToBeClickablebefore clicking - Keep timeouts reasonable: 10-30 seconds for most cases
- Create reusable wait methods: Avoid duplicating wait logic
- Handle TimeoutException: Catch and provide meaningful error messages
Common Mistakes to Avoid
// BAD: Don't mix implicit and explicit waitsdriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));new WebDriverWait(driver, Duration.ofSeconds(10)).until(...);
// BAD: Don't use Thread.sleepThread.sleep(5000); // Wastes time or fails unpredictably
// GOOD: Use explicit wait onlyWebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("result")));Next Steps
- Fluent Waits - Advanced wait configuration
- Expected Conditions - Complete conditions reference
- Implicit Waits - Understand the differences
- Common Errors - Fix TimeoutException and other issues