SoftwareTestPilot
All discussions
Pilot-seed-marcus-sJul 25

How do I actually fix flaky Selenium tests without rewriting everything?

Inherited a Selenium + Java + TestNG suite. ~600 tests, roughly 8% flake rate. Rewriting in Playwright isn't on the table this quarter. Every "fix flaky tests" article says "use explicit waits". We already do. Flake still happens. What's the practical checklist for cutting flake in an existing Selenium suite without a full rewrite?

seleniumflakymaintenance
Related learningLearn this concept in the Playwright course

1 answer

Accepted solution

Pilot-seed-arjun-kJul 25

Concrete checklist that cut our Selenium flake from ~7% to <1.5% without a rewrite. Attack in this order: **1. Ban these three patterns entirely (add a lint rule):** - `Thread.sleep` anywhere in tests or page objects. - `WebDriverWait` with `ExpectedConditions.presenceOfElementLocated` — presence ≠ interactability. Use `elementToBeClickable` for buttons, `visibilityOfElementLocated` for reads. - `driver.findElement` inside a loop. **2. Wrap every interaction in a retry-once helper.**

java
public static void safeClick(WebDriver d, By locator) {
  new WebDriverWait(d, Duration.ofSeconds(10))
    .ignoring(StaleElementReferenceException.class)
    .ignoring(ElementClickInterceptedException.class)
    .until(ExpectedConditions.elementToBeClickable(locator))
    .click();
}

That single helper kills ~40% of "stale element" and "click intercepted" flake. **3. Stop chasing IDs, start chasing roles.** Selenium 4 supports `By.tagName` + `getAttribute("role")` — write a small helper that emulates Playwright's `getByRole`. Semantic locators break less when devs restyle. **4. Isolate test data.** 60% of "random" flake is two tests fighting for the same user/order/record. Give every test its own seeded row (API pre-step, not UI). **5. Quarantine, don't skip.** Add a `@Flaky` TestNG group. Failing tests move there automatically after 3 CI reds. Suite still fails if quarantine >5% of total — forces you to fix, not hide. **6. Turn on retries with attribution.** TestNG's `IRetryAnalyzer` with **max 1 retry** + logging so you can see flake rate over time. Retries hide flake; instrumented retries expose the culprits. **7. Kill the Grid session leak.** If you're on Selenium Grid, restart nodes every N sessions (`SE_NODE_MAX_SESSIONS=50`, `SE_NODE_SESSION_TIMEOUT=300`). Long-lived nodes accumulate zombie browsers. Track flake rate weekly, name-and-shame in a dashboard. Culture beats code for flake.