Blog

What is a stale element and how to fix it

December 3, 2015

CoreValue code experts are big fans of sharing their experience with technologies and sophisticated solutions.

If you are reading this you must have encountered  stale element.

As you may already know a ‘stale element’ means == an old, outdated element…

An element can become outdated if a page is changed somewhere in between element declaration and actual use of element. (changes are usually caused by JavaScript, Ajax,JQuery etc.)

A common scenario looks like this:

Element declaration =>Actions that cause changes(JS,Ajax etc.)=>use of element => Stale Element exception.

The simple example is:

1
2
3
4
5
6
/*
WebElement element = driver.findElement(By.id(“search button”)); //we declare the element
element.click()              // this action triggers some updates (page/table refresh etc.)
element.click()                                        // this line would give stale element exception
*/

There are two possible ways to get Stale element exception:

  • The element has been replaced entirely.

In first case: JS library or Ajax replaced an element with another one with the same ID or attributes. This element may look identical but it is different; the driver does not know if the replaced element is actually what’s expected and will give a Stale Element exception.

A common technique in a web app is to prepare DIVs for each tab, but only attach one at a time. Your code might have a reference to an element that is no longer attached to the DOM (that is, that has an ancestor which is “document.documentElement”).

How to fight and avoid Stale Elements.

There are many ways of dealing with Stale Element Exception on the web. Here I gathered the ones that I personally find most useful.

  • A good practice is to use @FindBy annotation because of Lazy Initialization This way elements will be initialized right before actual usage.

Example: @FindBy(xpath=”someXpath” ) public WebElement someElement;

  • Use wait methods for JavaScript, Ajax, Jquery etc. This will solve the “Race condition” that causes this exception to occur.

Examples:

This method waits for all jQuery to finish.

1
2
3
4
5
6
7
8
public void waitForAjax() {
new WebDriverWait(driver, waitTimeout).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
JavascriptExecutor js = (JavascriptExecutor) d;
return (Boolean) js.executeScript(“return jQuery.active == 0”);
}
});
}

This method waits for page to be loaded.

1
2
3
4
5
6
7
8
9
10
11

public void waitForPageToLoad(WebDriver driver) {
ExpectedCondition<Boolean> pageLoadCondition = new
ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript(“return                            document.readyState”).equals(“complete”);
}
};
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(pageLoadCondition);
}

  • More common practice is to use try catch in a loop.
1
2
3
4
5
6
7
8
9
10
11
12
13

while(attempts < 3) {
try {
driver.findElement(by).click();
result = true;
break;
} catch(StaleElementException e) {

System.out.println(“Caught Stale Element here”);
}
attempts++;
}
return result;
}

NOTE: This approach is not very flexible and should only be used if ‘stale element’ cannot be prevented by other means. Also we should always put a system.out message into catch block, this will spare you few hours if you get an error anyway.

  • Working with lists solution.

If you have a piece of code similar to this one:

1
2
3
4

List<WebElement> elements = driver.findElements(By.xPath(“someXpath”));
for(WebElement element : elements) {
// your code should be here
}

Try changing it to a format below. Doing so your element will be declared directly before actual usage.

1
2
3
4
5
6

int listSize = driver.findElements(By.xPath(“someXpath”)).size();
for(int i = 1; i <= listSize; i++) {
String locator = someXpath+’[’+i+’]’;
WebElement element = driver.findElement(By.xPath(locator));
// your code should be here
}

Hope this information was helpful. Try preventing the problem so you won’t have to fix it later!

Tags



Share


2 replies
  1. Mihir
    Mihir says:

    Nice Article!!
    I had used all the solution except the last one..
    used the last solution just now in similar type of code.. works nicely..

    Thanks

    Reply
  2. VideoPortal
    VideoPortal says:

    The most frequent cause of this is that page that the element was part of has been refreshed, or the user has navigated away to another page. A less common, but still common cause is where a JS library has deleted an element and replaced it with one with the same ID or attributes. In this case, although the replacement elements may look identical they are different; the driver has no way to determine that the replacements are actually what’s expected.

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *

Recent Articles

Part 2: Optimizing and scaling microservices. Organic growth of eco-systems.

October 11, 2017 | Nikola Krastev

A microservices approach is not a silver bullet for all software architecture problems. It introduces tradeoffs and challenges of its own. However, process gains and improvements in human performance have been considered to be worth the overhead in technology. Here are some general arguments against using sophisticated SOA. Server performance and overhead in communication By […]

CoreValue President at IT Arena 2017

September 27, 2017

We are pleased to announce that CoreValue president Igor Kruglyak will participate in IT Arena 2017, to be held in Lviv, Ukraine, September 29 – October 1, 2017.