Blogs

Automating Management of Selenium Webdriver Binaries with Java

Category
Software development
Automating Management of Selenium Webdriver Binaries with Java

Manual setup of testing environment for Selenium can be tiresome. Installed browser version and Selenium webdriver binary version need to be in sync. When you need to do it on multiple machines, each with different OS, it takes a lot of time and effort.

There is a nice javascript tool webdriver-manager that is useful if you can install node.js on your testing environment, but it’s useless if you only have Java available.

At first I wrote custom Gradle build scripts. It took a lot of effort to maintain them and they were useless on projects that used Maven. Then I found one awesome Java project that solves the problem. It’s Boni Garcia’s Webdriver manager.

The project is actively maintained and has excellent documentation. WebdriverManager can be used as a standalone server that fetches Selenium webdriver binaries, or you can include it as a dependency in your project and use it directly in your test code.

Selenium web driver with Java: Selenium test example

We will create a simple Junit test with Selenium. We will use Gradle as our build tool.

Prerequisites

  • Java JDK 1.8.X
  • Gradle 5.X
  • Firefox browser

Test overview

  • fetch the right Firefox driver binary if needed
  • create instance of Firefox webdriver
  • visit Google search page with Firefox browser and do a search for AG04
  • Verify that first result is “Agency 04”
  • close browser after test

Project setup

We need to create a new directory for our project. We will create a simple Gradle project in it that uses Groovy as build script DSL in it by invoking gradle init command.

mkdir webdriver-manager
cd webdriver-manager
gradle init

Than we will add following code to gradle.build script

plugins {
    id 'java'
}
repositories {
    jcenter()
}
ext {
    junitVersion = '4.12'
    seleniumVersion = '3.141.59'
    logbackVersion = '1.2.3'
    webDriverManagerVersion = '3.3.0'
}
dependencies {
    testImplementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: seleniumVersion
    testImplementation group: 'io.github.bonigarcia', name: 'webdrivermanager', version: webDriverManagerVersion
    testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion
    testImplementation group: 'junit', name: 'junit', version: junitVersion
}

First test implementation

We’ll create a directory for com.ag04 test package.

mkdir -p src/test/java/com/ag04

There we will create out first test class.

touch src/test/java/com/ag04/GoogleTestExample.java

We’ll add the following Java code to GoogleTestExample class.

package com.ag04;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class GoogleTestExample {
    private WebDriver driver;
    @BeforeClass
    public static void setupWebdriverBinary() {
        WebDriverManager.firefoxdriver().setup();
    }
    @Before
    public void setup() {
        driver = new FirefoxDriver();
    }
    @After
    public void teardown() {
        if (driver != null) {
            driver.quit();
        }
    }
    @Test
    public void searchGoogleForAgency04() {
        driver.get("https://www.google.com");
        WebElement searchBar = driver.findElement(By.name("q"));
        searchBar.clear();
        searchBar.sendKeys("AG04");
        searchBar.submit();
        new WebDriverWait(driver, 5).until(ExpectedConditions.urlContains("/search"));
        assertThat(driver.getTitle(), containsString("AG04"));
    }
}

We are using standard Junit annotations. WebdriverManager does its magic in a method annotated with @BeforeClass.

Annotated with @Before and @After are setup and teardown of webdriver instance.

We start test by typing:

./gradlew clean test

We can see what the WebdriverManager does in the Gradle log output if we add the info parameter when we invoke the gradle test task.

./gradlew clean test --info
WebdriverManager does its magic!

Page objects pattern

A common pattern used in browser automation is Page objects pattern.

We will create a new directory for com.ag04.pages package.

mkdir src/test/java/com/ag04/pages

Next, we need two new classes for the search page and the results page.

touch src/test/java/com/ag04/pages/HomePage.java
touch src/test/java/com/ag04/pages/ResultsPage.java

We will add the following code to these classes.

package com.ag04.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.LoadableComponent;
import java.net.MalformedURLException;
import java.net.URL;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class HomePage extends LoadableComponent<HomePage> {
    private final WebDriver driver;
    private final URL url;
    @FindBy(name = "q")
    private WebElement searchBar;
    public HomePage(WebDriver driver) throws MalformedURLException {
        this.driver = driver;
        this.url = new URL("https://www.google.com");
    }
    public ResultsPage searchFor(String searchString) {
        searchBar.clear();
        searchBar.sendKeys(searchString);
        searchBar.submit();
        ResultsPage resultsPage = PageFactory.initElements(driver, ResultsPage.class);
        return resultsPage.get();
    }
    @Override
    protected void load() {
        driver.get(url.toString());
    }
    @Override
    protected void isLoaded() throws Error {
        assertThat(driver.getTitle(), containsString("Google"));
    }
}
package com.ag04.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.LoadableComponent;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public class ResultsPage extends LoadableComponent<ResultsPage> {
    private final WebDriver driver;
    private final URL url;
    @FindBy(css = "div[data-hveid] div.r")
    private List<WebElement> results;
    public ResultsPage(WebDriver driver) throws MalformedURLException {
        this.driver = driver;
        url = new URL("https://www.google.com/search");
    }
    public List<WebElement> getResults() {
        return results;
    }
    @Override
    protected void load() {
        // This page cannot be loaded manually, browser is redirected from search page.
    }
    @Override
    protected void isLoaded() throws Error {
        new WebDriverWait(driver, 5).until(ExpectedConditions.urlContains(url.getPath()));
    }
}

LoadableComponent

We extended LoadableComponent with our page objects so we get a standardized way of loading pages. See Selenium documentation for more info about LoadableComponent.

Contact

Looking for Java experts?

Looking for Java experts?

PageFactory

Selenium provides a nice @FindBy annotation for WebElements which provides improved readability of page objects. For annotations to work we need to use PageFactory to initialize WebElements. Check PageFactory in Selenium docs for detailed examples.

We will make changes to GoogleTestExample class to use page objects.

package com.ag04;
import com.ag04.pages.HomePage;
import com.ag04.pages.ResultsPage;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.PageFactory;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class GoogleTestExample {
    private WebDriver driver;
    private HomePage homePage;
    private ResultsPage resultsPage;
    @BeforeClass
    public static void setupWebdriverBinary() {
        WebDriverManager.firefoxdriver().setup();
    }
    @Before
    public void setup() {
        driver = new FirefoxDriver();
    }
    @After
    public void teardown() {
        if (driver != null) {
            driver.quit();
        }
    }
    @Test
    public void searchGoogleForAgency04() {
        homePage = PageFactory.initElements(driver, HomePage.class);
        resultsPage = homePage.get().searchFor("AG04");
        assertThat(driver.getTitle(), containsString("AG04"));
        assertThat(resultsPage.getResults().get(0).getText(), containsString("AG04 - Experts in enterprise software development"));
    }
}

Reports

When we invoke the Gradle test task with:

./gradlew clean test

There is a default Gradle HTML report generated in directory

build/reports/tests/test/

And voila, that’s how you automate the management of selenium web driver binaries with Java.

Source

The source for this example project can be found on GitHub.

Next

Blog

How We Are Using NgRx?

NgRx Notch Usage

Company

Our people really love it here

Evolution of expertise

The agency was founded in 2014 by seasoned industry veterans with experience from large enterprises. A group of Java engineers then evolved into a full-service company that builds complex web and mobile applications. 

Flexibility is our strong suit — both large enterprises and startups use our services. We are now widely recognized as the leading regional experts in the Java platform and Agile approach.

We make big things happen and we are proud of that.

Personal development

If you join our ranks you’ll be able hone your coding skills on relevant projects for international clients.

Our diverse client portfolio enables our engineers to work on complex long term projects like core technologies for Delivery Hero, Blockchain and NFTs for Fantasy Football or cockpit interface for giants like Strabag. 

Constant education and knowledge sharing are part of our company culture. Highly experienced mentors will help you out and provide real-time feedback and support.

Contact

We’d love to hear from you