Answer
Selenium Wait Types Compared
1. Implicit Wait — Global Element Search Timeout
Java
// Set ONCE — applies to every findElement() call globally
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
// Now every findElement() polls the DOM for up to 10s before throwing
driver.findElement(By.id("submit")); // waits up to 10s
// ⚠️ Problems with implicit wait:
// 1. Makes "element should not be present" tests SLOW (always waits 10s)
// 2. Unpredictable interaction with explicit waits
// 3. Hides performance issues — elements should load fast!
2. Explicit Wait — Wait for a Specific Condition
Java
// Wait for a SPECIFIC element to meet a SPECIFIC condition
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
// Visibility
WebElement btn = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("submit")));
// Clickable
WebElement link = wait.until(
ExpectedConditions.elementToBeClickable(By.cssSelector("a.nav-link")));
// Text present
wait.until(
ExpectedConditions.textToBePresentInElementLocated(
By.id("status"), "Order Confirmed"));
// URL change
wait.until(ExpectedConditions.urlContains("/dashboard"));
// Staleness — wait for old element to go stale (page refresh)
WebElement oldEl = driver.findElement(By.id("result"));
driver.navigate().refresh();
wait.until(ExpectedConditions.stalenessOf(oldEl));
// Alert
wait.until(ExpectedConditions.alertIsPresent());
// Attribute value
wait.until(ExpectedConditions.attributeToBe(By.id("btn"), "disabled", "true"));
// Number of elements
wait.until(ExpectedConditions.numberOfElementsToBe(By.cssSelector(".row"), 5));
Common ExpectedConditions
Java
// Visibility / Presence
visibilityOfElementLocated(By locator)
presenceOfElementLocated(By locator) // just in DOM, not visible
visibilityOfAllElementsLocatedBy(By locator) // all visible
// Clickability
elementToBeClickable(By locator)
// Text
textToBePresentInElementLocated(By, String)
textToBePresentInElementValue(By, String)
// URL / Title
urlContains(String fraction)
urlToBe(String exactUrl)
titleContains(String fraction)
titleIs(String exactTitle)
// Other
invisibilityOfElementLocated(By locator) // wait for element to disappear
alertIsPresent()
frameToBeAvailableAndSwitchToIt(By locator)
stalenessOf(WebElement element)
numberOfElementsToBeMoreThan(By, int)
3. FluentWait — Maximum Control
Java
// FluentWait: custom polling interval + ignored exceptions + custom message
FluentWait<WebDriver> fluentWait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(20)) // max wait
.pollingEvery(Duration.ofMillis(500)) // check every 500ms (not 250ms default)
.ignoring(NoSuchElementException.class) // don't throw if not found yet
.ignoring(StaleElementReferenceException.class)
.withMessage("Button was not clickable after 20s");
WebElement btn = fluentWait.until(driver ->
driver.findElement(By.id("save-btn")));
// Custom condition with FluentWait
WebElement result = fluentWait.until(driver -> {
WebElement el = driver.findElement(By.id("status"));
String text = el.getText();
return text.equals("Completed") ? el : null; // return null to keep waiting
});
Comparison Summary
| Implicit Wait | Explicit Wait | Fluent Wait | |
|---|---|---|---|
| Scope | Global | Single condition | Single condition |
| Condition | Element present | Any ExpectedCondition | Custom function |
| Polling | Fixed | Fixed (250ms) | Configurable |
| Ignore exceptions | No | No | Yes |
| Use case | Legacy code | Most production use | Complex dynamic pages |
Best Practice
Java
// ✅ Recommended: Explicit wait per interaction
// ❌ Avoid: Mixing implicit + explicit waits (causes timeout multiplication bugs)
// ❌ Avoid: Thread.sleep() — wastes time, not condition-based
