javaseleniumstaleobjectstate

Advanced Stale elements


I have been reading about stale elements and am still a bit confused. For instance, the following won't work, correct?

 public void clickFoo(WebElement ele) {
    try {
      ele.click();
    } catch (StaleElementReferenceException ex) {
      ele.click();
    }
 }

because if ele is stale, it will remain stale. The best thing is to redo the driver.findElement(By), but as you can see in this example, there is no xpath. You can attempt to ele.getAttribute("id") and use that, but if the element has no id, this also will not work. All methods calling this would have to put the try/catch around it, which may not be feasible.

Is there some other way the element could be refound? Also, assuming there is an id, would the id remain the same after the element goes stale? What in the WebElement object ele is different once it goes stale?

(Java Eclipse)


Solution

  • I would recommend you NOT create a method like the above. There's no need to add another function layer on top of .click(). Just call .click() on the element itself.

    driver.findElement(By.id("test-id")).click();
    

    or

    WebElement e = driver.findElement(By.id("test-id"));
    e.click();
    

    One way that I use regularly to avoid stale elements is find the element only when you need it and generally I do this by in a page object method. Here's a quick example.

    The page object for a home page.

    public class HomePage
    {
        private WebDriver driver;
        public WebElement staleElement;
        private By waitForLocator = By.id("sampleId");
    
        // please put the variable declarations in alphabetical order
        private By sampleElementLocator = By.id("sampleId");
    
        public HomePage(WebDriver driver)
        {
            this.driver = driver;
            // wait for page to finish loading
            new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(waitForLocator));
    
            // see if we're on the right page
            if (!driver.getCurrentUrl().contains("samplePage.jsp"))
            {
                throw new IllegalStateException("This is not the XXXX Sample page. Current URL: " + driver.getCurrentUrl());
            }
        }
    
        public void clickSampleElement()
        {
            // sample method code goes here
            driver.findElement(sampleElementLocator).click();
        }
    }
    

    To use it

    WebDriver driver = new FirefoxDriver();
    driver.manage().window().maximize();
    driver.get("http://www.example.com");
    HomePage homePage = new HomePage(driver);
    homePage.clickSampleElement();
    // do stuff that changes the page and makes the element stale
    homePage.clickSampleElement();
    

    Now I no longer have to rely on an old reference. I just call the method again and it does all the work for me.

    There are many references on the page object model. Here's one from the Selenium wiki. http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern

    If you want to read more info on what a stale element is, the docs have a good explanation. http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp