Flaky Tests in Selenium: 7 Common Causes and Production-Ready Fixes
Diagnose and fix the 7 most common causes of Selenium test flakiness with battle-tested code examples in Java and Python.
selenium flaky testsselenium test failuresfix selenium testsselenium wait strategiesselenium StaleElementReferenceExceptionselenium CI failuresselenium WebDriverWaitselenium test automationselenium debuggingbrowser automation reliability
Flaky Tests in Selenium: 7 Common Causes and Production-Ready Fixes
Selenium is the backbone of enterprise test automation, used by millions of teams worldwide. But its flexibility comes at a cost: Selenium does not protect you from yourself. Unlike newer frameworks that auto-wait and auto-retry, Selenium hands you the raw browser API and expects you to manage synchronization, state, and timing on your own.
This article cuts straight to the seven most frequent causes of Selenium flakiness, each with a concrete fix you can apply today. No theory lectures -- just patterns that work in production.
Cause 1: Using sleep() Instead of Explicit Waits
The most common flaky test pattern across every Selenium codebase on the planet:
# This is the source of 40% of all Selenium flakiness
On a fast machine or low-load CI runner, 3 seconds is plenty. On a constrained CI runner during peak hours, the search API takes 4 seconds. The test fails.
The Fix: Explicit Waits with Expected Conditions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
The explicit wait polls the DOM every 500ms (by default) until the condition is met or the timeout expires. If the results load in 1 second, the test proceeds in 1 second. If they take 12 seconds, the test waits 12 seconds. No wasted time, no premature failures.
Java equivalent:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
List results = driver.findElements(By.className("product-card"));
assertTrue(results.size() > 0);
Cause 2: StaleElementReferenceException After Page Updates
React, Vue, and Angular applications constantly re-render DOM elements. When you store a reference to an element and the framework re-renders, your reference points to a DOM node that no longer exists.
"""Click an element, retrying if it goes stale."""
for attempt in range(max_retries):
try:
element = WebDriverWait(driver, timeout).until(
EC.element_to_be_clickable(locator)
)
element.click()
return
except StaleElementReferenceException:
if attempt == max_retries - 1:
raise
# Element was re-rendered, try again
Usage
resilient_click(driver, (By.ID, "add-to-cart"))
Java equivalent:
public void resilientClick(By locator, int maxRetries) {
for (int i = 0; i < maxRetries; i++) {
try {
WebElement element = wait.until(
ExpectedConditions.elementToBeClickable(locator)
);
element.click();
return;
} catch (StaleElementReferenceException e) {
if (i == maxRetries - 1) throw e;
}
}
}
Rule of thumb: Never store element references across actions that could trigger a re-render. Re-find the element immediately before interacting with it.
Cause 3: ElementClickInterceptedException
Your test tries to click a button but another element -- a cookie banner, loading overlay, or tooltip -- is covering it.
Iframes are a notorious source of flakiness because the iframe content loads asynchronously. If you try to switch to an iframe before it is ready, Selenium throws a NoSuchFrameException.
When a Selenium test starts flaking, run through this checklist:
Is there a sleep()? Replace it with an explicit wait.
Does the test store element references across navigations? Re-find before interacting.
Does the test interact with dynamically loaded content? Add waits for the content.
Does the test click elements that might be covered? Wait for obstructions to clear.
Does the test switch frames or windows? Add waits for frame/window availability.
Does the test work with dropdowns? Wait for options to populate.
Does the test compare screenshots? Add rendering tolerance.
If you want automated detection instead of manual investigation, the DeFlaky CLI analyzes your test results and pinpoints which tests are flaky. It integrates with JUnit XML output from any Selenium framework -- pytest, JUnit, TestNG, NUnit -- and tracks reliability trends on the dashboard.
Measuring Improvement
After applying these fixes, measure the impact:
# Before fixes: run tests 20 times and count failures
Track your suite's overall flake rate over weeks, not days. A single clean run does not prove the fixes worked -- you need statistical confidence across many runs.
Conclusion
Selenium flakiness follows predictable patterns. The seven causes in this article account for the vast majority of intermittent failures in Selenium test suites. Apply the corresponding fixes systematically, starting with the ones that affect the most tests, and you will see measurable improvement in your pipeline reliability within days.
For ongoing monitoring, connect your test results to DeFlaky and let the dashboard track reliability trends automatically. The combination of robust test code and continuous monitoring is what separates teams with trustworthy pipelines from teams that re-run builds and hope for the best.
Stop guessing. DeFlaky your tests.
Detect flaky tests in minutes with a single CLI command.