How to use ExpectedConditions.visibilityOfElementLocated for multiple hits - selenium

I have a HTML site containing several context menues.
The xpath is: .//*[#id='TopIcon_Edit']/a/span. (This path will hit several elements)
In my test one of the context menues is visible.
I now want to verify that one context menu is visible, using
ExpectedConditions.visibilityOfElementLocated(By.xpath(".//*[#id='TopIcon_Edit']/a/span")).
Although I can see that the context menu is visible, the test tells me:
"Element does not meet condition visibility of element located by By.xpath: ..."
I assume that the method visibilityOfElementLocated(...) just evaluates the visibility of the first element it finds by the locator, which is not visible, as Selenium rightly sais.
I would appreciate any hints on how to solve this problem.
With kind regards,
Gerhard Schuster

Yes, when you search single element with Selenium and result returns more than one element, the method takes the first element and returns it.
So, you have to specify more precisely the xpath you using, for example: ".//*[#id='TopIcon_Edit']/a[1]/span", or similar, that will point only desired element.

If you can do away with xpath that would help. FindElement(By.cssSelector("#TopIcon_Edit span")).click() or do a list of web elements we = FindElements (By.cssSelector("#TopIcon_Edit span")); then filter your list based on style. Its far easier and provides greater flexibility to use cssSelectors.

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 :(

selenium elementIdElement functionality

The documentation on code.google.com describes the elementIdElement functionality as "Search for an element on the page, starting from the identified element". Does this mean the search is done for every element following that element throughout the rest of the web page or only for dependents of that element?
If it is the former, then how would I construct the "value" entry if the "using" parameter is "css selector" and I want to find a descendant of the current element's sibling? I thought the value would be "+ div .classname", but this doesn't seem to work.
One way you can do it is by emulating Selenium ByChained, by calling one wait after another:
browser
.useXpath()
.url('http://www.google.com')
.waitForElementVisible('.//body', 1000)
.waitForElementVisible(".//div[contains(#class, 'classVar')]")
.click('button')
The correct xpath string for navigating to an element's parent's following sibling for the existence of another element with a given class is
'(//div[#id="currentElementID"]/../following-sibling::*[1]//div[contains(#class,"classToLookFor")])[1]'
In this example, I know the current element's ID so that's what I use, but the '//div[#id="currentElementID"]' can be replaced with whatever you need to navigate to the starting element. Also, this example assumes the element I'm looking for is a div.

Finding clickon Element using Selenium. (JAVA)

I spend hours already trying to find the way to find the Element using Selenium WebDriver. I assume I need to use driver.findElement(By.xpath("")), but I am not quite sure how.
I somehow need to find and click on "clickon" element. The problem is that part of that element is changing (see screenshot) I need to pick up from the file and putted into the xpath.
I would appreciate any help.
We have been rigorously searching for automated functional testing solutions recently, and we began with Selenium. The entire reason we decided to search for other solutions was that our application also has dynamic IDs with no other obvious XPath mechanism to identify them. Selenium is unable to identify these elements on the page without some additional knowledge, just as you would be unable to identify these elements on the page if you didn't already know what they are.
If you are controlling the DOM creation, consider adding a unique ID or class to this element.
We recently came across eggPlant from testPlant, and it is an interesting approach to functional testing. It's essentially image based. Other viable solutions are Ranorex or HP's QTP or SmartBear's TestComplete.
You can use xpath. If the div class is constant, you can use something like:
driver.findElement(By.xpath("list-row field-item")).click();
To view the xpath, you can install firefox plugin called 'xpath checker' found here and right click on the dom element and click 'View Xpath' option to get the xpath of the element and then you can use that xpath in your code.
Or you can even use regex in the xpath which is suitable for the similar problems. Xpath with regex is really powerful.
It seems that you want to click the div that has the on click attribute that contains certain text that doesn't change, ignoring the part that does. In that case, use an xpath like this:
//div[contains(#onclick, '/challenge/index/rfp_id/')]
This will select the first div with an onclick attribute with a value containing /challenge/index/rfp_id.

How can i select this span element?

I am just starting with Selenium and now in need to select this element:
<span class=" close">Matrices</span>
This line of code returns zero elements, so i guess it's not the right one :-)
ReadOnlyCollection<IWebElement> matrixLink = driver.FindElements(By.PartialLinkText("Matrices"));
But I could not find another one suitable, besides the Xpath, but that looks like this (//*[#id=\"Navigation\"]/div[2]/div[2]/ul/li[7]/span), and that seems a bit fragile to me?
EDIT:
the span has the class 'close'.
It's part of a menu, where there are 19 span's with the class 'close' so it's not a unique selector unfortunately....
This will work:
//*[#id=\"Navigation\"]/descendant::span[text()='Matrices']
Note that if you can, be specific in your XPath queries, mainly to aid readability and improve performance...that is the * in your query will query all elements in the page. I don't know what kind of element the Navigation element is, but you should put it's exact element type in, for instance if it's a div, make it:
//div[#id=\"Navigation\"]/descendant::span[text()='Matrices']
A slight explanation for this XPath is that it will grab the Navigation element, and simply look anywhere inside it to find a span element that has the text of Matrices. Without the descendant bit in the XPath, it would only search for direct children. That means elements that a child of Navigation, nothing else - so if an element is a child of TestDiv which is a child of Navigation, descendant would catch it, without it you won't return any results.
As for why By.PartialLinkText would not work, this would only search for anchor links. It is common, as you have seen, that anchor links have a span element inside them or sometimes it is just a span on it's own.
By.PartialLinkText and similarly By.LinkText would not 'see' this element, since it's not an anchor element.
My favorite problem solver for these cases:
Install Selenium IDE
Click the link you need
In the "target" in Selenium IDE you will see different xpath possibilities
But I would use the approach, that its N-th element with "close" class (//span[7] or something like that)
You can use //span[text()='Matrices']
It will select your element.

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.