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)

Going headless

Going headless seems to be all the rage these days, so let's have a look at how we can add support a headless browser to our burgeoning framework.

It's actually a relatively simple change; first, we are going to use this code to modify our POM to add a <headless> property (we are going to set it to true because you are always going to want to start of running things in headless mode, right?):

<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>
<headless>true</headless>
</properties>

Then, we need to pass that in through maven-failsafe-plugin:

<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>
<headless>${headless}</headless>
<!--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>

Finally, we will use this code to update our DriverType enum to read in the new headless system property and apply it to the CHROME and FIREFOX entries:

package com.masteringselenium.config;

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.ie.InternetExplorerOptions;
import org.openqa.selenium.opera.OperaDriver;
import org.openqa.selenium.opera.OperaOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.safari.SafariOptions;

import java.util.HashMap;

public enum DriverType implements DriverSetup {


FIREFOX {
public RemoteWebDriver getWebDriverObject
(DesiredCapabilities capabilities) {
FirefoxOptions options = new FirefoxOptions();
options.merge(capabilities);
options.setHeadless(HEADLESS);

return new FirefoxDriver(options);
}
},
CHROME {
public RemoteWebDriver getWebDriverObject
(DesiredCapabilities capabilities) {
HashMap<String, Object> chromePreferences =
new HashMap<>();
chromePreferences.put("profile.password_manager_enabled"
, false);

ChromeOptions options = new ChromeOptions();
options.merge(capabilities);
options.setHeadless(HEADLESS);
options.addArguments("--no-default-browser-check");
options.setExperimentalOption("prefs",
chromePreferences);

return new ChromeDriver(options);
}
},
IE {
public RemoteWebDriver getWebDriverObject
(DesiredCapabilities capabilities) {
InternetExplorerOptions options = new
InternetExplorerOptions();
options.merge(capabilities);
options.setCapability(CapabilityType.ForSeleniumServer.
ENSURING_CLEAN_SESSION, true);
options.setCapability(InternetExplorerDriver.
ENABLE_PERSISTENT_HOVERING, true);
options.setCapability(InternetExplorerDriver.
REQUIRE_WINDOW_FOCUS, true);

return new InternetExplorerDriver(options);
}
},
EDGE {
public RemoteWebDriver
getWebDriverObject(DesiredCapabilities
capabilities) {
EdgeOptions options = new EdgeOptions();
options.merge(capabilities);

return new EdgeDriver(options);
}
},
SAFARI {
public RemoteWebDriver getWebDriverObject
(DesiredCapabilities capabilities) {
SafariOptions options = new SafariOptions();
options.merge(capabilities);

return new SafariDriver(options);
}
},
OPERA {
public RemoteWebDriver getWebDriverObject
(DesiredCapabilities capabilities) {
OperaOptions options = new OperaOptions();
options.merge(capabilities);

return new OperaDriver(options);
}
};

public final static boolean HEADLESS =
Boolean.getBoolean("headless");
}

We can now run our project again exactly the same way as before:

mvn clean verify -Dthreads=2

You will see the test start up again, but this time you won't see a browser window pop up. Everything should work exactly as before and the tests should pass as expected. If you want to see the browser window pop up again, you can just set headless to false:

mvn clean verify -Dthreads=2 -Dheadless=false

What happened to GhostDriver?

You may have noticed that I haven't mentioned GhostDriver or PhantomJS at all in the headless section. That's because PhatomJS is no longer under active development and GhostDriver no longer has a core maintainer. PhantomJS is still available and it's possible to get GhostDriver up and running. However, you are then testing with these issues:

  • An out-of-date rendering engine (an old version of QTWebkit)
  • A JavaScript engine that is not used in any of the major browsers
  • A tool that is not completely thread safe

With the release of headless modes from ChromeDriver and FirefoxDriver, it just doesn't make sense to keep using PhantomJS. It was great in its heyday, but it just not a useful tool to use with Selenium any more.