Selenium XPath find element where second text child element contains certain text (use contains on array item) - selenium

The page contains a multi-select dropdown (similar to the one below)
The html code looks like the below:
<div class="button-and-dropdown-div>
<button class="Multi-Select-Button">multi-select button</button>
<div class="dropdown-containing-options>
<label class="dropdown-item">
<input class="checkbox">
"
Name
"
</label>
<label class="dropdown-item">
<input class="checkbox">
"
Address
"
</label>
</div>
After testing in firefox developer tools, I was finally able to figure out the xPath needed in order to get the text for a certain label ...
The below XPath statement will return the the text "Phone"
$x("(//label[#class='dropdown-item'])[4]/text()[2]")
The label contains multiple text items (although it looks like there is just one text object when looking at the UI) in the label element. There are actually two text elements within each label element. The first is always empty, the second contains the actual text (as shown in the below image when observing the element through the Firefox developer tool's console window):
Question:
How do I modify the XPath shown above in order to use in Selenium's FindElement?
Driver.FindElement(By.XPath("?"));
I know how to use the contains tool, but apparently not with more complex XPath statements. I was pretty sure one of the below would work but they did not (develop tool complain of a syntax error):
$x("(//label[#class='dropdown-item' and text()[2][contains(., 'Name')]]")
$x("(//label[#class='dropdown-item' and contains(text()[2], 'Name')]")
I am using the 'contains' in order to avoid white-space conflicts.
Additional for learning purposes (good for XPath debugging):
just in case anyone comes across this who is new to XPath, I wanted to show what the data structure of these label objects looked like. You can explore the data structure of objects within your webpage by using the Firefox Console window within the developer tools (F12). As you can see, the label element contains three sub-items; text which is empty, then the inpput checkbox, then some more text which has the actual text in it (not ideal). In the picture below, you can see the part of the webpage that corresponds to the label data structure.

If you are looking to find the element that contains "Name" given the HTML above, you can use
//label[#class='dropdown-item'][contains(.,'Name')]

So finally got it to work. The Firefox developer environment was correct when it stated there was a syntax problem with the XPath strings.
The following XPath string finally returned the desired result:
$x("//label[#class='dropdown-item' and contains(text()[2], 'Name')]")

Related

How does dot(.) in xpath to take multiple form in identifying an element and matching a text

I have the below dom structure:
<h3 class="popover-title">
<div class="popup-title">
<div class="title-txt">Associated Elements &nbsp(5)</div>
</div>
</h3>
I am trying to write an xpath which will identify the title "Associated Elements" under h3 tag.
When my xpath is
//div[contains(#class, popover)]//h3[contains(.,'Associated Elements')]
the element is identified.
However when my xpath is
//div[contains(#class, popover)]//h3[contains(text(),'Associated Elements')]
the element is not identified.
As per my understanding the dot(.) is a replacement for text(), but then why does it not identify the element when I use the text() function.
However, for another dom structure:
<h3 class="popover-title">
<a class="btn-popover" href="#">x</a>
"Associated Elements"
</h3>
The xpath :
//div[contains(#class, popover)]//h3[contains(text(),'Associated Elements')]
&
//div[contains(#class, popover)]//h3[contains(.,'Associated Elements')]
works fine.
Can someone please explain the behaviour of dot(.) under both these scenarios?
Is there a better way to write an xpath that holds good for both the exmaples? Please suggest.
As selenium is tagged so this answer would be based on xpath-1.0 and the associated XML Path Language (XPath) Version 1.0 specifications.
contains(string, string)
The function boolean contains(string, string) returns true if the first argument string contains the second argument string, and otherwise returns false. As an example:
//h3[contains(.,'Associated Elements')]
Text Nodes
Character data is grouped into text nodes. As much character data as possible is grouped into each text node. The string-value of a text node is the character data. A text node always has at least one character of data. In the below example, text() selects all text node children of the context node:
//h3[text()='Associated Elements']
In your usecase, within the HTML the text Associated Elements &nbsp(5) have which is alternatively referred to as a fixed space or hard space, NBSP (non-breaking space) used in programming to create a space in a line that cannot be broken by word wrap. Within HTML, allows you to create multiple spaces that are visible on a web page and not only in the source code.
Analyzing your code trials
Your first code trial with:
//h3[contains(.,'Associated Elements')]
locates the element as it successfully identifies with partial text Associated Elements
Your second code trial with:
//h3[contains(text(),'Associated Elements')]
fails as the element contains some more characters e.g. in addition to the text Associated Elements.
Reference
You can find a couple of relevant discussions in:
How to locate the button element using Selenium through Python
What does contains(., 'some text') refers to within xpath used in Selenium
While fetching all links,Ignore logout link from the loop and continue navigation in selenium java
The text() in contains(text(),'Associated Elements') is a selector that matches all of the text nodes that are children of the context node - it returns a node-set. That node-set is converted to string and passed to the contains() function.
text() isn't a function but a node test. It is used to select all text-node children of the context node. So, if the context node is an element named x, then text() selects all text-node children of x.
When you use contains(., 'Associated Elements') only an individual text node is passed to the function and it is able to uniquely match the text.
Note: copied and edited from this and this post.

Selenium Web driver - Locate by Class name

I want to click on the search auto complete BUTTON in a webmail application.
<button class="_n_r ms-bg-color-themeLight-hover o365button _n_s ms-bg-color-themeLighter ms-font-color-neutralPrimary ms-border-color-themePrimary" type="button" autoid="_n_4" aria-label="Activate Search Textbox">
<span class="_n_u owaimg ms-Icon--search ms-icon-font-size-20 ms-fcl-ts-b"/>
<span class="_n_t ms-font-weight-semilight ms-font-color-neutralPrimary">Search Mail and People</span>
When clicking the BUTTON, we get this INPUT
<input class="_is_x ms-font-weight-semibold ms-font-color-neutralPrimary ms-bg-color-themeLight ms-bg-color-themeLight-hover allowTextSelection textbox ms-font-s ms-fwt-sl ms-fcl-np ms-bcl-nta ms-bcl-nsa-h hideClearButton" autoid="_is_3" role="combobox" aria-autocomplete="list" aria-label="Search mail and people, type your search term then press enter to search."/>
I'm getting the following error while trying to use the class name from the input.
"The given selector _n_r ms-bg-color-themeLight-hover o365button _n_sms-bg-color-themeLighter ms-border-color-themeLighter is either invalid or does not result in a WebElement. The following error occurred: InvalidSelectorError: Compound class names not permitted"
We tried to use selenium IDE to fetch the value, but we are getting only the xpath. Is there any way to locate autocomplete search field with out using the xpath?
That's a LOT of classes on that INPUT. :) I would use a different attribute. I would start with one of these and see which one works for you. You didn't specify the language you are using so here's some code in Java.
driver.findElement(By.cssSelector("input[autoid='_is_3']"));
driver.findElement(By.cssSelector("input[aria-label='Search mail and people, type your search term then press enter to search.']"));
Quick note since you were asking about classes. You can go the classes route and use CSS Selectors to find them. A simple example.
<button class="one two">
You can find the BUTTON above using
driver.findElement(By.cssSelector("button.one.two"));
A period (.) indicates a CSS class so you would need a period before each class name. You don't necessarily need to include all the classes, only enough to make the element unique so you can locate it.
CSS Selectors reference
CSS Selectors tips

Contains CSS Selector to fill a form with nightwatch / selenium

My Problem:
The Page I try to test with NightwatchJS Contains Some Input Fields that have the Same beginning, but a random number is added. I want to Fill the Textfield on the page. Only one with this name is present on the same time.
<input id="groupNamec7aed06a-67a1-4780-9cc3-5b985666adb9" class="d-styled-input" data-value-update="keyup" data-bind="value: name" title="">
Is the definition of the Field. groupName is every Time the same, but the number changes.
Is there a possibility to use CSS Selector in nightwatch instead of XPATH?
You can try this way :
input[id^="groupName"]
From MDN > Attribute selectors :
[attr^=value] : Represents an element with an attribute name of attr and whose first value is prefixed by "value".
Unfortunately CSS Selector does not provide such a way. You could use a different CSS Selector to match inputs with an id and get those as a list. Afterwards using getAttribute('id') you could do it manually, but this seems like unnecessary effort to me and I'd recommend just using Xpath.
Ofcourse you could try and get a different unique CSS Selector. If it's in a form you could locate the form and use :nth-child but if I remember correctly this has limited/no support in IE.
Edit Apparently IE9 and later does support :nth-child

Selenium - Search for an element within element

Hi I want to hold element references in files somewhere. and then in run time search for elements withing referenced elements in Selenium how to do that.
For example- a Frame contains multiple text boxes -and multiple frames of similar properties exist where the textboxes are also duplicate. Something like I wanna reference the text box under a particular frame. But i wanna predefine the frame. and the specify that search under that frame[Something like Aliases in Testcomplete]
For Example - similar concept exist in Cheezy's Page-Objects. but not quite.
if you have a structure like this:
<div class='some class'>
<input class='input-button' value='submit'>Submit</input>
</div>
<div class='some class2'>
<input class='input-button' value='submit'>Submit</input>
</div>
and you want to find the first 'Submit' which is within the 'some class' div, you can do this:
parent_element = driver.find_element(:xpath, "//div[#class='some class']")
child_element = parent_element.find_element(:xpath, ".//input")
p.s. this is ruby code.

How to verify text across HTML elements in Selenium

Given the following code, how would I verify the text within using Selenium?
<div class='my-text-block>
<p>My first paragraph of text</p>
<p>My second paragraph of text</p>
</div>
I am wanting to, in one verifyText statement to capture all the text:
My first paragraph of text
My second paragraph of text
Is it possible?
Since you've tagged this with selenium-webdriver, I'm assuming you want a code example but because you've not stated what language you're using, I'll give you a python example. It should be easy to translate that to a different language if needed.
ok(driver.find_element("class", "my-text-block").text == "What I expect it to be")
The text attribute on a WebElement object simply contains all visible text within that element and all children elements.
And some lovely docs, of course.