-1

Using the following code I keep getting a StaleElementReference Exception when running my Webdriver scripts on firefox v57. I have tried all sorts of things but other than a thread.sleep or catching the exception and retrying I cannot get it to work.

public List<String> readCoIData (String column) throws StaleElementReferenceException 
    {
        int colNumber 0; 
        WebTable searchResuIts = getTable(); 
        FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
        wait.pollingEvery(250, TimeLinit.MILLISECONDS); 
        wait.with Timeout (30, TimeLlnit.SECONDS); 
        wait.ignoring (NoSuchElementException.class) ; 

        CustomLogger.addInfo(Logger, "Ensure that that the first column row contains text: " column ) ; 
        int colcount = searchResults.getColumnCount(); 
        CustomLogger. addlnfoLog4jOnly (logger , "colcount= " colcount )
        for (int col =1; col <= colcount; col++)
        { 
            CustomLogger.addInfoLogJOnly(Logger, "Get the cell data for col. Use a string as this does not go stale unlike a reference.' 
            String locator = String.format("pf_table_t2 > tbody:nthchild(1) > tr:nth-child(1) > td:nth-child(%d)", col); 
            wait.until(ExpectedConditions.presenceOfElementLocated(By. cssSelector (locator))) ; 

            if (driver.FindElement(By.cssSelector(locator)).getText().contains (column)) 
            {
                colNumber = Col; 
            }
        }

        CustomLogger.addInfoLogJOnly(Logger, "Assert that there is not 0 columns"); 
        assertThat (column + " not found' , colNumber !=0, is (true));
        List<String> colvalues = new ArrayList<String>();
        CustomLogger.addInfoLogJOnly(Logger, "Get the object .pf_paging a"); 
        List<WebElement) paging = driver.findElements(By.cssSelector(.pf_paging a)); 
        if (paging.size() !=0) 
        {
        CustomLogger.addlnfoLogJOnly ( logger , "If more than one result page, wait..." );
        wait.until(ExpectedConditions.visibilityOf((WebElement driver.findElement(By.cssSelector(".pf_paging_next_active"))));
        CustomLogger.addInfoLogJOnly(Logger, "Span with '>>' is found so loop through all pages and get the data"); 
        while (driver.findElements(By.cssSelector(".pf_paging_next_active")). size()  == 1)
        {
          for (int i=2; i<=searchResults.getRowCount(); i++)
          {
            String locator = String.format("pf_table_t2 > tbody:nthchild(1) > tr:nth-child(%d) > td:nth-child(%d)", I, colNumber); col);
            String cell Text = driver.findElement(By.cssSelector(locator)).getText();
            colvalues.add(cellText);
          }
         CustomLogger.addInfoLogJOnLy(Logger, "Click the Next Page Button ' to move onto next page and wait for the page to be visible.' 
         driver.findElements(By.cssSelector(.pf_paging_next_active a").click(); 
         CustomLogger.addInfoLogJ0nly(Logger, "Get & Wait for table after clicking next"); 
         // Get the element table again as we have clicked 'filter' and the DOM would have changed. 
         searchResults.getTable();}

    public WebTable getTable() 
{
    CustomLogger.addInfoLog450nLy(Iogger, "Wait and get the element table again as we have previously clicked 'filter' and the DOM would have changed"); 
    new WebDriverWait(driver, 30).until((ExpectedConditions<Boolean> driver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"));

    FluentWait(WebDriver» wait new 
    wait.pollingEvery(250, TimeLinit.MILLISECONDSS); 
    wait.with Timeout(30, TimeLlnit.SECONDS); 
    wait.ignoring (NoSuchEIementException.class) ; 

    CustomLogger.addInfo(Logger, "Wait until the results table is present.. 
    wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("pf_table_t2"))));
    CustomLogger.addInfo(Logger, "Get the results table");
    SearchResuItsTable = driver.FindElement(By.cssSelector("pf_table_t2"));
    WebTabIe searchResuIts = new WebTable(SearchResultsTabIe); 
    return searchResuIts; 
}

Essentially the page has some filter criteria and a results table with results in blocks of 10 rows, to get each new set you have to click >. i.e. the page changes. I get StaleElement exception in two places, the first happens getting the text at the locator (then setting colNumber = Col). The 2nd happens adding celltext to the colValues array. In both places I have only just got the element again. Any help would be appreciated. Thanks in advance.
Note I don't get this with the Chrome browser.

rockOn123
  • 45
  • 1
  • 1
  • 7
  • 1
    You should spend some time reading up on what stale elements are and how to prevent them. Sleeps and waits don't fix stale elements. The problem is that you are accessing a variable that contains a stored web element after the page has changed. The best way to avoid the problem is to know the site and when things change. When they do change, refetch the element from the page instead of reaccessing an old variable reference. – JeffC Jan 08 '18 at 16:00
  • I have been reading up this, posting on here as a last resort. I can only see that the page has changed after I filter the results, which is why I then refetch the tr and td elements, if you see the Locator statements in the code above. Yet I'm still getting the StaleElement Exception. The only way I can seem to deal with it is to catch the exception, but I would prefer to be more proactive. – rockOn123 Jan 08 '18 at 16:24
  • Possible duplicate of [StaleElementReference Exception in PageFactory](https://stackoverflow.com/questions/44838538/staleelementreference-exception-in-pagefactory/44844879#44844879) – undetected Selenium Jan 08 '18 at 16:26

1 Answers1

0

Just to give you a brief (if you are not aware already) StaleElementReferenceException happens because location of the webelement on the webpage (more preciously on the DOM) has changed due some ajax or similar reason. Coincidentally this happens exactly between you capturing the webelement and performing the action on the webelement.

For Example:

//Getting the webelement
WebElement element = driver.findElement(By.id("id_value"));

//Location of the webelement changes between these two steps.

//Click on the webelement
element.click();

One of the ways to handle the StaleElementReferenceException is to catch the exception at the place where it happens and handle it by re-initializing the webelement.

For example:

try {
WebElement element = driver.findElement(By.id("id_value"));
element.click();
} catch (StaleElementReferenceException e) {
Thread.sleep(3000);
WebElement element = driver.findElement(By.id("id_value"));
element.click();
}

There are also others ways to handle the StaleElementReferenceException. You can refer this link.

Better and cleaner way to handle StaleElementReferenceException is to make method for action that you are trying to perform. For Example: If you want click on a webelement.

public static void click(By by) throws Exception {
    try {
        driver.findElement(by).click();
    } catch(StaleElementReferenceException staleElement) {
        Thread.sleep(3000);
        driver.findElement(by).click();
    } catch (Exception e) {
        e.printStacktrace();
    }
}

Similarly you can create other methods.

Alok
  • 1,441
  • 4
  • 20
  • 31
  • I've been catching and handling the exception in lots of places now and including this in a loop. It does make the code look messy and wanted to know if there was a more proactive / elegant way of handling it. I can't see visibly where the page is being changed. I can only assume the page is still refreshing the results even though the table exists/ or it's found the original version of the results table. With the catch and retry approach I have to code which row I got to and start again from there if i get a staleElement so that I don't process it again. – rockOn123 Jan 08 '18 at 15:56
  • @TimGONELLA I have updated my answer. You can make a method out of the generic actions(reusable methods) that you are performing and catch the stale element exception in that method. hope it helps. – Alok Jan 08 '18 at 17:16