With the widespread of JavaScript we more and more met with one of our favourite exception which is the StaleElementReferenceException.
It can be tricky because it does not have to appear on the test development machine. This issue can hide in the test code and appear in unexpected situations.

The exception happens when the dom changes and the system can’t be sure if the Webelement is still on the page.
Dom changes can be caused by page refresh, javascript effects, ajax responses and so on.

There are 3 quick strategies/solutions we can use in these cases:

  • Instead using simple wait like this:

    waitHandler(ExpectedConditions.elementToBeClickable(locator),BASIC_WAIT_TIME_IN_SECONDS);

    Put the wait into a “while”, catch the exception and continue the waiting. This way the system will always reload the specific element and the dom change will not affect the wait function.

    </li>
    </ul>
    <pre>	int count = 0;
    	while (count &amp;lt; 4) {
    			try {
    				waitHandler(ExpectedConditions.elementToBeClickable(locator),BASIC_WAIT_TIME_IN_SECONDS / 4);
    				getMyDriver().findElement(locator).click();
    				return;
    			} catch (TimeoutException e) {
    				Reporter.log(&amp;quot;Timeout: &amp;quot; + e.getMessage());
    				count++;			
    			} catch (StaleElementReferenceException e) {
    				Reporter.log(&amp;quot;Trying to recover from a stale element :&amp;quot; + e.getMessage());
    				count++;
    			}
    	}
    
    • Get the elements directly before their usage
      Let examine the following lines:
    	WebElement elementField = getMyDriver().findElement(by);
    	WebElement elementButton = getMyDriver().findElement(by);
    	elementField.click();
    	elementField.clear();
    	elementButton.click();
    

    In the following code when you click on the field there can be some javascript validation which can change the appearance of the whole button.
    It is much safer to get the Element directly before its usage.

    	WebElement elementField = getMyDriver().findElement(by1);
    	elementField.click();
    	elementField.clear();
    	WebElement elementButton = getMyDriver().findElement(by2);
    	elementButton.click();
    

     

  • Store the locators instead of using the WebElement references.
    In cases where you have to keep doing a function while an element is visible, you can get StaleElementReferenceException when the element changes.

    </li>
    </ul>
    <pre>	WebElement errorMessage = getMyDriver().findElement(by);	
    	while(!isElementVisible(errorMessage))){
    			doY();
    			waintUntilY();
    		}
    

    In the code above we do doY and wait with waitForY until the error message is not visible. When the condition changes – the error message becomes visible – the loop will be finished.
    The solution for this example is to use the locator in the condition instead of a specific element. That way we will reread the element from the dom and avoid the exception because of the item’s state change.

    	
    	while(!isElementVisible(By.xpath(&amp;quot;.//*[@id='errorMessage']&amp;quot;))){
    			doY();
    			waintUntilY();
    		}
    

     

The list is incomplete, but the above mentioned strategies can give you ideas and spare some headache.
One way to further improve test stability is the usage of javascript library with explicit Webdriver waits.
We will handle some of those cases in the following blog posts.

Webdriver wait for ajax to finish and jquery animation

Similar Posts from the author: