"StaleElementReferenceException" even after using FluentWait ignoring StaleElementReferenceException

611 views
Skip to first unread message

testingzeal

unread,
Jun 10, 2016, 5:19:49 PM6/10/16
to webdriver
I have a form that has 4 dropdowns. Based on first dropdown selection , second dropdown list is populated and based on second drop down selection third dropdown list is populated and based on third selection fourth drop down list is populated.

1.Department
2.Country
3.Language
4.Reason


I have created a method using fluent waits giving the drop down time to load based on prior selections. But below method still fails on StaleElementReferenceException. To verify if it is timing issue, i placed Thread.sleep(200) instead of fluent waits and the test is successful.

Please help me in understand how to avoid hard waits to handle this situation. 

My test runs on Windows 7 and IE11 browser.


public void submit()
{

Wait<WebDriver> wait1 = new FluentWait<WebDriver>(driver)
.withTimeout(shortTimeoutInSeconds, TimeUnit.SECONDS)
.pollingEvery(pollTimeInSeconds, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class);
wait.until(ExpectedConditions.elementToBeClickable(Department));


Department.click();

new Select(Department).selectByIndex(1);



Wait<WebDriver> wait2 = new FluentWait<WebDriver>(driver)
.withTimeout(shortTimeoutInSeconds, TimeUnit.SECONDS)
.pollingEvery(pollTimeInSeconds, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class);
wait.until(ExpectedConditions.elementToBeClickable(Country));


Country.click();

new Select(Country).selectByIndex(1);


Wait<WebDriver> wait3 = new FluentWait<WebDriver>(driver)
.withTimeout(shortTimeoutInSeconds, TimeUnit.SECONDS)
.pollingEvery(pollTimeInSeconds, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class);
wait.until(ExpectedConditions.elementToBeClickable(Language));


Language.click();

new Select(Language).selectByIndex(1);


}

darrell grainger

unread,
Jun 11, 2016, 9:01:23 AM6/11/16
to webdriver
A StaleElementReferenceException usually isn't because you aren't waiting. That would be an ElementNotFoundExcpetion. The stale element exception occurs because the DOM has updated by the time you reference a WebElement. The flow is typically:
  1. Execute a findElement()
  2. DOM updates due to javascript or AJAX
  3. Attempt to interact with the WebElement you found
Even when you have something like driver.findElement(byLocator).click() it is not atomic. In other words, there is a moment between findElement() and click().

I'd have to look at the implementation to figure out exactly what is going on but it is usually because you are not wait for the correct thing. Maybe rather than waiting for the element you are trying to select, you want to wait for the last item on the list. Once the last update to the list has occurred then it would be safe to find and select the drop down you want. 

Another possibility is that there is just something running in the background which refreshes things in the page. When this refresh occurs the DOM goes stale. When you use a FluentWait your timing is just right to expose the issue. When you use a Thread.sleep(200) your timing hides the issue. In other words, the sleep() isn't fixing the problem; it is just hiding it.

Finally, I tend to use WebDriverWait in place of WebDriver. You create an instance of WebDriverWait from a WebDriver instance but it acts more like a FluentWait. It has been a few years since I used a FluentWait. So I'm not exactly sure how you are using it. It looks like you are creating a reference to the WebElement, waiting then clicking it. Maybe your use of FluentWait is the wrong order.

testingzeal

unread,
Jun 13, 2016, 1:18:46 PM6/13/16
to webdriver
Thanks Darrell.

I tried below code , but still having issues and thread.sleep(200) is working perfect.

//Helper method = 1

public static void WaitForElementTobeClickable(final WebElement webElement, long shortTimeoutInSeconds)
{
try
{
WebDriverWait wait = (WebDriverWait)new WebDriverWait(driver,shortTimeoutInSeconds)
.ignoring(StaleElementReferenceException.class); 
wait.until(new ExpectedCondition<Boolean>(){ 
@Override 
public Boolean apply(WebDriver webDriver) { 
return webElement != null && webElement.isEnabled();
}); 

}
catch(Exception e)
{
e.printStackTrace();

}

}


//Helper method = 2

public static void selectClick(final WebElement webElement)throws Exception
{
try
{
CommonUtils.WaitForElementTobeClickable(webElement,shortTimeoutInSeconds);
webElement.click();
driver().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(new ExpectedCondition<Boolean>() {
   public Boolean apply(WebDriver driver) {
       return new Select(webElement).getOptions().size() > 1;
 }
});
new Select(webElement).selectByIndex(1);
}
catch(Exception e)
{
e.printStackTrace();
}
}


//Form method

@CacheLookup
@FindBy(how=How.ID,using="TDepartment")WebElement Department;
@CacheLookup
@FindBy(how=How.ID,using="TransLocation")WebElement Region;
@CacheLookup
@FindBy(how=How.ID,using="TransLocation")WebElement Language;

public EditTicket editTicket()throws Exception
{
CommonUtils.selectClick(Department);
CommonUtils.selectClick(Country);
CommonUtils.selectClick(Language);

}

Thanks for your time!

erki manniste

unread,
Jun 14, 2016, 7:43:38 AM6/14/16
to webdriver

Annotation Type CacheLookup



  • @Retention(value=RUNTIME)
     @Target(value=FIELD)
    public @interface CacheLookup
    Marker annotation to be applied to WebElements to indicate that it never changes (that is, that the same instance in the DOM will always be used)


https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/CacheLookup.html
Reply all
Reply to author
Forward
0 new messages