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>text</li>
<li>text</li>
<li>text</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?
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");
}
}
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.
Related
This is the code of the demo store I want to test:
<li class="level0 nav-2 parent">
<a href="http://demo-store.seleniumacademy.com/men.html"
class="level0 has-children">Men</a>
<ul class="level0">
<li class="level1 view-all">
<a class="level1" href="http://demo-
store.seleniumacademy.com/men.html">View All
Men</a>
</li>
<li class="level1 nav-2-1 first"><a></a></li>
<li class="level1 nav-2-2"><a href="http://demo-
store.seleniumacademy.com/men/shirts.html"
class="level1">text to get</a>
</li>
<li class="level1 nav-2-3"><a></a></li>
</ul>
</li>
I want to get text of those subcategories so I can later click on specific category by using text inside of a link element. My code is:
public Subcategory openSubcategory (String subcategoryName){
List<WebElement> subcategories = driver.findElements(By.cssSelector("a.level1"));
for (WebElement element: subcategories) {
if (element.getText().equals(subcategoryName)){
element.click();
break;
}
}
return new Subcategory(driver);
}
But it won't go inside loop, probably because element.getText() is empty.
To click on the WebElement with text as Shirts first you have to Mouse Hover the element with text as Men inducing WebDriverWait for the visibilityOfElementLocated and you can use the following locator strategies:
public Subcategory openSubcategory (String subcategoryName){
WebElement menuMen = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a[contains(#class,'has-children') and text()='Men']")));
new Actions(driver).moveToElement(menuMen).build().perform();
List<WebElement> subcategories = driver.findElements(By.xpath("//a[contains(#class,'has-children') and text()='Men']//following::ul[1]//li/a"));
for (WebElement element: subcategories) {
if (element.getText().equals(subcategoryName)){
element.click();
break;
}
}
return new Subcategory(driver);
}
element.getText() can be empty.
Try:
element.getAttribute("value");
// or
element.getAttribute("innerHTML");
Change your CSS to be:
"a[class*='level']";
// or
"a[]";
Debug the code and check if the element is not null
I need to click on all elements BASIC, TRACKS, ...
My idea is to extract all elements in list then using list count and loop, I'll click on each and every element.
Need to check that each and every element is working even if new element is added I don't want to check code.
<div class="headerarea" style="" xpath="1">
<h2>
<span id="ctl00_ctl00_phDesktop_lblModuleTitle">Abstract Setup</span>
</h2>
<ul>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl01_btnModuleNavigation" class="headerarea_active" href="https://staging.m-anage.com/Modules/Abstract/Setup/basics.aspx">Basic</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl02_btnModuleNavigation" href="https://staging.m-anage.com/testselenium/en-US/Abstract/AbstractSetup/Tracks">Tracks</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl03_btnModuleNavigation" href="https://staging.m-anage.com/Modules/Abstract/Setup/steps.aspx">WIZARD</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl04_btnModuleNavigation" href="https://staging.m-anage.com/Modules/Abstract/Setup/keywords.aspx">KEYWORDS</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl05_btnModuleNavigation" href="https://staging.m-anage.com/Modules/Abstract/Setup/categories.aspx">CATEGORIES</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl06_btnModuleNavigation" href="https://staging.m-anage.com/Modules/Abstract/Setup/conditions.aspx">CONDITIONS</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl07_btnModuleNavigation" href="https://staging.m-anage.com/Modules/Abstract/Setup/interests.aspx">Interests</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl08_btnModuleNavigation" href="https://staging.m-anage.com/Modules/Abstract/Setup/templates.aspx">Templates</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl09_btnModuleNavigation" href="https://staging.m-anage.com/testselenium/en-US/Abstract/AbstractSetup/Index">Submission fee</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl10_btnModuleNavigation" href="https://staging.m-anage.com/testselenium/en-US/Mail/MailServerSetup/Index?pModuleType=Abstract" style="">SMTP Setup</a></li>
<li>
<a id="ctl00_ctl00_phDesktop_rModuleNavigation_ctl11_btnModuleNavigation" href="https://staging.m-anage.com/testselenium/en-US/Abstract/AbstractSetup/Coauthor">Co-author</a></li>
</ul>
</div>
I tried travelling to child path but no success
Here is the java code that I tried.
List<WebElement> tags =
driver.findElements(By.xpath("//div[#class='headerarea']/ul/li"));
for(int i=0;i<tags.size();i++) {
while(???) {
//driver.findElement(By.xpath("//div[#class='headerarea']/ul/li")).click();
}
}
Try below code :
List<WebElement> links = driver.findElements(By.tagName("li"));
for (int i = 1; i < links.size(); i++)
{
System.out.println(links.get(i).getText());
}
You can also use WebDriverWait if you are facing synchronization issue.
WebDriverWait wait = new WebDriverWait(driver, 10);
List<WebElement> links = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.tagName(li)));
for (int i = 1; i < links.size(); i++)
{
System.out.println(links.get(i).getText());
}
List<WebElement> tags = driver.findElements(By.cssSelector(".headerarea ul>li"));
for(WebElement e : tags) {
e.click();
}
due to the fact i'm using selenium for the first time i have a questin on selecting a child element without parameters.
I'm trying to get the child-div "element to be clicked" to perform a click.
Java:
WebElement element = driver.findElement(By.className("parent"));
WebElement element2 = element.findElement(By.xpath("/div/div/div")); // should be wrong
element2.click();
Given HTML-Code:
<div class="parent">
<div>
<div>
<div>element to be clicked</div>
</div>
</div>
</div>
You can use
element.findElement(By.xpath("//div[text()='element to be clicked']"));
With RegEx
element.findElement(By.xpath("//div[matches(text(),'RegExExpression']"));
While there's nothing to identify directly, we can do something like this..
List<WebElement> divs = driver.findElements(By.tagname("div")); //This will return all div elements
Then we can try something unique to that div..
for(int i = 0; i < divs.size(); i++) {
if(divs.get(i).getText().equals("element to be clicked")) {
divs.get(i).click();
break;
}
}
Environment : Eclipse, Chrome, Java
I am dealing with test case for pagination in the application. I have tried with some code, but it moves only upto 2nd page.
Code :
List<WebElement> allpages = driver.findElements(By.xpath("//div[#class='pagination']//a"));
System.out.println(allpages.size());
if(allpages.size()>0)
{
System.out.println("Pagination exists");
for(int i=0; i<allpages.size(); i++)
{
Thread.sleep(3000);
allpages.get(i).click();
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
//System.out.println(i);
}
}
else
{
System.out.println("Pagination doesn't exists");
}
}
Size displayed is 12. The issue is it moves upto 2nd page only and then displays error of StaleElementReference
Here's the HTML Code for the same pagination.
HTML Code :
<div id="page-navigation" class="pull-right">
<div id="303b171e-5a26-e456" class="flex-view">
<div class="pagination">
<ul>
<li class="">
«
</li>
<li class="" data-value="0">
1
</li>
<li class="" data-value="1">
2
</li>
<li class="active" data-value="2">
3
</li>
.....
When the new page is loaded after clicking one of the pagination links, the allpages WebElements are no longer valid and need to be found again. You will have to put another call to allpages = driver.findElements(By.xpath("//div[#class='pagination']//a")); in your for loop so that you can get new references for each new page.
I've got the following HTML code:
<div class="ui-selectmenu-menu" style="z-index: 1; top: 251px; left: 37px;">
<ul class="ui-widget ui-widget-content ui-selectmenu-menu-dropdown ui-corner-bottom" aria-hidden="true" role="listbox" aria-labelledby="gwt-uid-191-button" id="gwt-uid-191-menu" style="width: 270px; height: auto;" aria-disabled="false" aria-activedescendant="ui-selectmenu-item-999">
<li role="presentation" class="ui-selectmenu-item-selected">
All Applications</li>
<li role="presentation" class="">
Option Alpha</li>
<li role="presentation" class="ui-corner-bottom">
Option Beta</li>
</ul>
</div>
...
<div class="ui-selectmenu-menu"...>...</div>
I'm able to get the WebElement for ui-selectmenu-menu like this (there are many on the page; hence, the use of findElements) :
List<WebElement> dropdowns = driver.findElements(By.className("ui-selectmenu-menu"));
And the ul below it like this:
WebElement ddChild = dropdowns.get(0).findElement(By.className("ui-selectmenu-menu-dropdown"));
I'm even able to grab all the li under the ddChild like this:
List<WebElement> ddOpts = ddChild.findElements(By.xpath("//*[#id='gwt-uid-191-menu']/li[*]"));
But the problem that I can't seem to figure out how to grab the text-value of the <a href="#nogo"... tag under each li element.
I'd like to be able to loop through all the ddOpts and grab the <a href="#nogo"... text values and save them to an ArrayList<String>.
So, for example, my first ArrayList<String> value would contain All Applications, then Option Alpha, then Option Beta, and then jump to the next ul element from the next dropdowns and do the whole process again, all while adding to the ArrayList<String>.
I'm sure its a simple solution but I've got limited experience with Selenium WebDriver.
Thanks!
PS: Is there a simple way to grab the child of a WebElement?
List<WebElement> ddOpts = ddChild.findElements(By.xpath("//*[#id='gwt-uid-191-menu']/li/a"));
ArrayList<String> links = new ArrayList<String>();
for(WebElement we : ddOpts) {
links.add(we.getText();
}
To extract the href attribute of the WebElement (referring to the anchor tag <a> in this example, do this:
List<WebElement> ddOpts = ddChild.findElements(By.xpath("//*[#id='gwt-uid-191-menu']/li/a"));
ArrayList<String> links = new ArrayList<String>();
for(WebElement we : ddOpts) {
// ADD all the href attribute strings to the list
links.add(we.getAttribute("href"));
}
This may also solve your problem:
List<WebElement> dropdowns = driver.findElements(By.className("x-combo-list"));
WebElement ddChild = dropdowns.get(0).findElement(By.className("x-combo-list-inner"));
List<WebElement> ddOpts = ddChild.findElements(By.xpath("//*[#id=\"x-auto-98\"]/div[4]"));
for(WebElement we:ddOpts){
System.out.println(we.getText());
if(we.getText().contains("ROLE_MANAGER")){
we.sendKeys("ROLE_MANAGER");
we.click();
break;
}
}
the below code will select the OptionAlpha in the dropdown of the above HTML code
driver.findElement(By.xpath("//*[#class='ui-selectmenu-menu')).click();
driver.findElement(By.xpath("//*[#class='ui-widget ui-widget-content ui-selectmenu-menu-dropdown ui-corner-bottom']//**[text()='Option Alpha']")).click();
Please try the below code to get all the links in the <a href
List<WebElement> allLis = driver.findElements(By.xpath("//*[#id='gwt-uid-191-menu']/li/a");
// Looping through above list using for-each loop
for(WebElement eachLi : allLis) {
System.out.println(eachLi.getText());
}
Hope this helps.
href="#nogo" is same for all the anchor tags, so it might create ambiguity in selecting the item by the method
dropdowns.findelement(By.linktext("#nogo"));