Retrieving a element with multiple xpaths - selenium

This isn't much of a coding question but one about what options should I take next. I've just started using selenium about a week ago and started to get the hang of most of its function.
I was working on a work project to login into various websites until I ran into a issue where I was getting this error when I tried to find the password field
Exception in thread "main" org.openqa.selenium.ElementNotVisibleException: element not visible
I went ahead and double checked the name & id but I couldn't find the field using locators like .id, name, and xpath. I inspected the xpath with Firebug and noticed that it returned two results instead of one.
Current Xpath looks like this
.//*[#id='password']
I was wondering if anyone could point me to the right direct when dealing with something like this.

Normally, id attribute suppose to be unique value, but there are some cases when front-end developer just hide part of DOM, create similar and forget to remove hidden one.
In such case you can (if it possible) ask developer to get rid of redundant code or use index as
"(.//*[#id='password'])[2]"

In cases like this you need to use another unique DOM element (parent, ancestor, sibling, child) with connection to the element you are looking for. For example In those html snippets
<div id='a'>
<div id='password'></div>
</div>
And
<div id='b'>
<div id='password'></div>
</div>
.//*[#id='password'] will have two results
However
.//*[#id='b']/[#id='password']
Will have only one result

Let me try to answer your queries one by one:
error when I tried to find the password field : This is because the property which you have mentioned id/name/css/xpath was incorrect.
ElementNotVisibleException : I doubt it was for the password_field at all. Reason behind that is, normally login field & password field stays on the same container. Either those resides on the HTML DOM (which gets loaded completely once the page loading is complete) or they may reside within a frame/iFrame (there are other measures to handle them which I am not covering here). But those 2 elements stays on the same container. So if you have found out the login_field element, password_field is just a step away.
inspected the xpath with Firebug and noticed that it returned two results : That's because the xpath which you are using doesnot identifies an unique element. There can be multiple elements on the HTML DOM with the same id attribute set to "password". But definitely the xpathof those elements will be different and unique.
What you should do?
I will suggest you the following:
a. Try to identify each element on a webpage following the attributes in sequence: id, name, visibleText, css, xpath.
b. Try to identify a unique logical xpath for elements using the other properties of the elements defined within the HTML tag. Cross check your xpath through Firebug/Firepath. There are some other handy xpath checker available too. Take help of those.
Let me know if this answers your question.

Related

Why do two identical looking elements return when using XPath to map elements for Selenium WebDriver?

I have had this question a while, but I had never done anything about it. When mapping some elements for UI tests I sometimes come across elements that return two identical results.
We have got around this in the past by using findelements and then using an index [1].
But I still don't understand why it returns two elements when I can only see one in the code that should be located.
An example would be the following. You can see this username field box below.
And if I use some XPath expression like,
//input[#name='username']
I'm expecting only to get one element in return, but using the tool Chropath I can see that I get two elements in return.
These elements look identical, one is not hidden, etc.
I have never understood why this is happening, because if I use a findelement, I get an element, not interactable error, as I guess the driver can’t decide which one to use? Or they are in the way of one another.
So the workaround I have always used is:
return self.browser.find_elements(by=By.XPATH, value="//input[#name='username']")[1]
when I realisticly should be able to use:
return self.browser.find_element(by=By.XPATH, value="//input[#name='username']")
Why is this?
Some excellent response and it has made me understand what’s going on now. Moving forward, I will use the following:
for e in self.browser.find_elements(by=By.XPATH, value="//input[#name='username']"):
if e.is_displayed():
return e
This seems to work for me.
I see this often when a website has both the "desktop" version and a mobile or smaller screen version. At full (or near full) screen, the desktop elements are visible while the small screen elements are hidden. Once you resize the browser small enough, the desktop elements are hidden and the small screen elements become visible.
To get around this in a generic way, filter the returned two elements based on visibility, e.g.
return [e in self.browser.find_elements(by=By.XPATH, value="//input[#name='username']") if e.is_displayed()]
That should always return the visible element of the two.
The answer is within the snapshot:
The following xpath
//input[#name='username']
Identifies 2 different elements within the HTML DOM. Among the two matching elements, the first matching element is for mobile displays which remains hidden while you access the DOM Tree in Desktop mode. In the given snapshot of the Chropath the classname as modal-content-mobile is the best hint.
Solution
In these cases there are different approaches to identify the desired element. While some users tends to use an index and some users tends to probe the displayedness, from a personal perspective I find it quite easier and handy to traverse up the DOM to find the difference in attribute values in any of their ancestors and then finally follow down till the desired element.
It is possible you can have more than one same element on the page with same name attribute. One must be hidden.
If you want to access the first one use following xpath.
return self.browser.find_element(by=By.XPATH, value="(//input[#name='username'])[1]")
If you want to access last one use following
return self.browser.find_element(by=By.XPATH, value="(//input[#name='username'])[last()]")
It's quite often occurs that multiple elements will match the same locator.
For example, several code blocks may be implemented for login: one for a computer browser, another for a mobile browser, etc. The proper elements will be presented according to what you use to browse that page.
Selenium find_element always returns the first element found matching the passed locator on the page.
So, in case the first matching element is hidden return self.browser.find_element(by=By.XPATH, value="//input[#name='username']") will always retunt that hidden element.
You will need to make your locator more precise to match the desired web element.
A locator like "(//input[#name='username'])[2]" may be good, but it's better to use a unique parent element here, something like "//div[#class='pc_modal']//input[#name='username']", so your code would be something like this:
return self.browser.find_element(By.XPATH, "//div[#class='pc_modal']//input[#name='username']")
Well, in the strictest sense of way, no two elements have the same XPath expression. If you look at the absolute path, you will find the difference. The key is to find a path which is unique. In many case, you will find a web page where you find many textboxes/labels/dropdowns that have the same ids but are only differentiated by their absolute path.
Most of the times, such things depend on the framework used to develop the webpage and also developer's preference. An application developed in React will have a different DOM structure than one developed using Angular, for instance.
Yes, you are correct that it becomes difficult to find out which is the element of interest in such situations. In such cases, do not only depend on the particular element but add either a parent/sibling or ancestor to access the element. Although it might take some time and will jot be straightforward but it will be possible to find a unique XPath most of the times.
There are some test automation tools, like Ranorex, that have an object browser (objext spy as it is called) that can be used to pin on any web element and access its properties like hidden, visible. enabled, etc. But such tools are not free :(

Is it possible to search for a dynamic button if the beginning of he ID is always the same?

I am using Selenium in some automation testing. On a certain page i need to click a button. This same page is used multiple times and when i originally tried to use the full xpath it would work on one of the pages but not the other. The full xpath for each page is slightly different so i dont want to use that.
The xpath of the button looks like this
.//*[#id='approve-gen8149262f2cdc49958632185c33b8e82f']
On both pages the id always starts with approve and then gets some generated numbers.
I am wondering if there is a way to search for just a section of the id so i can look for "approve" in order to find the button i need to click.
I have tried a number of things with no luck thus far.
You can also use CSS selector:
[id^="approve"]
Using XPath, you can select an element where one of its attribute begins with a given string. For instance:
//*[starts-with(#id, "approve-gen")]
See also:
Selecting elements whose attribute begins with something in XPath
You can also use the xpath with contains. for eg.
//*[contains(#id, 'approve-gen')]
Make sure that there are no other locators with id starts with 'approve-gen'.
Use
Step 1:
From the Given Info I have assumed the CSS Selector as
css=button[id*='approve-gen']
Also look for the Other Attributes of button that will bring uniqueness.
Step 2:
Perform Click on the button
driver.findElement(By.cssSelector("button[id*='approve-gen']")).click();

Handling dynamic ids and classes

I am using selenium to test a web application, The ids and classes are always changing dynamically.So that I am not able to give correct identification, is it possible to get ids of the element in run time and is there any other method to handle this situation.
It depends on if ids are completely random or if there is some part of the id which remains the same. If yes, then cssSelector is the obvious choice
driver.findElement(By.cssSelector("div[id*=somePart]");
where id* means id contains. If you cant use this approach you will have to track down your element using xpath or again cssSelectors. XPath example is here and CSS selector could look like this
By.cssSelector("boyd table input");
I would strongly recommend locating elements by XPath -- with the caveat that you make your XPaths robust and not just "copy" the xpath using your browser's developer tools. XPath is very easy to learn. You can use XPaths to walk up and down the DOM, and identify elements by their text, or their attributes.
For example, maybe you need to click a button that has a span that contains the text that appears on the button:
<div class="btn-row random-generated-number-1234897395">
...
<button id="random-generated-number-239487340924257">
<span>Click Here!</span>
</button>
...
</div>
You could then use an xpath like this:
//div[contains(#class, 'btn-row')]//button/span[text()='Click Here!']/..
(The /.. at the end walks back up from the span to the button.)
XPath is powerful and flexible and easy to learn. Use it when the ids and classes aren't reliable.

How to find XPath of an ExtJS element with dynamic ID

All the elements in the application which i am testing have dynanic ID's . The test always passes when i replay it without refreshing the page but as soon as i refresh the page, The Test Fails because Id's of all the elements changes randomly and selenium cannot match the recorded id's with the new ones .
I tried to use Xpath-position, It works for some objects but in case of Dropdown list and Buttons, it dosent work!
Can anyone please tell me how to find the Xpath (Meathods in JAVA or S*elence*) of an object OR How to create a new Locator Finder for Dropdown list and Buttons
I can show the properties (Inspected by Firebug) of the dropdown which is teasing me.
properties of Dropdown :
<div id="ext-gen1345" class="x-trigger-index-0 x-form-trigger x-form-arrow-trigger x-form-trigger-last x-unselectable" role="button" style="-moz-user-select: none;"></div>
properties of Dropdown*Choice*:
<ul>
<li class="x-boundlist-item" role="option">Rescue</li>
</ul>
Please search before posting, I have been answering this over and over.
ExtJS pages are hard to test, especially on finding elements.
Here are some of the tips I consider useful:
Don't ever use dynamically generated IDs. like (:id, 'ext-gen1345')
Don't ever use absolute/meaningless XPath, like //*[#class='someclass']/li/ul/li[2]/ul/li[2]/table/tbody/tr/td[2]/div
Take advantage of meaningful auto-generated partial ids and class names. (So you need show more HTML in your example, as I can make suggestions.)
For example, this ExtJS grid example: (:css, '.x-grid-view .x-grid-table') would be handy. If there are multiple of grids, try index them or locate the identifiable ancestor, like (:css, '#something-meaningful .x-grid-view .x-grid-table'). In your case, (:css, '#something-meaningful .x-form-arrow-trigger')
Take advantage of button's text.
For example, this ExtJS example: you can use XPath .//li[contains(#class, 'x-boundlist-item') and text()='Rescue']. However, this method is not suitable for CSS Selector or multi-language applications.
The best way to test is to create meaningful class names in the source code. If you don't have the access to the source code, please talk to your manager, using Selenium against ExtJS application should really be a developer's job. ExtJS provides cls and tdCls for custom class names, so you can add cls:'testing-btn-foo' in your source code, and Selenium can get it by (:css, '.x-panel .testing-btn-foo').
Other answers I made on this topic:
How to find ExtJS elements with dynamic id
How to find unique selectors for elements on pages with ExtJS for use with Selenium?
How to click on elements in ExtJS using Selenium?
Using class names in Watir
how to click on checkboxes on a pop-up window which doesn't have name, label
I would suggest you build a xpath from any of the parent of your DIV. you may get messed if there is no immediate parent node has such one.
example,
//*[#id='parentof div']/div
//*[#class='grand parent of div']/div/div
i did even something like this,
//*[#class='someclass']/li/ul/li[2]/ul/li[2]/table/tbody/tr/td[2]/div
But still, its not encouraged to do so.

How to handle dynamic id from xpath

I am trying to explore IDE with this site http://www.barnesandnoble.com/, by just recording and play back.
1.In the search box just enter any text to search,
2.Ten click on All Products, select Books.
When i record its xpath is as below
/html/body[#id='CDS']/div[#id='navContainer']/div[#id='bnnav2011']/div[#id='yui_3_3_0_1_1355746621091_93']/div[#id='bn-global-header']/div[#id='yui_3_3_0_1_1355746621091_92']/div[#id='yui_3_3_0_1_1355746621091_91']/form[#id='qs']/div[#id='yui_3_3_0_1_1355746621091_90']/div[#id='yui_3_3_0_1_1355746621091_89']/ul[#id='yui_3_3_0_1_1355746621091_88']/li[#id='yui_3_3_0_1_1355746621091_99']
But when we play ti again it gives error,[error] locator not found:
Wehn i search for its xpath , its chnaged and is as below
/html/body[#id='CDS']/div[#id='navContainer']/div[#id='bnnav2011']/div[#id='yui_3_3_0_1_1355748592221_91']/div[#id='bn-global-header']/div[#id='yui_3_3_0_1_1355748592221_97']/div[#id='yui_3_3_0_1_1355748592221_96']/form[#id='qs']/div[#id='yui_3_3_0_1_1355748592221_95']/div[#id='yui_3_3_0_1_1355748592221_94']/ul[#id='yui_3_3_0_1_1355748592221_93']/li[#id='yui_3_3_0_1_1355748592221_98']
Observe that, its ID's are changing.
Can any one tell me how to handle this ?
The IDE is not very smart at generating XPath queries, in fact, there isn't an automated tool out there that will calculate a reliable XPath query. Why? The reason is because to generate the XPath query, it will walk down the tree from the top (at the html element), down to the element you are interacting with.
Whilst this is fine for a lot of things, if you have elements that have dynamic values (dynamic text/ID/name/classes or even if it changes position), it's never going to work.
You'll need to look at a different way to get it, so you'll have to override what the IDE is giving you.
Looking at the source, they give whatever is selected a class value of ui-selectmenu-selected. So when the page loads, the 'All Products' list item (li) will have that class, when you change the item the new item will have that class.
So you could use this XPath:
//li[#class='ui-selectmenu-selected']
Or, this CSS selector:
li.ui-selectmenu-selected
Or, use this XPath to get the 'All Products' item specifically. It will start one level up, using the actual menu, then go down and find the item:
//ul[#class='ui-selectmenu']/li[text()='All Products' and not(#class='ui-selectmenu-hidden')]
You can try using xpath: Position. It seems that the IDs are changing all the time.
As an answer to your question you should move away from id's and try using xpath or css selectors where you can select the nth child of the parent.
Since you are new to selenium I would like to point to my notes here at.-
http://selenium-testing-notes.blogspot.in/
it will help you through a lot of other pitfalls I fell in.
The best way I found to help with selectors is to work with firebug with firepath installed. This setup can help you verifying your xpath and css selectors.
I saw your question based on that answer is first you need to add on fire-path in Firefox .Using firepath you can find the xpath locator. it is very simple to you
Example:
driver.find_element_by_xpath("see![image which i have attached in this question][1] the xpath path locator details").click()
Hi Arran i am able to click the All Products button using the xpath you have given ( xpath= //ul[#class='ui-selectmenu']/li[text()='All Products' and not(#class='ui-selectmenu-hidden')]
and also get the list available. But then not able to click the Books item from the Menu.