Skip to main content
SeleniumDecoded

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 timeout
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Wait for element to be visible
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("result"))
);
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# Create a wait with 10 second timeout
wait = WebDriverWait(driver, 10)
# Wait for element to be visible
element = 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 visible
await driver.wait(until.elementIsVisible(element), 10000);
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;
// Create a wait with 10 second timeout
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Wait for element to be visible
IWebElement 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 visible
wait.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 present
wait.until(ExpectedConditions.textToBePresentInElementLocated(
By.id("status"), "Complete"
));
wait = WebDriverWait(driver, 10)
# Wait for element to be visible
wait.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 present
wait.until(EC.text_to_be_present_in_element(
(By.ID, "status"), "Complete"
))
// Wait for element visibility
const element = await driver.wait(
until.elementLocated(By.id('modal')),
10000
);
await driver.wait(until.elementIsVisible(element), 10000);
// Wait for element to become invisible
await driver.wait(until.elementIsNotVisible(element), 10000);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// Wait for element to be visible
wait.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 present
wait.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 click
WebElement button = wait.until(
ExpectedConditions.elementToBeClickable(By.id("submit"))
);
button.click();
wait = WebDriverWait(driver, 10)
# Wait for element to be clickable, then click
button = wait.until(
EC.element_to_be_clickable((By.ID, "submit"))
)
button.click()
// Wait for element to be enabled and click
const 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 click
IWebElement button = wait.Until(
ExpectedConditions.ElementToBeClickable(By.Id("submit"))
);
button.Click();

Presence vs Visibility

ConditionDescription
presenceOfElementLocatedElement exists in DOM (may be hidden)
visibilityOfElementLocatedElement is visible on page
elementToBeClickableElement is visible and enabled

Expected Conditions Reference

ConditionUse Case
visibilityOfElementLocatedWait for element to be visible
invisibilityOfElementLocatedWait for spinner/overlay to disappear
elementToBeClickableBefore clicking buttons
presenceOfElementLocatedElement in DOM (may not be visible)
textToBePresentInElementWait for specific text
titleIs / titleContainsPage title verification
urlToBe / urlContainsURL verification
alertIsPresentWait for JavaScript alert
frameToBeAvailableAndSwitchToItWait for iframe
numberOfElementsToBeWait for specific count
stalenessOfWait 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 lambda
Boolean result = wait.until(driver -> {
WebElement element = driver.findElement(By.id("status"));
return element.getText().equals("Ready") && element.isDisplayed();
});
// Wait for attribute value
wait.until(driver -> {
String value = driver.findElement(By.id("progress"))
.getAttribute("data-complete");
return "true".equals(value);
});
wait = WebDriverWait(driver, 10)
# Custom condition using lambda
result = wait.until(lambda d:
d.find_element(By.ID, "status").text == "Ready"
)
# Wait for attribute value
wait.until(lambda d:
d.find_element(By.ID, "progress").get_attribute("data-complete") == "true"
)
// Custom condition with function
await driver.wait(async function() {
const element = await driver.findElement(By.id('status'));
const text = await element.getText();
return text === 'Ready';
}, 10000);
// Wait for attribute value
await 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 lambda
wait.Until(d => {
var element = d.FindElement(By.Id("status"));
return element.Text == "Ready" && element.Displayed;
});
// Wait for attribute value
wait.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 wait
wait.ignoring(StaleElementReferenceException.class);
// Custom message on timeout
wait.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 configuration
await 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 interval
wait.PollingInterval = TimeSpan.FromMilliseconds(100);
// Ignore specific exceptions
wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException));
// Custom message
wait.Message = "Element did not become visible within timeout";

Best Practices

  1. Use explicit waits over implicit waits: More control and predictable behavior
  2. Wait for the right condition: Use elementToBeClickable before clicking
  3. Keep timeouts reasonable: 10-30 seconds for most cases
  4. Create reusable wait methods: Avoid duplicating wait logic
  5. Handle TimeoutException: Catch and provide meaningful error messages

Common Mistakes to Avoid

// BAD: Don't mix implicit and explicit waits
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
new WebDriverWait(driver, Duration.ofSeconds(10)).until(...);
// BAD: Don't use Thread.sleep
Thread.sleep(5000); // Wastes time or fails unpredictably
// GOOD: Use explicit wait only
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("result")));

Next Steps