Selenium/Java
the task is to get text of two possible elements: elem1 and elem2.
When Scenario A - elem1 is displayed, and the locator of elem2 doesn't exist. And vice versa.
My code:
public void checkTextInPopUp() {
List<WebElement> commonDiv= driver.findElements(By.xpath(".//*
[#id='CheckStockProductAvailabilityWidget']/div/div"));
if (commonDiv.size()>=1) {
addToCartStock.click();
} else {
System.out.println(driver.findElement(By.id("ajaxErrorMsg")).getText());
closeCheckStock.click();
}
}
My code is always work only in scenario1 and failed when element2 is dispayed, saying: unable to locate element2.
Elem1 html:
<div id="CheckStockProductAvailabilityWidget" class="dijitContentPane"
lang="en" controllerid="CheckStockProductAvailabilityController"
widgetid="CheckStockProductAvailabilityWidget"
dojotype="wc.widget.RefreshArea" style="">
<div class="row-fluid">
<div class="span11">
<p id="ajaxErrorMsg" class="error-font-color">Price &
Availability Check cannot be executed for your order.</p>
</div>
</div>
</div>
</div>
Elem2 html:
<div id="CheckStockProductAvailabilityWidget" class="dijitContentPane"
lang="en" controllerid="CheckStockProductAvailabilityController"
widgetid="CheckStockProductAvailabilityWidget"
dojotype="wc.widget.RefreshArea" style="">
<div class="row-fluid">
<div class="span11">
<div class="row-fluid ">
<div class="span12">
Part# 00000
<br/>
<p>
</div>
</div>
<div class="row-fluid space-bottom">
<div class="row-fluid ">
<div class="row-fluid mobile-inline-block">
Both elements have a common , and both returns "1" when getting element.size
I've found out the solution by using try and catch. Will see if it's an ideal one.
public void getStockPopUpMessage() {
try {
driver.findElement(By.xpath(".//*[#id='ajaxErrorMsg']"));
System.out.println("Stock displays: " +
driver.findElement(By.xpath(".//*[#id='ajaxErrorMsg']")).getText());
closeCheckStock.click();
} catch (NoSuchElementException e) {
System.out.println("No ajax");
dothis();
}
}
You can modify the code as below
Code:
public void checkTextInPopUp(){
WebElement rootElement=driver.findElement(By.id("CheckStockProductAvailabilityWidget"));
List<WebElement> element1List=rootElement.findElements(By.xpath(".//div[#class='span11']/p"));
if (element1List.size()==1) {
---Do your stuff----
addToCartStock.click();
} else {
System.out.println(rootElement.findElement(By.xpath(".//div[#class='span12']")).getText());
}
}
}
Details:
Find the Root WebElement. Since, this element always visible in both element 1 and element2 HTML
Element 1 may or may not be visible at a time. To avoid NoSuchElementException, find the element using findElements Method and store the element in List (You can find the element using the root element)
If the element 1 is found, then element 1 will be visible and element1 size will be 1.
If the element 1 is not found, then element 2 will be visible and
element 1 size will be 0.
logic can be added based on the element size condition
Updated Code:
List<WebElement> elementList=driver.findElements(By.xpath("//p[#id='ajaxErrorMsg']"));
//If the element 1 html is present, then element list size will be 1, else it will be 0.
if(elementList.size()>0){
//element 1 related stuff
---Do your stuff----
addToCartStock.click();
}
else{
//element 2 related stuff
System.out.println(rootElement.findElement(By.xpath(".//div[#class='span12']")).getText());
}
Simply use
#FindAll ({
#FindBy(locator elem1)
#FindBy(locator elem2)enter code here
})
private WebElement elementer code hereX;
FindAll annotation works with OR logic. It will find elem1 or elem2 and store it as a web element. Alternatively you can store it in a List of web element within your object repository.
Related
I have an element on a website which looks like below
<div id="wrapperCategory" class="categoryItemWrapper">
<div class="panel panel-default panel-categoryItem text-center categoryItem disabledItem" ng-class="category.CategoryStyleClass" ng-click="setselectedProduct(productIndex,product,category); setselectedProductAmount(null);" title="Category">
<div class="panel-heading">
Category
</div>
<div class="panel-body">
Price
</div>
<div class="panel-footer availability" ng-class="category.AvailabilityStyleClass">
<span ng-bind-html="category.AvailabilityText">Avail</span>
</div>
</div>
</div>
I need to click on it to get forward. If I manually click on each of these divs or on span website goes forward but SeleniumWebdriver can't click any of them.
I tried click on span and on div with ng-click event buch each time i get an error:
Exception in thread "main" org.openqa.selenium.WebDriverException: Element <div class="panel panel-default panel-categoryItem text-center categoryItem" ng-class="category.CategoryStyleClass" ng-click="setselectedProduct(productIndex,product,category); setselectedProductAmount(null);" title="Category"></div> is not clickable at point (619.2666625976562, 474.23333740234375). Other element would receive the click: <div style="top: 0;left: 0;bottom: 0;right: 0;position: fixed;pointer-events: auto !important;z-index: 10000;" id="cover-1526454140024"></div>
I don't get it.
Can I somehow check which element is clickable and which element overlaps this which I want to click (I dont'see any div with id="cover-1526454140024" in code of the website) ?
Updated:
Unfortunately it still doesn't work after your solutions.
The same exception when trying to click.
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
JavascriptExecutor js = (JavascriptExecutor) Mundial.driver;
js.executeScript("arguments[0].scrollIntoView();", categoryItem);
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(categoryItem));
categoryItem.click();
List<WebElement> selects = driver.findElements(By.tagName("select"));
Select ticketsToSelect = new Select(selects.get(3));
ticketsToSelect.selectByValue("number:2");
It only works in case when I put sleep and scroll down manually. I don't get it.
As per your response :
You will have to scroll down to let the web element available to your script.For that you can use this code :
public static void scrollDown(WebDriver driver, String YoffSet){
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.executeScript(YoffSet);
}
here you can call this method anywhere from your code.
Then you can use this code to interact with the web element :
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("static ID")));
element.click();
I experienced lot of such issues, as Ankur says, use wait before click
WebElement seems_unclickable = wait.until(ExpectedConditions.elementToBeClickable(By.id(...
One of the way is ExpectedConditions commands
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("Yourid")));
More examples can be found at http://toolsqa.com/selenium-webdriver/wait-commands/
Try "scrollIntoView".
public void ScrollElementIntoView(IWebElement element)
{
var js = driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].scrollIntoView()", element);
}
I had the same issue and it was due to a having a non 100% zoom applied to the page body like:
body {
zoom: 90%;
}
Removing the css zoom fixed the issue.
I have a angular website and I am trying to automate it using Selenium/Java. I know protractor is more easy for angular sites but I wish to use selenium.
I have been using "contains" keyword in the xpath to find elements as there are no unique id's available.
The element I am facing problem with is in the attached image circled in red. When I search the console with the xpath as shown in the image, the element is highlighted. But when I use it in the code I get the element not found error.
Is there a better way to handle this and why I am getting the error. I already have a wait condition.
HTML Code:
<div class="status-selector ng-isolate-scope" fm-select=""
fm-select-options="::IssueDetailsCtrl.issue.allowedIssueStatuses"
fm-disabled="!IssueDetailsCtrl.issue.permissions.editStatus"
fm-model="IssueDetailsCtrl.issue.status"
fm-change="IssueDetailsCtrl.updateStatus()">
<div class="fm-select undefined selected" ng-class="getStyle()" tabindex=""
ng-keyup="handleKeys($event)" ng-keydown="handleKeyDown($event)" style="">
<div class="fm-select-title" ng-click="toggleVisibility()"
ng-class="{"fm-select-title-highlighted":
isOpen, "fm-select-disabled": fmDisabled }">
<div class="selected-item-icon" ng-class="selectedOption.imageClass"></div>
<span class="ng-binding">Open</span>
</div>
<!-- ngIf: isOpen -->
</div>
</div>
<div class="fm-select undefined selected" ng-class="getStyle()" tabindex=""
ng-keyup="handleKeys($event)" ng-keydown="handleKeyDown($event)" style="">
<div class="fm-select-title" ng-click="toggleVisibility()"
ng-class="{"fm-select-title-highlighted":
isOpen, "fm-select-disabled": fmDisabled }">
<div class="selected-item-icon" ng-class="selectedOption.imageClass"></div>
<span class="ng-binding">Open</span>
</div>
<!-- ngIf: isOpen -->
</div>
<div class="fm-select-title" ng-click="toggleVisibility()"
ng-class="{"fm-select-title-highlighted":
isOpen, "fm-select-disabled": fmDisabled }">
<div class="selected-item-icon" ng-class="selectedOption.imageClass"></div>
<span class="ng-binding">Open</span>
</div>
<div class="selected-item-icon" ng-class="selectedOption.imageClass"></div>
<span class="ng-binding">Open</span>
Wait condition:
public void waitAndClickElement(WebElement element) throws InterruptedException {
boolean clicked = false;
int attempts = 0;
while (!clicked && attempts < 20) {
try {
this.wait.until(ExpectedConditions.elementToBeClickable(element)).click();
System.out.println("Successfully clicked on the WebElement: " + "<" + element.toString() + ">");
clicked = true;
} catch (Exception e) {
System.out.println("Unable to wait and click on WebElement, Exception: " + e.getMessage());
Assert.fail("Unable to wait and click on the WebElement, using locator: " + "<" + element.toString() + ">");
}
attempts++;
}
}
Your app is Angular App and the button is dynamically attached to the DOM Tree only when certain condition satisfied by Angular ng-if, so need to wait Angular compile the HTML of the button before it attached to the DOM Tree.
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement ele = wait.until(ExpectedConditions.presenceOfElementLocated(
By.xpath("//div/span[text()='Open']"))
);
ele.click();
I would suggest you to use explicit wait in this case :
new WebDriver(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//span[#class='ng-binding' and text()='Open']"))).click();
Or :
You can use this Xpath also :
//div[#class='selected-item-icon']/following-sibling::span[text()='Open' and #class='ng-binding']
I have some trouble to get the texts in the following HTML code, I need some help please.
<div class="itemlist">
<ul>
<li>
<div class="Description">
<h2>Item 1</h2> // GET THIS
<h3 title="Shipping :01-02 Nov">Shipping :01-02Nov</h3> // GET THIS
</div>
<div class="price" style="margin: 0px auto; display: none;">
<span class="arial-12-88" style="display: inline;"></span>
<div class="currency-USD arial-24-26-bold">450 USD</div> // GET THIS
<span class="arial-12-d0" style="display: inline;"></span>
</div>
<div class="button_set" style="display: flex;">
<button class="learn">Learn More</button>
<a href="user/orderDetails.htm?m=add&pid=00020170918214914392zGPQW7nE06A2&count=1&fitting=">
<button class="add">Add To Cart</button></a> // GET THIS
</div>
</li>
next item ...
</ul>
</div>
The output should be:
Item 1
Shipping :01-02Nov
450 USD
My approach is too static and cannot handle changes in the item structure. Because not every item has e.g. the price on the same ChildNumber. The only equal things are the div class names.
I use at the moment as I used the debugger to find which child I have to call:
Element content = doc.getElementsByClass("itemlist").first();
Node child1 = content.childNode(1);
for (Node node : child1.childNodes()) {
try {
Node desc = node.childNode(3);
Node price = node.childNode(5);
Node stock = node.childNode(7);
// get description
Node desc_elem = desc.childNode(1);
Node desc_text = desc_elem.childNode(0);
String desc_txt = ((TextNode) desc_text).text().trim();
} catch (Exception e) {
continue;
}
Please help me to find a more dynamic way. Ideal would be to get all listitems and loop over them. Then call to get the div description, div price. Then I could read the text from the child.
//select the div with the item list
Element itemlist = doc.select("div.itemlist").first();
// select each li element
Elements items = itemlist.select("li");
// for each li element select the corresponding div with item name, shipping info and price
for(Element e : items){
System.out.println(e.select("div.Description h2").text());
System.out.println(e.select("div.Description h3").text());
System.out.println(e.select("div.currency-USD").text());
}
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;
}
}
In a list of 8 Elements I would select the one that contains the search text in children div. I need this because the elements of the list changes order every time. Here I would like to select the one that contains the text "TITLE TO LISTEN". How do I scroll through the list and select the wish li?
Thanks in advance
Here one li:
...
<li id="3636863298979137009" class="clearfix" data-size="1" data-fixed="1" data-side="r">
<div class="userContentWrapper">
<div class="jki">
<span class="userContent">
TITLE TO LISTEN
</div>
<div class="TimelineUFI uiContainer">
<form id="u_0_b0" class="able_item collapsed_s autoexpand_mode" onsubmit="return window.Event && E" action="/ajax/ufi/modify.php" method="post" >
<input type="hidden" value="1" name="data_only_response" autocomplete="off">
<div class="TimelineFeedbackHeader">
<a class="ction_link" role="button" title="Journal" data-ft="{"tn":"J","type":25}" rel="dialog" href="/ajax/" tabindex="0" rip-style-bordercolor-backup="" style="" rip-style-borderstyle-backup="" >LISTEN</a>
</div>
</form>
</div>
</div>
</li>
</ol>
</div>
...
I tried this code, but it don't work because the elements ids change each time.
driver.findElement(By.xpath("//li[8]/div[2]/div/div[2]/form/div/div/span[2]/a")).click();
For example:
If text contain "TEXT TO LISTEN": li[3]/div[2]/div/div/div[2]/div/div/span
Link "listen" i want to click : li[3]/div[2]/div/div[2]/form/div/div/span[2]/a
here is number 3, but the order may change. I would first like to get that number and then click on the right link
Use this
driver.findElement(By.xpath("//li[contains(text(), 'Your text goes here')]"))
EDIT: just realised it's very old ques and you might have got ans by now, so for others who are looking for answer to this question.
You could get list of all li elements, and then search for specified text
for(int i=0; i< listOfLiElements.Count, i++){
if(listOfLiElements[i].FindElement(By.ClassName("userContent")).Text == "TITLE TO LISTEN")
{
correctElement = listOfLiElements[i].FindElement(By.TagName("a"));
i =listOfLiElements.Count;
}
}
Well, then just iterate through for each and ask if the current element has the right text inside it.
List<Element> listOfLiTags = driver.findElement(By.Id("yourUlId")).findElements(By.TagName("li"));
for(Element li : listOfLiTags) {
String text = li.getElement(By.ClassName("userContent").getText();
if(text.equals("TITLE TO LISTEN") {
//do whatever you want and don't forget break
break;
}
}
Note that this is much more easier with CssSelector API.
List<Element> listOfSpans = driver.findElements(
By.CssSelector("ul[id=yourId] li span[class=userContent]");
Now just iterate and ask for the right text:)
You can try this :
public void ClickLink()
{
WebElement ol =driver.findElement(By.id("ol"));
List<WebElement> lis=ol.findElements(By.tagName("li"));
ArrayList<String> listFromGUI=new ArrayList<>();
for(int i=0;i<lis.size();i++)
{
WebElement li=ol.findElement(By.xpath("//ol[#id='ol']/li["+(i+1)+"]/div[2]/div/div/div[2]/div/div/span"));
if(li.getText().trim().equals("TEXT TO LISTEN"))
{
WebElement link=ol.findElement(By.xpath("//ol[#id='ol']/li["+(i+1)+"]/div[2]/div/div[2]/form/div/div/span[2]/a"));
if(link.getText().trim().equals("LISTEN"))
{
link.click();
break;
}
}
}
}