How can I find my web element using the correct relative xpath - selenium

I am having trouble identifying a specific web element from the DOM. It is a button element, and there are 4 of them in the DOM, exact the same. The one that I need is the third one from the top.
So far I have written the following Xpath:
//button[#class='btn btn-success add-instrument']
This gives me 4 options. I have also tried:
//button[contains(text(), 'texthere')]
This also gives me 4 options. I have tried traversing from above and below, but that does not work either.
I want to: Index the third element, but can't get it to work.
What I have tried (with both options, mentioned above)
//button[contains(text(), 'texthere')]//[3]
I have also tried other indexes, but it finds nothing.
SOLVED BY USING:
"(//button[#class='btn btn-success add-instrument'])[3]"

Try this below xpath.It will identify the 3rd button.
"(//button[contains(text(), 'texthere')])[3]"
or
"(//button[#class='btn btn-success add-instrument'])[3]"

Related

Selenium (Python): Strategy for locating item with inconsistent Xpath

writing a Python selenium script to auto-populate many forms. On one particular form, I have to add the entry, then click the "Add Another" button in order add the next entry. I successfully located the "Add Another" button via find.element(By.XPATH, xx), which works on the first two iterations with an xpath that looks like this:
//*[#id="7d977bf8-9863-5be0-ab89-c90cff57953d"]/div[3]/div[2]/div[2]/div/div[1]/div/div[2]/button[1]
But it is unable to locate the button on the third pass through. I found that the xpath changed ever so slighty: The index of the second /div in the path changed from "2" to "6":
//*[#id="7d977bf8-9863-5be0-ab89-c90cff57953d"]/div[3]/div[6]/div[2]/div/div[1]/div/div[2]/button[1]
My immediate reaction was to code for a NoSuchElementException and if the original is not found, search for the second. But given the observed behavior, I'm not sure I can be certain it's just those two Xpaths. I may need to "Add Another" 40 or 50 times, I could end up with a block of code that tries 10 or 20 xpaths (I am not a web developer, so I have no idea why this change of path is happening, or when it may happen again on the same Form).
So I'm trying to come up with another method to locate this button. Here is the HTML:
<button class="grid-button" data-bind="click: function() { imagetrend.formComposer.controlHandlers.grid.addAnotherButtonClickHandler($context) }, css: { 'disabled' : imagetrend.FormComposer.isReadOnly($context) }, disableEvent: { 'click': imagetrend.FormComposer.isReadOnly.bind(null, $context) }"> <i class="fa fa-lg fa-plus"></i> Add Another </button>
I don't see any unique element in there that I can search by given what I know about Selenium: Tag, ID, CSS_Selector...I tried locating by the "fa fa-lg fa-plus" class, but that isn't found (I think I've deduced that's for the large plug sign in the button).
So is there some sort of bulletproof way I can find this element without coding for every potential xpath I find along the way? Thanks.
I didn't find an alternate method to identify that element, but found that with only that second /div index changing, a wildcard character suited my needs.
so it ended up as:
driver.find_element(By.XPATH,'//*[#id="7d977bf8-9863-5be0-ab89-c90cff57953d"]/div[3]/div[*]/div[2]/div/div[1]/div/div[2]/button[1]').click()
And that XPATH matches any instance of the button that may pop up.
Thanks to Prophet and Akzy for keeping me on my toes!

Can't find unique xpath for clickable element

I'm trying to get an xpath so I can click a link as per href below:
<div id="viewIFL" style="">
<div class="moneycentrallink">
Track your cash in one place with
Money Central
</div>
</div>
When I use the below in ChroPath:
//a[contains(text(),'Money Central')]
It returns 2 elements matching for xpath="1" and xpath="2".
I then tried:
//a[contains(text(),'Money Central') and #xpath='2']
and at first it resolved to just 1 element found but when I tried searching again it returned 0 elements found. Also this does not work via Selenium either (returns unable to find element).
Any ideas what's going on and how I can find the unique xpath to clickable element? Thanks
Don't use xpath attribute in your xpath as ChroPath adds the xpath attribute in element to tell the user what is matching occurrence of that element. For example- If ChroPath added xpath=5 i.e. this element is the 5th for the corresponding xpath.
For your scenario, please inspect the element and see what ChroPath gives the relative xpath.
Also you can try //div[contains(text(),'Track your cash')]//a[contains(text(),'Money Central')]
Your problem is badly formulated.
There is always a unique path to an element of the form *[1]/*[4]/*[1]/*[2]. The problem is that this path isn't very useful because it only works if you know exactly what is in the document, and if you knew exactly what was in the document, you wouldn't need XPath to find it.
So you're actually looking for an XPath that will work on a set of possible documents in which some parts are known (fixed) and others are unknown (variable). To find an XPath that works on every document in that set, you need to define what is known and what is unknown. Looking at one sample document isn't going to tell you that.

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

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

Xpath finder for selenium using python -automation

I am trying to find an unique xpath for the below element, please advice if there are any better xpaths to make it for general text as I have currently given for that specific name.
<td tabindex="4" style="text-align: left;" title="name" class="">Name</td>
xpath i am using: //td[#title='name']
here if the name is changed with something else in the code, this wouldn't work, could someone help me identify unique xpath which works in general for any text. Thanks!
You can concatenate (using and / or) multiple attributes of element to find the element precisely .
By.xpath("//td[#title= 'name' and contains(text(), 'Name')]")
However we need to see more details of the code and your DOM of page to find element.
There will always be some element which will never change in the page(like name of table) using that as a relative point ,we can refer to the row of the table.
the simplest way to find the XPath of any element is to go to the developer options and select the markup of the element you want XPath of.
Right Click -> Copy -> XPath
I believe this is the simplest way. And you will also where you are doing wrong.
Screenshot attached for your reference.
I have used the general syntax - "//td[text()='{}']" and passing the name parameter when i define a method so that it won't be specific to one and others can test using the same locator with their name changed when someone else uses the testcase.
Thanks everyone for your response!

CSS locator for corresponding xpath for selenium

The some part of the html of the webpage which I'm testing looks like this
<div id="twoWideCallouts">
<div class="callout">
<a target="_blank" href="http://facebook.com">Facebook</a>
</div>
<div class="callout last">
<a target="_blank" href="http://youtube.com">Youtube</a>
</div>
I've to check using selenium that when I click on text, the URL opened is the same that is given in href and not error page.
Using Xpath I've written the following command
//i is iterator
selenium.getAttribute("//div[contains(#class, 'callout')]["+i+"]/a/#href")
However, this is very slow and for some of the links doesn't work. By reading many answers and comments on this site I've come to know that CSS loactors are faster and cleaner to maintain so I wrote it again as
css = div:contains(callout)
Firstly, I'm not able to reach to the anchor tag.
Secondly, This page can have any number of div where id = callout. Using xpathcount i can get the count of this, and I'll be iterating on that count and performing the href check. How can something similar be done using CSS locator?
Any help would be appreciated.
EDIT
I can click on the link using the locator css=div.callout a, but when I try to read the href value using String str = "css=div.callout a[href]";
selenium.getAttribute(str);. I get the Error - element not found. Console description is given below.
19:12:33.968 INFO - Command request: getAttribute[css=div.callout a[href], ] on session
19:12:33.993 INFO - Got result: ERROR: Element css=div.callout a[href not found on session
I tried to get the href attribute using xpath like this
"xpath=(//div[contains(#class, 'callout')])["+1+"]/a/#href" and it worked fine.
Please tell me what should be the corresponding CSS locator for this.
It should be -
css = div:contains(callout)
Did you notice ":" instead of "." you used?
For CSSCount this might help -
http://www.eviltester.com/index.php/2010/03/13/a-simple-getcsscount-helper-method-for-use-with-selenium-rc/
#
On a different note, did you see proposal of new selenium site on area 51 - http://area51.stackexchange.com/proposals/4693/selenium.
#
To read the sttribute I used css=div.callout a#href and it worked. The problem was with use of square brackets around attribute name.
For the first part of your question, anchor your identifier on the hyperlink:
css=a[href=http://youtube.com]
For achieving a count of elements in the DOM, based on CSS selectors, here's an excellent article.