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?
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.
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.
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.
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; }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With