9n. WebDriver – Locating elements: Part 4a (by xpath)

Welcome back, we will cover XPath strategies today. This is an advanced and effective locating strategy as well (by cssSelectors was too!). While being effective, it can sometimes be confusing. So, let us delve on how to understand our often misunderstood friend and come up with the good code once for all.

When all hope is lost, the only chance to save ourselves is to turn towards XPath strategy. Because, most of the time, we are going to be testing something that is existing and that cannot be modified. We don’t always have the control over the page to add in some Ids making automation that much of a simpler task. So stop ranting and get serious!

Prepare to be lit up

XPath (XML Path Language): According to w3schools, XPath is a “path-like” language used to identify and navigate through various elements and attributes in an XML document.

Thus XPath provides syntax for locating any element in an HTML document.

Sticky Note:

If you have never been exposed to XPath in your journey so far, make it a point to understand XPath terminologies before proceeding any further. Especially, nodes and relationship between these nodes viz., parent, children, siblings, ancestors, descendants.

If you are already aware of these terminologies and you wish to brush them a bit, just refer to the below image. Courtesy: w3schools

xpath DOM

Now onto the main task of the day: locating elements by XPath strategy! In this post, we will be looking into the following techniques,

  1. Shortcut
  2. Absolute XPath and Relative XPath
  3. Using tag and attributes
  4. Using two conditions
  5. Using contains()
  6. Finding multiple elements

Let us start with the easiest one for some motivation.

1. Shortcut:

Want to find the XPath of any element on the web page the easy way? Done. Want it to be in a perfect working condition almost every time? Also done. What about getting all this done in a jiffy? It got you covered rockstars! All you need is, ‘Firebug’! It is available as an add-on to Firefox browser.

Here comes the recipe:

  1. Click on the Firebug icon or press ‘F12’.
  2. Inspect the element whose XPath is required.
  3. The corresponding code will be highlighted in the ‘HTML’ section of the Firebug panel.
  4. Right click on the highlighted code and select ‘Copy XPath’
  5. And voila! You have the ready baked XPath copied to your clipboard!

A glimpse of what we just spoke,

xpath firebug

If you wish for a detailed post on Firebug, take a peek here.

2. Now for the long short:

In order to come up with an XPath from scratch, we first need an understanding of the two types of Xpaths available. They are, absolute XPath and relative XPath.

Bonus: Prepare to be lit up (ONE MORE TIME)

Absolute XPath Relative XPath
It starts with a single forward slash (/). It starts with a double forward slash (//).
‘/ ‘ instructs the XPath engine to search for the element with reference to the root node. ‘//’ instructs the XPath engine to search for a matching element anywhere in the DOM structure.
Element identification is faster compared to relative XPath. Takes more time to identify the element as only a partial path is specified.
Even with the slightest change to the HTML DOM structure (e.g. adding a tag or removing one), absolute XPath would fail. Relative XPaths are shorter and are less likely to change, making them more dependable.
E.g., /html/head/body/div[2]/form/input E.g., //input[@name=’username’]

With this basic knowledge, let us dive in!

3. Using tag and attributes:

It is possible to locate a specific web element with its HTML tag, its attributes such as Id, name, class, title, value, href, src etc., and their corresponding values.

Syntax: driver.findElement(By.xpath(“//tag_name[@attribute=’value’]”));

Explanation: Identifies the element pointed by the XPath. ‘//’ identifies the specified node and ‘@’ symbol is used to select the specified attribute which matches the given value.

Example: Let us locate the first name text box on the Gmail account sign up page.

Right click on the ‘first name’ text box and select inspect element to get the corresponding HTML code which is as below,

<input value="" name="FirstName" id="FirstName" spellcheck="false" 
class="form-error" aria-invalid="true" type="text">

We can see that the ‘input’ tag has a ‘name’ attribute whose value is ‘FirstName’.

Code: (Any one of the below options can be used)

driver.findElement(By.xpath("//input[@name='FirstName']"));
driver.findElement(By.xpath("//input[@id='FirstName']"));
driver.findElement(By.xpath("//input[@class='form-error']"));

In case you wish to use the absolute path,

driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]/div/form/div[1]/fieldset/label[1]/input"));

form tag has numerous child div tags. In our case, we wish to choose the first div tag. This can be specified as, ‘div[1]’. The number inside those square brackets [], indicates the exact sibling that is to be chosen.

4. Using two conditions

What if multiple tags have the same attribute value? Or what if you wish to locate an element only when it matches BOTH the specified conditions?

Syntax: driver.findElement(By.xpath(“//tag_name[@attribute1=’value1’] [@attribute2=’value2’]”));

Explanation: Identifies the element with the specified tag_name having attributes that match the given values.

Example: Let us locate the ‘Confirm your password’ text box on the Gmail account sign up page.

Right click on the ‘Create a Password’ and ‘Confirm your password’ text boxes and select inspect element to get the corresponding HTML code which is as below,

<input name="Passwd" id="Passwd" type="password">
<input name="PasswdAgain" id="PasswdAgain" type="password">

Notice that both textboxes have same values for ‘type’ attributes but different values for ‘id’ and ‘name’. So, in order to locate ‘Confirm your password’ text box, let us mention both its ‘type’ and ‘id’ values.

Code:

driver.findElement(By.xpath("//input[@type='password'][@id='PasswdAgain']"));

5. Using contains():

Nowadays, most of the attribute values such as ‘id’, ‘src’, ‘href’ etc. are dynamically generated with a constant prefix or suffix.

Imagine a web page with an image that changes every day. Its src can be ‘Image_random-generated-key_date.jpg’. In this case, we can locate the image by XPath with ‘img’ tag containing value of ‘Image’ in its ‘src’ attribute. Thus by specifying a partial value of the attribute, we can locate the element.

Syntax: driver.findElement(By.xpath(“//tag_name[contains(@attribute,’value’)]”));

Explanation: Identifies the element with the specified tag_name with an attribute that matches the given partial value.

Example: Let us locate the ‘Next step’ button on the Gmail account sign up page.

Right click on the button and inspect element to get the corresponding HTML code which is as below,

Code:

driver.findElement(By.xpath("//div[contains(@class,'button')]/input"));

Notice that this XPath identifies the div element that contains a class attribute with a partial value, ‘button’ (<div class=”form-element nextstep-button“>) and then locates its child ‘input’ tag which is the submit button.

6. Finding multiple elements

You might come across cases where you wish to find all the elements having a particular class or name and perform certain operations on them. The asterisk (*) symbol comes to our rescue!

Example: Let us locate all the elements having a class value ‘goog-inline-block’ on the Gmail account sign up page.

Code:

driver.findElements(By.xpath("//*[contains(@class,'goog-inline-block')]"));

This will locate all the tags that contain the value ‘goog-inline-block’ in its ‘class’ attribute.

Make it a point to use ‘findElements’ so that all the identified web elements can be added to a list. If ‘findElement’ is used, it will only return the first element that is identified.

Overall picture

Let us see a test case implementing all the techniques covered in this post so far,

Scenario

  1. Open Firefox browser.
  2. Navigate to google account creation page
  3. Locate ‘First Name’ text box using absolute XPath
  4. Enter ‘testFirst’ as the first name
  5. Locate ‘Last Name’ text box using tag and ‘id’ attribute (relative XPath of course!)
  6. Enter ‘testLast’ as last name
  7. Locate ‘Confirm your password’ text box using two conditions, type and id attributes
  8. Enter ‘Pass1234!’ as confirmation password
  9. locate all the elements that contain the value ‘goog-inline-block’ in its ‘class’ attribute using asterisk symbol
  10. Print the total number of located elements to the console
  11. Print the first identified element’s title value to the console
  12. Locate the ‘Next step’ button using contains()
  13. Print the value of its ‘name’ attribute to the console
  14. Verify eclipse IDE console output screen and JUnit pane for success result

JUnit code for this scenario is,

package com.blog.junitTests;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class ElementLocatorTest4 {
	//Declaring variables
	private WebDriver driver; 
	private String baseUrl;

	@Before
	public void setUp() throws Exception{
		// Selenium version3 beta releases require system property set up
		System.setProperty("webdriver.gecko.driver", "E:\\ Softwares\\Selenium\\geckodriver-v0.10.0-win64\\geckodriver.exe");
		// Create a new instance for the class FirefoxDriver
		// that implements WebDriver interface
		driver = new FirefoxDriver();
		// Implicit wait for 5 seconds
		driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
		// Assign the URL to be invoked to a String variable
		baseUrl = "https://accounts.google.com/SignUp";
	}
	
	@Test
	public void testPageTitle() throws Exception{
		// Open baseUrl in Firefox browser window
		driver.get(baseUrl);
		// Locate 'First Name' text box by absolute XPath
		// assign it to a variable of type WebElement	
		WebElement firstName = driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]"
			+ "/div/form/div[1]/fieldset/label[1]/input"));
		// Clear the default placeholder or any value present
		firstName.clear();
		// Enter/type the value to the text box
		firstName.sendKeys("testFirst");
		// Locate 'Last Name' text box by relative XPath: using tag and id attribute
		WebElement lastName = driver.findElement(By.xpath("//input[@id='LastName']"));
		lastName.clear();
		lastName.sendKeys("testLast");
		// Locate 'Confirm your password' text box by XPath: using two conditions   
		WebElement confirmPwd = driver.findElement(By.xpath("//input[@type='password'][@id='PasswdAgain']"));
		confirmPwd.clear();
		confirmPwd.sendKeys("Pass1234!");
		//Locate all elements with class 'goog-inline-block' by relative XPath: using asterisk symbol
		List<WebElement> dropdowns = driver.findElements(By.xpath("//*[contains(@class,'goog-inline-block')]"));
		// Prints to the console, the total number of elements located 
		System.out.println("Total elements containing the class 'goog-inline-block' are= " + dropdowns.size());	
		// Prints first identified element's title value to console
		System.out.println("Value of the dropdown's 'title' attribute = " + dropdowns.get(0).getAttribute("title"));
		// Locate 'Next step' button by XPath: contains() and child element
		WebElement submitBtn = driver.findElement(By.xpath("//div[contains(@class,'button')]/input"));
		// Prints submitBtn's 'name' attribute's value to the console 
		System.out.println("Value of the button's 'name' attribute = " + submitBtn.getAttribute("name"));
	}
	
	 @After
	  public void tearDown() throws Exception{
		// Close the Firefox browser
		driver.close();
	}
}

Execution Result:

Parts of the code are explained as part of each technique discussed in this post.

In JUnit window, green bar shows that the test case is executed successfully. Console window shows the absence of any errors. It also displays the total number of web elements located with the asterisk symbol along with the attribute values of a dropdown and a button.

xpath console output

Below image shows the Firefox output obtained upon successful execution of the test script.

xpath firefox output

Take a break fellas! Our next post will be the final one on locating elements strategies. So don’t miss it! See you soon and have a nice day!

2 Comments

  1. I should really appreciate the consistency in the quality of each article. This particular one made my day a lot better! I now can proudly say that I understand XPath now. Really excited to try out a few examples!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.