As we know that the Selenium 4.x came out along with a lot of new features and functionalities. In this article, I would like to share Selenium 4’s feature known as Relative Locators (formerly known as Friendly Locators). Relative locators help locate WebElements based on the location relative to other DOM elements.
In Selenium 3.x version, when elements were not uniquely identifiable using any of the locator strategies, we used to loop the web elements based on certain conditions and used axis names like following-sibling, preceding-sibling, parent to get the exact web element. For such scenarios, we can now use relative locators to identify a web element in relation to other web elements from DOM. There are five relative locators. All five methods are overloaded to accept the By or WebElement argument. Following are the relative locators:
- toLeftOf()
- toRightOf()
- above()
- below()
- near()
How to use Relative Locators?
In Selenium 4 Alpha, findElement accepts a new method withTagname(). withTagName() is a static method that internally creates a new instance of RelativeBy class and returns the same RelativeLocator.RelativeBy object. Following is the syntax:
driver.findElement(withTagName("li").above(By.id("pid6")));
In Selenium 4 Beta, support with(By) instead of withTagName() allowing users to pick a locator of their choice like By.id, By.cssSelector, By.tagName etc.We have to import the following static package to get this feature,
import static org.openqa.selenium.support.locators.RelativeLocator.with;
Following is the syntax when you are using the latest Selenium 4 version,
driver.findElement(with(By.tagName("li")).above(By.id("pid6")));
How do Relative Locators work?
To find the location of the element, Selenium leverages the JavaScript function getBoundingClientRect(). This function returns properties of an element like left, right, top and bottom. Elements are first sorted by proximity and then DOM insertion order, to make the result more accurate and deterministic. Proximity is determined using distance from center points of each element’s bounding client rect.
We will discuss more on each relative locators below and I am using https://automationbookstore.dev/ to explain the relative locators,
toLeftOf()
Searches DOM and returns the WebElement, which is to the left of the specified element. Java For Testers tile is to the left of the Advanced Selenium in Java tile. We can use it as below:
WebElement javaForTesters = driver.findElement(with(By.tagName("li")).toLeftOf(By.id("pid6"))); javaForTesters.click();
toRightOf()
Searches DOM and returns the WebElement, which is to the right of the specified element. Advanced Selenium in Java tile is to the right of the Java For Testers tile. We can use it as below:
WebElement advSeleInJava = driver.findElement(with(By.tagName("li")).toRightOf(By.id("pid5"))); advSeleInJava.click();
above()
Searches DOM and returns the WebElement, which is above the specified element. Experiences of Test Automation tile is above the Advanced Selenium in Java tile. We can use it as below:
WebElement expOfTestAutomation = driver.findElement(with(By.tagName("li")).above(By.id("pid6"))); expOfTestAutomation.click();
below()
Searches DOM and returns the WebElement, which is below the specified element. BDD in Action tile is below the How Google Tests Software tile. We can use it as below:
WebElement bddInAction = driver.findElement(with(By.tagName("li")).below(By.id("pid4"))); bddInAction.click();
near()
Searches DOM and returns the WebElement, which is at most 50px near to the specified element. Advanced Selenium in Java tile is 50px near to the Test Automation in the Real World tile. We can use it as below:
WebElement advSeleInJava = driver.findElement(with(By.tagName("li")).near(By.id("pid1"))); advSeleInJava.click();
We can set custom pixel values to locate the element along with the overloaded method of near(). By default near() will pick the 50px distance element. The below code will pick the 200px distance element. Java For Testers tile is 200px distance to Experiences of Test Automation tile. We can use it as below:
WebElement javaForTesters = driver.findElement(with(By.tagName("li")).near(By.id("pid2"), 200)); javaForTesters.click();
Chain of Relative Locators to find a WebElement
Sometimes finding an element using only one relative locator is not sufficient. Selenium 4 supports multiple relative locators to find a fixed web element. Locating The Cucumber for Java Book tile using a chain of Relative Locators. We can use it as below:
WebElement cucumberForJava = driver.findElement(with(By.tagName("li")).below(By.id("pid2")).toRightOf(By.id("pid6"))); cucumberForJava.click();
Below is the complete code for your reference,
import static org.openqa.selenium.support.locators.RelativeLocator.with; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import io.github.bonigarcia.wdm.WebDriverManager; public class RelativeLocatorsTests { private WebDriver driver; @BeforeClass public void setUp() { WebDriverManager.chromedriver().setup(); driver = new ChromeDriver(); driver.get("https://automationbookstore.dev/"); driver.manage().window().maximize(); } @Test(priority = 1) public void testToLeftOf() { WebElement javaForTesters = driver.findElement(with(By.tagName("li")).toLeftOf(By.id("pid6"))); javaForTesters.click(); } @Test(priority = 2) public void testToRightOf() { WebElement advSeleInJava = driver.findElement(with(By.tagName("li")).toRightOf(By.id("pid5"))); advSeleInJava.click(); } @Test(priority = 3) public void testAbove() { WebElement expOfTestAutomation = driver.findElement(with(By.tagName("li")).above(By.id("pid6"))); expOfTestAutomation.click(); } @Test(priority = 4) public void testBelow() { WebElement bddInAction = driver.findElement(with(By.tagName("li")).below(By.id("pid4"))); bddInAction.click(); } @Test(priority = 5) public void testNear() { WebElement advSeleInJava = driver.findElement(with(By.tagName("li")).near(By.id("pid1"))); advSeleInJava.click(); } @Test(priority = 6) public void testNearWithPixel() { WebElement javaForTesters = driver.findElement(with(By.tagName("li")).near(By.id("pid2"), 200)); javaForTesters.click(); } @Test(priority = 7) public void testMultiRelativeLocator() { WebElement cucumberForJava = driver .findElement(with(By.tagName("li")).below(By.id("pid2")).toRightOf(By.id("pid6"))); cucumberForJava.click(); } @AfterClass public void tearDown() { driver.quit(); } }
I hope you really enjoyed reading this article about Selenium 4 Relative Locators or Friendly Locators. Try to implement those locators in your live projects and save time.
make it perfect!