Search code examples
javaseleniumstaleelementreferenceexception

StaleElementReferenceException while iterating over embedded links


On my webpage I have a list of links to sections, each section has links to details. I'm trying to go to each section, then verify all the links are not broken.

List<WebElement> sections = driver.findElements(By.xpath("//*[@id='sections']/li/a"));
        System.out.println("sections: " + sections.size());
        sections.forEach(selement -> { 
            selement.click();
            List<WebElement> details = driver.findElements(By.xpath("//*[@id='details']/div/table/tbody/tr/td/table[1]/tbody/tr/td[2]/strong/a"));
            System.out.println("details: " + details.size());
            details.forEach(delement -> {
                url = delement.getAttribute("href");
                try {
                    huc = (HttpURLConnection) new URL(url).openConnection();
                    huc.setRequestMethod("HEAD");
                    huc.connect();
                    respCode = huc.getResponseCode();
                    if(respCode == 404) {
                        System.out.println(url + " link is broken");
                    } else if (respCode == 200) {
                        System.out.println(url + " link is ok");
                    } else {
                        System.out.println(url + " returned code " + respCode);
                    }
                    huc.disconnect();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            driver.navigate().back();
        });

The problem is I'm getting a StaleElementReferenceException after the first sections' details are checked. I'm guessing it's because after iterating over details and going back Selenium does not treat the rest of the sections list as current?

I could probably create a list of all the hrefs for sections and then iterate over that list navigating to specific section link and then checking for details' links. But maybe there is some other/simpler solution?


Solution

  • Yes, you are correct, after going back to the main page. list elements are changing and it will not refer same elements even though it is same. You can not use for each for the first/outer iteration. You can change it as follows. Also. list elements should be re identified/searched after going back.

    List<WebElement> sections = driver.findElements(By.xpath("//*[@id='sections']/li/a"));
            System.out.println("sections: " + sections.size());
            for(int i=0;i<sections.size();i++){ 
                WebElement selement = sections.get(i);
                selement.click();
                List<WebElement> details = driver.findElements(By.xpath("//*[@id='details']/div/table/tbody/tr/td/table[1]/tbody/tr/td[2]/strong/a"));
                System.out.println("details: " + details.size());
                details.forEach(delement -> {
                    url = delement.getAttribute("href");
                    try {
                        huc = (HttpURLConnection) new URL(url).openConnection();
                        huc.setRequestMethod("HEAD");
                        huc.connect();
                        respCode = huc.getResponseCode();
                        if(respCode == 404) {
                            System.out.println(url + " link is broken");
                        } else if (respCode == 200) {
                            System.out.println(url + " link is ok");
                        } else {
                            System.out.println(url + " returned code " + respCode);
                        }
                        huc.disconnect();
                    } catch (MalformedURLException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
                driver.navigate().back();
                sections = driver.findElements(By.xpath("//*[@id='sections']/li/a"));
            }