how to find XPath for complicated tag without id or name - xpath

I have to find out XPath for code :
<td>
<input type="button" onclick="redirectToUserList(5);" class="btnManage" value="Manage Users" style="background-color: transparent;">
Using firebug the XPath is :
/html/body/div/div/div[4]/table/tbody/tr/td/table/tbody/tr[2]/td/div/table/tbody/tr/td
/table/tbody/tr[5]/td/div/div/form/table/tbody/tr[2]/td[4]/input
But how can I have a shorter XPath? For example, I wish the following could run:
//input[#value='Manage Users']
Please advise how to find shorter XPath using standard syntax?

It is not mandatory to use id or name. You can use any attribute of that element.
Following are different xpaths for given locators
1. "//input[#value='Manage Users']"
2. "//input[contains(#onclick,'redirectToUserList')]"
3. "//input[#type='button' and #class='btnManage']"

You do not need to search for id or name, you can search for any attribute.
For example:
//input[#value="Manage Users"]
which sounds unique

As an addon to above given answers any specific attribute like id or name is never necessary.
We mostly take id and value to identify an element uniquely because other attributes may specify some other locators as well.
If any attribute is not creating confusion with some other locator you can choose it without any worry.
Lastly if you are not so good in writing xpath and also dont like large xpaths given by firebug just install an addon of firebug called as Firepath it will give you the shortest feasible xpath.
You can also go with other addons like Xpath Checker etc.

Related

Is there a way to use xpath to search for a value where a part of the value dynamically changes?

I’m trying to match a value where I don’t necessarily know the whole value every time i.e. it's randomly generated. Is there a way to search for a value where a part of the value dynamically changes?
Please see my example of value I'm trying to find and my attempted xPath:
<div class="target" testid="target”>
<h2>Hi, random user</h2>
<p>To get the xpath <b>target</b> of <b>[text I don’t know]</b> in <b>[text I don’t know]</b>, you need to do the following</p>
</div>
I’ve tried the following xpath I picked up from another question but it don’t get a match:
//p[matches(.,'^To get the xpath <b>target</b> of <b>.*</b> in <b>.*</b>, you need to do the following$')]
I’ve tried different combinations with and without the bold tag but can’t seem to get it to match. truthfully I'm not sure I've got the right syntax...
Try the plain text in the second argument of matches e.g.
//p[matches(., '^To get the xpath target of .*? in .*?, you need to do the following$')]
Online sample here.
Why not to use contains() method using the fixed attribute value?
Something like:
//p[contains(.,'you need to do the following')]

Creating a valid XPath that checks two attributes

I am using FirePath to generate valid XPaths for Behat automation tests and frequently find myself with this issue:
I need to generate an XPath for the automation tests, i.e. to click on an element, but the path contains two parts that I need to check for to confirm it is the correct one
<div id="flash-success" class="alert-box with-icon info"> Operation note created. </div>
So in the above code I can use any of these valid XPaths that will result in one matching node:
//*[#id='flash-success']
//*[#class='alert-box with-icon info']
//*[contains(text(), 'Operation note created.')]
Ideally I want to confirm that the XPath checks two parts, the id/class AND the text, something like this:
//*[#class='alert-box with-icon info']//*[contains(text(), 'Operation note created.')]
But that is NOT a valid XPath. Can anyone shed any light here, I have tried reading up on W3 and questions on here but have yet to find a solution
If you want to find an element were all 3 of your conditions must be true you can write:
//*[#id='flash-success'][#class='alert-box with-icon info'][contains(text(), 'Operation note created.')]
or
//*[#id='flash-success' and #class='alert-box with-icon info' and contains(text(), 'Operation note created.')]
If you want to find an element were ANY of your condtions are true you would write:
//*[#id='flash-success' or #class='alert-box with-icon info' or contains(text(), 'Operation note created.')]
As a sidenote, usually when checking against a class attribute in html you would do contains(#class,'alert-box') since there usually are mulitple classes that are space separated, which are often generated and do not have to be in any order.

Make 1 page objects Two Elements ID's to 1 page object Variable

I am using the page object Gem with Watir. During testing I found that I have a field that has the same contents that show in the same location but have separate unique ID's. The difference is before you get to the page.
I tried using Xpaths:
select_list(:selectionSpecial, :xpath => "//select[#id='t_id9' OR #id='t_id7']")
But was met with a script error.
They are static ID's but I want to force them into one variable since that would allow me to use "populate_page_with" feature.
I have a long winded way currently, but I am fishing for a more efficient way that works with the page object Features.
Does anyone know of a way to do this?
Your approach of using xpath can work. The problem is the syntax errors in the xpath selector. It should be:
"//select[#id='t_id9' or #id='t_id7']"
Note:
The start should be a // rather than a \
Using or is case-sensitive; it has to be lower case
There was also a missing closing ' for the first id attribute
Personally, I find css and xpath selectors harder to use. I would go with the id locator with a regex. The following gives the same results, but some will find it easier to read.
select_list(:selectionSpecial, :id => /^t_id(7|9)$/)

Dealing with duplicate ids in selenium webdriver

I am trying to automate some tests using selenium webdriver. I am dealing with a third-party login provider (OAuth) who is using duplicate id's in their html. As a result I cannot "find" the input fields correctly. When I just select on an id, I get the wrong one.
This question has already been answered for JQuery. But I would like an answer (I am presuming using Xpath) that will work in Selenium webdriver.
On other questions about this issue, answers typically say "you should not have duplicate id's in html". Preaching to the choir there. I am not in control of the webpage in question. If it was, I would use class and id properly and just fix the problem that way.
Since I cannot do that. What options do I get with xpath etc?
you can do it by driver.find_element_by_id, for example ur duplicate "duplicate_ID" is inside "div_ID" wich is unique :
driver.find_element_by_id("div_ID").find_element_by_id("duplicate_id")
for other duplicate id under another div :
driver.find_element_by_id("div_ID2").find_element_by_id("duplicate_id")
This XPath expression:
//div[#id='something']
selects all div elements in the XML document, the string value of whose id attribute is the string "something".
This Xpath expression:
count(//div[#id='something'])
produces the number of the div elements selected by the first XPath expression.
And this XPath expression:
(//div[#id='something'])[3]
selects the third (in document order) div element that is selected by the first XPath expression above.
Generally:
(//div[#id='something'])[$k]
selects the $k-th such div element ($k must be substituted with a positive integer).
Equipped with this knowledge, one can get any specific div whose id attribute has string value "something".
Which language are you working on? Dublicate id's shouldn't be a problem as you can virtually grab any attribute not just the id tag using xpath. The syntax will differ slightly in other languages (let me know if you want something else than Ruby) but this is how you do it:
driver.find_element(:xpath, "//input[#id='loginid']"
The way you go about constructing the xpath locator is the following:
From the html code you can pick any attribute:
<input id="gbqfq" class="gbqfif" type="text" value="" autocomplete="off" name="q">
Let's say for example that you want to consturct your xpath with the html code above (Google's search box) using name attribute. Your xpath will be:
driver.find_element(:xpath, "//input[#name='q']"
In other words when the id's are the same just grab another attribute available!
Improvement:
To avoid fragile xpath locators such as order in the XML document (which can change easily) you can use something even more robust. Two xpath locators instead of one. This can also be useful when dealing with hmtl tags that are really similar. You can locate an element by 2 of its attributes like this:
driver.find_element(:id, 'amount') and driver.find_element(xpath: "//input[#maxlength='50']")
or in pure xpath one liner if you prefer:
//input[#id="amount" and #maxlength='50']
Alternatively (and provided your xpath will only return one unique element) you can move one more step higher in the abstraction level; completely omitting the attribute values:
//input[#id and #maxlength]
It's not listed at http://selenium-python.readthedocs.io/locating-elements.html but I'm able access a method find_elements_by_id
This returns a list of all elements with the duplicate ID.
links = browser.find_elements_by_id("link")
for link in links:
print(link.get_attribute("href"))
you should use driver.findElement(By.xpath() but while locating element with firebug you should select absolute path for particular element instead of getting relative path this is how you will get the element even with duplicate ID's

XPath Find full HTML element ID from partial ID

I am looking to write an XPath query to return the full element ID from a partial ID that I have constructed. Does anyone know how I could do this? From the following HTML (I have cut this down to remove work specific content) I am looking to extract f41_txtResponse from putting f41_txt into my query.
<input id="f41_txtResponse" class="GTTextField BGLQSTextField2 txtResponse" value="asdasdadfgasdfg" name="f41_txtResponse" title="" tabindex="21"/>
Cheers
You can use contains to select the element:
//*[contains(#id, 'f41_txt')]
Thanks to Thomas Jung I have been able to figure this out. If I use:
//*[contains(./#id, 'f41_txt')]/#id
This will return just the ID I am looking for.
I suggest to not use numbers from Id , when you are composing xpath's using partial id. Those number reprezent DINAMIC elements. And dinamic elements change over the next deploys / releases in the System Under Test.The pourpose is to UNIQUE identify elements.
Using this may be a better option or something like this, yo got the idea:
//input[contains(#id, '_txtResponse')]/#id
It worked for me like below
//*[contains(./#id, 'f41_txt')]

Resources