Book Image

Mastering Selenium WebDriver 3.0 - Second Edition

Book Image

Mastering Selenium WebDriver 3.0 - Second Edition

Overview of this book

The second edition of Mastering Selenium 3.0 WebDriver starts by showing you how to build your own Selenium framework with Maven. You'll then look at how you can solve the difficult problems that you will undoubtedly come across as you start using Selenium in an enterprise environment and learn how to produce the right feedback when failing. Next, you’ll explore common exceptions that you will come across as you use Selenium, the root causes of these exceptions, and how to fix them. Along the way, you’ll use Advanced User Interactions APIs, running any JavaScript you need through Selenium; and learn how to quickly spin up a Selenium Grid using Docker containers. In the concluding chapters, you‘ll work through a series of scenarios that demonstrate how to extend Selenium to work with external libraries and applications so that you can be sure you are using the right tool for the job.
Table of Contents (15 chapters)

Downloading WebDriver binaries automatically

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>
This is a big file; it may be easier to copy and paste the latest revision in the driver-binary-downloader README.md on GitHub: https://github.com/Ardesco/selenium-standalone-server-plugin/blob/master/README.md.

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.