I came across this problem a few years ago, and at the time there wasn't an easy way to get hold of the binaries using Maven. I didn't find an elegant solution to this problem, so I did what anybody who is into open source software would do: I wrote a plugin to do it for me.
This plugin allows you to specify a series of driver binaries to automatically download and remove the manual setup steps. It also means that you can enforce the version of driver binaries that are used, which removes lots of intermittent issues caused by people using different versions of the binaries that can behave differently on different machines.
We are now going to enhance our project to use this plugin; the new project structure will look like this:
Let's start by tweaking our POM; we will use the following code to create a new property that we will call overwrite.binaries and a new property to set the version of the plugin:
<properties>
<project.build.sourceEncoding>UTF-
8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-
8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- Dependency versions -->
<selenium.version>3.12.0</selenium.version>
<testng.version>6.14.3</testng.version>
<!-- Plugin versions -->
<driver-binary-downloader-maven-plugin.version>1.0.17
</driver-binary-downloader-maven-plugin.version>
<maven-compiler-plugin.version>3.7.0
</maven-compiler-plugin.version>
<maven-failsafe-plugin.version>2.21.0
</maven-failsafe-plugin.version>
<!-- Configurable variables -->
<threads>1</threads>
<browser>firefox</browser>
<overwrite.binaries>false</overwrite.binaries>
</properties>
We then need to add the driver-binary-downloader plugin by using the following code:
<plugin>
<groupId>com.lazerycode.selenium</groupId>
<artifactId>driver-binary-downloader-maven-plugin</artifactId>
<version>${driver-binary-downloader-maven-plugin.version}
</version>
<configuration>
<rootStandaloneServerDirectory>${project.basedir}
/src/test/resources/selenium_standalone_binaries
</rootStandaloneServerDirectory>
<downloadedZipFileDirectory>${project.basedir}
/src/test/resources/selenium_standalone_zips
</downloadedZipFileDirectory>
<customRepositoryMap>${project.basedir}
/src/test/resources/RepositoryMap.xml
</customRepositoryMap>
<overwriteFilesThatExist>${overwrite.binaries}
</overwriteFilesThatExist>
</configuration>
<executions>
<execution>
<goals>
<goal>selenium</goal>
</goals>
</execution>
</executions>
</plugin>
Finally, we need to add some new system properties to our maven-failsafe-plugin configuration by using the following code:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<configuration>
<parallel>methods</parallel>
<threadCount>${threads}</threadCount>
<systemPropertyVariables>
<browser>${browser}</browser>
<!--Set properties passed in by the driver binary
downloader-->
<webdriver.chrome.driver>${webdriver.chrome.driver}
</webdriver.chrome.driver>
<webdriver.ie.driver>${webdriver.ie.driver}
</webdriver.ie.driver>
<webdriver.opera.driver>${webdriver.opera.driver}
</webdriver.opera.driver>
<webdriver.gecko.driver>${webdriver.gecko.driver}
</webdriver.gecko.driver>
<webdriver.edge.driver>${webdriver.edge.driver}
</webdriver.edge.driver>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
The plugin runs in the TEST_COMPILE phase by default. The order it is placed in the POM should not matter, as there shouldn't be any tests actually running in this phase. The new overwite.binaries property that we have added allows us to set the overwriteFilesThatExist configuration setting of the driver-binary-downloader-maven-plugin. By default, it will not overwrite files that already exist. This gives us an option to force the plugin to overwrite existing files if we want to download a new binary version or just refresh our existing binaries.
We have two more configuration settings that are just specifying file paths. The downloadedZipFileDirectory setting is used to specify the file path that will be used to download the binary ZIP files. The rootStandaloneServerDirectory setting is the file path where we extract the driver binaries.
Next, we will use customRepositoryMap to point at a customRepositoryMap.xml. This customRepositoryMap.xml is where download locations for all the binaries we want to download are stored.
Finally, we have added some system properties variables to maven-failsafe-plugin to expose the locations of the binaries when they have been downloaded. driver-binary-downloader-maven-plugin will set a Maven variable that will point to the location of the downloaded binaries. Even though it looks like the variables we are using to set our system properties don't exist, it will be fine.
This is where we have been slightly clever; we have set system properties that Selenium will use automatically to find the location of the driver binaries. This means that we don't need to add any additional code to make things work.
We now need to create RepositoryMap.xml to define the download locations for our binaries; we will probably also need to create the src/test/resources folder since we haven't used it before. The following code has a basic RepositoryMap.xml using the default download locations for the binaries:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
<windows>
<driver id="internetexplorer">
<version id="3.9.0">
<bitrate sixtyfourbit="true">
<filelocation>http://selenium-
release.storage.googleapis.com/3.9/
IEDriverServer_x64_3.9.0.zip</filelocation>
<hash>c9f885b6a339f3f0039d670a23f998868f539e65
</hash>
<hashtype>sha1</hashtype>
</bitrate>
<bitrate thirtytwobit="true">
<filelocation>http://selenium-
release.storage.googleapis.com/3.9/
IEDriverServer_Win32_3.9.0.zip</filelocation>
<hash>dab42d7419599dd311d4fba424398fba2f20e883
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="edge">
<version id="5.16299">
<bitrate sixtyfourbit="true" thirtytwobit="true">
<filelocation>https://download.microsoft.com/
download/D/4/1/D417998A-58EE-4EFE-A7CC-
39EF9E020768/MicrosoftWebDriver.exe
</filelocation>
<hash>60c4b6d859ee868ba5aa29c1e5bfa892358e3f96
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="googlechrome">
<version id="2.37">
<bitrate thirtytwobit="true" sixtyfourbit="true">
<filelocation>
https://chromedriver.storage.googleapis.com/
2.37/chromedriver_win32.zip</filelocation>
<hash>fe708aac4eeb919a4ce26cf4aa52a2dacc666a2f
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="operachromium">
<version id="2.35">
<bitrate sixtyfourbit="true">
<filelocation>https://github.com/operasoftware
/operachromiumdriver/releases/download/v.2.35
/operadriver_win64.zip</filelocation>
<hash>180a876f40dbc9734ebb81a3b6f2be35cadaf0cc
</hash>
<hashtype>sha1</hashtype>
</bitrate>
<bitrate thirtytwobit="true">
<filelocation>https://github.com/operasoftware/
operachromiumdriver/releases/download/v.2.35/
operadriver_win32.zip</filelocation>
<hash>55d43156716d7d1021733c2825e99896fea73815
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="marionette">
<version id="0.20.0">
<bitrate sixtyfourbit="true">
<filelocation>
https://github.com/mozilla/geckodriver/
releases/download/v0.20.0/
geckodriver-v0.20.0-win64.zip</filelocation>
<hash>e96a24cf4147d6571449bdd279be65a5e773ba4c
</hash>
<hashtype>sha1</hashtype>
</bitrate>
<bitrate thirtytwobit="true">
<filelocation>
https://github.com/mozilla/geckodriver
/releases/download/v0.20.0/
geckodriver-v0.20.0-win32.zip</filelocation>
<hash>9aa5bbdc68acc93c244a7ba5111a3858d8cbc41d
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
</windows>
<linux>
<driver id="googlechrome">
<version id="2.37">
<bitrate sixtyfourbit="true">
<filelocation>https://chromedriver.storage.
googleapis.com/2.37/
chromedriver_linux64.zip</filelocation>
<hash>b8515d09bb2d533ca3b85174c85cac1e062d04c6
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="operachromium">
<version id="2.35">
<bitrate sixtyfourbit="true">
<filelocation>
https://github.com/operasoftware/
operachromiumdriver/releases/download/
v.2.35/operadriver_linux64.zip</filelocation>
<hash>
f75845a7e37e4c1a58c61677a2d6766477a4ced2
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="marionette">
<version id="0.20.0">
<bitrate sixtyfourbit="true">
<filelocation>
https://github.com/mozilla/geckodriver/
releases/download/v0.20.0/geckodriver-v0.20.0-
linux64.tar.gz</filelocation>
<hash>
e23a6ae18bec896afe00e445e0152fba9ed92007
</hash>
<hashtype>sha1</hashtype>
</bitrate>
<bitrate thirtytwobit="true">
<filelocation>
https://github.com/mozilla/geckodriver/
releases/download/v0.20.0/geckodriver-v0.20.0-
linux32.tar.gz</filelocation>
<hash>
c80eb7a07ae3fe6eef2f52855007939c4b655a4c
</hash>
<hashtype>sha1</hashtype>
</bitrate>
<bitrate arm="true">
<filelocation>
https://github.com/mozilla/geckodriver/
releases/download/v0.20.0/geckodriver-v0.20.0-
arm7hf.tar.gz</filelocation>
<hash>
2776db97a330c38bb426034d414a01c7bf19cc94
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
</linux>
<osx>
<driver id="googlechrome">
<version id="2.37">
<bitrate sixtyfourbit="true">
<filelocation>
https://chromedriver.storage.googleapis.com/
2.37/chromedriver_mac64.zip</filelocation>
<hash>
714e7abb1a7aeea9a8997b64a356a44fb48f5ef4
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="operachromium">
<version id="2.35">
<bitrate sixtyfourbit="true">
<filelocation>
https://github.com/operasoftware/
operachromiumdriver/releases/download/v.2.35/
operadriver_mac64.zip</filelocation>
<hash>
66a88c856b55f6c89ff5d125760d920e0d4db6ff
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
<driver id="marionette">
<version id="0.20.0">
<bitrate thirtytwobit="true" sixtyfourbit="true">
<filelocation>
https://github.com/mozilla/geckodriver/
releases/download/v0.20.0/geckodriver-v0.20.0-
macos.tar.gz</filelocation>
<hash>
87a63f8adc2767332f2eadb24dedff982ac4f902
</hash>
<hashtype>sha1</hashtype>
</bitrate>
</version>
</driver>
</osx>
</root>
If you are on a corporate network that does not allow you to access the outside world, you can of course download the binaries and put them on a local file server. You can then update your RepositoryMap.xml to point at this local file server instead of the internet. This gives you a great deal of flexibility.
Right, let's run our project again to check that everything works; first of all use this code:
mvn clean verify -Dthreads=2
You will notice that everything worked as normal, despite the fact that we are no longer setting the webdriver.gecko.driver system property on the command line. Next, let's see whether we can now select chrome and have everything still just work by using the following code:
mvn clean verify -Dthreads=2 -Dbrowser=chrome
This time, you should see two Chrome browsers open up instead of Firefox ones. You may have noticed that the first time you ran this it downloaded a series of binaries, which may have slowed down the first run. This time around though, it had already downloaded them, so it just checked they were there and the test run completed a lot quicker. We no longer have to worry about setting any system properties because this is automatically being done by the plugin modifications we made in our POM file.
We can now give anybody access to our code, and when they check it and run it, things should just work.