Search code examples
eclipseseleniumselenium-webdrivercucumber-jvm

Selenium WebDriver Stale Element Reference Exception for GWT


Ok I read all the other links, and i tried variants of the different solutions mentioned, however none of them work for me.

My Issue, I have the following Code:

package com.autotest.test.css;


import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;

import com.google.common.base.Predicate;

import java.util.concurrent.TimeUnit;

import cucumber.annotation.*;
import cucumber.annotation.en.*;
import static org.junit.Assert.assertEquals;


public class SaleStepsPre {

    private WebDriver driver;
    private String baseUrl;


    @Before
    public void setUp() {
    System.setProperty("webdriver.chrome.driver", "/Users/AppData/Local/Google/Chrome/Application/chromedriver.exe");   
    driver = new ChromeDriver();

    baseUrl = "http://xxxxx";
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }

    @Given("^I navigate to the css application$")
    public void I_navigate_to_the_css_application() {
    driver.get(baseUrl + "/care/a#brochureware-home");
    }

    @When("^I select the prepaid catalog$")
    public void I_select_the_prepaid_catalog() {
    driver.findElement(By.xpath("//div[@id='brochureware-home']/div/div/div/div[2]/div[2]/div/div")).click();
    }

    @When("^I select the add to basket for product$")
    public void I_select_the_add_to_basket_for_product() {
    driver.findElement(By.xpath("//*[@id='salesItem']/div[1]/div[1]/div/div[5]/div[1]/button")).click();
    }

    @When("^then I Click on the basket icon to go to basket$")
    public void then_I_Click_on_the_basket_icon_to_go_to_basket()  {
        // times out after 5 seconds
        // while the following loop runs, the DOM changes - 
        // page is refreshed, or element is removed and re-added
        //driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 
        //WebElement searchBox;
        //searchBox = driver.findElement(By.xpath("//input[@type='text']"));
    //driver.findElement(By.xpath("html/body/div[2]/div[1]/nav/div[1]/div[3]/div[2]/div/ul[1]/li[5]/a/img")).click();
    driver.findElement(By.cssSelector("c-menuimage")).click();
    }

    //@When("^then I click on the checkout button$")
    //public void then_I_click_on_the_checkout_button() {
    //driver.findElement(By.xpath("(//button[@type='button'])[9]")).click();
    //}


    @Then("^show product y$")
    public void show_product_y()  {

}


}

However I get following error:

For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
      B
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html

This is the css path of basket icon, which is on a menu.

body > div:nth-child(3) > div:nth-child(1) > nav > div.container-fluid.c-wide > div.c-kill > div.collapse.navbar-collapse.c-2ndmenu > div > ul.nav.navbar-nav.navbar-left > li:nth-child(5) > a > img

The website is GWT, and the steps are: 1. Click on item add to basket 2. Adds to basket 3. Click on basket to go to basket.

However I cant seem to get this right.


Solution

  • I had problems, that the implicit wait only works for real page reloads, when the page is dynamicaly reloaded (like ajax) , then this will fail.

    You can try expected conditions to wait for for items, they are nice and easy to use and robust. You can configure them to ignore certain exceptions, so you can try to locate an element for a given time and then fail. This works even with ajax

    In my case i have a small method like (it ignored the NoSuchElement exception):

    protected <T> T waitForPageToLoad(ExpectedCondition<T> condition,   String errorMessage) {   
        Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(MAX_WAITING_TIME, SECONDS).ignoring(StaleElementReferenceException.class).ignoring(NoSuchElementException.class).pollingEvery(100, MILLISECONDS).withMessage(errorMessage);
        T result = wait.until(condition);
        return result;
    }
    

    MAX_WAITING_TIME is the time until this method throws an exception

    Then you can use this with an expected condition like this:

    public static final ExpectedCondition<Boolean> WAIT_FOR_BASKET = ExpectedConditions.visibilityOfElementLocated(By.cssSelector("c-menuimage"));
    

    I have plenty of them in a utility class so they are static. you can do it like you want.

    The full usage looks like:

    WebElement elem = waitForPageToLoad(waitForPageToLoad); 
    elem.click();
    

    This solution is originated here at stack overflow but i cant find the original question/answer, so kudos to the real guy who posted this