element not found when using xpath in angular site - java

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']

Related

Jsoup css selector "not", not return anything

I'm trying to ignore an item and not parse it on Jsoup
But css selector "not", not working !!
I don't understand what is wrong ??
my code:
MangaList list = new MangaList();
Document document = getPage("https://3asq.org/");
MangaInfo manga;
for (Element o : document.select("div.page-item-detail:not(.item-thumb#manga-item-5520)")) {
manga = new MangaInfo();
manga.name = o.select("h3").first().select("a").last().text();
manga.path = o.select("a").first().attr("href");
try {
manga.preview = o.select("img").first().attr("src");
} catch (Exception e) {
manga.preview = "";
}
list.add(manga);
}
return list;
html code:
<div class="col-12 col-md-6 badge-pos-1">
<div class="page-item-detail manga">
<div id="manga-item-5520" class="item-thumb hover-details c-image-hover" data-post-id="5520">
<a href="https://3asq.org/manga/gosu/" title="Gosu">
<img width="110" height="150" src="https://3asq.org/wp-content/uploads/2020/03/IMG_4497-110x150.jpg" srcset="https://3asq.org/wp-content/uploads/2020/03/IMG_4497-110x150.jpg 110w, https://3asq.org/wp-content/uploads/2020/03/IMG_4497-175x238.jpg 175w" sizes="(max-width: 110px) 100vw, 110px" class="img-responsive" style="" alt="IMG_4497"/> </a>
</div>
<div class="item-summary">
<div class="post-title font-title">
<h3 class="h5">
<span class="manga-title-badges custom noal-manga">Noal-Manga</span> Gosu
</h3>
If I debug your code and extract the HTML for:
System.out.println(document.select("div.page-item-detail").get(0)) (hint use the expression evaluator in IntelliJ IDEA (Alt+F8 - for in-session, real-time debugging)
I get:
<div class="page-item-detail manga">
<div id="manga-item-2003" class="item-thumb hover-details c-image-hover" data-post-id="2003">
<a href="http...
...
</div>
</div>
</div>
It looks like you want to extract the next div tag down with class containing item-thumb ... but only if the id isn't manga-item-5520.
So here's what I did to remove that one item
document.select("div.page-item-detail div[class*=item-thumb][id!=manga-item-5520]")
Result size: 19
With the element included:
document.select("div.page-item-detail div[class*=item-thumb]")
Result size: 20
You can also try the following if you want to remain based at the outer div tag rather than the inner div tag.
document.select("div.page-item-detail:has(div[class*=item-thumb][id!=manga-item-5520])")

Selenium check dynamic elements

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.

Element is not clickable at point - other element would receive the click

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.

Issue on parsing Html with jsoup for java

I am trying to parse HTML using jsoup.
I used "try jsoup" to check if parsing of the html is correct.
screenshot of the results : please open this link ^^
My code is :
URL url = new URL("http://tw.search.bid.yahoo.com/search/ac;_ylt=AtqkyTO06sgGHho20HzmPEX3_rF8?ei=UTF-8&p=%E8%A1%A3%E6%9C%8D");
Document doc;
try {
doc = Jsoup.parse(url, 3000);
Elements descriptions = doc.select("div#srp_sl_result"+" div.att-item");
for (Element element : descriptions) {
System.out.println(element.ownText());
System.out.println("--------------");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But the results are returning empty,
I am getting following output:
--------------
--------------
--------------
I am expecting output like:
女裝手套衣服*艾爾莎*暗釦長款披風式毛衣罩衫外套S~L【TAA1166】 出價 799 元 直購 799 元 運費80元 |
30 次 | 剩 16小時 60分 賣家:艾爾莎時尚精品 (評價 25229) 在新北市
☆意樂舖☆【塑鋼衣架】ABS強化多功能神奇魔術衣架(收納衣服.領帶.皮帶.肩帶) 出價 35 元 直購 35 元 運費
55元 | 8 次 | 1天 6小時 賣家:意樂舖(創意樂園小舖) (評價 14613) 在新北市
HappyLife【YK1324】韓國超人氣乾濕兩用衣架 防滑魔術衣架 止滑衣架 衣服衣櫃衣櫥收納 出價 25 元 直購
25 元 運費70元 | 16 次 | 2天 3小時 賣家:HappyLife快樂生活網 (評價 14360) 在新北市
Here is some sample HTML from the search page:
<div class="att-item item yui3-g " data-url="https://login.yahoo.com/config/login?.intl=tw&.pd=c%3D3Chd7Yq72e502eh4R99sgUvi5Q--&.done=https%3A%2F%2Ftw.search.bid.yahoo.com%2Fsearch%2Fauction%2Fproduct%3Fei%3DUTF-8%26p%3D%25E8%25A1%25A3%25E6%259C%258D&rr=2465463942">
<div class="yui3-u">
<div class="srp-pdimage">
<img height="120" alt=" (DAJIN達錦衣服設計中心)棒壘球帽字凸繡200元,棒球帽,帽子,棒壘球服,棒球衣 " src="https://s.yimg.com/hg/ac/30/ea/e79010279-ac-4511xf9x0430x0600-s.jpg" />
</div>
</div>
</div>
What should I change in my code?
How to achieve my goal.
Please help me!
You should use the text() method, not ownText(), as the documentation states, it:
Gets the combined text of this element and all its children.
Here is an updated example:
public static void main(String[] args) throws MalformedURLException {
URL url = new URL( "http://tw.search.bid.yahoo.com/search/"
+ "ac;_ylt=AtqkyTO06sgGHho20HzmPEX3_rF8?ei=UTF-8&p=%E8%A1%A3%E6%9C%8D");
Document doc;
try {
doc = Jsoup.parse(url, 3000);
Elements descriptions = doc.select("div#srp_sl_result div.att-item");
for (Element element : descriptions) {
System.out.println(element.text());
System.out.println("--------------");
}
} catch (IOException e) {
e.printStackTrace();
}
}
I've visited the page you are trying to parse and in the browser console I've written:
$('div#srp_sl_result div.att-item')
The search returned a div:
<div class="att-item item yui3-u" data-url="https://login.yahoo.com/config/login?.intl=tw&.pd=c%3D3Chd7Yq72e502eh4R99sgUvi5Q--&.done=https%3A%2F%2Ftw.search.bid.yahoo.com%2Fsearch%2Fauction%2Fproduct%3Fei%3DUTF-8%26p%3D%25E8%25A1%25A3%25E6%259C%258D&rr=3456505015" id="yui_3_14_1_3_1394093660536_452">
<div class="wrap" id="yui_3_14_1_3_1394093660536_451">
<div class="srp-pdimage" id="yui_3_14_1_3_1394093660536_450">
<a href="https://tw.page.bid.yahoo.com/tw/auction/f61398121;_ylt=Ali1FeHY3kStUUeBmGO4vupyFbN8;_ylv=3?u=Y2583393636" id="yui_3_14_1_3_1394093660536_456">
<img width="200" alt=" HappyLife【SP323】納川6+1家庭裝真空收納袋/真空袋/壓縮袋/棉被衣物衣服收納~附吸氣管 " src="https://s.yimg.com/hg/ac/b6/51/f61398121-ac-6849xf8x0600x0400-s.jpg" id="yui_3_14_1_3_1394093660536_455">
</a>
</div>
<div class="srp-pdhead">
<div class="srp-pdinfo">
<a class="srp-bid" href="https://tw.page.bid.yahoo.com/tw/show/bid_hist;_ylt=Ahu0X7QeYNL6gEwV.IhDhWlyFbN8;_ylv=3?aID=f61398121">6 次</a>
<span>出價</span>
<em>399</em>
<span>元</span>
<span class="sep">|</span>
</div>
<div class="srp-pdprice">
<span>直購</span>
<em>399</em>
<span>元</span>
</div>
</div>
<div class="srp-pdtitle">
HappyLife【SP323】納川6+1家庭裝真空收納袋/真空袋/壓縮袋/棉被衣物衣服收納~附吸氣管
</div>
<div class="srp-pdftitle">
HappyLife【SP323】納川6+1家庭裝真空收納袋/真空袋/壓縮袋/棉被衣物衣服收納~附吸氣管
</div>
<div class="srp-pdstore">
<a class="srp-ico" href="https://tw.help.yahoo.com/auct/policy/protection.html#reward" alt="享買賣家五萬保障"></a>
HappyLife快樂生活網
</div>
</div>
</div>
So I don't understand why you have so many elements returned. In any case element.ownText() returns the text of that div, excluding any inner element, so no text should be shown because that div has no text, only other elements

Selenium driver - select the desired li item in the list

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;
}
}
}
}

Categories

Resources