9o. WebDriver – Locating elements: Part 4b (by XPath contd.)

Hiya champs! Welcome to our final post on locating elements. Yay!!!

This is a continuation from our previous post, “9n. WebDriver – Locating elements: Part 4a (by XPath)”. You have heard me say this before and you will hear me say it again… read Part 4a before going any further for a complete grip on using XPath strategies.

In this post, we will be looking into the below techniques,

  1. Using Text()
  2. Using starts-with()
  3. Using XPath axes

These techniques along with the ones we saw in part 4a, can be combined and used to form an effective XPath that can locate any element on the web page. Time to walk through today’s techniques with examples.

1. Using text()

This is an easy way to locate elements by providing the text exactly as it appears on the web page.

Sticky Note:

Watch out! You might bump into ‘ElementNotFound’ exception even if a space is included by mistake. It is very important that the text being provided in the code matches the visible text exactly and I mean that literally!

Example: Let us locate the ‘Forgot account?’ link on the Facebook Sign Up page.

Right click on the ‘Forgot account?’ link and select inspect element to get the corresponding HTML code which is as below,

<a href="https://www.facebook.com/recover/initiate?lwv=111" 
data-testid="forgot_account_link">Forgot account?</a>

Let us locate this link by providing the text as it appears on the Facebook page.

Code:

driver.findElement(By.xpath("//a[text()='Forgot account?']"));

If you wish to locate all elements containing a partial text, contains() and text() techniques can be combined. All elements can be obtained in a list using findElements method.

Let us try to implement both contains() and text() in the same example. Since we just have one link with that text, findElement method will be used.

driver.findElement(By.xpath("//*[contains(text(),'Forgot')]"));

2. Using starts-with()

Starts-with() can be used to find an element by specifying a partial value (prefix) of the attribute. This function comes handy when attribute value changes dynamically on page reload.

Example: Let us locate the ‘New password’ text box on the Facebook Sign Up page.

Right click on the ‘New password’ text box and select inspect element to get the corresponding HTML code,

<input class="inputtext _58mg _5dba _2ph-" data-type="text" 
name="reg_passwd__" aria-required="1" placeholder="" id="u_0_d" 
aria-label="New password" type="password">

Let us locate this textbox by providing the ‘type’ attribute’s partial prefix value, ‘pass’. Notice that the password field in the ‘Sign in’ section also has ‘type’ as ‘password’.

<input class="inputtext" name="pass" id="pass" tabindex="2" type="password">

Hence the second element has to be located in our case.

Code:

driver.findElement(By.xpath("(//input[starts-with(@type,'pass')])[2]"));

3. Using XPath axes

XPath axis defines a node-set or the direction which is to be considered with respect to the current node as it navigates through the tree structure of the DOM.

The below table (courtesy: w3schools) shows all 13 XPath axes that are available along with their results.

Axis Name Result
ancestor Selects all ancestors (parent, grandparent, etc.) of the current node
ancestor-or-self Selects all ancestors (parent, grandparent, etc.) of the current node and the current node itself
attribute Selects all attributes of the current node
child Selects all children of the current node
descendant Selects all descendants (children, grandchildren, etc.) of the current node
descendant-or-self Selects all descendants (children, grandchildren, etc.) of the current node and the current node itself
following Selects everything in the document after the closing tag of the current node
following-sibling Selects all siblings after the current node
namespace Selects all namespace nodes of the current node
parent Selects the parent of the current node
preceding Selects all nodes that appear before the current node in the document, except ancestors, attribute nodes and namespace nodes
preceding-sibling Selects all siblings before the current node
self Selects the current node

Let us look at a few important ones,

3a. Parent axis

Selects the parent of the current node.

Example: Let us locate the anchor tag of Facebook logo present on the top left of the Facebook Sign Up page.

Upon inspecting the element,

<a href="https://www.facebook.com/" title="Go to Facebook Home">
   <i class="fb_logo img sp_euCDsy2vhU4 sx_af4dba">
       <u>Facebook</u>
   </i>
</a>

Code:

driver.findElement(By.xpath("//i[@class='fb_logo']/parent::a"));

The parent node ‘a’ with href and title attributes will be located.

3b. Ancestor axis

Selects all ancestors (parent, grandparent, etc.) of the current node.

Example: Let us locate the text ‘Birthday’ on the Facebook Sign Up page.

Upon inspecting the element,

Birthday

 

Code:

driver.findElement(By.xpath("//select[@id='month']/ancestor::div[@class='_5k_5']/preceding-sibling::div"));

‘select’ tag with id, ‘month’ is chosen. Navigating to its ancestor div tag with class, ‘_5k_5’. Then to its preceding sibling node with ‘div’ tag that has ‘Birthday’ as the text.

This particular example is chosen to show that multiple axes can be combined to achieve the desired result.

3c. Child axis

Selects all children of the current node

Example: Let us locate the ‘Log In’ button on the Facebook Sign Up page.

Upon inspecting the element,

<label id="loginbutton" class="uiButton uiButtonConfirm" for="u_0_q">
   
</label>

Code:

driver.findElement(By.xpath("//label[@id='loginbutton']/child::input"));

The child node of the label with id, ‘loginbutton’ – input tag with id, ‘u_0_q’ is located.

3d. Descendant axis

Selects all descendants (children, grandchildren, etc.) of the current node.

Example: Let us locate the ‘first name’ text box on the Facebook Sign Up page.

Upon inspecting the element,

 

First name

<input id=”u_0_1″ class=”inputtext _58mg _5dba _2ph-” data-type=”text” name=”firstname” aria-required=”1″ placeholder=”” aria-label=”First name” type=”text”> </div>

Code:

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

The descendant node of ‘div’ tag with class, ‘uiStickyPlaceholderInput’ – input tag with id ‘u_o_1’ is located.

3e. Following-sibling axis

Selects all siblings after the current node

Example: Let us locate the ‘log In’ link in the footer section of the Facebook Sign Up page.

Upon inspecting the element,

<td class="_51m- hLeft plm">
   <a href="/r.php" title="Sign Up for Facebook">Sign Up</a>
</td>
<td class="_51m- hLeft plm">
   <a href="/login/" title="Log into Facebook">Log In</a>
</td>

Code:

driver.findElement(By.xpath("//td[@class='_51m- hLeft plm']/following-sibling::td/child::a"));

The following sibling of td tag with class, ‘_51m- hLeft plm’ – is another td tag whose child is an anchor tag with title, Log into Facebook.

Combined following-sibling and child axes to locate the ‘Log In’ hyperlink in the footer section.

3f. Preceding-sibling axis

Selects all siblings before the current node

Example: Let us locate the ‘female’ radio button on the Facebook Sign Up page.

Upon inspecting the element,

<span class="_5k_2 _5dba">
   <input id="u_0_g" name="sex" value="1" type="radio">
   <label class="_58mt" for="u_0_g">Female</label>
</span>

Code:

driver.findElement(By.xpath("//label[@class='_58mt']/preceding-sibling::input"));

The preceding sibling of ‘label’ tag is the ‘input’ tag of type, ‘radio’. Thus the required radio button is located.

With that, some of the commonly used XPath axes types are covered.

We have been kind of on a dry spell on the BrainBell front. So why delay? Here we go,

BrainBell – Attention! Pay attention to the state of your brain.

  • Symptoms: nothing getting registered, starting to skim the post or forgetting what you just read.
  • Diagnosis: Your brain is overloaded.
  • Remedy: Take a break! But remember to be back soon 😉

I would personally suggest Pomodoro technique based on my experience. It is highly effective. Just give it a try!

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 www.facebook.com
  3. Locate ‘Forgot account?’ link using text()
  4. Print the link text to the console
  5. Locate ‘New password’ text box using starts-with()
  6. Enter the value, ‘test1234!’
  7. Locate ‘Log In’ button using child axis
  8. Print value attribute to console
  9. Locate Facebook logo with parent axis
  10. Print the value of its ‘title’ attribute to the console
  11. Locate ‘Log In’ link in footer section with following-sibling axis
  12. Print the value of its ‘title’ attribute to the console
  13. Locate ‘female’ radio button using preceding-sibling axis
  14. Click the radio button
  15. Locate the text ‘Birthday’ using ancestor axis
  16. Print its text to the console
  17. Locate the ‘First name’ text box using descendant axis
  18. Enter the value, ‘test first’
  19. 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.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 ElementLocatorTest4b {
    // Declaring variables
    private WebDriver driver;
    private String baseUrl;

    @Before
    public void setUp() throws Exception {
        // Selenium version 3 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://www.facebook.com/";
    }

    @Test
    public void testPageTitle() throws Exception {
        // Open baseUrl in Firefox browser window
        driver.get(baseUrl);

        // Locate 'Forgot Account' link using XPath: text()
        WebElement forgotAccLink = driver.findElement(By.xpath("//*[contains(text(),'Forgot')]"));
        // Prints the link text to the console
        System.out.println("Link text: " + forgotAccLink.getText());
        // Locate 'New password' text box by XPath: using starts-with()
        WebElement passwordNew = driver.findElement(By.xpath("(//input[starts-with(@type,'pass')])[2]"));
        // Clear the default placeholder or any value present
        passwordNew.clear();
        // Enter/type the value to the text box
        passwordNew.sendKeys("test1234!");
        
        // Locate 'Log In' button using XPath: child axis
        WebElement logIn = driver.findElement(By.xpath("//label[@id='loginbutton']/child::input"));
        // Prints 'value' attribute to console
        System.out.println("Child axis: " + logIn.getAttribute("value"));
        // Locate 'Facebook' logo using XPath: parent axis
        WebElement fbLogo = driver.findElement(By.xpath("//i[contains(@class,'fb_logo')]/parent::a"));
        // Prints 'title' attribute's value to console
        System.out.println("Parent axis: " + fbLogo.getAttribute("title"));
        // Locate 'Log In' link in footer section using XPath: following-sibling axis
        WebElement loginFooter = driver.findElement(By.xpath("//td[@class='_51m- hLeft plm']/following-sibling::td/child::a"));
        //Prints 'title' attribute's value to console
        System.out.println("Following-sibling: " + loginFooter.getAttribute("title"));
        // Locate 'female' radio button using XPath: preceding-sibling axis
        WebElement femaleRadioBtn = driver.findElement(By.xpath("//label[@class='_58mt']/preceding-sibling::input"));
        // Click the radio button
        femaleRadioBtn.click();
        // Locate 'Birthday' text using XPath: ancestor axis
        WebElement birthday = driver.findElement(By.xpath("//select[@id='month']/ancestor::div[@class='_5k_5']/preceding-sibling::div"));
        //Prints text to console
        System.out.println("Ancestor axis: " + birthday.getText());
        // Locate 'first name' test box using XPath: descendant axis
        WebElement firstName = driver.findElement(By.xpath("//div[contains(@class,'uiStickyPlaceholderInput')]/descendant::input"));
        firstName.clear();
        firstName.sendKeys("test first");
    }

    @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 shows all the printed results as expected.

XPath JUnit Console

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

XPath Firefox output

Well there it is! You should be all caught up on locating strategies for now. We will be seeing these strategies being applied in all our upcoming examples. So keep watching this space for more.

See you again in another post! Have a great day!

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.