Selenium – XPath Unleashed Part One
In one of the first articles on the site, I talked about locators and how to use them. In that article, I talked about how XPath locators can be horrible to use, this article title aside, they most definitely can be horrible. However, use them in the right way and they can be one of your most powerful allies when writing Selenium tests. So what is the right way to use XPath locators?
Before I cover that, let’s talk about the different types of XPaths that can be used:
Absolute XPath – This is the most direct path to an element. It begins at the root node so goes through the entire HTML DOM. It is extremely fragile as it relies on the location of the element in the DOM to never change. As an example, let’s say you have an online shop with a list of items on a page for a search, the items returned are always the same, however, the order is not. This means the immediate part of the XPath dealing with the element, so the item for sale itself, might not have changed, but because the order it appears on the page has changed, the path as a whole is different.
You can see that if any of those numbers in the divs changed, this whole path breaks and either references the wrong element or no element at all.
Relative XPath – This starts further into the DOM, so is shorter than an absolute path. It’s also a lot less fragile because it deals with referencing HTML classes or objects directly. Going back to the above example for the online shop, this would fix a lot of our problems as we’d begin the path at the item for sale element itself, rather than the root of the page.
//*[@class='featured-box']//*[text()='Amazing T-Shirt with Amazing Design']
When you right click on an item in your browser and copy the XPath, that will always be an example of an absolute XPath. You’ve probably seen it before when you’ve pasted that into your code and been shocked at how long the path can be. A relative XPath however, is typically something you will have to write yourself, which might seem daunting if you’ve not done it before, but it really isn’t that bad. Once you’ve written a couple and gotten used to the basic syntax, you’ll never look back and your mind will be blown at just how much power is behind a smart XPath.
So what kind of syntax makes up a smart XPath?
Basic XPath – To select a node, we can use the attribute of the element we would like to use. This can be an ID, value, name or class name.
This extremely simple path would select an input element with the name of ‘username’. This might be a username text input on a login page. This would be fine for a very simple page without many elements or nested objects on, but what about if our objects are dynamic?
Contains – This is a method used in XPath expressions. You would use it when an item attribute is dynamic and varies each time you visit the page. You can use part of the text for that attribute to find the element.
The above code would locate the same element as in our basic XPath example but would find it using only the text ‘user’ as opposed to using the full ‘username’ text. This could be useful if our username textbox was dynamic, but it’s dangerous with such a simple search term as it could match multiple elements on a page if there are elements with the text user in the name.
OR and AND – In the same way your main programming language uses an OR and AND keyword, XPath expressions can also use them.
//input[@type='submit' or @name='userLogin']
The above code will search for any elements of the type submit OR with the name userLogin. So it’s a very broad search. If you had more than one button on your page, this would match multiple elements even if the name part of the path references a specific button. How can we fix this?
//input[@type='submit' and @name='userLogin']
This code will now only match if the type is a submit button AND the name is ‘userLogin’. Now, even if we have multiple submit buttons on the page, as long as they don’t have also have the name ‘userLogin’, it will only match with one element. This allows you to be far more precise.
Start With – Similar to contains, if you have elements that have dynamic attributes, this can be a useful method to use in your expressions. Whereas contains will search the entire string for the text, Start-with, as the name suggests, only checks the very start of the attribute.
Going back to our online shop, let’s say we had a T-Shirt section and we wanted to match all the elements on the links to our black t-shirts for sale. It just so happens our development team are extremely consistent and use the format “<colour> T-Shirt with <design>” for their naming for every t-shirt on the site. Our Start-with syntax might look like:
While the above example is extremely basic in terms of the text it’s using, because of our awesomely consistent developers, this would in fact match with all our links for any black t-shirts on the page. So as long as you know that the text you are searching for is static, anything after that can be dynamic and it will still match.
Text – Text() is another method we can use to find
//td[text()='Black T-Shirt with 3 Wolfs One Moon Design']
So unlike contains and start-with, where we can match using partial text, this will match with an element with this exact text. Unfortunately, our shop sells this t-shirt so we would, in fact, return one result. As it’s exact, any typo or formatting mistakes will cause the element not to match, so you do need to be more careful when using this.
The final and most complicated area of building an XPath locator is axes methods. Writing about that will take up an entire article in itself, so I will save that for part two. Part one should give you a good start and a lot to play with when it comes to building your own XPath locators.
As an exercise, I suggest picking a site with a lot of elements on it and see if you can match elements you’re looking for using any of the above. You can combine any of the methods or syntax above to build bigger and more complex expressions to be even more accurate, so experiment and become confident with how you use these. You don’t even need to write code or tests to test your XPaths, you can use Ctrl+F when inspecting your site in dev mode and type an expression, you’ll get matches as you type so you’ll know straight away if your expression is working.
I guarantee, when it clicks and you become confident doing it, you will go back and rewrite a lot of your tests or page factory classes to make them more flexible and robust. I did just that myself when I discovered the true power of smart XPaths.