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
Related
<ul class="list-group opened-list d-none" xpath="1">
<li class="list-group-item col-12" xpath="1">My team</li>
<li class="list-group-item col-12" xpath="1">My name</li>
<li class="list-group-item col-12" xpath="1">My film</li>
<li class="list-group-item col-12" xpath="1">My football teammate</li>
</ul>
Dropdown list without select tag
To get all li elements use .list-group.opened-list .list-group-item css selector.
Code below wait visibility of li elements and then print text for each:
WebDriverWait wait = new WebDriverWait(driver, 10);
List<WebElement> options = wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector(".list-group.opened-list .list-group-item")));
options.forEach(element -> System.out.println(element.getText()));
If you want to select one of the element by text, check example here.
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.
I have the following html code and I want to click on the second option "Plan b".
<ul class="clearfix all">
<li data-content="a" data-tab-target="tab1" class="active"><span>Plan a</span</li>
<li data-content="b" data-tab-target="tab2" class=""><span>Plan b</span></li>
<li data-content="c" data-tab-target="tab3" class=""><span>Plan c</span></li>/ul>
I tried to do somthing like this:
1.
#FindBy(css = "li:nth-child(2)")
WebElement sparpreis;
sparpreis.click();
2.
#FindBy(xpath = "//*[#class='clearfix all']/ul/li[2]")
WebElement sparpreis;
sparpreis.click();
My error messages:
org.openqa.selenium.ElementNotVisibleException: element not visible
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#class='clearfix all']/ul/li[2]"}
Perhaphs I should activate the second "class"?
The /ul is not needed, try the following:
#FindBy(xpath = "//ul[contains(#class, 'clearfix all')]/li[2]")
As per the HTML you have shared, to click on the second option Plan b you can use either of the following code block :
css
#FindBy(css = "ul.clearfix.all li[data-content=b] > span")
WebElement sparpreis;
sparpreis.click();
xpath
#FindBy(xpath = "//ul[#class='clearfix all']//li[#data-content='b']/span")
WebElement sparpreis;
sparpreis.click();
I tried using cssSelector and using xpath but could not find how to select one value from the list.
r.driver.findElement(By.xpath("//div[contains(.,'DOLO -650')]"));
r.driver.findElement(By.className("ui-autocomplete ui-front ui-menu ui-widget ui-widget-content")).click();
List<WebElement> opt = r.driver.findElements(By.xpath("//ul[#class='ui-autocomplete ui-front ui-menu ui-widget ui-widget-content']/li"));
for (WebElement options:opt) {
if(options.getText().equals(opt)) {
options.click(); return;
}
}
WebElement dd = r.driver.findElement(By.id("ui-id-1")); dd.click();
dd.findElement(By.cssSelector("li[value="+ Product+"]")).click();
r.driver.findElement(By.cssSelector("li:nth-child(1).NoBullet.jms-bullet>")).click();
WebElement element = r.driver.findElement(By.name("DOLO -650"));
element.sendKeys("DOLO -650");
element.submit();
<ul id="ui-id-1" class="ui-autocomplete ui-front ui-menu ui-widget ui-widget-content">
<li id="ui-id-6" class="ui-menu-item">DOLO -120 60ML</li>
<li id="ui-id-7" class="ui-menu-item ui-state-focus">DOLO -650</li>
<li id="ui-id-8" class="ui-menu-item">DOLO 100ML</li>
</ul>
You have to try below code to get all li element and select which matches with your expectation
List<WebElement> opt = driver.findElements(By.xpath("//ul[#id='ui-id-1']/li"));
for(WebElement options:opt)
{
if(option.getText().equals("DOLO -650"))
{
options.click();
break;
}
}
WebElement autoOptions= driver.findElement(By.id("ui-id-1"));
autoOptions.sendKeys("DOLO");
List<WebElement> opt = driver.findElements(By.xpath("//ul[#class='ui-autocomplete ui-front ui-menu ui-widget ui-widget-content']/li"));
for(WebElement option:opt)
{
if(option.getText().equals("DOLO -650"))
{
System.out.println(option);
option.click();
break;
}
}
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"));