Skip to content

Commit

Permalink
Merge pull request #3 from cdagli/master
Browse files Browse the repository at this point in the history
Better README. Renamed Env Variables to be more specific
  • Loading branch information
cdagli authored May 3, 2018
2 parents aef3ca6 + a3c4ac6 commit bbd2605
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 68 deletions.
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
language: node_js
node_js:
- "node"
- "node"
env:
global:
- BROWSER_DRIVER_INSTALLER_CHROME_VERSION=67
- BROWSER_DRIVER_INSTALLER_CHROMEDRIVER_PATH=./output/chromedriver
- BROWSER_DRIVER_INSTALLER_FIREFOX_VERSION=57
- BROWSER_DRIVER_INSTALLER_GECKODRIVER_PATH=./output/geckodriver
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
[![Build Status](https://travis-ci.org/unscrambl/browser-driver-installer.svg?branch=master)](https://travis-ci.org/unscrambl/browser-driver-installer)

# browser-driver-installer
Installs Chrome and Gecko drivers that match with the specified browser versions
Installs Chrome and Gecko drivers that match with the specified browser versions. It uses the [chromedriver](https://www.npmjs.com/package/chromedriver) and [geckodriver](https://www.npmjs.com/package/geckodriver) NPM packages to download the drivers.

#### Usage:

**Post Install Script:** If your environment has the `BROWSER_DRIVER_INSTALLER_CHROME_VERSION`, `BROWSER_DRIVER_INSTALLER_CHROMEDRIVER_PATH`, `BROWSER_DRIVER_INSTALLER_FIREFOX_VERSION`, `BROWSER_DRIVER_INSTALLER_GECKODRIVER_PATH` variables defined, a post-install script will download the `ChromeDriver` and `GeckoDriver` executables to the specified paths automatically.


**As a module:**
```
const driverInstaller = require('browser-driver-installer').driverInstaller;
driverInstaller(BROWSER_NAME, BROWSER_VERSION, TARGET_PATH);
```


**CLI Usage:**

````
Usage: index [options]
Options:
--browser-name <browserName> Browser to install the driver for
--browser-version <browserVersion> Browser version string e.g. 65, 67.0.23
--target-path <targetPath> Path to install driver executable
-h, --help output usage information
````

## LICENSE
[Apache 2.0](https://github.com/unscrambl/browser-driver-installer/blob/master/LICENSE)
21 changes: 13 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
const program = require('commander');
const driverInstaller = require('./installer').driverInstaller;

program
.option('--chrome-version [chromeVersion]', 'Chrome browser major version string e.g. 65')
.option('--chrome-driver-target-path [chromeDriverTargetPath]', 'Path to install Chrome driver executable')
.option('--firefox-version [firefoxVersion]', 'Firefox browser major version string e.g. 57')
.option('--firefox-driver-target-path [firefoxDriverTargetPath]',
'Path to install Firefox driver(geckoDriver) executable')
.parse(process.argv);
if (require.main === module)
{
program
.option('--browser-name <browserName>', 'Browser to install the driver for')
.option('--browser-version <browserVersion>', 'Browser version string e.g. 65, 67.0.23')
.option('--target-path <targetPath>', 'Path to install driver executable')
.parse(process.argv);

driverInstaller(program.chromeVersion, program.chromeDriverTargetPath, program.firefoxVersion, program.firefoxDriverTargetPath);
driverInstaller(program.browserName, program.browserVersion, program.targetPath);
}
else
{
module.exports.driverInstaller = driverInstaller;
}
90 changes: 45 additions & 45 deletions installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ const path = require('path');
const execSync = require('child_process').execSync;
const shell = require('shelljs');

const TEMP_DIR = 'temp';
const BROWSER_MAJOR_VERSION_REGEX = new RegExp(/^(\d+)/);
const CHROME_BROWSER_NAME = 'chrome';
const CHROME_DRIVER_NAME = 'chromedriver';
const CHROME_DRIVER_BIN_PATH = path.join('node_modules', 'chromedriver', 'lib', 'chromedriver', CHROME_DRIVER_NAME);
const CHROME_DRIVER_VERSION_REGEX = new RegExp(/\w+ ([0-9]+.[0-9]+).+/);
const GECKO_DRIVER_NAME = 'geckodriver';
const GECKO_DRIVER_BIN_PATH = path.join('node_modules', 'geckodriver', GECKO_DRIVER_NAME);
const GECKO_DRIVER_VERSION_REGEX = new RegExp(/\w+\s(\d+.\d+.\d+)/);
const BROWSER_MAJOR_VERSION_REGEX = new RegExp(/^(\d+)/);
const FIREFOX_BROWSER_NAME = 'firefox';
const TEMP_DIR = 'temp';
const VALID_BROWSER_NAMES = [CHROME_BROWSER_NAME, FIREFOX_BROWSER_NAME];

function installDriverWithVersion(driverName, driverBinPath, installPath, versionObject)
function installDriverWithVersion(driverName, driverBinPath, targetPath, versionObject)
{
if (checkDirectoryAndVersion(driverName, installPath, versionObject.driverVersion))
if (checkDirectoryAndVersion(driverName, targetPath, versionObject.driverVersion))
{
return false;
}
Expand All @@ -29,8 +32,8 @@ function installDriverWithVersion(driverName, driverBinPath, installPath, versio
]).then(
function ()
{
shell.mkdir('-p', installPath);
shell.cp('-n', path.join(TEMP_DIR, driverBinPath), installPath);
shell.mkdir('-p', targetPath);
shell.cp('-n', path.join(TEMP_DIR, driverBinPath), targetPath);
shell.rm('-rf', TEMP_DIR);
console.log('package dependencies have been installed');
return true;
Expand All @@ -41,48 +44,48 @@ function installDriverWithVersion(driverName, driverBinPath, installPath, versio
});
}

function checkDirectoryAndVersion(driverName, installPath, driverExpectedVersion)
function checkDirectoryAndVersion(driverName, targetPath, driverExpectedVersion)
{
if (!shell.test('-e', installPath))
if (!shell.test('-e', targetPath))
{
return false;
}
console.log(`Directory '${installPath}' does exist.`);
console.log(`Directory '${targetPath}' does exist.`);
console.log(`Checking if the directory contains a ${driverName}...`);

if (!shell.test('-e', path.join(installPath, driverName)))
if (!shell.test('-e', path.join(targetPath, driverName)))
{
console.log(`Could not find the ${driverName} in the directory '${installPath}'. Attempting to install it...`);
console.log(`Could not find the ${driverName} in the directory '${targetPath}'. Attempting to install it...`);
return false;
}

console.log(`${driverName} found.`);
const driverMajorVersion = driverVersionString(driverName, installPath);
const driverMajorVersion = driverVersionString(driverName, targetPath);
if (driverMajorVersion !== driverExpectedVersion)
{
console.log(
`${driverName} expected version (${driverExpectedVersion}) does not match with the installed version (${driverMajorVersion}).`
);
console.log('Removing the old version...');
shell.rm(path.join(installPath, driverName));
shell.rm(path.join(targetPath, driverName));
return false;
}

console.log(`${driverName} version ${driverExpectedVersion} has already been installed!`);
return true;
}

function driverVersionString(driverName, installPath)
function driverVersionString(driverName, targetPath)
{
let versionOutput = null;
if (driverName === CHROME_DRIVER_NAME)
{
versionOutput = execSync(path.join(installPath, driverName) + ' -v').toString();
versionOutput = execSync(path.join(targetPath, driverName) + ' -v').toString();
return versionOutput.match(CHROME_DRIVER_VERSION_REGEX)[1];
}
else if (driverName === GECKO_DRIVER_NAME)
{
versionOutput = execSync(path.join(installPath, driverName) + ' -V').toString();
versionOutput = execSync(path.join(targetPath, driverName) + ' -V').toString();
return versionOutput.match(GECKO_DRIVER_VERSION_REGEX)[1];
}
else
Expand All @@ -91,52 +94,49 @@ function driverVersionString(driverName, installPath)
}
}

function driverInstaller(detectedChromeVersion, chromeDriverTargetPath, detectedFirefoxVersion, geckoDriverTargetPath)
function driverInstaller(browserName, browserVersion, targetPath)
{
const browserVersionsObject = JSON.parse(shell.cat(path.resolve(__dirname, 'driverVersions.json')));
// ChromeDriver NPM package versions are defined according to https://github.com/giggio/node-chromedriver/releases
const chromeDriverVersions = browserVersionsObject.chromeDriverVersions;

if (typeof browserName !== 'string' || typeof browserVersion !== 'string' || typeof targetPath !== 'string')
{
throw new Error('Parameters are not valid strings.');
}
// GeckoDriver NPM package versions are defined according to https://github.com/mozilla/geckodriver/releases
const geckoDriverVersions = browserVersionsObject.geckoDriverVersions;
// ChromeDriver NPM package versions are defined according to https://github.com/giggio/node-chromedriver/releases
const browserVersionsObject = JSON.parse(shell.cat(path.resolve(__dirname, 'driverVersions.json')));

detectedChromeVersion = majorBrowserVersion(detectedChromeVersion);
detectedFirefoxVersion = majorBrowserVersion(detectedFirefoxVersion);
let browserDriverVersions = null;
let driverBinPath = null;
let driverName = null;

if (detectedChromeVersion && !chromeDriverVersions[detectedChromeVersion])
if (browserName.toLowerCase() === CHROME_BROWSER_NAME)
{
throw new Error(
`Failed to locate a version of ChromeDriver that matches the installed version of Chrome (${detectedChromeVersion}). Valid Chrome versions are: ${Object.keys(chromeDriverVersions).join(', ')}`
);
browserDriverVersions = browserVersionsObject.chromeDriverVersions;
driverBinPath = CHROME_DRIVER_BIN_PATH;
driverName = CHROME_DRIVER_NAME;
}
else if (detectedChromeVersion && typeof (chromeDriverTargetPath) === 'string')
else if (browserName.toLowerCase() === FIREFOX_BROWSER_NAME)
{
return installDriverWithVersion(CHROME_DRIVER_NAME, CHROME_DRIVER_BIN_PATH, chromeDriverTargetPath,
chromeDriverVersions[detectedChromeVersion]);
browserDriverVersions = browserVersionsObject.geckoDriverVersions;
driverBinPath = GECKO_DRIVER_BIN_PATH;
driverName = GECKO_DRIVER_NAME;
}
else
{
console.log('No Chrome version or target path is provided. Skipping...');
throw new Error(
`Browser name "${browserName}" is not a valid browser name. Valid browser names are: ${(VALID_BROWSER_NAMES).join(', ')}`
);
}

if (detectedFirefoxVersion && !geckoDriverVersions[detectedFirefoxVersion])
browserVersion = majorBrowserVersion(browserVersion);

if (browserVersion && !browserDriverVersions[browserVersion])
{
throw new Error(
`Failed to locate a version of GeckoDriver that matches the installed version of Firefox (${detectedFirefoxVersion}). Valid Firefox versions are: ${Object.keys(geckoDriverVersions).join(', ')}`
`Failed to locate a version of ${driverName} that matches the installed version of ${browserName} (${browserVersion}). Valid ${browserName} versions are: ${Object.keys(browserDriverVersions).join(', ')}`
);
}
else if (detectedFirefoxVersion && (typeof geckoDriverTargetPath) === 'string')
{
return installDriverWithVersion(GECKO_DRIVER_NAME, GECKO_DRIVER_BIN_PATH, geckoDriverTargetPath,
geckoDriverVersions[
detectedFirefoxVersion]);
}
else
{
console.log('No Firefox version or target path is provided. Skipping...');
}

return false;
return installDriverWithVersion(driverName, driverBinPath, targetPath, browserDriverVersions[browserVersion]);
}

function majorBrowserVersion(browserVersionString)
Expand Down
26 changes: 15 additions & 11 deletions installer.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
'use strict';
/* eslint-disable no-console */

const chai = require('chai');
const installer = require('./installer');
const expect = require('chai').expect;
Expand Down Expand Up @@ -34,43 +37,44 @@ describe('browserDriverInstaller', function ()
it('should not attempt to install anything if one of the path, version or both parameters are not provided',
function ()
{
expect(installer.driverInstaller()).to.be.false;
expect(console.log).to.have.been.calledWith(
'No Chrome version or target path is provided. Skipping...');
expect(console.log).to.have.been.calledWith(
'No Firefox version or target path is provided. Skipping...');
expect(function () { installer.driverInstaller(); }).to.throw(
'Parameters are not valid strings.');
});

it('should throw an error if the provided version does not included in the JSON file', function ()
{
const wrongVersionNumber = '1';
expect(function () { installer.driverInstaller(wrongVersionNumber, '/some/target/path'); }).to.throw(
/Failed to locate a version of ChromeDriver that matches the installed version of Chrome \(1\). Valid Chrome versions are:*/
expect(function ()
{
installer.driverInstaller('chrome', wrongVersionNumber,
'/some/target/path');
}).to.throw(
/Failed to locate a version of chromedriver that matches the installed version of chrome \(1\). Valid chrome versions are:*/
);
});

it('should install the chromedriver to specified path if the version is included in the JSON file',
function ()
{
return installer.driverInstaller('54', DRIVER_OUTPUT_PATH).then(function ()
return installer.driverInstaller('chrome', '54', DRIVER_OUTPUT_PATH).then(function ()
{
expect(shell.test('-e', path.resolve(DRIVER_OUTPUT_PATH, 'chromedriver'))).to.be.true;
});
});

it('should install the geckodriver to specified path if the version is included in the JSON file', function ()
{
return installer.driverInstaller(null, null, '55', DRIVER_OUTPUT_PATH).then(function ()
return installer.driverInstaller('firefox', '55', DRIVER_OUTPUT_PATH).then(function ()
{
expect(shell.test('-e', path.resolve(DRIVER_OUTPUT_PATH, 'geckodriver'))).to.be.true;
});
});

it('should not install again if the wanted version is already installed', function ()
{
return installer.driverInstaller('54', DRIVER_OUTPUT_PATH).then(function ()
return installer.driverInstaller('chrome', '54', DRIVER_OUTPUT_PATH).then(function ()
{
expect(installer.driverInstaller('54', DRIVER_OUTPUT_PATH)).to.be.false;
expect(installer.driverInstaller('chrome', '54', DRIVER_OUTPUT_PATH)).to.be.false;
});
});
});
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
"license": "Apache-2.0",
"main": "index.js",
"name": "browser-driver-installer",
"repository": "github:unscrambl/browser-driver-installer",
"scripts": {
"postinstall": "node ./index.js --chrome-version $CHROME_VERSION --chrome-driver-target-path $CHROMEDRIVER_PATH --firefox-version $FIREFOX_VERSION --firefox-driver-target-path $GECKODRIVER_PATH",
"postinstall": "./postinstall",
"test": "node_modules/mocha/bin/mocha *.spec.js"
},
"version": "0.0.1"
"version": "1.0.4"
}
17 changes: 17 additions & 0 deletions postinstall
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

if [[ (-n "${BROWSER_DRIVER_INSTALLER_CHROME_VERSION}") && (-n "${BROWSER_DRIVER_INSTALLER_CHROMEDRIVER_PATH}")]]; then
node ./index.js --browser-name chrome \
--browser-version "$BROWSER_DRIVER_INSTALLER_CHROME_VERSION" \
--target-path "$BROWSER_DRIVER_INSTALLER_CHROMEDRIVER_PATH"
else
echo "Environment variables for Chrome are not set, skipping post-install for Chrome"
fi

if [[ (-n "${BROWSER_DRIVER_INSTALLER_FIREFOX_VERSION}") && (-n "${BROWSER_DRIVER_INSTALLER_GECKODRIVER_PATH}")]]; then
node ./index.js --browser-name firefox \
--browser-version "$BROWSER_DRIVER_INSTALLER_FIREFOX_VERSION" \
--target-path "$BROWSER_DRIVER_INSTALLER_GECKODRIVER_PATH"
else
echo "Environment variables for Firefox are not set, skipping post-install for Firefox"
fi

0 comments on commit bbd2605

Please sign in to comment.