Selenium: How to tell if RemoteWebDriver.findElements(By) can throw StaleElementReferenceException at all?

回眸只為那壹抹淺笑 提交于 2019-11-26 21:10:53

You pinpointed issue about "StaleElementReferenceException", this is related when webElement instances changes, when DOM is changed due some activity on page.

It is related to how WebDriver internally handles references to webElements, and this issue happens when during runtime references to object(s) are changed.

Now, let’s assume when you have fetched the element and before doing any action on it, something got refreshed on your page. It could be the whole page that is being refreshed or some call which has refreshed only a section of the DOM where your element falls.

In this scenario the internal id which WebDriver was using, and stored somewhere in cache has become stale (not referenced anymore), so now for every operation on this WebElement, we will get StaleElementReferenceException.

So to try to avoid it on critical places try to use this method, for determine if element is stale.

public static boolean isStale(WebElement e){
    try{
        e.isDisplayed();
        return false;
    }catch(StaleElementReferenceException ex){
        return true;
    }
}

Usually refreshing of page, pageObject, or just this particular element would help in 90% of cases.

And after refreshing page/element WebDriver will assign a different internal Id to this element, and will be able to use it again without any problem.

This problem is solver with PageObject / PageFactory design patter.

public class SomePage {
    @FindBy(how = How.NAME, using = "q")
    private WebElement searchBox;


    public SomePage() {
        PageFactory.initElements(driver, this);
    }


    public void searchFor(String text) {
        searchBox.sendKeys(text);
    }
}

Hope this helps,

StaleElementReferenceException

StaleElementReferenceException extends WebDriverException and indicates that a reference to an element is now "stale" and the element reference is no longer present on the DOM of the page.


Answering your queries one by one:

  • StaleElementReferenceException can be thrown only if the code operates on a WebElement instance, calling methods on it after the corresponding DOM element has been reloaded or removed: You are almost there. Here are the complete complete list of the causes:
    • The element has been deleted entirely.
    • The element is no longer attached to the DOM.
    • The webpage on which the element was part of has been refreshed.
    • The (previous) element has been deleted by a JavaScript or AjaxCall and is replaced by a (new) element with the same ID or other attributes.
  • Solution : If a old element has been replaced with new identical one, the simple strategy would be to use findElement or findElements to look out for the element again.
  • I looked for that kind of code in the source of the RemoteWebDriver implementation of WebDriver interface : From user level perspective it wouldn't add any value even knowing the algorithm or the flow chart. As a end user you need to get a clear understanding of the implementation which will help you to deliver optimized Test Code.
  • Besides trying to figure that out by inspecting Selenium source, are there better ways to tell if a WebDriver method in general - or just findElements(By) in particular - can throw StaleElementReferenceException : There is no single or full proof way to predict whether findElement(By) or findElements(By) can through StaleElementReferenceException or not. If the AUT (Application Under Test) is based on either JavaScript, AjaxCalls or jQuery, most of the WebElements will be dynamic and that's where WebDriverWait comes to our rescue before looking out for the element(s).

References

Here are the references of this discussion:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!