Eldar Zaripov
Eldar Zaripov

Reputation: 1

throwing a StaleElementReferenceException during dictionary iteration in a for loop

The following code is provided below:

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.concurrent.TimeUnit;

public class BaseClass {
    protected static ChromeDriver chromeDriver;

    @BeforeEach
    public void before() {
        System.setProperty("webdriver.chrome.driver", System.getenv("CHROME_DRIVER"));
        chromeDriver = new ChromeDriver();
        chromeDriver.manage().window().maximize();
        chromeDriver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
        chromeDriver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        chromeDriver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
    }

    @AfterEach
    public void after() {
        chromeDriver.quit();
    }

}
import org.openqa.selenium.*;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.util.*;

public class NotebookListPage {
    private static NotebookListPage instance;
    private ChromeDriver chromeDriver;
    private WebDriverWait wait;
    private Actions actions;
    public Dictionary<String, List<PageItem>> onePageCatalog = new Hashtable<>();
    private int currentPage = 0;

    private NotebookListPage(ChromeDriver chromeDriver) {
        this.chromeDriver = chromeDriver;
        this.wait = new WebDriverWait(chromeDriver, 22);
        wait.pollingEvery(Duration.ofSeconds(4));
        wait.ignoring(NoSuchElementException.class);
        this.actions = new Actions(chromeDriver);
    }
    
    public static synchronized NotebookListPage getInstance(ChromeDriver chromeDriver) {
        if (instance == null) {
            instance = new NotebookListPage(chromeDriver);
        }
        return instance;
    }
    private WebElement getLowPriceField() {
        return chromeDriver.findElement(By.xpath("//div[@data-auto='filter-range-glprice']/descendant::span[@data-auto='filter-range-min']/descendant::input[@type='text']"));
    }

    private WebElement getHighPriceField() {
        return chromeDriver.findElement(By.xpath("//div[@data-auto='filter-range-glprice']/descendant::span[@data-auto='filter-range-max']/descendant::input[@type='text']"));
    }

    private WebElement getLenovoButton() {
        return chromeDriver.findElement(By.xpath("//label[@data-auto='filter-list-item-152981']/descendant::span[@class='_1Mp5C']"));
    }

    private WebElement getHPButton(){
        return chromeDriver.findElement(By.xpath("//label[@data-auto='filter-list-item-152722']/descendant::span[@class='_1Mp5C']"));
    }

    private WebElement getRecommendation() {
        return chromeDriver.findElement(By.xpath("//div[@data-grabber = 'SearchRecommendations']"));
    }

    private List<WebElement> getItems() {
        return chromeDriver.findElements(By.xpath("//div[@data-apiary-widget-name = '@light/Organic']"));
    }

    private List<WebElement> getForward() {
        return chromeDriver.findElements(By.xpath("//span[@class='_3e9Bd']"));
    }


    private WebElement getCurrentPage() {
        return chromeDriver.findElement(By.xpath("//div/div[@class='Xe4rX _18sEx _3-NJO']"));
    }
    
    public void initFilters(String lowPrice, String highPrice) throws InterruptedException {

        getLowPriceField().click();
        getLowPriceField().sendKeys(lowPrice);

        getHighPriceField().click();
        getHighPriceField().sendKeys(highPrice);

        getLenovoButton().click();
        getHPButton().click();
    }

    public void Parsing() {
        currentPage = currentPage + 1;
        onePageCatalog.put(Integer.toString(currentPage), new ArrayList<>());
        actions.moveToElement(getRecommendation()).perform();
        for (int i = 0; i < getItems().size(); ++i) {
            String name = getItems().get(i).findElement(By.xpath("//h3[@data-auto='snippet-title']")).getText();
            String stringPrice = getItems().get(i).findElement(By.xpath("//span[@class='_3MgRl']")).getText().replaceAll("[^0-9]", "");
            int price = Integer.parseInt(stringPrice);
            onePageCatalog.get(Integer.toString(currentPage)).add(new PageItem(name, price));
        }
        if (!getForward().isEmpty()) {
            getForward().get(0).click();
            wait.until(d -> Integer.parseInt(getCurrentPage().getText()) != currentPage);
            Parsing();
        }

    }
}

public class PageItem {
    String name;
    int price;

    public PageItem(String name, int price) {
        this.name = name;
        this.price = price;
    }
}

The meaning of the last part of the code is that when iterating the dictionary in the for loop, a web element is searched for on a web page and immediately converted to a string. However, in line "107", namely: 
" String string Price = getItems().get(i).findElement(By.xpath("//span[@class='_3MgRl']")).getText().replaceAll("[^0-9]", "");" 
StaleElementReferenceException is thrown. I can't understand how it may be possible. It is me second version of code, and in the end, I still come to the conclusion that I need to iterate the dictionary/map and parse it from the WebElement format to the String format. 

If you can explain what the problem is and help me solve this problem, I will be very grateful!

in early versions of the program, before the for loop and in the loop itself, I refreshed the locator, but it didn't help either.

as far as I understand, the locator becomes irrelevant immediately after the search until it is converted to text. But I can't figure out how to fix it.

Upvotes: 0

Views: 38

Answers (0)

Related Questions