Simplifying WebDriver instantiation
⚠ Development of this library is discontinued ⚠
I'm not working with Selenium anymore, so there's no reason for me to keep updating this
This project aims to simplify the process of constructing a WebDriver
instance in Selenium test cases
by taking care of downloading the required binaries at runtime and unifying the way instances are created.
Overall, there are 3 things webdriver-manager
can do for you:
- Google Chrome (chromedriver)
- Mozilla Firefox (geckodriver)
- Opera (operachromiumdriver)
- Microsoft Internet Explorer (IEDriverServer)
- Microsoft Edge (Microsoft WebDriver)
Of course, browsers that do not require a separate driver binary are also supported:
- HtmlUnit
- Safari
Java 8 or higher is required!
<dependency>
<groupId>com.github.nscuro</groupId>
<artifactId>webdriver-manager</artifactId>
<version>${webdriver-manager.version}</version>
</dependency>
For the latest available version see here.
Note that webdriver-manager
requires you to provide the actual Selenium dependencies yourself:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!-- Only required if you plan on using HTMLUnit -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>htmlunit-driver</artifactId>
<version>${htmlunit-driver.version}</version>
</dependency>
Optimally, this allows you to update to a newer Selenium version without having to wait for
webdriver-manager
to do it. As long as Selenium does not introduce breaking changes, this
should work just fine.
Binaries can be downloaded using the BinaryManager
class:
BinaryManager binaryManager = BinaryManager.createDefault();
File chromeDriverBinary = binaryManager.getLatestWebDriverBinary(Browser.CHROME, Os.WINDOWS, Architecture.X64);
For more ways to download binaries please refer to the BinaryManager documentation.
Using BinaryManager.createDefault()
will provide you with a BinaryManager
instance that
should be able to fulfill all basic needs.
You can however use a builder for customization purposes:
BinaryManager binaryManager = BinaryManager
.builder()
// A HttpClient MUST be provided. If you do not care about this step, use .defaultHttpClient()
.httpClient(myHttpClient)
// You can also use .defaultBinaryDestinationDir(), which will cause all downloaded
// binaries to be placed in $HOME/.webdriver-manager
.binaryDestinationDir(Paths.get("/home/darthvader/webdriver"))
.addBinaryProvider(myCustomBinaryProvider)
// When a BinaryProvider has a constructor that only takes a HttpClient,
// you can pass it as method reference. The builder will then inject the HttpClient
// that was chosen in the first builder step.
.addBinaryProvider(ChromeDriverBinaryProvider::new) // For Google Chrome
.addBinaryProvider(GeckoDriverBinaryProvider::new) // For Mozilla Firefox
.build();
Some binaries are being downloaded from GitHub (currently Firefox's geckodriver
& Opera's operachromiumdriver
).
GitHub limits the amount of requests being performed against their API, in which case you must
provide API credentials in order to authorize yourself.
Currently, you need to set the WDM_GH_USER
and WDM_GH_TOKEN
ENVIRONMENT variables for
this to work - where WDM_GH_USER
is your GitHub username and WDM_GH_TOKEN
is a personal access token
whith the permission to access public repositories:
export WDM_GH_USER=<your-github-username>
export WDM_GH_TOKEN=<your-token>
With vanilla Selenium, in order to get a WebDriver
instance up and running you'd have to do the following:
// Manually download the required binary, placing it somewhere on your filesystem...
System.setProperty("webdriver.chrome.driver", "/the/path/to/chromedriver.exe");
WebDriver webDriver = new ChromeDriver(new ChromeOptions());
Whereas if you'd want to get a remote instance from your Selenium Grid, it'd be as easy as:
WebDriver webDriver = new RemoteWebDriver(new URI("http://my-grid-domain:4444/wd/hub"), new ChromeOptions());
What webdriver-manager
offers you is a simple interface that reduces all this down to:
// WebDriverFactory myWebDriverFactory = ...
WebDriver webDriver = myWebDriverFactory.createWebDriver(new ChromeOptions());
There are two implementations of this interface, but you are of course free to write your own.
Using the LocalWebDriverFactory
, you can create WebDriver
instances on the current machine.
It will automatically download any required binaries, as long as you provide a BinaryManager
instance at construction:
// With BinaryManager, the factory will be able to download required binaries
WebDriverFactory factory = new LocalWebDriverFactory(BinaryManager.createDefault());
WebDriver webDriver = factory.createWebDriver(new ChromeOptions());
// Without BinaryManager, the factory will not download any binaries
// Do this when you exclusively use Browsers that do not require a separate binary (e.g. HTMLUnit or Safari)
WebDriverFactory factory = new LocalWebDriverFactory();
WebDriver webDriver = factory.createWebDriver(DesiredCapabilities.htmlUnit());
Per default, LocalWebDriverFactory
will always download the latest version of a binary.
This behavior may not always be what you want - i.e. you use an older browser version or the latest binary version
does not support your system's architecture anymore.
In order to solve this issue, you can provide a WebDriverFactoryConfig
in which you explicitly state which version shall be downloaded:
WebDriverFactoryConfig config = new WebDriverFactoryConfig();
config.setBinaryVersionForBrowser(Browser.CHROME, "2.32");
config.setBinaryVersionForBrowser(Browser.FIREFOX, "v0.17.0");
WebDriverFactory factory = new LocalWebDriverFactory(BinaryManager.createDefault(), config);
Alternatively to the local instantiation, you can use RemoteWebDriverFactory
with your Selenium Grid server:
WebDriverFactory factory = new RemoteWebDriverFactory("http://my-grid-domain:4444/wd/hub");
WebDriver webDriver = factory.createWebDriver(new FirefoxOptions());
Because you are connecting to a remote machine, there's naturally no need to download any binaries (on your machine, that is).
Building upon the above WebDriverFactory
, WebDriverManager
s are used to manage the created instances (keeping references to them, limiting overall instance count, making sure they're properly closed...).
As the name suggests, this WebDriverManager
manages a single WebDriver
instance.
You request a WebDriver
instance by calling the manager's getWebDriver()
method,
it basically behaves like WebDriverFactory
, except:
- If no WebDriver is currently active, a new instance will be created.
- If a WebDriver is currently active and its Capabilities match the given desired ones, the currently active instance will be returned.
- If a WebDriver is currently active and its Capabilities DO NOT match the given desired ones, the currently active instance will be closed and a new one will be created.
This is useful when your tests run sequentially, as an instance can now be reused as long as the requested
Capabilities
stay the same.
Example usage with JUnit Jupiter:
class ExampleTest {
private static WebDriverManager webDriverManager;
private WebDriver webDriver;
@BeforeAll
static void beforeAll() {
WebDriverFactory webDriverFactory = new LocalWebDriverFactory(BinaryManager.createDefault());
webDriverManager = new SingletonWebDriverManager(webDriverFactory);
}
@BeforeEach
void beforeEach() {
webDriver = webDriverManager.getWebDriver(new ChromeOptions());
}
@Test
void testDuckDuckGo() {
webDriver.get("https://duckduckgo.com");
// ...
}
@AfterAll
static void afterAll() {
webDriverManager.shutdown();
}
}
For all available implementations, please refer to the javadoc.