Code works in debugging mode but not when executed Normally in JAVA



Tried the below code on this demo site where I find an product from the productlist and then try to click on the checkbox against it. When executed normally StaleElementException gets displayed but when executed on debug mode then it gets executed successfully. What could the solution for it ??

The exception is:

Exception in thread "main" org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document at
org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83) at
org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552) at
org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:285) at
org.openqa.selenium.remote.RemoteWebElement.getText(RemoteWebElement.java:166) at
TC.ss1.main(ss1.java:82) 

The code is:

    driver.get("https://www.nopcommerce.com/en/demo");
    Webdriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    Webdriver.manage().window().maximize();
    Webdriver.findElement(By.xpath("//a[@class='btn admin-button']")).click();
    
    Set<String> id =driver.getWindowHandles();
    Iterator<String> it=id.iterator();
    String ParentWindow = it.next();
    String ChildWindow = it.next();
    Webdriver.switchTo().window(ChildWindow);
    System.out.println(driver.getTitle());
    
    WebElement URL = driver.findElement(By.xpath("//div[@class='title']"));
    Assert.assertTrue(URL.isDisplayed());
    
    Webdriver.findElement(By.id("Email")).isDisplayed();
    Webdriver.findElement(By.id("Password")).isDisplayed();
    Webdriver.findElement(By.xpath("//input[@value='Log in']")).click();
    Thread.sleep(2000);
    
    Webdriver.findElement(By.xpath("//ul[@class='sidebar-menu tree']/li[2]")).click();
    Thread.sleep(2000);
    Webdriver.findElement(By.xpath("//a[@href='/Admin/Product/List']")).click();
    Thread.sleep(3000);
    
    Select dropdown = new Select(driver.findElement(By.name("products-grid_length")));
    dropdown.selectByVisibleText("7");
    Thread.sleep(2000);
    List<WebElement> Productname = driver.findElements(By.xpath("//tr[@role='row']//td[3]");
    int page=0;
    for(int i=1;i<Productname.size();i++)
    {
        page++;
        Thread.sleep(2000);
        String title = Productname.get(i).getText();
        if(!title.equals("Custom T-Shirt"))
        {
            driver.findElement(By.xpath("//i[@class='k-icon k-i-arrow-e']")).click();
            break;
        }
        else
        {
            driver.findElement(By.xpath("//*[@id='products-grid']/tbody/tr[4]/td[1]/input")).click();
            break;
        }
    }
    
    List<WebElement> Productname1 = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));
    for(int j=1;j<Productname1.size();j++)
    {
        //page++;
        Thread.sleep(2000);
        String title1 = Productname1.get(j).getText();
        if(title1.equals("Custom T-Shirt"))
        {
            driver.findElement(By.xpath("//*[@id='products-grid']/tbody/tr[4]/td[1]/input")).click();
            break;
        }   
    }
    }}

Answer

StaleElementException:

Basically, when you are trying to access the same list on the next page. The previously captured web element is no longer treated as referenced and those referenced web element will throw Exception “Stale Element Exception”. See below code as you are using the same reference stored on the List<WebElement> Productname1 list to access the web element which is not present or is changed due to page refresh or change in the dom.

List<WebElement> Productname = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));

List<WebElement> Productname1 = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));

Basically when all element gets loaded in DOM then Web element gets a referenced web element and as soon as DOM gets reloaded or changed then earlier captured Web element is no longer treated as referenced and those referenced web element will throw error Stale Element Exception.

When you try to interact with the staled WebElement, the StaleElementException is thrown.

Solution:

The simple hack to solve this problem is to update the Weblement list on page refresh/ change or when you move to the next page.

    List<WebElement> Productname = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));
        int page=0;
        for(int i=1;i<Productname.size();i++)
        {
            page++;
            Thread.sleep(2000);
//Update reference
            Productname = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));
            String title = Productname.get(i).getText();
            if(!title.equals("Custom T-Shirt"))
            {
                driver.findElement(By.xpath("//i[@class='k-icon k-i-arrow-e']")).click();
                break;
            }
            else
            {
                driver.findElement(By.xpath("//*[@id='products-grid']/tbody/tr[4]/td[1]/input")).click();
                break;
            }
        }

        List<WebElement> Productname1 = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));
        for(int j=0;j<Productname1.size();j++)
        {
            //page++;
            Thread.sleep(2000);
//Update reference
            Productname1 = driver.findElements(By.xpath("//tr[@role='row']//td[3]"));
            String title1 = Productname1.get(j).getText();
            if(title1.equals("Custom T-Shirt"))
            {
                driver.findElement(By.xpath("//*[@id='products-grid']/tbody/tr[4]/td[1]/input")).click();
                break;
            }   
        }


Source: stackoverflow