diff --git a/lib/binaries/chrome_xml.ts b/lib/binaries/chrome_xml.ts index 606425ce..300d92ce 100644 --- a/lib/binaries/chrome_xml.ts +++ b/lib/binaries/chrome_xml.ts @@ -73,12 +73,17 @@ export class ChromeXml extends XmlConfigSource { /** * Gets a specific item from the XML. + * + * Resolves with URL, or rejects if there is an error retrieving the XML, or the requested + * was not found in the list. */ private getSpecificChromeDriverVersion(inputVersion: string): Promise { return this.getVersionList().then(list => { const specificVersion = getValidSemver(inputVersion); if (specificVersion === '') { - throw new Error(`version ${inputVersion} ChromeDriver does not exist`) + const msg = `Requested version ${inputVersion} does not look like a Chrome version. +Expected e.g. "2.34" or "89.0.4389.0".`; + throw new Error(msg); } let itemFound = ''; for (let item of list) { @@ -117,7 +122,7 @@ export class ChromeXml extends XmlConfigSource { } } if (itemFound == '') { - return {url: '', version: inputVersion}; + throw new Error(`There is no chromedriver available for version ${specificVersion}.`); } else { return {url: Config.cdnUrls().chrome + itemFound, version: inputVersion}; } diff --git a/lib/cli/programs.ts b/lib/cli/programs.ts index 39d27ea5..908ce6b5 100644 --- a/lib/cli/programs.ts +++ b/lib/cli/programs.ts @@ -1,7 +1,8 @@ -import * as minimist from 'minimist'; +import {Logger} from './logger'; +import {MinimistArgs, Option, Options} from './options'; -import {Args, MinimistArgs, Option, Options} from './options'; +const logger = new Logger('program'); /** * Dictionary that maps the command and the program. @@ -71,11 +72,22 @@ export class Program { * method. * @param args The arguments that will be parsed to run the method. */ - run(json: JSON): Promise { + run(json: JSON): void; + run(json: JSON, testing: true): Promise; + run(json: JSON, testing?: true): void|Promise { for (let opt in this.options) { this.options[opt].value = this.getValue_(opt, json); } - return Promise.resolve(this.runMethod(this.options)); + const promise = Promise.resolve(this.runMethod(this.options)); + if (testing) { + return promise; + } else { + promise.catch(err => { + // Exit gracefully when the program promise rejects + logger.error(err); + process.exit(-1); + }); + } } private getValue_(key: string, json: JSON): number|boolean|string { diff --git a/lib/cmds/update.ts b/lib/cmds/update.ts index 9fc9b95c..a0c8fe76 100644 --- a/lib/cmds/update.ts +++ b/lib/cmds/update.ts @@ -125,34 +125,27 @@ function update(options: Options): Promise { if (standalone) { let binary: Standalone = binaries[Standalone.id]; binary.versionCustom = options[Opt.VERSIONS_STANDALONE].getString(); - promises.push(FileManager.downloadFile(binary, outputDir) - .then((downloaded: boolean) => { - if (!downloaded) { - logger.info( - binary.name + ': file exists ' + - path.resolve(outputDir, binary.filename())); - logger.info(binary.name + ': ' + binary.filename() + ' up to date'); - } - }) - .then(() => { - updateBrowserFile(binary, outputDir); - })); + promises.push(FileManager.downloadFile(binary, outputDir).then(downloaded => { + if (!downloaded) { + logger.info(binary.name + ': file exists ' + path.resolve(outputDir, binary.filename())); + logger.info(binary.name + ': ' + binary.filename() + ' up to date'); + } + updateBrowserFile(binary, outputDir); + })); } if (chrome) { let binary: ChromeDriver = binaries[ChromeDriver.id]; binary.versionCustom = options[Opt.VERSIONS_CHROME].getString(); - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); + promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL) + .then(() => updateBrowserFile(binary, outputDir))); } if (gecko) { let binary: GeckoDriver = binaries[GeckoDriver.id]; if (options[Opt.VERSIONS_GECKO]) { binary.versionCustom = options[Opt.VERSIONS_GECKO].getString(); } - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); + promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL) + .then(() => updateBrowserFile(binary, outputDir))); } if (ie64) { let binary: IEDriver = binaries[IEDriver.id]; @@ -160,16 +153,14 @@ function update(options: Options): Promise { binary.versionCustom = options[Opt.VERSIONS_IE].getString(); } binary.osarch = Config.osArch(); // Win32 or x64 - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); + promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL) + .then(() => updateBrowserFile(binary, outputDir))); } if (ie32) { let binary: IEDriver = binaries[IEDriver.id]; binary.osarch = 'Win32'; - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); + promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL) + .then(() => updateBrowserFile(binary, outputDir))); } if (android) { let binary = binaries[AndroidSDK.id]; @@ -178,24 +169,15 @@ function update(options: Options): Promise { let oldAVDList: string; updateBrowserFile(binary, outputDir); - promises.push(q.nfcall(fs.readFile, path.resolve(sdk_path, 'available_avds.json')) - .then( - (oldAVDs: string) => { - oldAVDList = oldAVDs; - }, - () => { - oldAVDList = '[]'; - }) - .then(() => { - return updateBinary(binary, outputDir, proxy, ignoreSSL); - }) - .then(() => { - initializeAndroid( - path.resolve(outputDir, binary.executableFilename()), - android_api_levels, android_architectures, android_platforms, - android_accept_licenses, binary.versionCustom, - JSON.parse(oldAVDList), logger, verbose); - })); + promises.push( + q.nfcall(fs.readFile, path.resolve(sdk_path, 'available_avds.json')) + .then((oldAVDs: string) => oldAVDList = oldAVDs, () => oldAVDList = '[]') + .then(() => updateBinary(binary, outputDir, proxy, ignoreSSL)) + .then( + () => initializeAndroid( + path.resolve(outputDir, binary.executableFilename()), android_api_levels, + android_architectures, android_platforms, android_accept_licenses, + binary.versionCustom, JSON.parse(oldAVDList), logger, verbose))); } if (ios) { checkIOS(logger); @@ -207,9 +189,7 @@ function update(options: Options): Promise { updateBrowserFile(binary, outputDir); } - return Promise.all(promises).then(() => { - writeBrowserFile(outputDir); - }); + return Promise.all(promises as Promise[]).then(() => writeBrowserFile(outputDir)); } function updateBinary( diff --git a/lib/files/downloader.ts b/lib/files/downloader.ts index 1d4ab4b5..1e8d7b6f 100644 --- a/lib/files/downloader.ts +++ b/lib/files/downloader.ts @@ -40,70 +40,65 @@ export class Downloader { let resContentLength: number; return new Promise((resolve, reject) => { - req = request(options); - req.on('response', response => { - if (response.statusCode === 200) { - resContentLength = +response.headers['content-length']; - if (contentLength === resContentLength) { - // if the size is the same, do not download and stop here - response.destroy(); - resolve(false); - } else { - let curl = outputDir + '/' + fileName + ' ' + options.url; - if (HttpUtils.requestOpts.proxy) { - let pathUrl = url.parse(options.url.toString()).path; - let host = url.parse(options.url.toString()).host; - let newFileUrl = url.resolve(HttpUtils.requestOpts.proxy, pathUrl); - curl = outputDir + '/' + fileName + ' \'' + newFileUrl + - '\' -H \'host:' + host + '\''; - } - if (HttpUtils.requestOpts.ignoreSSL) { - curl = 'k ' + curl; - } - logger.info('curl -o' + curl); + req = request(options); + req.on('response', response => { + if (response.statusCode === 200) { + resContentLength = +response.headers['content-length']; + if (contentLength === resContentLength) { + // if the size is the same, do not download and stop here + response.destroy(); + resolve(false); + } else { + let curl = outputDir + '/' + fileName + ' ' + options.url; + if (HttpUtils.requestOpts.proxy) { + let pathUrl = url.parse(options.url.toString()).path; + let host = url.parse(options.url.toString()).host; + let newFileUrl = url.resolve(HttpUtils.requestOpts.proxy, pathUrl); + curl = + outputDir + '/' + fileName + ' \'' + newFileUrl + '\' -H \'host:' + host + '\''; + } + if (HttpUtils.requestOpts.ignoreSSL) { + curl = 'k ' + curl; + } + logger.info('curl -o' + curl); - // only pipe if the headers are different length - file = fs.createWriteStream(filePath); - req.pipe(file); - file.on('close', () => { - fs.stat(filePath, (error, stats) => { - if (error) { - (error as any).msg = 'Error: Got error ' + error + ' from ' + fileUrl; - return reject(error); - } - if (stats.size != resContentLength) { - (error as any).msg = 'Error: corrupt download for ' + fileName + - '. Please re-run webdriver-manager update'; - fs.unlinkSync(filePath); - reject(error); - } - if (callback) { - callback(binary, outputDir, fileName); - } - resolve(true); - }); - }); - } + // only pipe if the headers are different length + file = fs.createWriteStream(filePath); + req.pipe(file); + file.on('close', () => { + fs.stat(filePath, (error, stats) => { + if (error) { + (error as any).msg = 'Error: Got error ' + error + ' from ' + fileUrl; + return reject(error); + } + if (stats.size != resContentLength) { + (error as any).msg = 'Error: corrupt download for ' + fileName + + '. Please re-run webdriver-manager update'; + fs.unlinkSync(filePath); + reject(error); + } + if (callback) { + callback(binary, outputDir, fileName); + } + resolve(true); + }); + }); + } - } else { - let error = new Error(); - (error as any).msg = - 'Expected response code 200, received: ' + response.statusCode; - reject(error); - } - }); - req.on('error', error => { - if ((error as any).code === 'ETIMEDOUT') { - (error as any).msg = 'Connection timeout downloading: ' + fileUrl + - '. Default timeout is 4 minutes.'; - } else if ((error as any).connect) { - (error as any).msg = 'Could not connect to the server to download: ' + fileUrl; - } - reject(error); - }); - }) - .catch(error => { - logger.error((error as any).msg || (error as any).message); - }); + } else { + let error = new Error('Expected response code 200, received: ' + response.statusCode); + reject(error); + } + }); + req.on('error', error => { + if ((error as any).code === 'ETIMEDOUT') { + (error as any).msg = + 'Connection timeout downloading: ' + fileUrl + '. Default timeout is 4 minutes.'; + } else if ((error as any).connect) { + (error as any).msg = 'Could not connect to the server to download: ' + fileUrl; + } + reject(error); + }); + }); } } diff --git a/lib/files/file_manager.ts b/lib/files/file_manager.ts index 2770765b..f03e8d73 100644 --- a/lib/files/file_manager.ts +++ b/lib/files/file_manager.ts @@ -171,42 +171,36 @@ export class FileManager { */ static downloadFile(binary: T, outputDir: string, callback?: Function): Promise { - return new Promise((resolve, reject) => { - let outDir = Config.getSeleniumDir(); - let downloaded: BinaryMap = FileManager.downloadedBinaries(outputDir); - let contentLength = 0; - - // Pass options down to binary to make request to get the latest version to download. - binary.getUrl(binary.version()).then(fileUrl => { - binary.versionCustom = fileUrl.version; - let filePath = path.resolve(outputDir, binary.filename()); - let fileName = binary.filename(); - - // If we have downloaded the file before, check the content length - if (downloaded[binary.id()]) { - let downloadedBinary = downloaded[binary.id()]; - let versions = downloadedBinary.versions; - let version = binary.versionCustom; - - for (let index in versions) { - let v = versions[index]; - if (v === version) { - contentLength = fs.statSync(filePath).size; - - Downloader.getFile(binary, fileUrl.url, fileName, outputDir, contentLength, callback) - .then(downloaded => { - resolve(downloaded); - }); - } + const downloaded: BinaryMap = FileManager.downloadedBinaries(outputDir); + + // Pass options down to binary to make request to get the latest version to download. + return binary.getUrl(binary.version()).then(fileUrl => { + const url = fileUrl.url; + if (!url) { + logger.debug('Bad binary entry from FileManager', binary); + throw new Error('Developer error: tried to download a binary with no URL.'); + } + const version = binary.versionCustom = fileUrl.version; + const filePath = path.resolve(outputDir, binary.filename()); + const fileName = binary.filename(); + + // If we have downloaded the file before, check the content length + if (downloaded[binary.id()]) { + const downloadedBinary = downloaded[binary.id()]; + const versions = downloadedBinary.versions; + + for (let index in versions) { + let v = versions[index]; + if (v === version) { + const contentLength = fs.statSync(filePath).size; + return Downloader.getFile(binary, url, fileName, outputDir, contentLength, callback); } } - // We have not downloaded it before, or the version does not exist. Use the default content - // length of zero and download the file. - Downloader.getFile(binary, fileUrl.url, fileName, outputDir, contentLength, callback) - .then(downloaded => { - resolve(downloaded); - }); - }); + } + + // We have not downloaded it before, or the version does not exist. Use the default content + // length of zero and download the file. + return Downloader.getFile(binary, url, fileName, outputDir, 0, callback) }); } diff --git a/lib/utils.ts b/lib/utils.ts index 8fd10977..fa7b3443 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -12,11 +12,11 @@ function spawnFactory(sync: true): (cmd: string, args: string[], stdio?: any, opts?: child_process.SpawnSyncOptions) => child_process.SpawnSyncReturns; function spawnFactory(sync: boolean): - (cmd: string, args: string[], stdio?: string, + (cmd: string, args: string[], stdio?: child_process.StdioOptions, opts?: child_process.SpawnOptions|child_process.SpawnSyncOptions) => child_process.ChildProcess | child_process.SpawnSyncReturns { - return (cmd: string, args: string[], stdio?: string, - opts?: child_process.SpawnOptions|child_process.SpawnSyncOptions) => { + return (cmd: string, args: string[], stdio?: child_process.StdioOptions, + opts: child_process.SpawnOptions|child_process.SpawnSyncOptions = {}) => { if ((Config.osType() === 'Windows_NT') && (cmd.slice(-4) !== '.exe')) { if (fs.existsSync(cmd + '.exe')) { cmd += '.exe'; @@ -26,7 +26,6 @@ function spawnFactory(sync: boolean): } } if (stdio) { - opts = opts || {}; opts.stdio = stdio; } if (sync) { diff --git a/package-lock.json b/package-lock.json index d789a063..cd517bfb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,12 +29,12 @@ "@types/form-data": "^0.0.33", "@types/glob": "^5.0.29", "@types/ini": "^1.3.28", - "@types/jasmine": "^2.5.43", + "@types/jasmine": "^3.6.7", "@types/minimatch": "^2.0.28", "@types/minimist": "^1.1.28", - "@types/node": "^7.0.4", - "@types/q": "^0.0.32", - "@types/request": "^0.0.39", + "@types/node": "^14.14.35", + "@types/q": "^1.5.4", + "@types/request": "^2.48.5", "@types/rimraf": "^0.0.28", "@types/selenium-webdriver": "^2.53.35", "@types/semver": "^5.3.30", @@ -42,10 +42,10 @@ "clang-format": "^1.0.35", "gulp": "^4.0.0", "gulp-clang-format": "^1.0.23", - "jasmine": "^2.4.1", + "jasmine": "^3.6.4", "run-sequence": "^1.1.5", "selenium-webdriver": "~3.0.1", - "typescript": "~2.3.0" + "typescript": "^4.2.3" }, "engines": { "node": ">=6.9.x" @@ -60,6 +60,12 @@ "@types/node": "*" } }, + "node_modules/@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, "node_modules/@types/chalk": { "version": "0.4.31", "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-0.4.31.tgz", @@ -99,9 +105,9 @@ "dev": true }, "node_modules/@types/jasmine": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.5.tgz", - "integrity": "sha512-mkrHFZTgOXkZhau36K628iKFkjbp11t/bHCkY4Mefu4R6McMg2FD9P3naBv/0Ygyn4sz8baColJp2gdmSekgiw==", + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.7.tgz", + "integrity": "sha512-8dtfiykrpe4Ysn6ONj0tOjmpDIh1vWxPk80eutSeWmyaJvAZXZ84219fS4gLrvz05eidhp7BP17WVQBaXHSyXQ==", "dev": true }, "node_modules/@types/minimatch": { @@ -117,25 +123,41 @@ "dev": true }, "node_modules/@types/node": { - "version": "7.0.52", - "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.52.tgz", - "integrity": "sha512-jjpyQsKGsOF/wUElNjfPULk+d8PKvJOIXk3IUeBYYmNCy5dMWfrI+JiixYNw8ppKOlcRwWTXFl0B+i5oGrf95Q==", + "version": "14.14.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", + "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==", "dev": true }, "node_modules/@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", "dev": true }, "node_modules/@types/request": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/request/-/request-0.0.39.tgz", - "integrity": "sha1-FouWz0JTxdVNQD90b4Lueu1Hziw=", + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", "dev": true, "dependencies": { - "@types/form-data": "*", - "@types/node": "*" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "node_modules/@types/request/node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" } }, "node_modules/@types/rimraf": { @@ -156,6 +178,12 @@ "integrity": "sha512-PBHCvO98hNec9A491vBbh0ZNDOVxccwKL1u2pm6fs9oDgm7SEnw0lEHqHfjsYryDxnE3zaf7LvERWEXjOp1hig==", "dev": true }, + "node_modules/@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, "node_modules/@types/xml2js": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.0.32.tgz", @@ -1453,15 +1481,6 @@ "through": "~2.3.1" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -2808,9 +2827,9 @@ } }, "node_modules/glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2821,6 +2840,9 @@ }, "engines": { "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { @@ -3617,23 +3639,22 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "node_modules/jasmine": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.9.0.tgz", - "integrity": "sha1-dlcfklyHg0CefGFTVy5aY0HPk+s=", + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.4.tgz", + "integrity": "sha512-hIeOou6y0BgCOKYgXYveQvlY+PTHgDPajFf+vLCYbMTQ+VjAP9+EQv0nuC9+gyCAAWISRFauB1XUb9kFuOKtcQ==", "dev": true, "dependencies": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.9.0" + "glob": "^7.1.6", + "jasmine-core": "~3.6.0" }, "bin": { "jasmine": "bin/jasmine.js" } }, "node_modules/jasmine-core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.9.1.tgz", - "integrity": "sha1-trvB2OZSUNVvWIhGFwXr7uuI8i8=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.6.0.tgz", + "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", "dev": true }, "node_modules/jsbn": { @@ -5690,9 +5711,9 @@ "dev": true }, "node_modules/typescript": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.3.4.tgz", - "integrity": "sha1-PTgyGCgjHkNPKHUUlZw3qCtin0I=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6218,6 +6239,12 @@ "@types/node": "*" } }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, "@types/chalk": { "version": "0.4.31", "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-0.4.31.tgz", @@ -6257,9 +6284,9 @@ "dev": true }, "@types/jasmine": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.5.tgz", - "integrity": "sha512-mkrHFZTgOXkZhau36K628iKFkjbp11t/bHCkY4Mefu4R6McMg2FD9P3naBv/0Ygyn4sz8baColJp2gdmSekgiw==", + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.7.tgz", + "integrity": "sha512-8dtfiykrpe4Ysn6ONj0tOjmpDIh1vWxPk80eutSeWmyaJvAZXZ84219fS4gLrvz05eidhp7BP17WVQBaXHSyXQ==", "dev": true }, "@types/minimatch": { @@ -6275,25 +6302,40 @@ "dev": true }, "@types/node": { - "version": "7.0.52", - "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.52.tgz", - "integrity": "sha512-jjpyQsKGsOF/wUElNjfPULk+d8PKvJOIXk3IUeBYYmNCy5dMWfrI+JiixYNw8ppKOlcRwWTXFl0B+i5oGrf95Q==", + "version": "14.14.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", + "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==", "dev": true }, "@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", "dev": true }, "@types/request": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/request/-/request-0.0.39.tgz", - "integrity": "sha1-FouWz0JTxdVNQD90b4Lueu1Hziw=", + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", "dev": true, "requires": { - "@types/form-data": "*", - "@types/node": "*" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + }, + "dependencies": { + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } } }, "@types/rimraf": { @@ -6314,6 +6356,12 @@ "integrity": "sha512-PBHCvO98hNec9A491vBbh0ZNDOVxccwKL1u2pm6fs9oDgm7SEnw0lEHqHfjsYryDxnE3zaf7LvERWEXjOp1hig==", "dev": true }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, "@types/xml2js": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.0.32.tgz", @@ -7396,12 +7444,6 @@ "through": "~2.3.1" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -8459,9 +8501,9 @@ } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -9128,20 +9170,19 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jasmine": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.9.0.tgz", - "integrity": "sha1-dlcfklyHg0CefGFTVy5aY0HPk+s=", + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.4.tgz", + "integrity": "sha512-hIeOou6y0BgCOKYgXYveQvlY+PTHgDPajFf+vLCYbMTQ+VjAP9+EQv0nuC9+gyCAAWISRFauB1XUb9kFuOKtcQ==", "dev": true, "requires": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.9.0" + "glob": "^7.1.6", + "jasmine-core": "~3.6.0" } }, "jasmine-core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.9.1.tgz", - "integrity": "sha1-trvB2OZSUNVvWIhGFwXr7uuI8i8=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.6.0.tgz", + "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", "dev": true }, "jsbn": { @@ -10887,9 +10928,9 @@ "dev": true }, "typescript": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.3.4.tgz", - "integrity": "sha1-PTgyGCgjHkNPKHUUlZw3qCtin0I=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "unc-path-regex": { diff --git a/package.json b/package.json index 16be5f0b..7d6b1ef3 100644 --- a/package.json +++ b/package.json @@ -8,16 +8,16 @@ "format-enforce": "gulp format:enforce", "gulp": "gulp", "jasmine": "jasmine", - "prepublish": "npm run format-enforce && tsc && gulp copy", + "prepack": "npm run format-enforce && tsc && gulp copy", "tsc": "tsc", "test": "npm run test-unit && npm run test-e2e", "pretest-unit": "npm run build", "test-unit": "jasmine", - "pretest-e2e:update": "webdriver-manager update --android --android-accept-licenses --avds none", - "pretest-e2e:start": "webdriver-manager start --detach --seleniumPort 4444 --android --appium-port 4723 --quiet", + "pretest-e2e:update": "node built/lib/webdriver.js update --android --android-accept-licenses --avds none", + "pretest-e2e:start": "node built/lib/webdriver.js start --detach --seleniumPort 4444 --android --appium-port 4723 --quiet", "pretest-e2e": "npm run build && npm run pretest-e2e:update && npm run pretest-e2e:start", "test-e2e": "jasmine JASMINE_CONFIG_PATH=e2e_spec/support/headless.json", - "posttest-e2e": "webdriver-manager shutdown" + "posttest-e2e": "node built/lib/webdriver.js shutdown" }, "keywords": [ "angular", @@ -58,12 +58,12 @@ "@types/form-data": "^0.0.33", "@types/glob": "^5.0.29", "@types/ini": "^1.3.28", - "@types/jasmine": "^2.5.43", + "@types/jasmine": "^3.6.7", "@types/minimatch": "^2.0.28", "@types/minimist": "^1.1.28", - "@types/node": "^7.0.4", - "@types/q": "^0.0.32", - "@types/request": "^0.0.39", + "@types/node": "^14.14.35", + "@types/q": "^1.5.4", + "@types/request": "^2.48.5", "@types/rimraf": "^0.0.28", "@types/selenium-webdriver": "^2.53.35", "@types/semver": "^5.3.30", @@ -71,10 +71,10 @@ "clang-format": "^1.0.35", "gulp": "^4.0.0", "gulp-clang-format": "^1.0.23", - "jasmine": "^2.4.1", + "jasmine": "^3.6.4", "run-sequence": "^1.1.5", "selenium-webdriver": "~3.0.1", - "typescript": "~2.3.0" + "typescript": "^4.2.3" }, "engines": { "node": ">=6.9.x" diff --git a/spec/binaries/chrome_xml_spec.ts b/spec/binaries/chrome_xml_spec.ts index ebaa2855..e86a178a 100644 --- a/spec/binaries/chrome_xml_spec.ts +++ b/spec/binaries/chrome_xml_spec.ts @@ -5,89 +5,84 @@ import {ChromeXml} from '../../lib/binaries/chrome_xml'; describe('chrome xml reader', () => { let out_dir = path.resolve('selenium_test'); + // TODO: this test loads the live driver manifest from Google's public website, which means + // results depend on that file continuing to have the contents we expected. We should test + // against a local fixture instead. + afterAll(() => { rimraf.sync(out_dir); }); - it('should get a list', (done) => { + it('should get a list', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Darwin'; chromeXml.osarch = 'x64'; - chromeXml.getVersionList().then(list => { + return chromeXml.getVersionList().then(list => { for (let item of list) { expect(item).toContain('/chromedriver_mac'); expect(item).not.toContain('m1'); } - done(); }); }); - it('should get the 2.27, 64-bit version (arch = x64)', (done) => { + it('should get the 2.27, 64-bit version (arch = x64)', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Darwin'; chromeXml.osarch = 'x64'; - chromeXml.getUrl('2.27').then(binaryUrl => { + return chromeXml.getUrl('2.27').then(binaryUrl => { expect(binaryUrl.url).toContain('2.27/chromedriver_mac64.zip'); - done(); }); }); - it('should get the 2.27, 64-bit version (arch = x86)', (done) => { + it('should not find the 2.27, 64-bit version (arch = x86)', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Darwin'; chromeXml.osarch = 'x86'; - chromeXml.getUrl('2.27').then(binaryUrl => { - expect(binaryUrl.url).toEqual(''); - done(); - }); + return expectAsync(chromeXml.getUrl('2.27')).toBeRejected(); }); - it('should get the 2.20, 32-bit version (arch = x64)', (done) => { + it('should get the 2.20, 32-bit version (arch = x64)', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Darwin'; chromeXml.osarch = 'x64'; - chromeXml.getUrl('2.20').then(binaryUrl => { + return chromeXml.getUrl('2.20').then(binaryUrl => { expect(binaryUrl.url).toContain('2.20/chromedriver_mac32.zip'); - done(); }); }); - it('should get the 2.20, 32-bit version (arch = x86)', (done) => { + it('should get the 2.20, 32-bit version (arch = x86)', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Darwin'; chromeXml.osarch = 'x86'; - chromeXml.getUrl('2.20').then((binaryUrl) => { + return chromeXml.getUrl('2.20').then((binaryUrl) => { expect(binaryUrl.url).toContain('2.20/chromedriver_mac32.zip'); - done(); }); }); // This test case covers a bug when all the following conditions were true. // arch was 64 with multiple major versions available. - it('should not get the 85.0.4183.38, 32-bit version (arch = x64)', (done) => { + it('should not get the 85.0.4183.38, 32-bit version (arch = x64)', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Windows_NT'; chromeXml.osarch = 'x64'; - chromeXml.getUrl('85.0.4183.87').then((binaryUrl) => { + return chromeXml.getUrl('85.0.4183.87').then((binaryUrl) => { expect(binaryUrl.url).toContain('85.0.4183.87/chromedriver_win32.zip'); - done(); }); }); - it('should get the 87.0.4280.88, 64-bit, m1 version (arch = arm64)', (done) => { + it('should get the 87.0.4280.88, 64-bit, m1 version (arch = arm64)', () => { let chromeXml = new ChromeXml(); chromeXml.out_dir = out_dir; chromeXml.ostype = 'Darwin'; chromeXml.osarch = 'arm64'; - chromeXml.getUrl('87.0.4280.88').then((binaryUrl) => { + return chromeXml.getUrl('87.0.4280.88').then((binaryUrl) => { expect(binaryUrl.url).toContain('87.0.4280.88/chromedriver_mac64_m1.zip'); - done(); }); }); }); diff --git a/spec/binaries/config_source_spec.ts b/spec/binaries/config_source_spec.ts index af51af3b..54c8cf23 100644 --- a/spec/binaries/config_source_spec.ts +++ b/spec/binaries/config_source_spec.ts @@ -44,13 +44,9 @@ describe('config', () => { 0.01/foobar.zip - `; - }); - spyOn(fs, 'statSync').and.callFake(() => { - return { - mtime: 0 - } + ` as any; }); + spyOn(fs, 'statSync').and.callFake(() => {return {mtime: 0} as any}); Config.runCommand = 'start'; let xmlConfig = new XMLConfig('xml', 'url'); xmlConfig.testGetXml() @@ -66,13 +62,9 @@ describe('config', () => { it('on udpate: should check the timestamp, invaidate cache, and try to make a web request', done => { spyOn(fs, 'readFileSync').and.callFake(() => { - return 'foobar'; - }); - spyOn(fs, 'statSync').and.callFake(() => { - return { - mtime: 0 - } + return 'foobar' as any; }); + spyOn(fs, 'statSync').and.callFake(() => {return {mtime: 0} as any}); Config.runCommand = 'update'; let xmlConfig = new XMLConfig('xml', 'url'); xmlConfig.testGetXml() @@ -88,7 +80,7 @@ describe('config', () => { it('on update: if the size of the file is zero, invalidate the cache', done => { spyOn(fs, 'statSync').and.callFake(() => { - return {size: 0}; + return {size: 0} as any; }); Config.runCommand = 'update'; let xmlConfig = new XMLConfig('json', 'url'); @@ -107,12 +99,10 @@ describe('config', () => { describe('github json', () => { it('on start: should read the json file and not check the timestamp', done => { spyOn(fs, 'readFileSync').and.callFake(() => { - return '{ "foo": "bar" }'; + return '{ "foo": "bar" }' as any; }); spyOn(fs, 'statSync').and.callFake(() => { - return { - mtime: 0 - } + return {mtime: 0} as any; }); Config.runCommand = 'start'; let jsonConfig = new JSONConfig('json', 'url'); @@ -129,12 +119,10 @@ describe('config', () => { it('on udpate: should check the timestamp, invaidate cache, and try to make a web request', done => { spyOn(fs, 'readFileSync').and.callFake(() => { - return 'foobar'; + return 'foobar' as any; }); spyOn(fs, 'statSync').and.callFake(() => { - return { - mtime: 0 - } + return {mtime: 0} as any; }); Config.runCommand = 'update'; let jsonConfig = new JSONConfig('json', 'url'); @@ -151,7 +139,7 @@ describe('config', () => { it('on update: if the size of the file is zero, invalidate the cache', done => { spyOn(fs, 'statSync').and.callFake(() => { - return {size: 0}; + return {size: 0} as any; }); Config.runCommand = 'update'; let jsonConfig = new JSONConfig('json', 'url'); diff --git a/spec/cli/programs_spec.ts b/spec/cli/programs_spec.ts index dffb5fdb..6dc439da 100644 --- a/spec/cli/programs_spec.ts +++ b/spec/cli/programs_spec.ts @@ -53,7 +53,7 @@ describe('program', () => { expect(options['fooNumber3'].getNumber()).toEqual(30); }; program.action(callbackTest); - program.run(json); + return program.run(json, true); }); it('should be able to extract the mixed type and get the right type', () => { @@ -76,6 +76,6 @@ describe('program', () => { expect(options['fooNumber3'].getNumber()).toEqual(null); }; program.action(callbackTest); - program.run(json); + return program.run(json, true); }); }); diff --git a/spec/cmds/status_spec.ts b/spec/cmds/status_spec.ts index ffd28b3a..a9157ce1 100644 --- a/spec/cmds/status_spec.ts +++ b/spec/cmds/status_spec.ts @@ -16,23 +16,17 @@ describe('status', () => { // chrome 2.20[last], 2.24 // geckodriver {{config version}} [last] // standalone 2.24 [last], {{config version}} - beforeAll((done) => { + beforeAll(() => { argv = { '_': ['update'], 'gecko': 'false', 'versions': {'chrome': '2.24', 'standalone': '2.44.0'}, 'out_dir': tmpDir }; - program.run(JSON.parse(JSON.stringify(argv))) - .then(() => { - argv['versions']['chrome'] = '2.20'; - program.run(JSON.parse(JSON.stringify(argv))).then(() => { - done(); - }); - }) - .catch(err => { - done.fail(); - }); + return program.run(JSON.parse(JSON.stringify(argv)), true).then(() => { + argv['versions']['chrome'] = '2.20'; + return program.run(JSON.parse(JSON.stringify(argv)), true); + }); }); it('should show the version number of the default and latest versions', () => { diff --git a/spec/cmds/update_spec.ts b/spec/cmds/update_spec.ts index 90e8a7f5..ef92dce1 100644 --- a/spec/cmds/update_spec.ts +++ b/spec/cmds/update_spec.ts @@ -33,7 +33,7 @@ describe('update', () => { clearBrowserFile(); }); - it('should create a file for chrome', (done) => { + it('should create a file for chrome', () => { Config.osType_ = 'Linux'; Config.osArch_ = 'x64'; argv = { @@ -43,22 +43,18 @@ describe('update', () => { 'gecko': false, 'out_dir': tmpDir }; - program.run(JSON.parse(JSON.stringify(argv))) - .then(() => { - let updateConfig = - fs.readFileSync(path.resolve(tmpDir, 'update-config.json')).toString(); - let updateObj = JSON.parse(updateConfig); - expect(updateObj['chrome']['last']).toContain('chromedriver_2.20'); - expect(updateObj['chrome']['all'].length).toEqual(1); - expect(updateObj['chrome']['last']).toEqual(updateObj['chrome']['all'][0]); - expect(updateObj['standalone']).toBeUndefined(); - expect(updateObj['ie']).toBeUndefined(); - done(); - }) - .catch((err: Error) => {done.fail()}); + return program.run(JSON.parse(JSON.stringify(argv)), true).then(() => { + let updateConfig = fs.readFileSync(path.resolve(tmpDir, 'update-config.json')).toString(); + let updateObj = JSON.parse(updateConfig); + expect(updateObj['chrome']['last']).toContain('chromedriver_2.20'); + expect(updateObj['chrome']['all'].length).toEqual(1); + expect(updateObj['chrome']['last']).toEqual(updateObj['chrome']['all'][0]); + expect(updateObj['standalone']).toBeUndefined(); + expect(updateObj['ie']).toBeUndefined(); + }); }); - it('should create a file for standalone', (done) => { + it('should create a file for standalone', () => { Config.osType_ = 'Linux'; Config.osArch_ = 'x64'; argv = { @@ -68,19 +64,15 @@ describe('update', () => { 'gecko': false, 'out_dir': tmpDir }; - program.run(JSON.parse(JSON.stringify(argv))) - .then(() => { - let updateConfig = - fs.readFileSync(path.resolve(tmpDir, 'update-config.json')).toString(); - let updateObj = JSON.parse(updateConfig); - expect(updateObj['standalone']['last']).toContain('standalone-2.53.1.jar'); - expect(updateObj['standalone']['all'].length).toEqual(1); - expect(updateObj['standalone']['last']).toEqual(updateObj['standalone']['all'][0]); - expect(updateObj['chrome']).toBeUndefined(); - expect(updateObj['ie']).toBeUndefined(); - done(); - }) - .catch((err: Error) => {done.fail()}); + return program.run(JSON.parse(JSON.stringify(argv)), true).then(() => { + const updateConfig = fs.readFileSync(path.resolve(tmpDir, 'update-config.json')).toString(); + const updateObj = JSON.parse(updateConfig); + expect(updateObj['standalone']['last']).toContain('standalone-2.53.1.jar'); + expect(updateObj['standalone']['all'].length).toEqual(1); + expect(updateObj['standalone']['last']).toEqual(updateObj['standalone']['all'][0]); + expect(updateObj['chrome']).toBeUndefined(); + expect(updateObj['ie']).toBeUndefined(); + }); }); // TODO(cnishina): Create a test for Windows for IE driver. This will require rewriting