Top

Selenium 4 Relative Locators

Selenium 4 Relative Locators

Relative Locators

Selenium 4 brings Relative Locators (originally named Friendly Locators). This functionality was added to help you locate elements that are nearby other elements.

The available options are:

  • above(): sought-after element appears above specified element
  • below(): sought-after element appears below specified element
  • toLeftOf(): sought-after element appears to the left of specified element
  • toRightOf(): sought-after element appears to the right of specified element
  • near(): sought-after element is at most 50 pixels away from specified element. There’s also an overloaded method to allow you to specify the distance.

All of these methods are overloaded to accept a By or a WebElement.

 

Use of Relative Locators

Given this book store application, we may want to verify that the book to the left of “Advanced Selenium in Java” is “Java For Testers”. Relative locators allows us to do this.

Here is the DOM snippet for the books

“Advanced Selenium in Java” is represented in the DOM by id pid6, and “Java For Testers” is pid5.

The WebDriver::findElement method can accept the withTagName() method which returns a RelativeLocator.RelativeBy object (a descendant of By).

From here, I can specify relative locators. I know that “Java For Testers” is to the left of “Advanced Selenium in Java” (pid6) and is below “Test Automation in the Real World” (pid1). So, I can specify both of these:

This returns “Java For Testers” (pid5).

We can use the above() and toRightOf() methods to locate “Experiences of Test Automation” (pid2):

 

How does it work?

I could not identify “Java For Testers” with just a toLeftOf(By.id(“pid6”)) call. This alone would return “Test Automation in the Real World” (pid1). That’s because driver.findElement() searches from the root of the DOM, and the first <li> element that’s to the left of “Advanced Selenium in Java” is “Test Automation in the Real World”.

Selenium uses the JavaScript function getBoundingClientRect() to find the relative elements. This function returns properties of an element such as right, left, bottom, and top.

Looking at the properties of these three books, we see that both “Test Automation in the Real World” (pid1) and “Java For Testers” (pid5) both have the same position on the x-axis.

 

Therefore, they are both to the left of  “Java For Testers”, with “Test Automation in the Real World” (pid1) being the first one found.

 

 

Another thing to consider is changes in app viewports. If I ran the passing tests from above on my app in mobile view, then naturally it would fail as the books are no longer to the left/right of other books:

 

 

I also ran into an issue with friendly locators when I attempted to use it on this ToDo application.

 

 

I tried to use the toLeftOf() method to locate the input toggle next to the ‘goodbye world’ item. Visually, this input toggle is clearly to the left of the ‘goodbye world’ label. Here’s this div in the DOM:

Here’s the code I used to locate the input element to the left of the label:

However, I hit an exception:

org.openqa.selenium.NoSuchElementException: Cannot locate an element using [unknown locator]

It seems that even though this <input> is to the left of the <label> visually, it actually is not. I called the getBoundingClientRect() function for both of these elements, and they actually overlap. Notice they both have an x position of 838, so technically the <input> is not to the left of the <label>.

And when I highlight the <label> element, I now see visually that it indeed overlaps the <input> element.

 

Note: This is an alpha version of Selenium WebDriver. I’ve spoken with Selenium project lead, Simon Stewart, and based on feedback, the implementation could change.

 

See Code on Github

Angie Jones
13 Comments
  • Adea Natchiah-Blay

    Thank you for sharing, Angie.

    October 7, 2019 at 2:10 am Reply
  • Pratik Jain

    Thanks for sharing. Really very informative

    October 8, 2019 at 3:28 am Reply
  • Nick Baynham

    This is great! The “gotchas” you pointed out are significant as well

    October 8, 2019 at 5:20 am Reply
  • pennytests

    Thank you Angie

    October 9, 2019 at 1:21 pm Reply
  • Indy

    Hi Angie,

    withTagName(), toLedtOf() annd below() are methods of which class? Could you please confirm?
    driver.findElement(withTagName(“li”)
    .toLeftOf(By.id(“pid6”))
    .below(By.id(“pid1”)));
    Thanks.
    October 17, 2019 at 1:47 am Reply
    • Angie Jones

      RelativeLocator.RelativeBy

      October 18, 2019 at 2:55 pm Reply
  • Stéphane Colson
    Thanks for the article Angie.
    I saw that these locators were already available on Taiko with the same options: https://taiko.gauge.org/#relativeselector
    By the way, what do you think of this new browser automation tool made by the Gauge team of thoughtworks and supposed to be better and replace Selenium?
    October 21, 2019 at 5:32 am Reply
  • Zoé Thivet

    Great article 🙂 I learned about getBoundingClientRect()

    December 25, 2019 at 5:29 pm Reply
  • Charlie Pradeep

    Thanks for providing the information about relative locators. It is a good one Angie. Waiting for the selenium physical conference to meet you 🙂

    August 17, 2021 at 9:28 am Reply
  • Bikash Ranjan

    This is very informative and was a good to know article. Thanks Angie, looking forward to more of it

    October 20, 2021 at 4:35 am Reply
  • lesa koorsse

    Very useful. Thanks Angie

    March 23, 2022 at 5:00 am Reply
  • Shreen

    Hi Angie, how can I use withTagName() method with page factory ?
    eg with something like this –
    @FindBy(xpath = “//label[@class=’text-normal’]”)
    WebElement abc;

    March 29, 2022 at 3:55 pm Reply

Post a Comment