Selenium WebDriver core API for automating web browsers across different platforms and programming languages.
—
Selenium provides sophisticated waiting mechanisms for handling dynamic content, including explicit waits with pre-built conditions and custom wait logic support.
Explicit wait implementation extending FluentWait for WebDriver-specific operations.
/**
* WebDriverWait class for explicit waiting with WebDriver
* Extends FluentWait<WebDriver> with WebDriver-specific functionality
*/
class WebDriverWait extends FluentWait<WebDriver> {
/**
* Create WebDriverWait with specified timeout
* @param driver - WebDriver instance
* @param timeout - Duration to wait before timeout
*/
WebDriverWait(WebDriver driver, Duration timeout);
/**
* Create WebDriverWait with timeout and polling interval
* @param driver - WebDriver instance
* @param timeout - Duration to wait before timeout
* @param sleep - Polling interval duration
*/
WebDriverWait(WebDriver driver, Duration timeout, Duration sleep);
/**
* Wait until condition returns non-null/true value
* @param isTrue - Function that returns result when condition met
* @return Result of the condition function
* @throws TimeoutException if timeout reached
*/
<V> V until(Function<WebDriver, V> isTrue);
/**
* Wait until expected condition is met
* @param condition - ExpectedCondition to wait for
* @return Result of the expected condition
* @throws TimeoutException if timeout reached
*/
<V> V until(ExpectedCondition<V> condition);
}Generic fluent wait implementation with configurable timeout, polling, and exception handling.
/**
* FluentWait class providing fluent interface for configurable waiting
* @param <T> - Type of object to wait on (typically WebDriver)
*/
class FluentWait<T> {
/**
* Create FluentWait for specified object
* @param input - Object to wait on
*/
FluentWait(T input);
/**
* Set maximum timeout duration
* @param timeout - Maximum time to wait
* @return FluentWait instance for chaining
*/
FluentWait<T> withTimeout(Duration timeout);
/**
* Set polling interval
* @param interval - Time between condition checks
* @return FluentWait instance for chaining
*/
FluentWait<T> pollingEvery(Duration interval);
/**
* Add exception type to ignore during waiting
* @param exceptionType - Exception class to ignore
* @return FluentWait instance for chaining
*/
FluentWait<T> ignoring(Class<? extends Throwable> exceptionType);
/**
* Add multiple exception types to ignore
* @param firstType - First exception type
* @param secondType - Second exception type
* @return FluentWait instance for chaining
*/
FluentWait<T> ignoring(Class<? extends Throwable> firstType, Class<? extends Throwable> secondType);
/**
* Set custom timeout message
* @param message - Message to include in TimeoutException
* @return FluentWait instance for chaining
*/
FluentWait<T> withMessage(String message);
/**
* Set custom timeout message with supplier
* @param messageSupplier - Function to generate timeout message
* @return FluentWait instance for chaining
*/
FluentWait<T> withMessage(Supplier<String> messageSupplier);
/**
* Wait until condition returns non-null/true value
* @param isTrue - Function that returns result when condition met
* @return Result of the condition function
* @throws TimeoutException if timeout reached
*/
<V> V until(Function<T, V> isTrue);
}Utility class providing pre-built expected conditions for common wait scenarios.
/**
* ExpectedConditions utility class with pre-built wait conditions
* All methods return ExpectedCondition instances for use with WebDriverWait
*/
class ExpectedConditions {
/**
* Wait for element to be present in DOM (not necessarily visible)
* @param locator - By locator for element
* @return ExpectedCondition for element presence
*/
static ExpectedCondition<WebElement> presenceOfElementLocated(By locator);
/**
* Wait for all elements to be present in DOM
* @param locator - By locator for elements
* @return ExpectedCondition for elements presence
*/
static ExpectedCondition<List<WebElement>> presenceOfAllElementsLocatedBy(By locator);
/**
* Wait for element to be visible (present in DOM and displayed)
* @param locator - By locator for element
* @return ExpectedCondition for element visibility
*/
static ExpectedCondition<WebElement> visibilityOfElementLocated(By locator);
/**
* Wait for existing element to become visible
* @param element - WebElement to wait for
* @return ExpectedCondition for element visibility
*/
static ExpectedCondition<WebElement> visibilityOf(WebElement element);
/**
* Wait for all elements to become visible
* @param elements - List of WebElements to wait for
* @return ExpectedCondition for all elements visibility
*/
static ExpectedCondition<List<WebElement>> visibilityOfAllElements(List<WebElement> elements);
/**
* Wait for all elements located by locator to become visible
* @param locator - By locator for elements
* @return ExpectedCondition for all elements visibility
*/
static ExpectedCondition<List<WebElement>> visibilityOfAllElementsLocatedBy(By locator);
/**
* Wait for element to be clickable (visible and enabled)
* @param locator - By locator for element
* @return ExpectedCondition for element clickability
*/
static ExpectedCondition<WebElement> elementToBeClickable(By locator);
/**
* Wait for existing element to be clickable
* @param element - WebElement to wait for
* @return ExpectedCondition for element clickability
*/
static ExpectedCondition<WebElement> elementToBeClickable(WebElement element);
/**
* Wait for element to be selected
* @param element - WebElement to check
* @return ExpectedCondition for element selection
*/
static ExpectedCondition<Boolean> elementToBeSelected(WebElement element);
/**
* Wait for element located by locator to be selected
* @param locator - By locator for element
* @return ExpectedCondition for element selection
*/
static ExpectedCondition<Boolean> elementSelectionStateToBe(By locator, boolean selected);
/**
* Wait for text to be present in element
* @param element - WebElement to check
* @param text - Text to wait for
* @return ExpectedCondition for text presence
*/
static ExpectedCondition<Boolean> textToBePresentInElement(WebElement element, String text);
/**
* Wait for text to be present in element located by locator
* @param locator - By locator for element
* @param text - Text to wait for
* @return ExpectedCondition for text presence
*/
static ExpectedCondition<Boolean> textToBePresentInElementLocated(By locator, String text);
/**
* Wait for specific text in element's value attribute
* @param locator - By locator for element
* @param text - Text to wait for in value
* @return ExpectedCondition for value text
*/
static ExpectedCondition<Boolean> textToBePresentInElementValue(By locator, String text);
/**
* Wait for page title to be exact match
* @param title - Expected page title
* @return ExpectedCondition for title match
*/
static ExpectedCondition<Boolean> titleIs(String title);
/**
* Wait for page title to contain text
* @param title - Text that title should contain
* @return ExpectedCondition for title containing text
*/
static ExpectedCondition<Boolean> titleContains(String title);
/**
* Wait for URL to be exact match
* @param url - Expected URL
* @return ExpectedCondition for URL match
*/
static ExpectedCondition<Boolean> urlToBe(String url);
/**
* Wait for URL to contain text
* @param fraction - Text that URL should contain
* @return ExpectedCondition for URL containing text
*/
static ExpectedCondition<Boolean> urlContains(String fraction);
/**
* Wait for URL to match regex pattern
* @param regex - Regular expression pattern
* @return ExpectedCondition for URL pattern match
*/
static ExpectedCondition<Boolean> urlMatches(String regex);
/**
* Wait for alert to be present
* @return ExpectedCondition for alert presence
*/
static ExpectedCondition<Alert> alertIsPresent();
/**
* Wait for element to become invisible or not present
* @param locator - By locator for element
* @return ExpectedCondition for element invisibility
*/
static ExpectedCondition<Boolean> invisibilityOfElementLocated(By locator);
/**
* Wait for element with text to become invisible
* @param locator - By locator for element
* @param text - Text that element should not contain
* @return ExpectedCondition for element invisibility
*/
static ExpectedCondition<Boolean> invisibilityOfElementWithText(By locator, String text);
/**
* Wait for attribute to contain specific value
* @param locator - By locator for element
* @param attribute - Attribute name
* @param value - Expected attribute value
* @return ExpectedCondition for attribute value
*/
static ExpectedCondition<Boolean> attributeContains(By locator, String attribute, String value);
/**
* Wait for attribute to be specific value
* @param locator - By locator for element
* @param attribute - Attribute name
* @param value - Expected attribute value
* @return ExpectedCondition for attribute value
*/
static ExpectedCondition<Boolean> attributeToBe(By locator, String attribute, String value);
/**
* Wait for frame to be available and switch to it
* @param frameLocator - Frame locator (string name/id or By locator)
* @return ExpectedCondition for frame availability
*/
static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(String frameLocator);
static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(By frameLocator);
/**
* Wait for number of windows to be specific count
* @param expectedNumberOfWindows - Expected window count
* @return ExpectedCondition for window count
*/
static ExpectedCondition<Boolean> numberOfWindowsToBe(int expectedNumberOfWindows);
/**
* Combine multiple conditions with AND logic
* @param conditions - ExpectedConditions to combine
* @return ExpectedCondition that passes when all conditions pass
*/
static ExpectedCondition<Boolean> and(ExpectedCondition<?>... conditions);
/**
* Combine multiple conditions with OR logic
* @param conditions - ExpectedConditions to combine
* @return ExpectedCondition that passes when any condition passes
*/
static ExpectedCondition<Boolean> or(ExpectedCondition<?>... conditions);
/**
* Negate an expected condition
* @param condition - ExpectedCondition to negate
* @return ExpectedCondition that passes when original condition fails
*/
static ExpectedCondition<Boolean> not(ExpectedCondition<?> condition);
}import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
try {
driver.get("https://example.com");
// Wait for element to be present and visible
WebElement submitButton = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("submit"))
);
// Wait for element to be clickable before interaction
WebElement loginButton = wait.until(
ExpectedConditions.elementToBeClickable(By.id("login"))
);
loginButton.click();
// Wait for text to appear in element
WebElement statusMessage = driver.findElement(By.id("status"));
wait.until(ExpectedConditions.textToBePresentInElement(statusMessage, "Login successful"));
// Wait for page title change
wait.until(ExpectedConditions.titleIs("Dashboard - MyApp"));
// Wait for URL change
wait.until(ExpectedConditions.urlContains("/dashboard"));
} finally {
driver.quit();
}import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
// Configure FluentWait with custom settings
FluentWait<WebDriver> fluentWait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofMilliseconds(500))
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class)
.withMessage("Element was not found within 30 seconds");
// Use fluent wait with custom condition
WebElement dynamicElement = fluentWait.until(driver -> {
WebElement element = driver.findElement(By.id("dynamic-content"));
return element.isDisplayed() && !element.getText().isEmpty() ? element : null;
});
// Wait for complex condition
Boolean complexCondition = fluentWait.until(driver -> {
List<WebElement> items = driver.findElements(By.className("item"));
return items.size() >= 5 && items.stream().allMatch(WebElement::isDisplayed);
});import org.openqa.selenium.support.ui.ExpectedCondition;
// Custom condition: Wait for element to have specific CSS class
public static ExpectedCondition<Boolean> elementToHaveClass(By locator, String className) {
return driver -> {
WebElement element = driver.findElement(locator);
String classes = element.getAttribute("class");
return classes != null && classes.contains(className);
};
}
// Custom condition: Wait for element count to be specific number
public static ExpectedCondition<Boolean> numberOfElementsToBe(By locator, int expectedCount) {
return driver -> driver.findElements(locator).size() == expectedCount;
}
// Custom condition: Wait for element to be stale (removed from DOM)
public static ExpectedCondition<Boolean> stalenessOf(WebElement element) {
return driver -> {
try {
element.isEnabled(); // Any method call will throw if stale
return false;
} catch (StaleElementReferenceException e) {
return true;
}
};
}
// Usage of custom conditions
wait.until(elementToHaveClass(By.id("loading"), "complete"));
wait.until(numberOfElementsToBe(By.className("result-item"), 10));
wait.until(stalenessOf(oldElement));// Wait for multiple conditions using AND
ExpectedCondition<Boolean> loginComplete = ExpectedConditions.and(
ExpectedConditions.titleIs("Dashboard"),
ExpectedConditions.presenceOfElementLocated(By.id("user-menu")),
ExpectedConditions.invisibilityOfElementLocated(By.id("loading-spinner"))
);
wait.until(loginComplete);
// Wait for any of multiple conditions using OR
ExpectedCondition<Boolean> pageReady = ExpectedConditions.or(
ExpectedConditions.presenceOfElementLocated(By.id("content")),
ExpectedConditions.presenceOfElementLocated(By.id("error-message"))
);
wait.until(pageReady);
// Use NOT to wait for condition to become false
wait.until(ExpectedConditions.not(
ExpectedConditions.attributeContains(By.id("status"), "class", "loading")
));// Wait for AJAX request to complete (jQuery example)
public static ExpectedCondition<Boolean> jQueryAjaxCompleted() {
return driver -> {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (Boolean) js.executeScript("return jQuery.active === 0");
};
}
// Wait for element to stop moving (animations complete)
public static ExpectedCondition<Boolean> elementToStopMoving(By locator) {
return driver -> {
WebElement element = driver.findElement(locator);
Point location1 = element.getLocation();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Point location2 = element.getLocation();
return location1.equals(location2);
};
}
// Wait for page to be fully loaded
public static ExpectedCondition<Boolean> pageToBeFullyLoaded() {
return driver -> {
JavascriptExecutor js = (JavascriptExecutor) driver;
return js.executeScript("return document.readyState").equals("complete");
};
}
// Usage
wait.until(jQueryAjaxCompleted());
wait.until(elementToStopMoving(By.id("animated-element")));
wait.until(pageToBeFullyLoaded());// Retry pattern with multiple attempts
public WebElement findElementWithRetry(By locator, int maxAttempts) {
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return wait.until(ExpectedConditions.presenceOfElementLocated(locator));
} catch (TimeoutException e) {
if (attempt == maxAttempts) {
throw new NoSuchElementException(
"Element not found after " + maxAttempts + " attempts: " + locator
);
}
// Refresh page or perform other recovery action
driver.navigate().refresh();
}
}
throw new IllegalStateException("Should not reach here");
}
// Wait with graceful degradation
public boolean waitForElementOptional(By locator, Duration timeout) {
try {
WebDriverWait shortWait = new WebDriverWait(driver, timeout);
shortWait.until(ExpectedConditions.presenceOfElementLocated(locator));
return true;
} catch (TimeoutException e) {
return false;
}
}
// Usage
WebElement element = findElementWithRetry(By.id("flaky-element"), 3);
boolean isPresent = waitForElementOptional(By.id("optional-element"), Duration.ofSeconds(5));// Use shorter timeouts for fast-failing conditions
WebDriverWait shortWait = new WebDriverWait(driver, Duration.ofSeconds(2));
boolean isElementPresent = false;
try {
shortWait.until(ExpectedConditions.presenceOfElementLocated(By.id("fast-element")));
isElementPresent = true;
} catch (TimeoutException e) {
isElementPresent = false;
}
// Use longer timeouts for slow operations
WebDriverWait longWait = new WebDriverWait(driver, Duration.ofSeconds(30));
longWait.until(ExpectedConditions.textToBePresentInElementLocated(
By.id("slow-loading-content"), "Data loaded successfully"
));
// Optimize polling frequency based on expected timing
FluentWait<WebDriver> fastPolling = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMilliseconds(100)); // Fast polling for quick changes
FluentWait<WebDriver> slowPolling = new FluentWait<>(driver)
.withTimeout(Duration.ofMinutes(2))
.pollingEvery(Duration.ofSeconds(2)); // Slow polling for long operationsInstall with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-api