</>

Technology

Selenium

Difficulty

Advanced

Interview Question

Scenario: Your Selenium test is flaky — sometimes passes, sometimes fails. How do you debug and fix it?

Answer

Debugging and Fixing Flaky Selenium Tests

What Makes Tests Flaky?

CODE
Root Causes of Flakiness:
1. Timing/Synchronization — element not ready yet
2. StaleElementReferenceException — DOM changed between find and use
3. Test order dependency — Test B relies on state left by Test A
4. Environment inconsistency — different browser version, network speed
5. Thread safety — parallel tests sharing state
6. Hardcoded sleeps — sleep(3000) too short on slow machine
7. Implicit + explicit wait conflicts — doubled timeouts
8. Element covered by another — ads, spinners, cookie banners

Diagnosis Steps

Step 1 — Capture Evidence

Java
// Add a TestNG listener that screenshots on every failure
@Override
public void onTestFailure(ITestResult result) {
    // Screenshot
    File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(screenshot, new File("fails/" + result.getName() + ".png"));

    // Page source
    String source = driver.getPageSource();
    FileUtils.writeStringToFile(new File("fails/" + result.getName() + ".html"), source);

    // Current URL
    System.out.println("FAIL URL: " + driver.getCurrentUrl());
    System.out.println("FAIL Title: " + driver.getTitle());
}

Step 2 — Add Detailed Logging

Java
// Log what happens at each step
public void click(By locator) {
    log.info("Waiting for element: " + locator);
    WebElement el = waitForClickable(locator);
    log.info("Clicking: " + locator);
    el.click();
    log.info("Clicked: " + locator);
}

Step 3 — Run in Isolation

Java
// Run the specific flaky test 10 times alone
// testng.xml
<suite name="Flaky Debug" verbose="2">
    <test name="FlickyTest" preserve-order="true">
        <classes>
            <class name="com.tests.PaymentTest">
                <methods>
                    <include name="testCheckoutFlow"/>
                </methods>
            </class>
        </classes>
    </test>
</suite>

Common Fixes

Fix 1 — Replace sleep() With Explicit Wait

Java
// ❌ Flaky
Thread.sleep(3000);
driver.findElement(By.id("result")).click();

// ✅ Reliable
wait.until(ExpectedConditions.elementToBeClickable(By.id("result"))).click();

Fix 2 — Wait for Loading Spinners to Disappear

Java
// Wait for spinner to vanish before acting
protected void waitForPageLoad() {
    By spinner = By.cssSelector(".spinner, .loading-overlay, [data-loading='true']");
    try {
        new WebDriverWait(driver, Duration.ofSeconds(3))
            .until(ExpectedConditions.visibilityOfElementLocated(spinner));
    } catch (TimeoutException ignored) {}
    wait.until(ExpectedConditions.invisibilityOfElementLocated(spinner));
}

Fix 3 — Handle StaleElementReferenceException

Java
protected WebElement findWithRetry(By locator) {
    for (int attempt = 0; attempt < 3; attempt++) {
        try {
            return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
        } catch (StaleElementReferenceException e) {
            log.warn("Stale element, retrying: " + locator + " attempt " + attempt);
        }
    }
    throw new RuntimeException("Element stale after 3 attempts: " + locator);
}

Fix 4 — Wait for AJAX/Network Calls

Java
// Wait for jQuery AJAX to complete
public void waitForAjax() {
    wait.until(driver -> {
        Boolean isIdle = (Boolean) ((JavascriptExecutor) driver)
            .executeScript("return jQuery.active === 0");
        return isIdle;
    });
}

// Wait for Angular to stabilize
public void waitForAngular() {
    js.executeAsyncScript(
        "var callback = arguments[arguments.length - 1];" +
        "angular.getTestability(document.body).whenStable(callback);");
}

Fix 5 — Fix Test Order Dependency

Java
// ❌ Depends on previous test
@Test(priority = 2)
public void testCheckout() {
    // Assumes testLogin() ran first and left cookies
}

// ✅ Each test sets its own state
@Test
public void testCheckout() {
    loginPage.login("alice@test.com", "Pass@123");  // explicit setup
    productPage.addToCart("Laptop");
    cartPage.checkout();
}

Fix 6 — Dismiss Cookie Banners / Popups

Java
@BeforeMethod
public void dismissCookieBanner() {
    try {
        WebElement cookieBtn = new WebDriverWait(driver, Duration.ofSeconds(3))
            .until(ExpectedConditions.elementToBeClickable(
                By.cssSelector("#cookie-accept, .cookie-consent-btn")));
        cookieBtn.click();
    } catch (TimeoutException e) {
        // No cookie banner — that's fine
    }
}

Fix 7 — JS Click for Intercepted Clicks

Java
// ❌ org.openqa.selenium.ElementClickInterceptedException
element.click();

// ✅ JavaScript click bypasses element interception
((JavascriptExecutor) driver).executeScript("arguments[0].click();", element);

Retry Mechanism for Critical Tests

Java
// TestNG retry analyzer — re-run flaky tests up to 2 times
public class RetryAnalyzer implements IRetryAnalyzer {
    private int count = 0;
    private static final int MAX_RETRY = 2;

    @Override
    public boolean retry(ITestResult result) {
        if (count < MAX_RETRY) {
            count++;
            log.warn("Retrying test: " + result.getName() + " (attempt " + count + ")");
            return true;
        }
        return false;
    }
}

// Apply to test
@Test(retryAnalyzer = RetryAnalyzer.class)
public void testFlickyFeature() { ... }

Follow AutomateQA

Related Topics