Monday 23 March 2020

XPath Writing Techniques and Best Practices


      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:
  1. id attribute should be used if available
  2. 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']
  1. Should be as small as possible
  2. Use the Relative XPath instead of Absolute XPath Statements
  3. A locator should not get effected by changes to its parents
  4. Always avoid using indexes in Xpath.
  5. Verify the xpath using Selenium IDE commands
  6. Use XPath functions in XPath wherever necessary to better identification
  7. Identification of objects with same attribute values
  8. Don't identify the images using src or alt attributes
  9. Handle multiple Xpaths for a single object by using ‘|’ operator