
Using direct XPath in your test
As I mentioned in the first part of this section, having //
as the start of your XPath is seen as a greedy query since it will parse the entire DOM until it finds the element that you want to find. If you want to work against an element that is always in a certain place, you can use a more direct XPath.
Finding elements by direct XPath
Instead of using //
, you can use a single /
, but you will need to make sure that the first node in your query is HTML. Let's see an example of this:
- Open Selenium IDE.
- Navigate to http://book.theautomatedtester.co.uk/chapter2.
- Type
xpath=/html/body/div[2]/div[3]/input
into the Target input of Selenium IDE. - Click on the Find button.
The previous locator will find the same element as before. This type of XPath query will find the element fractionally quicker, but if your UI is going to change, it may fail if the element is moved into a different area of the page. One thing to really note is that XPath locators can be extremely fragile. They can find what you want, but when you make a small change to your HTML, they will break, meaning that you need to do maintenance on that test. I would recommend using these only if you have to.
You may have noticed that parent and child nodes are in the same query. Since HTML has a tree structure, it just notifies the query that it needs to start at the HTML node, then move to its child node, body, then to the body's child, and so on until it reaches the end of the query. Once it has done this, it will stop executing the query.
Using XPath to find the nth element of a type
There are a lot of occasions when, as a Selenium user, you will have to click on an edit button in a table so that you can update something specific. Have a look at the button that you wish to click; it does not have a unique name or ID. An example of this is the button with the value Sibling Button.
When doing a query against the DOM, an array of elements is returned to Selenium that matches the query. For example, if you were to do //div
on the Chapter 2
page of the website, there are three elements returned to Selenium. If your test only depends on the first item in your test, then it will try and access only the first item. If you want to interact with the second element, then your query will look like //div[2]
. Note that the second to nth element need to be sibling nodes of the first element that is returned. If they are not and you were to access the element, it will fail, saying that it could not find them.
We can see this with the input buttons that are present on the page. They all reside in their own containing div
element, so do not have any sibling elements that are also input elements. If you were to put //input[2]
into Selenium IDE, it will not be able to find the element and fail.
You can see an example of this in the following screenshot:

Using element attributes in XPath queries
There are times when you need to find elements that are the same except for one or two attributes. To handle this, we can add the attributes to the query so that we can try to make the element more unique for use in the test. The format can be used for any attribute on any element. It will always follow xpath=//element[@attribute='attribute value']
. For example, if you have two div
elements on the page, but they only differ in the class attribute, your XPath query will look like the following: xpath=//div[@class='classname']
.
Try doing this with Selenium yourself by trying to identify something unique about the div
elements on the page. When you have completed the task, your query should look like one of these shown in the following screenshot:

Performing partial match on attribute content
As mentioned earlier, there are times when there is no way for a developer to create a static ID for elements on the page. This can be down to the fact that the element is being loaded asynchronously via AJAX or because it is using the key of the data as it is stored in the database.
There are times where only part of the ID is dynamic. This is to allow the developer to cram more information onto the page so that the user has everything they need. We need to have a mechanism to work with these elements. To make a partial match, your query needs to have the word contains
with the attribute and the partial match that it needs. For example, if you want to access the element with the following text in it This element has an ID that changes every time the page is loaded, you use //div[contains(@id,'time_')]
. This is due to the first part of the ID always being static. The locator can also use starts-with
instead of contains
to make the XPath query stricter in what is returned. The queries in the following screenshot find the same element on the page:

Finding an element by the text it contains
Finding elements by the text they contain can be quite useful when working with web pages that have been created dynamically. The elements can be obtained by using a web-based WYSIWYG editor, or you might just like to find a paragraph on the page with specific text to then do further queries.
To do this, your query will need to have the text()
method called in the query. It will match the entire contents of the node if it has the //element[text()='inner text']
format. As seen in the previous section, your query can use the contains
keyword to a bit more leniency in what it finds. Next, you can find a screenshot of queries that find the same element as the previous section:
