Skip to content

Commit

Permalink
provide async function to install driver
Browse files Browse the repository at this point in the history
  • Loading branch information
dmlemeshko committed Mar 27, 2020
1 parent 6e74f85 commit 68465d8
Show file tree
Hide file tree
Showing 9 changed files with 998 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,13 @@ typings/

# next.js build output
.next
node_modules
/lib
/bin

# VSCode
.DS_Store
.vscode

# driver archive
msedgedriver.*
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
src
tsconfig.json
tslint.json
.prettierrc
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 120,
"trailingComma": "all",
"singleQuote": true
}
45 changes: 45 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "ms-chromium-edge-driver",
"version": "0.0.1",
"keywords": [
"msedgedriver",
"webdriver",
"selenium"
],
"description": "NPM wrapper for Webdriver Chromium-based Edge driver",
"main": "lib/install.js",
"bin": {
"msedgedriver": "./bin/msedgedriver"
},
"typings": "lib/install.d.ts",
"files": [
"lib/**/*"
],
"repository": "[email protected]:dmlemeshko/ms-edge-driver.git",
"author": "<[email protected]>",
"license": "Apache-2.0",
"devDependencies": {
"@types/extract-zip": "^1.6.2",
"@types/got": "^9.6.9",
"@types/lodash": "^4.14.149",
"@types/node": "^13.9.2",
"typescript": "^3.8.3"
},
"scripts": {
"install": "node lib/install.js",
"build": "tsc",
"devBuild": "rm -rf lib bin && tsc -p .",
"prepare" : "npm run build",
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
"lint": "tslint -p tsconfig.json"
},
"dependencies": {
"extract-zip": "^1.6.7",
"lodash": "4.17.15",
"got": "^10.6.0",
"tslint": "^6.1.0",
"tslint-config-prettier": "^1.18.0",
"util": "^0.12.2",
"windows-registry": "^0.1.5"
}
}
46 changes: 46 additions & 0 deletions src/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { exec } from 'child_process';
import { promisify } from 'util';
import * as _ from 'lodash';

const execAsync = promisify(exec);
const MAC_EDGE_BINARY_PATH = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge';
const HKEY_WITH_EDGE_VERSION =
'\\SOFTWARE\\WOW6432Node\\Microsoft\\EdgeUpdate\\Clients\\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}';

const getBrowserBinaryOnWin = () => {
let key;
let subKey;
try {
const Key = require('windows-registry').Key;
const windef = require('windows-registry').windef;
key = new Key(windef.HKEY.HKEY_LOCAL_MACHINE, '', windef.KEY_ACCESS.KEY_READ);
subKey = key.openSubKey(HKEY_WITH_EDGE_VERSION, windef.KEY_ACCESS.KEY_READ);
const path = subKey.getValue('InstallLocation') as string;
const version = subKey.getValue('Version') as string;
return { path, version };
} catch (err) {
process.stdout.write(`MS Edge browser is not found in registry: ${err.stderr} \n`);
} finally {
if (subKey) {
subKey.close();
}
if (key) {
key.close();
}
}
};

const getBrowserBinaryOnMac = async (edgeBinaryPath: string | undefined) => {
const binaryPath = typeof edgeBinaryPath === 'undefined' ? MAC_EDGE_BINARY_PATH : edgeBinaryPath;
try {
const { stdout } = await execAsync(`"${binaryPath}" --version`);
const found = stdout.toString().match(/\d{1,}.\d{1,}.\d{1,}.\d{1,}/g);
if (found) {
return { path: binaryPath, version: found[0] };
}
} catch (err) {
process.stdout.write(`MS Edge browser is not found in Applications: ${err.stderr} \n`);
}
};

export { getBrowserBinaryOnWin, getBrowserBinaryOnMac };
128 changes: 128 additions & 0 deletions src/install.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import * as Fs from 'fs';
import * as _ from 'lodash';
import { promisify } from 'util';
import { URL } from 'url';
import got from 'got';
import { resolve } from 'path';
import { pipeline } from 'stream';
import * as extract from 'extract-zip';
import { getBrowserBinaryOnWin, getBrowserBinaryOnMac } from './browser';
const cdnUrl = process.env.EDGE_DRIVER_CDNURL || 'https://msedgedriver.azureedge.net';
const mainDir = resolve(__dirname, '..');
const outFile = 'msedgedriver.zip';
const platform: string = process.platform;
const arch: string = process.arch;
let edgeDriverVersion = process.env.npm_config_edge_driver_version || process.env.EDGE_DRIVER_VERSION;
let edgeBinaryPath = process.env.npm_config_edge_binary_path || process.env.EDGE_BINARY_PATH;
let edgeDriverPath = process.env.npm_config_edge_driver_path || process.env.EDGE_DRIVER_PATH;

const extractZipAsync = promisify(extract);
const pipelineAsync = promisify(pipeline);

enum OS {
WIN32 = 'win32',
WIN64 = 'win64',
MAC32 = 'mac32',
MAC64 = 'mac64',
LINUX = 'linux',
}

const getOS = (): OS => {
if (platform === 'win32') {
return arch === 'x64' ? OS.WIN64 : OS.WIN32;
} else if (platform === 'darwin') {
return arch === 'x64' ? OS.MAC64 : OS.MAC32;
} else {
return OS.LINUX;
}
};

const isBrowserBinaryDefined = () => !_.isEmpty(edgeBinaryPath);
const isDriverVersionDefined = () => !_.isEmpty(edgeDriverVersion);
const isDriverPathDefined = () => !_.isEmpty(edgeDriverPath);

const osName = getOS();

const isWin = (): boolean => {
return [OS.WIN32, OS.WIN64].includes(osName);
};

const fileName = isWin() ? 'msedgedriver.exe' : 'msedgedriver';

const getBrowser = async () => {
if (![OS.WIN32, OS.WIN64, OS.MAC64].includes(osName)) {
process.stdout.write(`MS does not provide driver for ${osName} platform\n`);
process.exit(1);
}

if (!isDriverVersionDefined()) {
const binaryData = isWin() ? getBrowserBinaryOnWin() : await getBrowserBinaryOnMac(edgeBinaryPath);

if (binaryData) {
process.stdout.write(`Microsoft Edge installed. Version: ${binaryData.version}\n`);
return binaryData;
} else {
return { path: '', version: 'LATEST' };
}
} else {
process.stdout.write(`Microsoft Edge binary path is not provided\n`);
return { path: '', version: 'LATEST' };
}
};

const downloadDriver = async (version: string | undefined) => {
if (version === 'LATEST') {
process.stdout.write(`Getting the latest driver version\n`);
const response = await got.get(`${cdnUrl}/LATEST_STABLE`);

version = response.body.replace(/[^\d.]/g, '');
}

process.stdout.write(`Downloading MS Edge Driver ${version}...\n`);

const downloadUrl = `${cdnUrl}/${version}/edgedriver_${osName}.zip`;
const mainDir = resolve(__dirname, '..');
const tempDownloadedFile = resolve(mainDir, outFile);
try {
await pipelineAsync(got.stream(new URL(downloadUrl)), Fs.createWriteStream(tempDownloadedFile));
return true;
} catch (err) {
process.stdout.write(`${err}: ${downloadUrl}\n`);
return false;
}
};

const getBinary = async (downloaded: boolean) => {
if (!downloaded) {
process.stdout.write(`Driver was not downloaded\n`);
process.exit(1);
}

process.stdout.write('Extracting driver binary... \n');
const downloadedFile = resolve(mainDir, outFile);
const extractPath = resolve(mainDir, 'bin');
Fs.mkdirSync(extractPath, { recursive: true });

await extractZipAsync(resolve(downloadedFile), { dir: extractPath });
process.stdout.write('Done. \n');
Fs.unlinkSync(downloadedFile);
return resolve(extractPath, fileName);
};

const findDriverInPath = () => {
const driverPath = resolve(mainDir, 'bin', fileName);
return Fs.existsSync(driverPath) ? driverPath : null;
};

const installDriver = async () => {
const binaryData = await getBrowser();
let driverPath = findDriverInPath();
if (!driverPath) {
const isDowloaded = await downloadDriver(binaryData.version);
driverPath = await getBinary(isDowloaded);
}

return { browserPath: binaryData.path, driverPath };
};

export { installDriver };
11 changes: 11 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]
}
3 changes: 3 additions & 0 deletions tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["tslint:recommended", "tslint-config-prettier"]
}
Loading

0 comments on commit 68465d8

Please sign in to comment.