Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix 'stale element reference exception' while trying to pick date from date-picker?

I am trying to select date from the Datepicker.Following is the code

WebDriver d=new FirefoxDriver();
Actions a=new Actions(d);
String date="14";
d.get("http://www.eyecon.ro/bootstrap-datepicker/");
d.findElement(By.cssSelector("div#dp3>span")).click();
List<WebElement> trs=d.findElements(By.cssSelector("div.datepicker-days>table>tbody>tr"));
       for(WebElement tr:trs) {
            List<WebElement> tds=tr.findElements(By.tagName("td"));
            for(WebElement td:tds) {
                if(date.equals(td.getText())) {
                    a.moveToElement(td).click().build().perform();

                }
            }

}

With the above code i got stale element reference exception at this line of code

"if(date.equals(td.getText())) {"

so i have changed the code to this

for(WebElement td:tds) {
                while(i<4) {
                    try {
                        if(date.equals(td.getText())) {
                            a.moveToElement(td).click().build().perform();

                        }
                        break;
                    }catch(Exception ex) {

                    }
                    System.out.println(i);
                    i++;
                }
            }

Now i am able to select the date.But the script is still throwing the stale element reference exception.The script is showing error at this line now

List<WebElement> tds=tr.findElements(By.tagName("td"));

I am working on this for the past 3 days.Any suggestions on how to solve this. Thanks in advance

like image 584
Rachel D'cruz Avatar asked Feb 11 '15 11:02

Rachel D'cruz


2 Answers

In your first code, after you clicked on the element, the DOM changed, as in the Date became "14", and since the both the for-loop were still iterating, hence it threw StaleElementReferenceException.

Similarly, in the second code, you did break the "inside for-loop" that was iterating the td elements, but you didn't break the "outside" one, that continued with iterating the tr elements, hence it threw StaleElementReferenceException yet again.

Resolution:- You should've come out of both the for-loops using break after the element was clicked, and hence averting the StaleElementReferenceException, in the process.

Below code shows how you could've broken out of both the for-loops without any exception:

    WebDriver d=new FirefoxDriver();
    d.manage().window().maximize(); //Maximizing window
    d.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS); //Implicit wait for 20 seconds

    Actions a=new Actions(d);
    String date="14";
    int flag=0;

    d.get("http://www.eyecon.ro/bootstrap-datepicker/");
    d.findElement(By.cssSelector("div#dp3>span")).click();
    List<WebElement> trs=d.findElements(By.cssSelector("div.datepicker-days>table>tbody>tr"));
    for(WebElement tr:trs) {
        List<WebElement> tds=tr.findElements(By.tagName("td"));
        for(WebElement td:tds) {
            if(date.equals(td.getText())) {
                a.moveToElement(td).click().build().perform();
                flag=1; // Set to 1 when the required element was found and clicked.
                break; //To come out of the first for-loop
            }
        }
        if(flag==1)
            break; //Since the element was found, come out of the second for-loop.
    }

NOTE:- I have added the code for maximizing windows and providing implicit wait too, which is actually advised when you are writing selenium scripts.

like image 168
Subh Avatar answered Oct 07 '22 01:10

Subh


You should use WebDriverWait and ExpectedConditions to tackle staleness of an element. Below is modified block of your code which I tested and it works.

 driver.findElement(By.cssSelector("div#dp3>span")).click();
 WebDriverWait wait = new WebDriverWait(driver, 30);
 List<WebElement> trs = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("div.datepicker-days>table>tbody>tr")));
 datePicker:
 {
    for (WebElement tr : trs) {
       List<WebElement> tds = tr.findElements(By.tagName("td"));
       for (WebElement td : tds) {
                 wait.until(ExpectedConditions.not(ExpectedConditions.stalenessOf(td)));
                 if (date.equals(td.getText())) {
                        td.click();
                        break datePicker;
                 }
        }
     }
 }

For more information check WebDriverWait and ExpectedConditions here

like image 22
nilesh Avatar answered Oct 07 '22 01:10

nilesh