Published on

Understanding Selenium 4

Authors
  • avatar
    Name
    Bharath
    Twitter

Selenium 4

What's new?

We have been waiting for Selenium 4 release whilst using Selenium 3.x for a long time. Now that Selenium 4 is released, let's look at key changes. Official Upgrade Document captures the essentials and I did not face any challenge during the change.

  • W3C WebDriver standard capabilities
  • Consolidation of FindElement methods
  • TimeUnit to Duration in Java

There is a huge enhancement to Selenium Grid in terms of Architecture and stability which we will cover in another blog.

We will check on BiDi API and DevTools.

BiDi API

Selenium has introduced mechanisms for user to perform advanced browser actions. BiDi API (BiDirectional API) let's user to control events of browser DOM. It is still in early stages and not all browsers have implemented per the W3C spec

Register Basic Auth

We can handle basic auth of website easily using HasAuthentication

Predicate<URI> uriPredicate = uri -> uri.getHost().contains("your-domain.com");
((HasAuthentication) driver).register(uriPredicate, UsernameAndPassword.of("admin", "password"));
driver.get("https://your-domain.com/login");

After this, user does not have to append user name and password to the URL for basic auth resulting in password leaks.

Mutation Observation

When there are DOM changes, we can now listen and interact on it. This is particularly helpful in validation and page load conditions.

AtomicReference<DomMutationEvent> seen = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
EventType<Void> domMutation = domMutation(mutation -> {
    String id = mutation.getElement().getAttribute("id");
    if ("spchl".equals(id)) {
        seen.set(mutation);
        latch.countDown();
    }
});

With a DomMutationEvent, we can fetch the element and operate on it. Though there may be multiple dom changes, we can search and filter as required.

Network Interception

With the new Network Interception feature, we can let go of legacy Proxy approaches to inspect network traffic. Earlier, we had to create a proxy server (BrowserMob Proxy) and route Selenium calls via proxy to capture network logs.

With NetworkInterceptor, we can tweak the application response and test various functional flows easily.

Routable routable = Route.matching(req -> req.getUri().contains("/main/home.jsp"))
    .to(() -> req -> new HttpResponse()
        .setStatus(200)
        .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
        .setContent(utf8String("Creamy, delicious cheese!")));
  • A step is considered duplicate if the annotation and step name is present more than once.
  • If alias scanning is included, steps are considered duplicate if step name is present more than once.

DevTools

Selenium 4 provides direct access to the Chrome DevTools Protocol (CDP), but we should avoid using it directly. It is better to use WebDriver Bidi APIs as it will be stable across releases.

Performance Metrics

Using DevTools, we can collect performance metrics during the execution and use it for validation.

WebDriver driver = new ChromeDriver();
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();

devTools.send(Performance.enable(Optional.empty()));
List<Metric> metricList = devTools.send(Performance.getMetrics());

driver.get("https://google.com");
driver.quit();

for (Metric m : metricList) {
    System.out.println(m.getName() + " = " + m.getValue());
}

If a certain metric value is beyond threshold value, the test can be failed.

Network Conditions

We can also emulate Network conditions to better test the application.

Note: This feature involves Chrome's Emulation feature specific to browser version

WebDriver driver = new ChromeDriver();
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();

devTools.send(Network.enable(Optional.of(1000000), Optional.empty(), Optional.empty()));
    devTools.send(
        emulateNetworkConditions(false, 100, 200000, 100000,
            Optional.of(ConnectionType.CELLULAR4G)));
long startTime = System.currentTimeMillis();
driver.navigate().to("https://www.google.com");

long endTime = System.currentTimeMillis();

System.out.println("Load time is " + (endTime - startTime));

GeoLocation

We can tweak the user's geolocation via DevTools GeoLocation feature.

Note: This feature involves Chrome's Emulation feature specific to browser version

WebDriver driver = new ChromeDriver();
driver.navigate().to("https://the-internet.herokuapp.com/");
driver = new Augmenter().augment(driver);
DevTools devTools = ((HasDevTools) driver).getDevTools();
devTools.createSession();
devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043),
    Optional.of(13.4501),
    Optional.of(1)));
driver.get("https://my-location.org/");