These days most of the QEs uses
Selenium for automating their UI Pages. With the latest front-end technologies,
there are lot of dynamic elements which makes it difficult to develop the
consistent automation code. One of the best ways to handle such elements is by
writing robust xpath. This article describes some basics and best
practices of writing your own xpath and Xpath axes to overcome such
difficulties.
Terminology used in XPath:
XPath is a syntax for defining parts of an XML document. It uses
the path expressions to navigate in XML documents. It is like a small
programming language, it has functions, expressions, wild card characters etc. XML
documents consist of trees of nodes. The topmost element of the tree is called
the root element followed by descendant nodes.
Let’s look into the terminology
used to identify these nodes:
- Each element has one parent except root
- Each element may have
zero or one or more child elements referred as child
- Nodes can have same
parent called siblings. Among siblings, the nodes which are to the
immediate left are referred as preceding-sibling
and other left nodes as preceding.
The nodes to the immediate right are referred as following-sibling and other right nodes are referred as following.
- A nodes parent,
parent’s parent is referred as Ancestor
- A nodes children,
children’s children is referred as Descendant
The below image will give more
insight about the above terminology. This is a sample hierarchy in a company. Here
I am considering Manager2 as node for reference.
Manager2 node has
- Manager3 as following
sibling node
- Manager1 as Preceding
sibling node
For Manager2,
- Director1 is the parent
node
- CTO is the ancestor node
(Parent of Parent).
For Manager2,
- Lead is the Child node
- QE1 and QE2 are
Descendant nodes
Basic Operators in XPath:
Operator
|
Meaning
|
[]
|
predicate
|
/
|
starts search selection from root element in
document
|
//
|
starts search selection anywhere in document
|
|
|
Used for combining more than one xpath
|
and
|
Boolean and
|
or
|
Boolean or
|
@
|
Denotes attributes
|
*
|
Represents any node of the document
|
contains
|
Used for denoting the regex expressions in Xpath
|
Start-with starting text of the attribute that is used
to locate an
element
As described above, any relative xpath would start with // and absolute
xpath would start with /.
XPath Axes:
Below examples describes the
usage of those XPath axe. I am using stubhub.com as a reference site.
1. Child
Axes:
The child axis defines the children of the context node.
Syntax: child::*
The first step is to
find the root node of the context node and then forming xpath with the help of child
keyword.
In the below example, I am trying
to write the xpath for location text. Here location text is a <div> tag
and it is under <a> tag. So, I have written xpath for <a> tag first
and then used key word child to get the <div> tag.
xpath:
//a[@class=’geo-display’]/child::div[@class=’geo-location-text’]
2. Parent
Axes:
The parent axis
contains only a maximum of one node. The parent node may be either the root node
or an element node.
The root node
has no parent; therefore, when the context node is the root node, the parent
axis is empty. For all other element nodes, the parent axis contains one node.
If we consider
the same example, I can write xpath for location <a> tag by writing xpath
for
<div > tag
and then go from there by using parent key word.
xpath: // div[@class=’geo-location-text’] /parent::
a[@class=’geo-display’]
3. Following
Axes:
selects
everything in the document after the closing tag of the current node.
It will identify
the immediate node which start after the current node.
In the below
example I have identified Help Link in the menu by identifying the logo first.
Logo is <a> tag and I have written xpath for identifying it. Then I used “following”
key word as the help link is the tag after the closing tag of <a>.
Xpath: //a[@id='logo']/following::span[text()='Help']
4. Preceding
Axes:
The preceding
axis contains all nodes in the same document as the context node that are
before the context node in document order.
I will take the
above example to explain this. I can use the preceding to get the logo from
help menu option.
Xpath: //span[text()='Help']/preceding::a[@id='logo']
5. Ancestor:
To find an
element on the basis of the parent element we can use ancestor attribute of
XPath. It Selects all ancestors (parent, grandparent, etc.) of the current node.
This example is
to identify the menu banner. I identified the Logo which is <a> tag. Then
I used ancestor keyword as menu <div> is ancestor tag of <a>.
Xpath: //a[@id='logo']/ancestor::div[@id='global-header-container']
6. Descendant:
Descendant lets
you select all descendants [e.g., Children and Grandchildren] of the current
node.
The Example here is
to identify the “sports” link from the “find events” Menu option. I identified
the “Find events” link first and then navigated to “Sports” link by using
descendant keyword.
Xpath: //li[@id='header-explore-menu']/descendant::a[@id='sports-ticket']
Best Practices of writing XPath:
If we use relative or improper xpath, we will have several issues when UI
changes. In order to avoid such problems, it’s necessary to follow some best
practices in the XPath Statements before using them in Selenium Automation.
Following are the few best
practices while writing a XPath:
- id
attribute should be used if available
- Combination
of attributes such as name, type, class, value etc makes XPath more
specific
Eg:
//span[contains(@class, 'category-ui-testing-automation') and @name='post']
- Should
be as small as possible
- Use
the Relative XPath instead of Absolute XPath Statements
- A
locator should not get effected by changes to its parents
- Always
avoid using indexes in Xpath.
- Verify
the xpath using Selenium IDE commands
- Use
XPath functions in XPath wherever necessary to better identification
- Identification
of objects with same attribute values
- Don't
identify the images using src or alt attributes
- Handle
multiple Xpaths for a single object by using ‘|’ operator