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,
- Using Text()
- Using starts-with()
- 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,
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,
<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
- Open Firefox browser.
- Navigate to www.facebook.com
- Locate ‘Forgot account?’ link using text()
- Print the link text to the console
- Locate ‘New password’ text box using starts-with()
- Enter the value, ‘test1234!’
- Locate ‘Log In’ button using child axis
- Print value attribute to console
- Locate Facebook logo with parent axis
- Print the value of its ‘title’ attribute to the console
- Locate ‘Log In’ link in footer section with following-sibling axis
- Print the value of its ‘title’ attribute to the console
- Locate ‘female’ radio button using preceding-sibling axis
- Click the radio button
- Locate the text ‘Birthday’ using ancestor axis
- Print its text to the console
- Locate the ‘First name’ text box using descendant axis
- Enter the value, ‘test first’
- 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.
Below image shows the Firefox output obtained upon successful execution of the test script.
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!