Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid "StaleElementReferenceException" in Selenium?

I am implementing a lot of Selenium tests using Java. Sometimes, my tests fail due to a StaleElementReferenceException. Could you suggest some approaches to making the tests more stable?

like image 346
hoang nguyen Avatar asked Oct 19 '12 04:10

hoang nguyen


People also ask

What is StaleElementReferenceException and avoid in selenium?

New Selenium IDEThe StaleElementReferenceException is thrown if the webdriver makes an attempt to access a web element which is currently not available or invalid in DOM. This can be due to refresh of the page or an element is accidentally deleted or modified or no longer connected to DOM.

What is the reason of StaleElementReferenceException?

A stale element reference exception is thrown in one of two cases, the first being more common than the second: The element has been deleted entirely. The element is no longer attached to the DOM.

How do you resolve non Interactable elements?

To fix this, we can either apply explicit wait so that the webdriver waits for the expected condition - invisibilityOfElementLocated of the overlaying webelement. Or, we can apply the expected condition - elementToBeClickable on the webelement that we want to interact with.


2 Answers

This can happen if a DOM operation happening on the page is temporarily causing the element to be inaccessible. To allow for those cases, you can try to access the element several times in a loop before finally throwing an exception.

Try this excellent solution from darrelgrainger.blogspot.com:

public boolean retryingFindClick(By by) {     boolean result = false;     int attempts = 0;     while(attempts < 2) {         try {             driver.findElement(by).click();             result = true;             break;         } catch(StaleElementException e) {         }         attempts++;     }     return result; } 
like image 125
jspcal Avatar answered Sep 20 '22 15:09

jspcal


I was having this issue intermittently. Unbeknownst to me, BackboneJS was running on the page and replacing the element I was trying to click. My code looked like this.

driver.findElement(By.id("checkoutLink")).click(); 

Which is of course functionally the same as this.

WebElement checkoutLink = driver.findElement(By.id("checkoutLink")); checkoutLink.click(); 

What would occasionally happen was the javascript would replace the checkoutLink element in between finding and clicking it, ie.

WebElement checkoutLink = driver.findElement(By.id("checkoutLink")); // javascript replaces checkoutLink checkoutLink.click(); 

Which rightfully led to a StaleElementReferenceException when trying to click the link. I couldn't find any reliable way to tell WebDriver to wait until the javascript had finished running, so here's how I eventually solved it.

new WebDriverWait(driver, timeout)     .ignoring(StaleElementReferenceException.class)     .until(new Predicate<WebDriver>() {         @Override         public boolean apply(@Nullable WebDriver driver) {             driver.findElement(By.id("checkoutLink")).click();             return true;         }     }); 

This code will continually try to click the link, ignoring StaleElementReferenceExceptions until either the click succeeds or the timeout is reached. I like this solution because it saves you having to write any retry logic, and uses only the built-in constructs of WebDriver.

like image 28
Kenny Avatar answered Sep 16 '22 15:09

Kenny