Understanding WebElement.findElement() and XPATH - selenium

I want to use the WebElement.findElement() API to locate a node inside the parent node using XPATH //span[#class='child-class']. I thought this would return me the <div> that is inside the parent. However, it is returning me the first one it found in the entire DOM tree. Did I use the wrong XPATH?
I have also tried using .//span[#class='child-class'] as the XPATH, but that does return anything.
Thank you.
UPDATE:
given the HTML below, I want to define a locator for the child-title <span> and child-date <span> and locate them using WebElement.findElement() API regardless of the parent being "//a/li[1]" or "//a/li[2]"
<a>
<li> parent 1
<div>
<span class="child-title child-style">title 1</span>
<span class="child-date child-style"> date 1</span>
<span class="child-author">author 1</span>
</div>
</li>
</a>
<a>
<li> parent 2
<div>
<span class="child-title child-style">title 2</span>
<span class="child-date child-style"> date 2</span>
<span class="child-author">author 3</span>
</div>
</li>
</a>
<a>
<li> parent 3
<div>
<span class="child-title child-style">title 3</span>
<span class="child-date child-style"> date 3</span>
<span class="child-author">author 3</span>
</div>
</li>
</a>
I have a WebElement parent2 initialized and located using "//a/li[2]",
WebElement child = parent2.findElement(By.xpath("//span[#class='child-author']")); would give me "author 1"
WebElement child = parent2.findElement(By.xpath("span[#class='child-author']")); would give me NoSuchElementException

There are my 2 comments with your sample code
1 - With your posted HTML, the xpath //a/li[2] is not found (we only have 3 elements with //a/li[1])
2 - Assume that we do have right code, you need to understand the differences between single slash and double slash in Xpath
a/b (single slash): select element that has "tag b" and "stands right after" an element that has "a tag"
E.g.:
<a>
<b>
<d>
<c>
</c>
</d>
</b>
</a>
AND
a//b (double slash): select element that has "tag b" and is n-level-child an element that has "a tag"
E.g.:
<a>
<c>
<d>
<b>
</b>
</d>
</c>
</a>
So, with your code
<a>
<li> parent 1
<div>
<span class="child-title child-style">title 1</span>
<span class="child-date child-style"> date 1</span>
<span class="child-author">author 1</span>
</div>
</li>
</a>
If you want to get Date Info, you should use
WebElement parent = driver.findElement(By.xpath("//a/li"));
WebElement date = parent.findElement(By.xpath("div/span[contains(#class, 'child-date')]"));
WebElement date = parent.findElement(By.xpath("//span[contains(#class, 'child-date')]"));
The code
WebElement date = parent.findElement(By.xpath("span[contains(#class, 'child-date')]"));
Will bring out NoSuchElementException because there is no [span] tag right after [li] tag
Hope help

Try something like:
Use dot(.) before double slash(//)
It looks for child under the given parent element.

Completely new question ... completely new answer. :(
Try something like:
WebElement parent1 = driver.findElement(By.xpath("//a[1]/li")); // use a[2] for parent2
WebElement author = parent1.findElement(By.xpath("span[#class='child-author']"));
WebElement date = parent1.findElement(By.xpath("span[contains(#class, 'child-date')]"));
WebElement title = parent1.findElement(By.xpath("span[contains(#class, 'child-title')]"));

Try something like :
//a/li[contains(text(), 'parent 1')]/div
It requests for "the <div> inside a <li> whose text contains 'parent 1' and who is inside a <a>.
It might not work if you have more parents because it works with a contains() (this xpath would also select <li> parent 10 ... </li>). It would be better if "parent x" were an attribute of the <li> instead of its text.

Related

Testcafe: finding elements with mutiple conditions

I'm trying to create a selector that matches "several" items in my dom.
Dom may look like this:
<a class="email-item">
<span class="title">Newsletter</span>
<span class="from">a#a.com</span>
</a>
<a class="email-item">
<span class="title">Newsletter</span>
<span class="from">a#a.com</span>
</a>
<a class="email-item">
<span class="title">Newsletter</span>
<span class="from">b#b.com</span>
</a>
I try to find all a-elements that do have the title "Newsletter" as innerText AND are from "a#a.com"
so kind of a combo-selector...
Thanks for your help!
Ray
Use the filter method to find elements that match the conditions.

how to match text in a div element using xpath?

I am trying to locate an xml element in selenium using xpath. It is nested in inside .
I have numbers 3498546 and 3498755 in hand. I need to match these numbers to the numbers listed in elements and locate the specific .
I have tried using various combinations with below:
xpath=//*[#id="tabs"]/ul/li/[contains(div,'3498546')]
But it never worked.
Below is and example html code, I have around 100 listed in
<div id="tabs">
<ul>
<li class="unknown">
<span style="">DELIVERED</span>
<a title="A1" onclick="submitForm('e1:eForm',1);return false;"
class="eLink" href="#">
<div class="c1">"Year 2008
"
<br>"3498546
"
<br>
</div>
<strong>Date: </strong>05/14/2019
</a>
</li>
<li class="unknown">
<span style="">DELIVERED</span>
<a title="A2" onclick="submitForm('e1:eForm',1);return false;"
class="eLink" href="#">
<div class="c1">"Year 2008
"
<br>"3498755
"
<br>
</div>
<strong>Date: </strong>05/14/2019</a>
</li>
</ul>
</div>
I want to be able to locate and click the element which has the text 3498546 or 3498755.
Here is the xpath based on the 3498546.
//div[#class='c1'][contains(normalize-space(.),'3498546')]
you can change the 3498546 value to the required number and use the same. In case you want to get all the elements having numbers and click each one of them then you can use the below xpath.
//div[#id='tabs']//div[#class='c1']
To click() on either of the elements with text as 3498546 or 3498755 you can use the following solutions:
3498546:
Java & partialLinkText:
driver.findElement(By.partialLinkText("3498546")).click();
3498755:
Java & partialLinkText:
driver.findElement(By.partialLinkText("3498755]")).click();
//div[contains(text(),'3498755')]
All you need is to look for the div element that its text contains the numbers you're looking for.

How can I find the exact value using xpath in selenium webdriver for text that contains ?

I'm having an issue selecting the exact text 'Section' from the code using xpath.
** To be clear I require the exact text selection to be made from the innerText or innerHTML of the element if that is possible, not the id. **
I'm able to use the contains text function, but that results in other partial matches that contain 'Section' being returned/highlighted as well:
//div[#aria-hidden='false']//ul/li[contains(text(),'Section')]
I've tried using the following methods, but I don't know if I've got the syntax correct, as nothing is returned/highlighted:
//div[#aria-hidden='false']//ul/li[text()='Section')]
//div[#aria-hidden='false']//ul/li[.='Section']
//div[#aria-hidden='false']//ul/li[normalize-space(.)='Section']
This is what is shown when inspecting the Section node:
<li id="GOS--/40" class="nodecollapsed item parent-node xh-highlight" style="" xpath="1">
Section <span class="child-count"></span>
</li>
This is what is shown in the element properties:
id: "GOS--/40"
innerHTML: "↵ Section <span class="child-count"></span>↵ "
innerText: " Section "
Here is the xml which shows the other partial matches that are returned:
<div class="selection-list-dialog modal-dialog Dialog">
<div class="modal-content">
<div class="modal-header SectionHeader">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<span class="modal-title" data-lang="StandardItems">Standard Items</span>
</div>
<div class="modal-body selection-list-container" style="margin-top: 30px" id="base">
<div>
<span data-lang="SelectItemInstructions">Select the items you are interested in from the list.</span>
</div>
<br/>
<div class="pull-left selection-tree-container">
<h4 class="selection-list-title">
<span data-lang="Available">Available</span>
</h4>
<ul class="selection-list selection-tree-list">
<li id="CS--/14" class="nodecollapsed item parent-node">
Country Section <span class="child-count"></span>
</li>
<li id="Sec1--/23" class="nodecollapsed item parent-node">
Section 1 <span class="child-count"></span>
</li>
<li id="Sec2--/24" class="nodecollapsed item parent-node">
Section 2 <span class="child-count"></span>
</li>
<li id="GOS--/40" class="nodecollapsed item parent-node">
Section <span class="child-count"></span>
</li>
<li id="RS--/43" class="nodecollapsed item parent-node">
Regional Section <span class="child-count"></span>
</li>
This was a tough one. The problem is that you have a number of similar options all containing "Section" in some flavor and it's hard to distinguish them apart. What adds to this is that each one contains a non-breaking space which means that normalize-space() won't work (directly) either.
But... I found that the below XPath will work.
//li[normalize-space()='Section\u00a0']
normalize-space() removes whitespace (but not &nbsp) so you have to add it in there with \u00a0. I've tested this locally and it's working.
Try following xpath see if it helps.
//li[starts-with(#id,'GOS')][#class='nodecollapsed item parent-node xh-highlight']
OR
//li[#class='nodecollapsed item parent-node xh-highlight'][#xpath='1']
you can try the below XPath to find a section node
Try if it helps
//li[#id='GOS--/40'][contains(text(),'Section')]
Let me throw my hat into the ring....
//li[(normalize-space(text()) = 'Section')]
Here is the method that will fetch the text from the parent only. (exclude the text in the child(ren))
In Python:
def get_pure_element_text(element):
return driver.execute_script(
"""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element).strip()
This method will iterate all the firstChild (direct children) and extract all text from all the text nodes.
In this context If you want to retrieve the text of li which have the id GOS--/40 then use the method as below.
element = driver.find_element_by_xpath("//li[#id='GOS--/40']")
print(get_pure_element_text(element))
Sharing this method, at least might help the others (if not the OP in this context).
C# implementation:(not tested)
string get_pure_text(IWebDriver driver, IWebElement element){
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
return (string)js.ExecuteScript(""""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element");
Usage:
string output = get_pure_text(driver,element)

Unable to locate click the check box

Please help me the locate the check box and select. There are multiple check boxes, there is no way to locate them uniquely.
Here is the Code for one of such check box.
Thanks in Advance for the Help!!!
<div class="col-xs-2 col-sm-2 col-lg-2" style="height:65px">
<ul class="list-inline pull-right">
<li>
<md-input-container class="md-block">
<md-checkbox value="$index+1check" class="checkbox ng-valid ng-dirty ng-touched ng-empty" ng-model="item.Selectedd" ng-click="toggle($index+1, selected,item.TitleId,item)" icon,md-checkbox.md-checked._md-icon="{background-color: green;}" id="Cbk_List" role="checkbox" tabindex="0" aria-checked="false" aria-invalid="false" style=""><div class="_md-container md-ink-ripple" md-ink-ripple="" md-ink-ripple-checkbox=""><div class="_md-icon"></div></div><div ng-transclude="" class="_md-label">
</div></md-checkbox>
</md-input-container>
</li>
<li>
<div class="manageTitle_CirclCard">
<div class="ng-binding">2</div>
</div>
</li>
</ul>
</div>
You should try to locate using cssSelector with it's attribute tabindex as below :-
#Cbk_List[tabindex='0']
Edited :- If checkbox element has not any attributes with unique value, you should try using xpath with index, assuming you want to get first checkbox element, then try below xpath :-
(.//*[#id = 'Cbk_List'])[1]
Note :- In above xpath, just change the index from 1 to desire one checkbox to find.

Selenium WebDriver - Finding Elements using cssSelector and nth child

<ul>
<li class="active">
<a href="#">
<i class="fa fa-home"></i><br>
<span class="title">Home</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-rss-square"></i><br>
<span class="title">Posts</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-calendar"></i><br>
<span class="title">Events</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-bar-chart-o"></i><br>
<span class="title">My Activity</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-edit"></i><br>
<span class="title">Assessments</span>
</a>
</li>
</ul>
I want to locate the respective span element. I want to check the order of the span elements using css selector. So when I use selenium IDE,I will verify it like below(using nth child concept).
verifyText | css=.title:nth(0) | Home
verifyText | css=.title:nth(1) | Posts
verifyText | css=.title:nth(2) | Events
verifyText | css=.title:nth(3) | My Activity
verifyText | css=.title:nth(4) | Assessments
But when I do the same thing in Selenium WebDriver I am not able to locate the elements with the order which I did using Selenium IDE.
Below are the codes that I used in WebDriver and it dint work.
driver.findElement(By.cssSelector(".title:nth(0)")); // to locate the "Home" element
driver.findElement(By.cssSelector(".title:nth-of-type(0)")); // to locate the "Home" element
driver.findElement(By.cssSelector(".title:nth-child(0)")); // to locate the "Home" element
Could anyone please help me.
You can generate the css-selector from ul like ul > li:nth-child(1) for home. See below:
driver.findElement(By.cssSelector("ul > li:nth-child(1)")); >> home
driver.findElement(By.cssSelector("ul > li:nth-child(2)")); >> posts
driver.findElement(By.cssSelector("ul > li:nth-child(3)")); >> events
also reachin span is the same:
driver.findElement(By.cssSelector("ul > li:nth-child(1) > a > span")); >> home
do you need css specifically? if not, you can also go for xpath, which imho reads better/clearer:
driver.findElement(By.xpath("(//span[#class='title'])[0]")); // home
driver.findElement(By.xpath("(//span[#class='title'])[1]")); // posts
...
<body>
<div class=parent>
<div></div>
<div></div>
<div></div>
</div>
</body>
If you already have the parent element and just need to find nth child
parent.find_element_by_css_selector('div:nth-child(2)')
would select the second div
We can write this way-
To get all the span text like-
Home
Posts
Events
My Activity
Assessments
Then driver.findElements(By.cssSelector("ul>li>a span:nth-child(3)"));
and
To get individual span text then you need to pass the index position in nth-child(index) method.driver.findElement(By.cssSelector("ul>li:nth-child(1)>a span")).getText();//Home driver.findElement(By.cssSelector("ul>li:nth-child(2)>a span")).getText();//Posts driver.findElement(By.cssSelector("ul>li:nth-child(3)>a span")).getText();//Events driver.findElement(By.cssSelector("ul>li:nth-child(4)>a span")).getText();//My Activity driver.findElement(By.cssSelector("ul>li:nth-child(5)>a span")).getText();//Assessments For more details please visit- CSS Selector in Details
driver.find_element_by_css_selector('ul>li:nth-of-type(1)>a>')