Stopping the Flake: Moving from Implicit to Explicit Waits in Selenium
Stop flaky Selenium tests by replacing global implicit waits and Thread.sleep() with targeted Explicit Waits using WebDriverWait and ExpectedConditions.
13 Jan 2026, 16:45 UTC

The Race Condition Problem
You've written a test that passes locally but fails randomly in your CI/CD pipeline with a NoSuchElementException or ElementNotInteractableException. This is the classic "flaky test" syndrome. It happens because the test script executes commands faster than the browser can render the DOM (Document Object Model), especially in Single Page Applications (SPAs) where content is injected dynamically via JavaScript.
The instinctive reaction is often to add Thread.sleep() or a global implicit wait. However, these are blunt instruments that either waste time or create unpredictable timing conflicts. The engineering solution is Explicit Waits: telling the driver to poll for a specific state before proceeding.
Implicit vs. Explicit: The Core Difference
An Implicit Wait is a global setting. Once set, the WebDriver will poll the DOM for a certain duration every time you call findElement(). If the element isn't there immediately, it waits. While simple, it only checks for the presence of an element in the DOM, not whether that element is actually visible or clickable.
An Explicit Wait is a targeted instruction. Using WebDriverWait combined with ExpectedConditions, you define exactly what "ready" looks like for a specific interaction. This allows the script to move forward the millisecond a condition is met, rather than waiting for a hard-coded timer to expire.
Implementing WebDriverWait
To implement an explicit wait, you instantiate a WebDriverWait object with a maximum timeout and a polling interval. You then use the until() method to pass an ExpectedCondition.
Commonly used conditions include:
visibilityOfElementLocated: The element is in the DOM and has a height and width greater than zero.elementToBeClickable: The element is visible and enabled.presenceOfElementLocated: The element exists in the DOM, even if it isn't visible yet.
Worked Example (Python)
In this scenario, we are interacting with a search button that only becomes active after an AJAX request completes.
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
# Initialize driver
driver = webdriver.Chrome()
try:
driver.get("https://example.com/dynamic-page")
# Define a wait object with a 10-second timeout
wait = WebDriverWait(driver, timeout=10)
# Wait specifically for the search button to be clickable
# This replaces: driver.find_element(By.ID, "submit-btn").click()
search_button = wait.until(
EC.element_to_be_clickable((By.ID, "submit-btn"))
)
search_button.click()
except Exception as e:
print(f"Element not found or not clickable: {e}")
finally:
driver.quit()Execution Details
- Where to run: Within your test suite or automation script.
- Permissions: Standard user permissions for the browser driver.
- Placeholders: Replace
"https://example.com/dynamic-page"and"submit-btn"with your actual target URL and element ID. - Expected Check: The script should pause briefly during the AJAX load and resume immediately once the button is active.
- Risk: If the condition is never met, a
TimeoutExceptionis thrown, which should be caught to avoid crashing the entire suite.
The Danger of Mixing Wait Types
A critical limitation to remember: never mix implicit and explicit waits in the same session.
Implicit waits are managed by the browser driver (e.g., ChromeDriver), while explicit waits are managed by the language binding (e.g., Selenium Python/Java). When mixed, the total wait time becomes unpredictable. For example, if you have a 10-second implicit wait and a 10-second explicit wait, the driver might actually wait 20 seconds—or fail instantly—depending on how the specific driver implementation handles the conflict.
Verification and Maintenance
To verify your implementation is working as intended, try these two tests:
- The Timeout Test: Temporarily reduce your
WebDriverWaittimeout to 1 second. If the element takes 2 seconds to load, you should see aTimeoutException. This confirms the wait is actually controlling the execution flow. - The Performance Check: Compare the total execution time of a page using
Thread.sleep(5)versusWebDriverWait. The explicit wait should consistently finish faster because it doesn't wait for the full duration if the element appears early.
Avoid setting timeouts to excessively high values (e.g., 60 seconds). While this might stop the tests from failing, it can mask genuine performance regressions where a page is taking far longer to load than it should for a real user.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.