A Sneak Peek into Selenium 4.0 Relative Locators with .NET Core 3.1

Enes Kuhn

Selenium 4 is launching “soon”. The most exciting news: Selenium will be W3C standardized. 

Browsers, such as Chrome, Firefox, Safari are all following W3C standardization, so from now on browser drivers will interact with Selenium WebDriver in W3C standard protocol.

Why is this very cool? To date, some Selenium commands worked differently on different browsers. As automation engineers, we had to modify our code to deal with those changes. The new version will bring standardization and stability and will not require you to modify your code to work with different browsers. Cheers to that! 

Prepare the local environment

I will be working with C# Selenium WebDriver so let’s download and install the latest .NET Core.

Download the .NET Core DSK kit from the Microsoft site
Install the dotnet SDK

After installation, open the CMD prompt and type in “dotnet”. You should see the message like shown below:

Awesome, .NET Core is now up on a local machine and we should start using it, right? Well, in order to proceed, we will need an IDE. I like to use Visual Studio so let’s install the latest Community version.

Download and install the VS Community version

Now Select .NET desktop development and click Install.

After installation, run the Visual Studio and select “Create a new project”:

Pick NUnit Test Project (.NET Core) and click the Next button.

Select NUnit Test Project

Name it and click on Create.

I named it “HelloWorld” 

Your screen should look like this:

Select View > Test Explorer to bring up the Test Explorer window.

Click on the Run and verify result.

Initial test passed

In order to install necessary packages, navigate to Project > Manage NuGet Packages, search for “selenium” and Install first three from the list:

  • Selenium.WebDriver
  • Selenium.Support
  • Selenium.WebDriver.ChromeDriver

Update the UnitTest1.cs class like shown below and run the test. The test will open the Chrome browser. You should navigate to the Google home page, validate the page title, and close the session.

using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
namespace HelloWorld
{
    public class Tests
    {
        public IWebDriver driver;
[SetUp]
        public void Setup()
        {
            driver = new ChromeDriver();
            driver.Navigate().GoToUrl("https://www.google.com/");
        }
[Test]
        public void Test1()
        {
            Assert.AreEqual("Google", driver.Title);
        }
[TearDown]
        public void Close()
        {
            driver.Close();
        }
    }
}

Move to Selenium 4 alpha

Now for the exciting part: let’s move to the latest Selenium 4.0.0 alpha 5 version!

Bring up the Package Manager Console (View > Other Windows > Package Manager Console)…

…and type in the commands shown below, one by one:

Install-Package Selenium.Support -Version 4.0.0-alpha05

Install-Package Selenium.WebDriver -Version 4.0.0-alpha05

Find packages updated to the new version:

Go back to UnitTest1.cs class select ChromeDriver() and click f12:

We are now using Selenium 4 alpha. Good!

Selenium 4 Relative Locators

Relative aka Friendly locators are the brand new way of fetching an UI web element by using the location of another (known) element. There are five overloaded methods that can accept By or IWebElement parameters:

  1. Above — finds an element that’s above a known element
  2. Below — finds an element that’s below a known element
  3. LeftOf — finds an element that sits on the left of a known element
  4. RightOf — finds an element that sits on the right of a known element
  5. Near — finds an element that sits in a circle of 50 pixels of a known element. Distance is configurable

All of those methods are called on a static RelativeBy.WithTagName(<tag of the searched element>) method. If you think about it, it definitely makes sense to use some sort of “element identification”. For example, if we use LeftOf() method, we can found loads of elements that sit on the left side such as input fields, lists, buttons, images, etc. With WithTagName() method, we say what kind of element we are searching for, by its tag name.

Search for the element on the right

See the sample above; in this case, we are searching for a button that sits on the right side of a header logo image.

What is even better, we can combine those methods and find an element more efficient way. I like to call it Super Mario way. The same way we use controls to climb stairs in the arcade game.

Run, Super Mario, run!

I updated the HelloWorld project used in the begging. Let’s get to work! 

using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
namespace HelloWorld
{
    public class Tests
    {
        public IWebDriver driver;
[SetUp]
        public void Setup()
        {
            driver = new ChromeDriver();
            //using a demo online shopping app
            driver.Navigate().GoToUrl("https://automationpractice.com/index.php");
            driver.Manage().Window.Maximize();
        }
[Test]
        public void Test1()
        {
            //this is an old way of using WebDriver - just to make sure it works on version 4.0.0 :)
            Assert.AreEqual("My Store", driver.Title);
            IWebElement SearchInput = driver.FindElement(By.Name("search_query"));
            IWebElement SearchButton = driver.FindElement(By.Name("submit_search"));
            SearchInput.SendKeys("demo");
            SearchButton.Click();
//try to click on the search button that's above menu
            SearchInput = driver.FindElement(By.Name("search_query"));
            SearchInput.SendKeys(" demo 2");
            driver.FindElement(RelativeBy.WithTagName("button").Above(By.Id("block_top_menu"))).Click();
            SearchInput = driver.FindElement(By.Name("search_query"));
            SearchInput.SendKeys(" xxx");
//try to click on the search button looking from the logo (it's on the right side)
            driver.FindElement(RelativeBy.WithTagName("button").RightOf(By.Id("header_logo"))).Click();
//click on the Logo image that's on the left of search input field and below the telephone icon
            driver.FindElement(RelativeBy.WithTagName("a")
                .LeftOf(By.Id("search_query_top"))
                .Below(By.ClassName("icon-phone"))).Click();
//add black blose to the chart. the second on the list
            driver.FindElement(RelativeBy.WithTagName("span")
                .RightOf(By.XPath("(//ul[@id='homefeatured']//img)[1]"))
                ).Click();
        }
[TearDown]
        public void Close()
        {
            driver.Close();
        }
    }
}

Above() method

See the code given below; we are trying to click on an element with the tag “button” that sits above the menu.

driver.FindElement(RelativeBy.WithTagName("button").Above(By.Id("block_top_menu"))).Click();

Click on the element on the left, below a known one

In this case, we are trying to click on the company logo that will take us to a home page. It is located right under the telephone icon and has an input field, and has an element with id = ‘search_query_top’ on the right.

Note: besides using By.Id and By.ClassName we can also use IWebElement objects.

driver.FindElement(RelativeBy.WithTagName("a")
 .LeftOf(By.Id("search_query_top"))
 .Below(By.ClassName("icon-phone"))).Click();

Click on an element on the right of a known one

This case shows the real power of relative locators. On the home page, we have the list of “popular best sellers”. In case we want to click on the second item in the list, simply call Relative Locators as shown below:

driver.FindElement(RelativeBy.WithTagName("span")
 .RightOf(By.XPath("(//ul[@id='homefeatured']//img)[1]"))
 ).Click();

If we run the test, it will add the black blouse to the chart:

What if screen resolution changes?

One question that popped up was: What if the screen resolution changes? Will it bring the test down? It is a real-life scenario, right? During the test creation process, we can use high-end monitors with high resolution and if we run it with some sort of task scheduler on a remote server — I guess, it could fail.

I am going to run the same test, in a debugging mode and stop on the line:

//try to click on the search button looking from the logo (it's on the right side)
driver.FindElement(RelativeBy.WithTagName("button").RightOf(By.Id("header_logo"))).Click();

Now, I am going to resize the browser screen until the input field and the button goes under the logo.

Resized browser window

Now, continue the test run!

Test failed

The test failed! That is good.

The bad thing is that we should be very careful when it comes to responsive design.

When will it go live?

Well, back in 2018 Simon Stewart, the founding member of Selenium, had officially confirmed the release date and some of the major updates for Selenium 4 at the Selenium Conference in Bangalore. 

The new (4.0) version of the Selenium was meant to be released by Christmas 2018. Currently, we are on the alpha 5 version so I guess it will be released in a year from now. There are still some bugs that are about to be fixed. Until released, we can play with alpha versions and prepare for an interesting future.

Is this a game-changer?

I do not think so. It is a cool concept of having a possibility to fetch an element in a different way, especially for those with dynamic attributes or even those with just one attribute. In the end, I do not see loads of locators fetched that way in the near future. 

However, Selenium 4 has other cool stuff that can make our life easier and I’ll try to cover those as well.

Till the next time, happy testing!

Leave a Reply

Your email address will not be published.

After you leave a comment, it will be held for moderation, and published afterwards.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.