logo logo

Advanced XPath Locators for UI Test Automation

Advanced XPath Locators for UI Test Automation

XPath is one of the most important locators we use in Selenium when we need to interact with elements that don’t have unique IDs, names, or classes. Some XPaths are quite straightforward, but there may be cases when the elements cannot be easily identified, so we need to single them out based on specific characteristics or relations to other elements. For these cases, we’ll need to use advanced XPath locators.

Locating the last element

XPath allows us to use the index of the element, to locate the nth element with a certain attribute. For example,  //*[@class='MyClass'][1] will return the first element with the class name ‘MyClass’. But we can also identify the last element with this attribute, even if we don’t know beforehand the total number of elements. For this, XPath allows us to use the method [last()].  We can also use [last()-1] to find the second to last, and so on. Let’s check an example – we have this table:

Table Example

With this HTML code:

HTML code
HTML code generated using https://html5-editor.net/

If I need to get the last person’s first name, without knowing the total number of rows in the table or the text value inside the cell, I need to identify the first cell (td element) of the last row (tr element). In Xpath, this will translate to: //tr[last()]/td[1]

Locating elements by parents

The HTML document has a tree structure, which means that elements are ancestors, descendants, parents, children, and siblings 👨‍👩‍👦‍👦 How does the parent axis work? Let’s see another example:

XPath Parent

If we want to identify the paragraph that contains the image (may not be a probable test case, but for the sake of the example, let’s say that’s what we need), we can use the img element and its unique alt attribute and transverse the HTML up from there:

//img[@alt='smiley']/parent::p.

This means that we identify the p element that is the parent of //img[@alt='smiley'].

A shorter way to write this (but a bit harder to read) is: //img[@alt='smiley']/..

Using ancestors in XPath

Ancestors in XPath have a broader range than the parent axis, because they also take into account higher levels inside the HTML tree. In our example above, we can replace parent with ancestor and we will get the same result. However, if we want to go higher than the parent level, or we are unsure of the relationship between the elements, we will use the ancestor axis. So we can have:

//img[@alt='smiley']/ancestor::p which will return the paragraph parent of the image,

//img[@alt='smiley']/ancestor::div – returns the div ancestor, or

//img[@alt='smiley']/ancestor::* which matches all the image’s ancestors, regardless of their tag.

Working with siblings

The sibling axis is used when we need to identify an element based on information from another element at the same level, with the same parent. We can go back to our first table and, try to find the age of the person named Madison. The name cell and the age cell are siblings (they are both td elements under the tr parent), so we can use this to create our XPath. Basically what we are looking for is the cell preceded by the one with the text ‘Madison’:

//td[preceding-sibling::td[text()='Madison']]

Or, in other words, the cell following the one with the text ‘Madison’:

//td[text()='Madison']/following-sibling::td

Both XPaths will return the same unique element.

More advanced Xpath locators

Advanced XPath: “Cousins”

Not really the official term, but, similar to siblings, these are elements located at the same level inside the HTML tree, except instead of having the same parent, they have a common ancestor on a higher level. I’ll reuse the HTML from the first table, but the content of the cells will be inside div tags:

Advanced XPath: Cousins

Now if I want to identify the age cell again, based on the ‘Madison’ name value, I won’t be able to use the sibling axis, because the ‘Madison’ div and the ’22’ div each have their own td parent. However, I can make use of the fact that the parent tds are siblings, and so my resulting XPath should be:

//div[text()='Madison']/../following-sibling::td/div or

//div[text()='Madison']/ancestor::td/following-sibling::td/div or

//div[text()='Madison']/parent::td/following-sibling::td/div

Advanced XPath: “Uncles”

Let’s look at a slightly different HTML code:

Advanced XPath: Uncle

The information is the same as above. But because the bold tags are added only around the names, to get the age of the person named ‘Madison’, I need to go to the name’s parent/ancestor, and then select the parent’s sibling. This makes the relationship between the age element and the name element an “uncle/nephew” one. The resulting XPath is almost the same as above, but simplified because we don’t need to go down another level in the last td. So our XPath will be:

//b[text()='Madison']/../following-sibling::td or

//b[text()='Madison']/ancestor::td/following-sibling::td or

//b[text()='Madison']/parent::td/following-sibling::td

Avatar

About the author

Andreea Draniceanu

Andreea is a QA engineer, experienced in web and desktop applications, and always looking to improve her automation skills and knowledge. Her current focus is automation testing with C#.

Join TestProject Community

Get full access to the world's first cloud-based, open source friendly testing community. Enjoy TestProject's end-to-end test automation Platform, Forum, Blog and Docs - All for FREE.

Join Us Now  

Comments

11 1 comment

Leave a Reply

popup image

Become a master for Selenium testing

Getting started with web testing? We’ve got you covered with a FREE ready-to-go test automation platform that’s already bundled up with Selenium to simplifying and enhancing your experience.
Get Started
FacebookLinkedInTwitterEmail