Beginner Chapter 6 · 11 min read

Waits — Implicit, Explicit & Fluent

Handle dynamic page loading with implicit waits, explicit WebDriverWait with ExpectedConditions, and fluent waits with custom polling.

Handling Dynamic Content with Waits

Modern web apps load content dynamically — elements appear after AJAX calls, animations, or JavaScript execution. Without proper waits, tests fail with "element not found" errors even though the element exists — it just hasn't loaded yet.

Types of Waits

  • Implicit Wait — Global timeout for all findElement calls. Simple but imprecise.
  • Explicit Wait (WebDriverWait) — Wait for a specific condition on a specific element. The recommended approach.
  • Fluent Wait — Explicit wait with custom polling interval and exception ignoring.
  • Thread.sleep / time.sleep — Hard wait. Never use in production tests!

ExpectedConditions

Selenium provides built-in conditions: visibilityOfElementLocated, elementToBeClickable, presenceOfElementLocated, titleContains, alertIsPresent, and many more.

WaitsTest.java
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.*;
import org.testng.Assert;
import org.testng.annotations.*;
import java.time.Duration;
import java.util.function.Function;

public class WaitsTest {

    WebDriver driver;

    @BeforeMethod
    public void setup() {
        driver = new ChromeDriver();
    }

    @Test
    public void testImplicitWait() {
        // Global wait — applies to all findElement calls
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://www.selenium.dev/selenium/web/web-form.html");

        // Will wait up to 10s for element to appear
        WebElement input = driver.findElement(By.name("my-text"));
        Assert.assertTrue(input.isDisplayed());
    }

    @Test
    public void testExplicitWait() {
        driver.get("https://www.selenium.dev/selenium/web/web-form.html");

        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

        // Wait for element to be visible
        WebElement input = wait.until(
            ExpectedConditions.visibilityOfElementLocated(
                By.name("my-text")));
        Assert.assertTrue(input.isDisplayed());

        // Wait for element to be clickable
        WebElement button = wait.until(
            ExpectedConditions.elementToBeClickable(
                By.cssSelector("button[type='submit']")));
        Assert.assertTrue(button.isEnabled());

        // Wait for title
        boolean titleMatch = wait.until(
            ExpectedConditions.titleContains("Web form"));
        Assert.assertTrue(titleMatch);
    }

    @Test
    public void testExplicitWait_MultiplConditions() {
        driver.get("https://www.selenium.dev/selenium/web/web-form.html");
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

        // Wait for presence (in DOM, may not be visible)
        wait.until(ExpectedConditions.presenceOfElementLocated(
            By.name("my-text")));

        // Wait for URL to contain
        wait.until(ExpectedConditions.urlContains("web-form"));

        // Wait for number of elements
        wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(
            By.tagName("input"), 3));
    }

    @Test
    public void testFluentWait() {
        driver.get("https://www.selenium.dev/selenium/web/web-form.html");

        Wait<WebDriver> fluentWait = new FluentWait<>(driver)
            .withTimeout(Duration.ofSeconds(15))
            .pollingEvery(Duration.ofMillis(500))
            .ignoring(NoSuchElementException.class)
            .ignoring(StaleElementReferenceException.class);

        WebElement element = fluentWait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver d) {
                return d.findElement(By.name("my-text"));
            }
        });

        Assert.assertTrue(element.isDisplayed());
    }

    @Test
    public void testCustomWaitCondition() {
        driver.get("https://www.selenium.dev/selenium/web/web-form.html");
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

        // Custom condition: wait until element has a specific attribute value
        wait.until(d -> {
            WebElement el = d.findElement(By.name("my-text"));
            String type = el.getAttribute("type");
            return "text".equals(type);
        });
    }

    @AfterMethod
    public void teardown() { if (driver != null) driver.quit(); }
}
test_waits.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import (
    NoSuchElementException, StaleElementReferenceException)
import pytest

@pytest.fixture
def driver():
    d = webdriver.Chrome()
    yield d
    d.quit()


def test_implicit_wait(driver):
    """Global wait for all find_element calls"""
    driver.implicitly_wait(10)
    driver.get("https://www.selenium.dev/selenium/web/web-form.html")

    input_el = driver.find_element(By.NAME, "my-text")
    assert input_el.is_displayed()


def test_explicit_wait(driver):
    """Wait for specific conditions"""
    driver.get("https://www.selenium.dev/selenium/web/web-form.html")
    wait = WebDriverWait(driver, 10)

    # Wait for visibility
    input_el = wait.until(
        EC.visibility_of_element_located((By.NAME, "my-text")))
    assert input_el.is_displayed()

    # Wait for clickable
    button = wait.until(
        EC.element_to_be_clickable(
            (By.CSS_SELECTOR, "button[type='submit']")))
    assert button.is_enabled()

    # Wait for title
    assert wait.until(EC.title_contains("Web form"))


def test_explicit_wait_multiple(driver):
    """Multiple wait conditions"""
    driver.get("https://www.selenium.dev/selenium/web/web-form.html")
    wait = WebDriverWait(driver, 10)

    # Presence in DOM
    wait.until(EC.presence_of_element_located((By.NAME, "my-text")))

    # URL condition
    wait.until(EC.url_contains("web-form"))

    # Number of elements
    inputs = wait.until(
        EC.presence_of_all_elements_located((By.TAG_NAME, "input")))
    assert len(inputs) > 3


def test_fluent_wait(driver):
    """Custom polling and exception ignoring"""
    driver.get("https://www.selenium.dev/selenium/web/web-form.html")

    wait = WebDriverWait(
        driver, timeout=15, poll_frequency=0.5,
        ignored_exceptions=[
            NoSuchElementException,
            StaleElementReferenceException
        ])

    element = wait.until(
        EC.visibility_of_element_located((By.NAME, "my-text")))
    assert element.is_displayed()


def test_custom_wait_condition(driver):
    """Wait with custom lambda condition"""
    driver.get("https://www.selenium.dev/selenium/web/web-form.html")
    wait = WebDriverWait(driver, 10)

    # Custom: wait until element has specific attribute
    wait.until(lambda d:
        d.find_element(By.NAME, "my-text").get_attribute("type") == "text")

Selenium Beginner Waits — Implicit, Explicit & Fluent

Written by PV

© 2026 All Rights Reserved