36

I'm currently checking to see if a WebElement is stale by doing the following:

public static boolean isStale(WebElement element) {
    try {
        element.click();
        return false;
    } catch (StaleElementReferenceException sere) {
        return true;
    }
}

This is the same as the solution offered to this question:

Check for a stale element using selenium 2?

However, this seems rather messy to me. Is there a cleaner way that I can check if an element is stale, without having to throw and catch an exception?

(Also, as a side, if I have to stick with throwing and catching an exception, is there something better to do than clicking/sending keys/hovering to throw said exception? I might have a WebElement that I don't want to do any of these actions on, as it may inadvertently affect something else.)

Community
  • 1
  • 1
James Dunn
  • 8,064
  • 13
  • 53
  • 87
  • You can use `getLocation` or any other getter on the web element instead of click. Note that some of the getters might not connect to the web driver and hence might not throw the `StaleElementReferenceException` – Dakshinamurthy Karra Aug 21 '14 at 05:46

5 Answers5

32

Webdriver itself uses the try/catch-construction to check for staleness as well.

from org.openqa.selenium.support.ui.ExpectedConditions.java:

  public static ExpectedCondition<Boolean> stalenessOf(final WebElement element) {
    return new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver ignored) {
        try {
          // Calling any method forces a staleness check
          element.isEnabled();
          return false;
        } catch (StaleElementReferenceException expected) {
          return true;
        }
      }

      @Override
      public String toString() {
        return String.format("element (%s) to become stale", element);
      }
    };
}

The isEnabled() check is better than using a click action - clicking an element might cause unwanted side effects, and you just want to check the element's state.

Community
  • 1
  • 1
Marielle
  • 898
  • 6
  • 8
21

I know this already has an accepted answer and I don't know the bigger context of how you use the staleness check but maybe this will help you or others. You can have ExpectedConditions.stalenessOf(WebElement) do the work for you. For example,

WebElement pageElement = driver.findElement(By.id("someId"));
WebDriverWait wait = new WebDriverWait(webDriver, 10);
// do something that changes state of pageElement
wait.until(ExpectedConditions.stalenessOf(pageElement));

In this case, you don't have to do pageElement.click(), etc. to trigger the check.

From the docs, .stalenessOf() waits until an element is no longer attached to the DOM.

References: ExpectedConditions

JeffC
  • 22,180
  • 5
  • 32
  • 55
  • why is `element.click` affected by implicit wait of the driver? – rrw Mar 31 '16 at 06:47
  • @richmondwang the OP is using `.click()` to test if the element exists and trap the exception if it doesn't exist. With the method I show above, we check for staleness in another way so the `.click()` is no longer needed. – JeffC Apr 01 '16 at 03:49
  • okay, lets say there is no `.click()`, but still other methods of the webelement is affected by the implicitWait of the driver (according to some tests and debugging I've made). `ExpectedConditions.stalenessOf(pageElement)` is using `.isDisplayed()` underneath (if im not mistaken), hence this will also wait for the timeout before it will (say it is already stale) throw `StaleElementReferenceException`. I am wondering why are they affected of the implicitWait if they're already stale? – rrw Apr 01 '16 at 07:26
  • because if you rely on the staleness of an element for your test to continue, in large scale this is very slow because of the implicitWait, so I was wondering. What I did though, is I created a method that will take an anonymous function. Inside the method, I turned off the implicitWait, run the anon function, and then turn the implicitWait again. what do you think? is there any other possible ways more elegant and maybe more efficient? – rrw Apr 01 '16 at 07:51
  • The docs state that you shouldn't mix implicit and explicit waits... you will get unexpected results. That's probably what you are seeing. The ExpectedConditions polls every 500ms (by default) so it's pretty fast... you shouldn't see any slowness because of the wait for staleness. – JeffC Apr 02 '16 at 20:32
  • well, when i tested it, it waited for the implicitWait which was set to 7 seconds. – rrw Apr 03 '16 at 03:27
  • That's mixing implicit and explicit waits which you shouldn't do. Please read the docs: http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits. – JeffC Apr 04 '16 at 20:15
  • maybe I should have opened a new question instead of commenting here.. thank though! :) – rrw Apr 05 '16 at 01:37
  • No need for a new question... this question has been asked a lot. Just google or search this site some and you'll find lots of discussion around it. – JeffC Apr 06 '16 at 13:22
  • couple of related and useful links would like to share here http://sqa.stackexchange.com/questions/12866/how-fluentwait-is-different-from-webdriverwait http://www.obeythetestinggoat.com/how-to-get-selenium-to-wait-for-page-load-after-a-click.html – vikramvi Aug 16 '16 at 12:26
3

Classic statement for C# to check staleness of web element

protected bool IsStale
{
    get { return ExpectedConditions.StalenessOf(webElement)(WebDriver); }
}
Kovpaev Alexey
  • 1,725
  • 6
  • 19
  • 38
  • In Java this would be: `return ExpectedConditions.stalenessOf(element).apply(driver)` and in my opinion should be considered the correct answer being a straight query as to whether the element is stale rather than making an unwanted call on the element in order to catch (or not) the exception. – Easty77 Dec 03 '22 at 12:34
0

I don't fully understand what you want to do. What do you mean by 'messy' solution?

Maybe you can use an explicite wait an as expected condition stalenessOf in combination with not. But every solution with that don't seems stable to me.

What I do is, that I have an clicking routine in a helperclass, the idea is like:

public void ClickHelper(WebDriver driver, By by){
    int counter = 1;
    int max = 5;
    while (counter <= max) {
       try {
            WebElement clickableWebElement = driver.findElement(by);
            clickableWebElement.click();
            return;
            } catch (StaleElementReferenceException e) {
                System.out.print("\nTry " + counter + " with StaleElementReferenceException:\n" + e.getMessage() + "\n");
            }
       versuche++;
    }
    throw new RuntimeException("We tried " + max + " times, but there is still an Exception. Check Log!");
}
           

Be careful, I just entered this by simplyfying my own methode (there are some more checks and personally I use xpath and not by etc). There might be some typo-mistakes, but i guess you will understand the basic idea. Since I use this Helpermethode, I don't have to care about Staleness of webelements. You can alter the max-value, but personally I think, if the website is such unstable, that the Element is stale so much, I would talk to the developer, because this would not be a good website.

Gaurang Tandon
  • 6,504
  • 11
  • 47
  • 84
Matthias
  • 318
  • 1
  • 7
  • 1
    "What do you mean by 'messy' solution?" - using exceptions for control flow is an antipattern: http://wiki.c2.com/?DontUseExceptionsForFlowControl – johnmarinelli Oct 01 '18 at 10:36
-1

This should work without dependency of display/ enabled:

def is_element_on_page(element):
            try:
                element.get_attribute('')
                return True
            except StaleElementReferenceException:
                return False
Dana
  • 109
  • 1
  • 6