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
2. Explicit Waits (Recommended)
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 Type | Use Case |
|---|---|
| Implicit | Simple tests, learning Selenium |
| Explicit | Production tests, specific conditions |
| Fluent | Complex 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...