Resolving the “Element is no longer attached to the DOM” StaleElementReferenceException in Selenium WebDriver

Resolving the "Element is no longer attached to the DOM" StaleElementReferenceException in Selenium WebDriver

21 May 2024 Stephan Petzl Leave a comment Tech-Help

Selenium WebDriver is a powerful tool for automating web applications, but it can sometimes present challenges such as the StaleElementReferenceException. This exception occurs when an element that was previously located in the DOM is no longer present. Below, we will explore the best practices to handle this issue effectively.

Understanding the StaleElementReferenceException

The StaleElementReferenceException typically arises due to a race condition. Consider the following scenario:

WebElement element = driver.findElement(By.id("foo"));
// DOM changes - page is refreshed, or element is removed and re-added
element.click();
    

In this example, by the time the click() method is called, the element reference is no longer valid. This can happen due to various reasons such as page refreshes, AJAX updates, or dynamic content changes.

Solution: Explicit Waits with WebDriverWait

To mitigate this issue, you can use explicit waits to ensure the DOM is in a stable state before interacting with elements. Here’s an example:

// Times out after 5 seconds
WebDriverWait wait = new WebDriverWait(driver, 5);

// Wait until the specified element is present
wait.until(presenceOfElementLocated(By.id("container-element")));

// Now it's safe to interact with the element
driver.findElement(By.id("foo")).click();
    

The presenceOfElementLocated() method ensures that the element is present in the DOM before any interaction occurs. Here’s how you can define this method:

private static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
    return new Function<WebDriver, WebElement>() {
        @Override
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    };
}
    

Alternative: Implicit Waits

Another approach is to use implicit waits, although it is generally considered less reliable than explicit waits:

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    

Handling AJAX Updates

AJAX updates can also cause StaleElementReferenceException. A practical solution is to wait for a specific condition using JavaScript:

webDriverWait.until((webDriver1) -> 
    (((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete")));

if ((Boolean) ((JavascriptExecutor) webDriver).executeScript("return window.jQuery != undefined")) {
    webDriverWait.until((webDriver1) -> 
    (((JavascriptExecutor) webDriver).executeScript("return jQuery.active == 0")));
}
    

Retries on Stale Elements

For a more robust solution, you can implement a method to retry actions on stale elements:

WebElement getStaleElemById(String id) {
    try {
        return driver.findElement(By.id(id));
    } catch (StaleElementReferenceException e) {
        System.out.println("Attempting to recover from StaleElementReferenceException ...");
        return getStaleElemById(id);
    }
}
    

Conclusion

Handling StaleElementReferenceException requires understanding the root cause, which is often related to dynamic changes in the DOM. Using explicit waits and retries are effective strategies to address this issue.

For those looking to streamline their test automation process, consider using Repeato, a no-code test automation tool for iOS and Android. Repeato’s intuitive test recorder and computer vision-based approach make it particularly fast to edit and run tests. Advanced users can also leverage the scripting interface to automate complex use cases. Learn more about how Repeato can enhance your testing workflow in our blog post.

Like this article? there’s more where that came from!