In this 3rd Selenium 4 article, we will explore Relative Locators (formerly called Friendly Locators). The purpose of Relative Locators is to find a specific element regarding the position of another element. There’s a total of 5 overloaded methods with an option of 2 parameters. We can use the By locator parameter or WebElement element parameter.The following is a list of all 5 Relative Locator methods in alphabetical order:
- above() – finds an element or elements located above a fixed element.
- below() – finds an element or elements located below a fixed element.
- near() – finds an element or elements located near a fixed element.
- toLeftOf() – finds an element or elements located to the left of a fixed element.
- toRightOf() – finds an element or elements located to the right of a fixed element.
Relative Locators join the existing group of Selenium’s 8 locators: id, className, cssSelector, linkText, name, partialLinkText, tagName, and xpath. As an automation engineer, one of the first steps is learning how to locate an element 🧐
Therefore, by the end of this article, you will read about different import statements for Relative Locators, how to use 1 Relative Locator, how to use multiple Relative Locators, and how to find more than 1 WebElement using a Relative Locator. Code will be located on GitHub https://github.com/RexJonesII/TestProject-TestNG.
Tutorial Chapters
- New Selenium 4 Features (Chapter 1)
- Selenium WebDriver 4 (Chapter 2)
- You’re here → Relative Locators (Chapter 3)
Import Relative Locators
There are 2 import statements for Relative Locators. One import statement is static and the other import statement is not static. The difference dictates how we write our Relative Locator syntax.
For example, if we include static in our import statement then we can bypass writing RelativeLocator and a dot operator (.). On the flip side, we are required to include RelativeLocator and a dot operator (.) if we omit static. Here’s an example of not including static in the import statement and how our code must be written to use a Relative Locator:
import org.openqa.selenium.support.locators.RelativeLocator; public class DifferentImportStatements { WebDriver driver; @Test public void useRelativeLocatorInSyntax () { driver.findElement(RelativeLocator.withTagName("")); } }
Notice the import statement is import org.openqa.selenium.support.locators.RelativeLocator;. This package was imported by default in Eclipse IDE as a quick fix.
The package allows us to write driver.findElement(RelativeLocator.withTagName(“”)). It’s valid and will work without a problem. Nevertheless, we can also begin our statement using withTagName.
An error stating “The method withTagName(String) is undefined for the type” shows up if we remove RelativeLocator. before withTagName(“”) and not update our import statement.
In order to resolve the error, we include static in the import statement before the package. At the end, add a dot operator (.) plus an asterisk (*) or withTagName. Anyone of the following import statements permit us to start our syntax using withTagName without an error.
import static org.openqa.selenium.support.locators.RelativeLocator.*; import static org.openqa.selenium.support.locators.RelativeLocator.withTagName; public class DifferentImportStatements { WebDriver driver; @Test public void skipRelativeLocatorInSyntax () { driver.findElement(withTagName("")); } }
❗ Note: Other IDE’s by default, may import the package with static in their import statement. From this point, we will only use static with RelativeLocator.*.
Use One Relative Locator To Find A WebElement
Relative Locators are beneficial for unstable applications, elements with dynamic values, and elements without unique attribute values. For instance, TestProject has a way to search for articles on their blog site. We can search for a Test Framework such as TestNG, a blogger’s name, etc. Here’s a screenshot of the Search Articles WebElement and DOM for the search icon.
In the span tag, the search icon has an attribute value of glass for class. After searching for the class name, the DOM shows a total of 3 elements with this element displaying 2 of 3. It’s not unique and can lead to a flaky Test Script. The following code snippet uses a Relative Locator to find the search icon located to the right of Search Articles:
@Test public void searchForBlogger () { WebElement searchArticles = driver.findElement(By.xpath("//section[@id='search-2']/form/label/input")); searchArticles.sendKeys("Rex Jones II"); driver.findElement(withTagName("span") .toRightOf(searchArticles)) .click(); }
We see the withTagName() method as a parameter of findElement(). The method returns RelativeBy which is a class that extends the By class. Here’s a breakdown of the entire Test Script to click the search icon:
- The searchArticles WebElement is found using xpath.
- Rex Jones II is sent to the searchArticles text box.
- Next, the Test Script finds an element with a span tag name.
- The element with a span tag is located to the right of searchArticles.
- On the last line, the Search icon is clicked.
The following are screenshots revealing how to successfully search for an article on TestProject’s blog site.
Use Multiple Relative Locators To Find A WebElement
Some use cases may arise where 1 Relative Locator will not find a specific WebElement. We could face a scenario with multiple WebElements that are above, below, near, to the left of or right of a fixed WebElement. A perfect illustration resembles a grid table like TestProject’s Addons page:
An Addon is a collection of code actions that we reuse to simplify our project (check out their official Docs to read more information about Addons). In the following example, our goal is to retrieve the Remember me verbiage that’s located above the Sign In button and to the right of a checkbox. Here’s a screenshot of TestProject’s Sign In page, code snippet for getting Remember me, and Console printing Remember me.
@Test public void getRememberMeText () { WebElement signInButton = driver.findElement(By.id("tp-sign-in")); WebElement rememberMeCheckbox = driver.findElement(By.id("rememberMe")); WebElement rememberMe = driver.findElement(withTagName("span") .above(signInButton) .toRightOf(rememberMeCheckbox)); System.out.println("Text = " + rememberMe.getText()); }
We used the WebElement element parameter for our Relative Locators. First, we found the signInButton then located the rememberMecheckbox. Both WebElements were used withTagName to get the text of Remember me.
- findElement.(withTagName(“span”)
- above(signInButton)
- toRightOf(rememberMeCheckbox))
It would not have been sufficient if we only used above(signInButton). The functionality of driver.findElement() locates an element starting from the DOM’s root. As a result, the Test Script would have found the first <span> tag which is the checkbox and not Remember me.
Find A List of WebElements Using Relative Locators
In the previous 2 sections, we used driver.findElement() to locate 1 WebElement. Selenium also provides a way to find multiple WebElements via driver.findElements() which returns List <WebElement>. Therefore, we can use Relative Locators to return all WebElements matching a specified mechanism. The Addons page supplies a way to filter by platform. We can filter by Web, Android, and iOS.
Our Test Script will get the names of each platform to the right of Search For Addons. This time, the Relative Locator uses a By locator parameter. Here’s the code snippet using driver.findElements() for a list of WebElements and Console screenshot:
@Test public void getAddOnPlatforms () { List <WebElement> allPlatforms = driver.findElements(withTagName("img") .toRightOf(By.id("q"))); for (WebElement platform : allPlatforms) { System.out.println(platform.getAttribute("alt")); } }
An enhanced for loop was included to cycle through each platform and print their names. We found 3 tags with an image to the right of Search For Addons. The Console prints Platform Web, Platform Android, and Platform iOS with PASSED as the result.
That concludes the Selenium 4 series which has new features for the entire Selenium Suite: Selenium IDE, Selenium WebDriver, and Selenium Grid 😊
What has been your experience with Selenium 4? Share in the comments below!