Quick Tips
3 min

Selenium Wait Strategies

Master different wait strategies in Selenium WebDriver

...
seleniumwaitsui-testingwebdriver

Selenium Wait Strategies

Why Use Waits?

  • Modern web apps load content dynamically
  • Elements may not be immediately available
  • Timing issues cause flaky tests
  • Never use Thread.sleep() - it's inefficient and unreliable

1. Implicit Waits

Global timeout for all element lookups

// Java
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
 
// Now all findElement() calls wait up to 10 seconds
WebElement element = driver.findElement(By.id("dynamic-content"));
# Python
from selenium.webdriver.support.ui import WebDriverWait
 
driver.implicitly_wait(10)  # seconds
 
# All find operations wait up to 10 seconds
element = driver.find_element(By.ID, "dynamic-content")
// JavaScript
await driver.manage().setTimeouts({ implicit: 10000 });
 
// All element lookups wait up to 10 seconds
const element = await driver.findElement(By.id('dynamic-content'));

Pros: Simple, applies globally
Cons: Fixed timeout, can slow down tests

Wait for specific conditions on specific elements

// Java
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
 
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
 
// Wait for element to be visible
WebElement element = wait.until(
    ExpectedConditions.visibilityOfElementLocated(By.id("submit-btn"))
);
 
// Wait for element to be clickable
WebElement button = wait.until(
    ExpectedConditions.elementToBeClickable(By.id("submit"))
);
button.click();
 
// Wait for text to be present
wait.until(
    ExpectedConditions.textToBePresentInElementLocated(
        By.id("status"), 
        "Success"
    )
);
 
// Wait for element to disappear
wait.until(
    ExpectedConditions.invisibilityOfElementLocated(By.id("loading"))
);
# Python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
 
wait = WebDriverWait(driver, 10)
 
# Wait for element to be visible
element = wait.until(
    EC.visibility_of_element_located((By.ID, "submit-btn"))
)
 
# Wait for element to be clickable
button = wait.until(
    EC.element_to_be_clickable((By.ID, "submit"))
)
button.click()
 
# Wait for title
wait.until(EC.title_contains("Dashboard"))

3. Common Expected Conditions

// Element conditions
ExpectedConditions.presenceOfElementLocated(By.id("element"))
ExpectedConditions.visibilityOfElementLocated(By.id("element"))
ExpectedConditions.elementToBeClickable(By.id("button"))
ExpectedConditions.invisibilityOfElementLocated(By.id("loader"))
ExpectedConditions.stalenessOf(element)
 
// Text conditions
ExpectedConditions.textToBePresentInElementLocated(By.id("msg"), "Success")
ExpectedConditions.textToBePresentInElementValue(By.id("input"), "value")
 
// Attribute conditions
ExpectedConditions.attributeToBe(By.id("input"), "disabled", "true")
ExpectedConditions.attributeContains(By.id("div"), "class", "active")
 
// Frame and window conditions
ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("iframe"))
ExpectedConditions.numberOfWindowsToBe(2)
 
// Alert conditions
ExpectedConditions.alertIsPresent()
 
// Selection conditions
ExpectedConditions.elementToBeSelected(By.id("checkbox"))

4. Fluent Waits

Custom polling interval and exceptions to ignore

Wait<WebDriver> wait = new FluentWait<>(driver)
    .withTimeout(Duration.ofSeconds(30))
    .pollingEvery(Duration.ofSeconds(2))
    .ignoring(NoSuchElementException.class)
    .ignoring(StaleElementReferenceException.class);
 
WebElement element = wait.until(driver -> {
    return driver.findElement(By.id("dynamic-element"));
});
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException
 
wait = WebDriverWait(driver, 30, poll_frequency=2, 
                     ignored_exceptions=[NoSuchElementException])
 
element = wait.until(
    lambda d: d.find_element(By.ID, "dynamic-element")
)

5. Custom Wait Conditions

// Java - Custom condition
public class ElementHasAttributeValue 
    implements ExpectedCondition<Boolean> {
    
    private By locator;
    private String attribute;
    private String value;
    
    public ElementHasAttributeValue(By locator, String attr, String val) {
        this.locator = locator;
        this.attribute = attr;
        this.value = val;
    }
    
    @Override
    public Boolean apply(WebDriver driver) {
        WebElement element = driver.findElement(locator);
        String actualValue = element.getAttribute(attribute);
        return actualValue != null && actualValue.equals(value);
    }
}
 
// Usage
wait.until(new ElementHasAttributeValue(
    By.id("status"), 
    "data-loaded", 
    "true"
));
# Python - Custom condition
class element_has_class:
    def __init__(self, locator, class_name):
        self.locator = locator
        self.class_name = class_name
    
    def __call__(self, driver):
        element = driver.find_element(*self.locator)
        classes = element.get_attribute("class")
        return self.class_name in classes
 
# Usage
wait.until(element_has_class((By.ID, "status"), "completed"))

6. Practical Examples

Wait for AJAX to complete:

// Wait for jQuery AJAX
wait.until(driver -> {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    return (Boolean) js.executeScript("return jQuery.active == 0");
});
 
// Wait for Angular
wait.until(driver -> {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    return (Boolean) js.executeScript(
        "return window.getAllAngularTestabilities()" +
        ".findIndex(x => !x.isStable()) === -1"
    );
});

Wait for element count:

// Wait until at least 5 products are loaded
wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(
    By.className("product-item"), 
    4
));

Wait for URL change:

// Wait for URL to contain text
wait.until(ExpectedConditions.urlContains("/dashboard"));
 
// Wait for specific URL
wait.until(ExpectedConditions.urlToBe("https://example.com/home"));

Chain multiple conditions:

// Wait for loading to disappear AND content to appear
wait.until(ExpectedConditions.and(
    ExpectedConditions.invisibilityOfElementLocated(
        By.id("loading-spinner")
    ),
    ExpectedConditions.visibilityOfElementLocated(
        By.id("content")
    )
));

7. Best Practices

public class PageObject {
    private WebDriver driver;
    private WebDriverWait wait;
    
    public PageObject(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }
    
    // Reusable wait method
    private WebElement waitForElement(By locator) {
        return wait.until(
            ExpectedConditions.visibilityOfElementLocated(locator)
        );
    }
    
    // Reusable clickable wait
    private WebElement waitAndClick(By locator) {
        WebElement element = wait.until(
            ExpectedConditions.elementToBeClickable(locator)
        );
        element.click();
        return element;
    }
    
    public void clickSubmit() {
        waitAndClick(By.id("submit-btn"));
    }
}

Quick Reference

When to Use Each Wait

Wait TypeUse Case
ImplicitSimple tests, learning Selenium
ExplicitProduction tests, specific conditions
FluentComplex scenarios, custom polling

Common Mistakes to Avoid

Don't:

Thread.sleep(5000);  // Hard-coded sleep
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
wait.until(...); // Mixing implicit and explicit

Do:

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("element")));

Performance Tips

  • Use explicit waits over implicit waits
  • Set reasonable timeout values (5-15 seconds)
  • Wait for specific conditions, not just presence
  • Use invisibilityOf to wait for loaders to disappear
  • Reuse WebDriverWait instances
  • Handle StaleElementReferenceException with fluent waits

Key Takeaways

  • Never use Thread.sleep() - use proper waits
  • Explicit waits are more flexible and reliable
  • Wait for clickable before clicking elements
  • Wait for visibility before interacting with elements
  • Use custom conditions for complex scenarios
  • Combine waits with Page Object Model for clean code

Comments (0)

Loading comments...