1

I have a scenario as outlined in the screenshot below: enter image description here

So, I've built some code which will allow me to click on the bar charts on the left....each time I do it will display a relational bar chart on the right. If the bar chart is particularly big on the left it might take a while for the relational bar chart on the right to show. To counter this, I built a fluentWait method, as below:

    public static void fluentWaitOnRelationalBarChartSelector(InternetExplorerDriver driver)
    {
        WebElement relationalBarSelect = (new WebDriverWait(driver, 20))
                .until(ExpectedConditions.elementToBeClickable(By.tagName("rect")));
        relationalBarSelect.click();
    }

However, not always, but sometimes, I am getting an error in the console as below:

Exception in thread "main" org.openqa.selenium.StaleElementReferenceException: Element is no longer valid
(WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 33 milliseconds

What I'm not sure on is why this timeout is occurring after 33 milliseconds when I have applied a wait of 20 seconds? Is there a way of me being able to cater for this StaleElementReferenceException?

Any help would be appreciated.

Nash N
  • 342
  • 2
  • 17
Andy Tilston
  • 227
  • 1
  • 5
  • 18
  • Just a correction @Andy. `FluentWait` is a class of selenium java binding and mechanism is different then `WebDriverWait` which is a subclass of `FluentWait`. See [this](https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/FluentWait.html) – Saifur Dec 18 '14 at 13:01
  • Thanks for the tip, Saifur :-) – Andy Tilston Dec 18 '14 at 13:39
  • You are welcome. Let me know if the solution works though. – Saifur Dec 18 '14 at 13:40

2 Answers2

1

StaleElementReferenceException is a very painful and very specific to the element. It generally means the element is unavailable to interact with selenium due to a lot of issue with some very specific to your set up. To resolve this there are two different mechanism people use(at least according to my knowledge). FluentWait will probably save your life. Something like the following:

// Waiting 30 seconds for an element to be present on the page, checking
   // for its presence once every 5 seconds.
   Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
       .withTimeout(30, SECONDS)
       .pollingEvery(5, SECONDS)
       .ignoring(NoSuchElementException.class);

   WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
     public WebElement apply(WebDriver driver) {
       return driver.findElement(By.id("foo"));
     }
   });

taken from here. It's worth mentioning that it allows you to wait for an element ignoring some other exceptions as well.

If that does not work then estimate a number of loop that might be enough for that element to be ready for interact. Not my favorite but works.

public void StaleElementHandleByID (String elementID){
int count = 0; 
while (count < 4){
    try {
       WebElement yourSlipperyElement= driver.findElement(By.id(elementID));
       yourSlipperyElement.click(); 
     } catch (StaleElementReferenceException e){
       e.toString();
       System.out.println("Trying to recover from a stale element :" + e.getMessage());
       count = count+1;
     }
   count = count+4;
}

taken from here

Community
  • 1
  • 1
Saifur
  • 16,081
  • 6
  • 49
  • 73
0

Even though nothing on the page visibly changes, there might be JavaScript among other things that change the properties of a WebElement, after the page loads. This JavaScript might be triggered by a previous action that your script has performed (Ex: Click on some other WebElement).

If you try to interact (click, sendkeys etc...) with the WebElement after it's properties change, selenium will throw a StaleElementReferenceException. In such cases, your code should retry the action couple times, rather than throwing an exception on the first try, see below.

public static Boolean executeElementClick
  (WebDriver driver, WebElement element, int MaxTimeToWait) throws Exception {
    // Local variable declaration
    String sElementString = "";
    String sElementXpath = "";
    Boolean returnValue = false;
    int index = 0;

    // Set browser timeout to 1 second. Will be reset to default later
    driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);

    // Keep trying until 'MaxTimeToWait' is reached 
    for (int loop = 0; loop < MaxTimeToWait; loop++) {
        try {
            // Get element xPath - and find element again
            if (element != null && loop < 1 && sElementXpath.equals("")) {
                sElementString = (element).toString();
                if (sElementString.contains("xpath: ")) {
                    // Retrieve xPath from element, if available
                    index = sElementString.indexOf("xpath: ");
                    sElementXpath = sElementString
                                       .substring(index + 7, sElementString.length());
                }
            }

            // Find Element again
            if (!sElementXpath.equals("") && loop > 0) {
                element = driver.findElement(By.xpath(sElementXpath));
            }

            // Execute the action requested
            element.click();
            returnValue = true;

        } catch (Exception e) {
            Thread.sleep(1000);
            returnValue = false;
        }

        if (returnValue) {
            System.out.println("**** PASSED: Clicked on '" + sElementString + "'");
            break;
        }
    }
    // Reset browser timeout to default
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

    return returnValue;
}
Nash N
  • 342
  • 2
  • 17