Selenium 4 Looks Pretty
Tags: todayilearned, java, selenium, testing
Published: 2021-10-31 17:22:05

Hello there! 👋

I'm Lucas, a Brazilian QA engineer, and this is Another QA Content nobody asked for (but i made it anyway 😂). My goal with this blog is to talk about things related to the QA world in my own way, giving my opinion and point of view. If you like it, follow me for more posts like this one!

Selenium 4 is finally officially released! And I've been playing with some of the new features. In this post, I'll show you in practice some cool new things you can do with Selenium now.

I won't be focusing on good practices, like using hooks or not setting long explicit waits. The main goal here is to test out some new stuff. I'll show code snippets to summarize, but you can find a link to the Github repo at the end of this post if you want to check out the full code.

![lets get to work](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3j43il2mpmogoxsa9t8e.gif)

---

## 😃 Relative Locators are here

Remember [Taiko's Proximity Selectors](https://dev.to/lucashdoa/interacting-with-a-web-page-without-inspecting-it-using-taiko-2597)? Selenium now has its own similar feature called Relative Locators. It works similarly, you can find web elements that are _above_, _below_, _toRightOf_, _toLeftOF_ or even _near_ a fixed reference element.

And it's simple to use. All you have to do is import the _with_ class. Use _with_ to encapsulate the _By_ object and then, you'll be able to chain a relative selector.

For this example, we'll be using [BlazeDemo](https://blazedemo.com/) (a sample travel agency website). Let's try to perform a simple click at the button "Find Flights" without creating a specific _selector/xpath_ for it.

![button we want to interact](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo4j0zzojk21qaafxwbf.png)

To achieve our goal, let's use the destination city _select_ as reference. Inspecting it, we can see that one option to retrieve it is by its "name" _attribute_.

Let's implement a simple test then. We'll select "Dublin" as the destination city and then assert that the available flights page title is displayed correctly.

```java
/**
* File: AppTest.java
*/

class AppTest {

    @Test
    void relativeSelector(){
        // 1. Configuration steps;
        String expectedTitle = "Flights from Paris to Dublin:";
        System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe");
        WebDriver driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://blazedemo.com/");
        // 2. Retrieve the select "Destination city" and select option 'Dublin';
        WebElement toDestination = driver.findElement(By.cssSelector("[name='toPort']"));
        Select selectElement = new Select(toDestination);
        selectElement.selectByVisibleText("Dublin");
        // 3. Use Relative Locator 'below' to retrieve the "Find Flights" button;
        WebElement findFlightsButton = driver.findElement(with(By.tagName("input")).below(toDestination));
        findFlightsButton.click();
        // 4. Assert that the button was clicked by validating page title.
        String actualTitle = driver.findElement(By.tagName("h3")).getText();
        Assertions.assertEquals(expectedTitle, actualTitle);
        driver.quit();
    }
}
```

I've added a sleep to the code snippet above so that we can see the test in action!

![test 1 running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xol9z1de8qij1gjc7pf7.gif)

This is useful when you don't have access to the source code (to add an _'id'_ or _'test-id'_ in the HTML) and want to avoid writing a complex _xpath_.

---

## 🤯 Support for Chrome DevTools Protocol

The Chrome DevTools Protocol (CDP) is a protocol to communicate with Chromium-based browser internal configurations. Tools can build an API around it to allow a low-level browser configuration (e.g. instrument, inspect, debug and profile). If you're interested in learning more about what you can do with it, visit [CDP Github.io page](https://chromedevtools.github.io/devtools-protocol/).

Selenium 4 brings its own API to communicate with CDP. Now its possible to do a lot of advanced browser configurations for your tests, like changing the client's geolocation for example.

We can implement a sample test for the above situation using the page [gps-coordinates/my-location](https://www.gps-coordinates.net/my-location). It has a feature that show user's location coordinates and address based on the geolocation. We'll implement a test that simply asserts that the location shown is the location we set. See an example below:

![geolocation example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uc18sm47kf0hbdlfjizh.png) 

Since I need some vacation, let's teleport ourselves to Cancún/Mexico using code! I've already googled the latitude and longitude values for us, so let's jump to the part where i show you the code:

```java
/**
* File: AppTest.java
*/

class AppTest {

    @Test
    void setGeolocation throws InterruptedException(){
        // 1. Configuration Steps
        String expectedAddress = "Calle 50 Poniente, 77510 Cancun, ROO, Mexico";
        System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe");
        WebDriver driver = new ChromeDriver();
        driver.manage().window().maximize();
        // 2. Create map with arguments for "Emulate.setGeolocationOverride"
        Map<String, Object> coordinatesMap = new HashMap<String, Object>();
        coordinatesMap.put("latitude", 21.17429);
        coordinatesMap.put("longitude", -86.84656);
        coordinatesMap.put("accuracy", 1);
        // 3. Calls CDP's "Emulation.setGeolocationOverride" to set new geolocation
        ((ChromeDriver)driver).executeCdpCommand("Emulation.setGeolocationOverride", coordinatesMap);
        driver.get("https://www.gps-coordinates.net/my-location");
        Thread.sleep(3000);
        // 4. Asserts that the Address shown is Cancún/Mexico
        String actualAddress = driver.findElement(By.id("addr")).getText();
        Assertions.assertEquals(expectedAddress, actualAddress);
        driver.quit();
    }
}

```

And it's time to see our second test running!

 ![test 2 running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrldlhg82ffutimsbqpd.gif)

We've just teleported! Of course, you'll have to believe that i'm not writing this from Cancún 😂. But you'll have to agree with me, this new feature (calling CDP commands) is really powerful. This geolocation change allow us to test features like "Find the nearest store" for example.

This is it for today. Have you learned some other new stuff on Selenium 4 already? Share with me in the comments!

![goku teleporting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8q9g2cinqfx57hpvcd5i.gif)

---

If you've read this far, I hope the content has added something for you. If it didn't, remember: This is just another ordinary QA content 😬.

🍀 See ya!

### 👩‍💻 Full Code
[lucashdoa/selenium4-demo](https://github.com/lucashdoa/selenium4-demo)

### 🔍 References
[Chrome DevTools Protocol docs](https://chromedevtools.github.io/devtools-protocol/)
[Naveem AutomationLabs YouTube Channel - Mock Geo Location using ChromeDevTools](https://www.youtube.com/watch?v=czp7mxGHL88&t=1051s)
[Angie Jones's blog - Mocking Geolocation](https://angiejones.tech/selenium-4-mocking-geolocation/)
[Selenium docs - Locating elements](https://www.selenium.dev/documentation/webdriver/locating_elements/)

### 😁 Let's chat!
[Github](https://github.com/lucashdoa)
[Linkedin](https://www.linkedin.com/in/lucashdoa/)

{% user lucashdoa %}