0

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.

Enter image description here

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.

Enter image description here

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian Mitchell
  • 345
  • 3
  • 21
  • could you please provide the url? thanks – Manish Jan 31 '23 at 16:12
  • Unfortunately i cant share the url as its internal, but i just wondered if other software testers have come across this issue. – Brian Mitchell Jan 31 '23 at 16:22
  • 1
    Screenshots of the UI are great, screenshots of code or HTML are not. Please read why [a screenshot of code/HTML is a bad idea](https://meta.stackoverflow.com/questions/303812/discourage-screenshots-of-code-and-or-errors). Paste the code/HTML and properly format it instead. – JeffC Feb 01 '23 at 17:25

5 Answers5

1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JeffC
  • 22,180
  • 5
  • 32
  • 55
1

The answer is within the snapshot:

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.

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
0

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()]")
KunduK
  • 32,888
  • 5
  • 17
  • 41
0

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']")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prophet
  • 32,350
  • 22
  • 54
  • 79
-1

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Manish
  • 484
  • 3
  • 12
  • `Well in the strictest sense of way, no two elements have the same xpath.` This is in no way true. It very much depends on how you write the XPath. It's very easy to write a single XPath that will return hundreds of elements on the page. Then you later contradict this yourself when you state, " it will be possible to find a unique xpath most of the times." Most of the time is not "no two elements have the same xpath." – JeffC Feb 01 '23 at 17:24
  • How a pwrwon writes the xpath and what the absolute path of the element are two different things. If you look at the absolute path, it will always be different unless and until two the elements are the same. The way that you write xpath makes it possible to write a single xpath the returns hundreds ds of elements. A simple `\\div` would do what you described. – Manish Feb 01 '23 at 18:15
  • Using an absolute XPath as a locator is never a good practice. They are usually very long, unreadable, and most importantly they are extremely brittle. – JeffC Feb 01 '23 at 18:17