javaseleniumstaleelementreferenceexception

Actions.click() throws StaleElementReferenceException, but WebElement.click() does not


In my test project, I have a static class that contains a number of methods for basic interactions with WebElements. I have two separate methods for clicking a WebElement, one that uses the WebElement.click() method:

public static void click(WebElement element, WebDriverWait w) {
        if (element == null) {
            return;
        }
        try {
            w.until(ExpectedConditions.elementToBeClickable(element)).click();
        } catch (TimeoutException ex) {
            Assert.fail("Test failed, because element with locator: " + element.toString().split("->")[1] + " was not found on the page or unavailable");
        }
    }

and one that uses the Actions.click(WebElement).build().perform() method:

public static void click(WebElement element, Actions a, WebDriverWait w) {
        if (element == null) {
            return;
        }
        try {
            a.click(w.until(ExpectedConditions.elementToBeClickable(element))).build().perform();
        } catch (TimeoutException ex) {
            Assert.fail("Test failed, because element with locator: " + element.toString().split("->")[1] + " was not found on the page or unavailable");
        }
    }

I also have a method for finding and then clicking an option from a menu:

public void selectItem(IMenuButton button) {
        for (WebElement item : w.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector("*[role='menuitem']")))) {
            if (item.findElement(By.tagName("span")).getText().trim().equalsIgnoreCase(button.getButton())) {
                
                // This throws StaleElementReferenceException
                Interaction.click(item, a, w);
                
                // This works
                Interaction.click(item, w);
                
                return;
            }
        }
        Assert.fail("No menu item found for: " + button.getButton());
    }

When I use Interaction.click(item, w), it works, but Interaction.click(item, a, w) throws StaleElementReferenceException, and I can't figure out why. I need the method that uses Actions.click() in case the option needs to be scrolled into view. Any ideas?


Solution

  • Usually, when you scroll down or up - the DOM changes. StaleElementReferenceException means that an element you once found has been moved or deleted. When going over elements inside a loop, very often elements inside a dropdown or scrollView, you need to find them all over again. Otherwise you will get this exception over and over again.

    Try to do this:

    try {
        Interaction.click(item, a, w);
    } catch (StaleElementReferenceException sere) {
        // re-find the item by ID, Xpath or Css
        item = driver.findElementByID("TheID");
        //click again on the element 
        Interaction.click(item, a, w);
    }