Search code examples
javaselenium-webdrivertestng

How to fetch all links and click those links one by one using Selenium WebDriver


I am using Selenium WebDriver with java.

I am fetching all links from webpage and trying to click each link one by one. I am getting below error:

error org.openqa.selenium.StaleElementReferenceException: Element not found in the cache - perhaps the page has changed since it was looked up Command duration or timeout: 30.01 seconds For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html Build info: version: '2.25.0', revision: '17482', time: '2012-07-18 21:09:54'

and here is my code :

public void getLinks()throws Exception{
    try {
        List<WebElement> links = driver.findElements(By.tagName("a"));
        int linkcount = links.size(); 
         System.out.println(links.size()); 
          for (WebElement myElement : links){
         String link = myElement.getText(); 
         System.out.println(link);
         System.out.println(myElement);   
        if (link !=""){
             myElement.click();
             Thread.sleep(2000);
             System.out.println("third");
            }
            //Thread.sleep(5000);
          } 
        }catch (Exception e){
            System.out.println("error "+e);
        }
    }

actually, it's displaying in output

[[FirefoxDriver: firefox on XP (ce0da229-f77b-4fb8-b017-df517845fa78)] -> tag name: a]

as link, I want to eliminate these form result.


Solution

  • There is no such a good idea to have following scenario :

    for (WebElement element : webDriver.findElements(locator.getBy())){
      element.click();
    }
    

    Why? Because there is no guarantee that the element.click(); will have no effect on other found elements, so the DOM may be changed, so hence the StaleElementReferenceException.

    It is better to use the following scenario :

    int numberOfElementsFound = getNumberOfElementsFound(locator);
    for (int pos = 0; pos < numberOfElementsFound; pos++) {
      getElementWithIndex(locator, pos).click();
    }
    

    This is better because you will always take the WebElement refreshed, even the previous click had some effects on it.

    EDIT : Example added

      public int getNumberOfElementsFound(By by) {
        return webDriver.findElements(by).size();
      }
    
      public WebElement getElementWithIndex(By by, int pos) {
        return webDriver.findElements(by).get(pos);
      }
    

    Hope to be enough.