-1

I am currently working on an automation framework using java, selenium, selenium-grid, pageObject with pageFactory.

I am trying to create a method for testing the following html code:

<section class="footer-links">
<div class="footer-layout">
    <ul>
        <li class="title">Header</li>
        <li><a href="/home/">text</a></li>
        <li><a href="/about/">text</a></li>
        <li><a href="/games/">text</a></li>
        <li><a href="/games/download/" >text</a></li>
        <li><a href="/games/mobile/" >text</a></li>
        <li><a href="/events/" >text</a></li>
    </ul>
    <ul>
        <li class="title">Header</li>
        <li><a href="/publishers/" >text</a></li>
        <li><a href="/smth/" target="_blank" >text</a></li>
        <li><a href="/promo/press/" >text</a></li>
    </ul>
    <ul>
        <li class="title">Header</li>
        <li><a href="/support/" >text</a></li>
        <li><a href="/support/payment-inquiries/"  class="loginModalShow" rel="nofollow" >text</a></li>
        <li><a href="/support/general-inquiries/" >text</a></li>
        <li><a href="/support/game-inquiries/"  class="loginModalShow" rel="nofollow" >text</a></li>
    </ul>
    <ul>
        <li class="title">Header</li>
        <li><a href="/blog/" >text</a></li>
        <li><a href="/search/" rel="nofollow" >text</a></li>
        <li><a href="/directory/pc-games/" >text</a></li>
    </ul>
</div>

The code above represents a footer containing 4 lists with some links.

What I am trying to do with the following method is to iterate once through the 4 lists and again inside each list clicking the links and verifying the url to which they redirect against their href attribute value.

@FindBy(css = ".footer-links .footer-layout ul")
public List<WebElement> footerLinksLists;

public void checkFooterLinks(){
    if (footerLinksLists.size()==4){
        for(int i=0; i<footerLinksLists.size(); i++){
            List<WebElement> links =  wait.until(ExpectedConditions.visibilityOfAllElements(footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)")))); // footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)"));
            for (int j=0; j<links.size(); j++) {
                WebElement link = wait.until(ExpectedConditions.elementToBeClickable(links.get(j).findElement(By.cssSelector("a"))));
                String href = link.getAttribute("href");
                link.click();
                if(driver.getCurrentUrl().contains(href)){
                    log.info("Link " + href +" is ok");
                }
                driver.navigate().back();
            }
        }
    }else{
        log.info("the footer does not contain 4 link lists");
    }
}

After starting my test it breaks after entering the for loop with the following error

org.openqa.selenium.StaleElementReferenceException: The element reference of <li> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed

In my test class I have the following code for initializing pageobject containing the method:

WebDriver driver = driverFactory.getDriver();
    WebDriverWait wait = driverFactory.getWait(driver);

homepagePageObject homePage = new homepagePageObject(driver, wait);
    PageFactory.initElements(driver,homePage);
    homePage.createAccount();
    homePage.checkVerifyAccountRibbon();
    homePage.signOut();
    homePage.Login();
    homePage.checkFooterLinks();

Initially I thought it had something to do with waiting for each element but I am receiving the same error after adding the waits/expectedConditions.

Can somebody explain what am I doing wrong and what would be the best solution in this case?

oTTomation
  • 9
  • 1
  • 4

2 Answers2

1

Because page get refresh and List element lost its value.

You have to manage it By reassign links value.

public void checkFooterLinks(){
    if (footerLinksLists.size()==4){
        for(int i=0; i<footerLinksLists.size(); i++){
            List<WebElement> links =  wait.until(ExpectedConditions.visibilityOfAllElements(footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)")))); // footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)"));
            for (int j=0; j<links.size(); j++) {
                WebElement link = wait.until(ExpectedConditions.elementToBeClickable(links.get(j).findElement(By.cssSelector("a"))));
                String href = link.getAttribute("href");
                link.click();
                if(driver.getCurrentUrl().contains(href)){
                    log.info("Link " + href +" is ok");
                }
                driver.navigate().back();
            }
        links = wait.until(ExpectedConditions.visibilityOfAllElements(footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)"))));
        }
    }else{
        log.info("the footer does not contain 4 link lists");
    }
}
Ishita Shah
  • 3,955
  • 2
  • 27
  • 51
0

This method doesn't do what you want it to do.

First, it only goes through this loop if the number of footerlinks is 4. If the number of links is changed, or there is a bug that causes it to be 3, the whole method is skipped and you just get a log statement to the fact. Since there are no assertions, and the method does not return anything, this method will pass every time it is run.

Second, if the link does not contain the expected href, the if-statement won't execute. All that means is that you won't have the OK statement in the logs. The method will still execute and succeed.

I would suggest to include some assertions with this test. Either as part of each iteration. So something like this:

List<WebElement> links =  wait.until(ExpectedConditions.visibilityOfAllElements(footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)")))); // footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)"));
        for (int j=0; j<links.size(); j++) {
            WebElement link = wait.until(ExpectedConditions.elementToBeClickable(links.get(j).findElement(By.cssSelector("a"))));
            String href = link.getAttribute("href");
            link.click();
            **assertTrue("The expected URL did not match",driver.getCurrentUrl().contains(href));**
            driver.navigate().back();
        }

or as a return from the method itself

public boolean checkFooterLinks(){
  if (!footerLinksLists.size()==4){
     return false;
   }

    for(int i=0; i<footerLinksLists.size(); i++){
        List<WebElement> links =  wait.until(ExpectedConditions.visibilityOfAllElements(footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)")))); // footerLinksLists.get(i).findElements(By.cssSelector("li:not(:first-child)"));
        for (int j=0; j<links.size(); j++) {
            WebElement link = wait.until(ExpectedConditions.elementToBeClickable(links.get(j).findElement(By.cssSelector("a"))));
            String href = link.getAttribute("href");
            link.click();
            if(!driver.getCurrentUrl().contains(href)){
                return false;
            }
            driver.navigate().back();
        }
    }
   return true;

}

and then let the test verify the links are ok with

assertTrue("something is not right with the footer links",checkFooterLinks())

What this gives you is that if the number of the links are no 4, or the link opened up does not match the expected, the test will fail.

That said, I can see the value of checking the links and that they contain an expected href value, but I'm not sure what value checking the actual url will give you.

If the href is corrupt, and points to www.google.com, the test will pass as the two values match. Just food for thought.