Best way to avoid or solve StaleElementReferenceException for lists

702 views
Skip to first unread message

Alex

unread,
Jan 12, 2012, 7:20:16 AM1/12/12
to Selenium Users
I'm currently trying to automate Google Calendar as some sort of
showcase to demonstrate the power of Selenium WebDriver / Selenium 2.
As this website is using an massive amount of AJAX there are many
points where you get the stated exception. To solve it for single
elements I'm usually just reloading the element.

So for example I would write something like this

----------
...

By locator = By.id("anID");
...
WebElement element = driver.findBy(locator);
...
for (int i = 0; i < RETRY_COUNT; i++) {
try {
element = driver.findElement(locator);
element.getText();
return element;
} catch (StaleElementReferenceException e) {
try {
Thread.sleep(RETRY_TIMER);
} catch (InterruptedException ie) {}
}
}
throw new StaleElementReferenceException("Severe Error: Stale
WebElement could not become revived after " + RETRY_COUNT + "
tries.");
----------

This is just an example - in my code I would define a method that will
do that job for me and returns the "stalesafe" element back.

Now to the bigger problem: Doing this in lists (created by
driver.findElements(locator)) doesn't work the same way. You will get
the list but iterating over it gets problematic. Refreshing the
elements is not working the same way.

I tried to solve this by adding a method to refresh an element of a
list but it isn't working as expected -- I'm still running into
StaleElementReferenceExceptions for the elements in a list sometimes.

Do you know a way to get rid of this problem?
Many thanks in advance
Alex

----------
For people just getting the exception who doesn't know, what this
means: Usually this exception just means, that an WebElement you are
trying to work with is not valid anymore because it got removed from
the DOM (for example because you did something like clicking an
element on your website and this led to a reload of the DOM).

John Crawford

unread,
Jan 19, 2012, 3:04:45 PM1/19/12
to seleniu...@googlegroups.com
Hi Alex, et al,

FWIW, I had a problem similar to this, and I solved it as follows. First, as in your example, I used a try/catch block to catch any StaleElementReferenceException that may be thrown. Second, inside the "catch", I recursively called the method in which all this occurred, effectively starting all over again, from scratch, with a brand new list (followed by "return").

Of course, whether and exactly how this will work for depends on exactly what you are doing. There is a theoretical possibility of an infinite loop, if you keep getting the same exception over and over; but in practice I found it to work very well, for my application - the StaleElementReferenceException only occurred when the list I was traversing refreshed itself in mid-stream, which generally only happened once.

Hope that helps,
 - John C.


--
You received this message because you are subscribed to the Google Groups "Selenium Users" group.
To post to this group, send email to seleniu...@googlegroups.com.
To unsubscribe from this group, send email to selenium-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/selenium-users?hl=en.


Message has been deleted
Message has been deleted

rickard josefsson

unread,
Feb 28, 2014, 4:46:22 AM2/28/14
to seleniu...@googlegroups.com, alexande...@googlemail.com
I know this is a old post but thought I would give my answer anyways. My function looks a little something like this:

    public WebElement reload(WebElement e) {
        By by = parseBy(e);
        if (by == null) {
            return null;
        }
        return Config.driver.findElement(by);
    }

    public By parseBy(WebElement e) {
        String selectorExpression = e.toString();
        Matcher matcher = Pattern.compile("-> ([^:]+): (.*)]").matcher(
selectorExpression);
        matcher.find();
        String selectorType = matcher.group(1);
        String selector = matcher.group(2);

        switch (selectorType) {
            case "id":
                return By.id(selector);
            case "class name":
                return By.className(selector);
            case "css selector":
                return By.cssSelector(selector);
        }
        return null;
    }

It's a rather simple function and is easely modefied to handle List of elementes if you want instead of single WebElements.
Reply all
Reply to author
Forward
0 new messages