diff --git a/lib/cli/index.ts b/lib/cli/index.ts index 50408e33..54c1b917 100644 --- a/lib/cli/index.ts +++ b/lib/cli/index.ts @@ -5,14 +5,16 @@ import * as start from '../cmds/start'; import * as status from '../cmds/status'; import * as update from '../cmds/update'; -const CHROME = 'chrome'; -const chromeOption: yargs.Options = { +const CHROMEDRIVER_ALIAS = 'chrome'; +const CHROMEDRIVER = 'chromedriver'; +const chromedriverOption: yargs.Options = { describe: 'Install or update chromedriver.', default: true, type: 'boolean' }; -const CHROME_LOGS = 'chrome_logs'; -const chromeLogsOption: yargs.Options = { +const CHROMEDRIVER_LOGS_ALIAS = 'chrome_logs'; +const CHROMEDRIVER_LOGS = 'chromedriver_logs'; +const chromedriverLogsOption: yargs.Options = { describe: 'File path to chrome logs.', type: 'string' }; @@ -30,8 +32,9 @@ const edgeOption: yargs.Options = { '"C:\Program Files (x86)\Microsoft Web Driver\MirosoftWebDriver.exe"', type: 'string' }; -const GECKO = 'gecko'; -const geckoOption: yargs.Options = { +const GECKODRIVER_ALIAS = 'gecko'; +const GECKODRIVER = 'geckodriver'; +const geckodriverOption: yargs.Options = { describe: 'Install or update geckodriver.', default: true, type: 'boolean' @@ -41,8 +44,9 @@ const githubTokenOption: yargs.Options = { describe: 'Use a GitHub token to prevent rate limit issues.', type: 'string' }; +const IEDRIVER_ALIAS = 'ie'; const IEDRIVER = 'iedriver'; -const ieOption: yargs.Options = { +const iedriverOption: yargs.Options = { describe: 'Install or update ie driver.', default: false, type: 'boolean' @@ -58,6 +62,31 @@ const logLevelOption: yargs.Options = { default: 'info', type: 'string' }; +const MAX_VERSIONS_CHROMEDRIVER_ALIAS = 'max_versions.chrome'; +const MAX_VERSIONS_CHROMEDRIVER = 'max_versions.chromedriver'; +const maxVersionsChromedriverOption: yargs.Options = { + describe: 'The chromedriver max version used only for update.', + type: 'string' +}; +const MAX_VERSIONS_GECKODRIVER_ALIAS = 'max_versions.gecko'; +const MAX_VERSIONS_GECKODRIVER = 'max_versions.geckodriver'; +const maxVersionsGeckodriverOption: yargs.Options = { + describe: 'The geckodriver max version used only for update.', + type: 'string' +}; +const MAX_VERSIONS_IEDRIVER_ALIAS = 'max_versions.ie'; +const MAX_VERSIONS_IEDRIVER = 'max_versions.iedriver'; +const maxVersionsIedriverOption: yargs.Options = { + describe: 'The ie driver max version used only for update.', + type: 'string' +}; +const MAX_VERSIONS_SELENIUM_ALIAS = 'max_versions.standalone'; +const MAX_VERSIONS_SELENIUM = 'max_versions.selenium'; +const maxVersionsSeleniumOption: yargs.Options = { + describe: 'The selenium server standalone max version used only for update.', + type: 'string' +}; + const OUT_DIR = 'out_dir'; const outDirOption: yargs.Options = { describe: 'Location of output.', @@ -68,34 +97,40 @@ const proxyOption: yargs.Options = { describe: 'Use a proxy server to download files.', type: 'string' }; -const STANDALONE = 'standalone'; -const standaloneOption: yargs.Options = { +const SELENIUM_ALIAS = 'standalone'; +const SELENIUM = 'selenium'; +const seleniumOption: yargs.Options = { describe: 'Install or update selenium server standalone.', default: true, type: 'boolean' }; -const STANDALONE_NODE = 'standalone_node'; -const standaloneNodeOption: yargs.Options = { +const SELENIUM_NODE_ALIAS = 'standalone_node'; +const SELENIUM_NODE = 'selenium_node'; +const seleniumNodeOption: yargs.Options = { describe: 'Start the selenium server standalone with role set to "node".', type: 'boolean' }; -const VERSIONS_CHROME = 'versions.chrome'; -const versionsChromeOption: yargs.Options = { +const VERSIONS_CHROMEDRIVER_ALIAS = 'versions.chrome'; +const VERSIONS_CHROMEDRIVER = 'versions.chromedriver'; +const versionsChromedriverOption: yargs.Options = { describe: 'The chromedriver version.', type: 'string' }; -const VERSIONS_GECKO = 'versions.gecko'; -const versionsGeckoOption: yargs.Options = { +const VERSIONS_GECKODRIVER_ALIAS = 'versions.gecko'; +const VERSIONS_GECKODRIVER = 'versions.geckodriver'; +const versionsGeckodriverOption: yargs.Options = { describe: 'The geckodriver version.', type: 'string' }; -const VERSIONS_IE = 'versions.ie'; -const versionsIeOption: yargs.Options = { +const VERSIONS_IEDRIVER_ALIAS = 'versions.ie'; +const VERSIONS_IEDRIVER = 'versions.iedriver'; +const versionsIedriverOption: yargs.Options = { describe: 'The ie driver version.', type: 'string' }; -const VERSIONS_STANDALONE = 'versions.standalone'; -const versionsStandaloneOption: yargs.Options = { +const VERSIONS_SELENIUM_ALIAS = 'versions.standalone'; +const VERSIONS_SELENIUM = 'versions.selenium'; +const versionsSeleniumOption: yargs.Options = { describe: 'The selenium server standalone version.', type: 'string' }; @@ -122,20 +157,31 @@ yargs .command( 'start', 'Start up the selenium server.', (yargs: yargs.Argv) => { - return yargs.option(CHROME, chromeOption) - .option(CHROME_LOGS, chromeLogsOption) + return yargs + .option(CHROMEDRIVER, chromedriverOption) + .alias(CHROMEDRIVER_ALIAS, CHROMEDRIVER) + .option(CHROMEDRIVER_LOGS, chromedriverLogsOption) + .alias(CHROMEDRIVER_LOGS_ALIAS, CHROMEDRIVER_LOGS) .option(DETACH, detachOption) .option(EDGE, edgeOption) - .option(GECKO, geckoOption) - .option(IEDRIVER, ieOption) + .option(GECKODRIVER, geckodriverOption) + .alias(GECKODRIVER_ALIAS, GECKODRIVER) + .option(IEDRIVER, iedriverOption) + .alias(IEDRIVER_ALIAS, IEDRIVER) .option(LOG_LEVEL, logLevelOption) .option(OUT_DIR, outDirOption) - .option(STANDALONE, standaloneOption) - .option(STANDALONE_NODE, standaloneNodeOption) - .option(VERSIONS_CHROME, versionsChromeOption) - .option(VERSIONS_GECKO, versionsGeckoOption) - .option(VERSIONS_IE, versionsIeOption) - .option(VERSIONS_STANDALONE, versionsStandaloneOption); + .option(SELENIUM, seleniumOption) + .alias(SELENIUM_ALIAS, SELENIUM) + .option(SELENIUM_NODE, seleniumNodeOption) + .alias(SELENIUM_NODE_ALIAS, SELENIUM_NODE) + .option(VERSIONS_CHROMEDRIVER, versionsChromedriverOption) + .alias(VERSIONS_CHROMEDRIVER_ALIAS, VERSIONS_CHROMEDRIVER) + .option(VERSIONS_GECKODRIVER, versionsGeckodriverOption) + .alias(VERSIONS_GECKODRIVER_ALIAS, VERSIONS_GECKODRIVER) + .option(VERSIONS_IEDRIVER, versionsIedriverOption) + .alias(VERSIONS_IEDRIVER_ALIAS, VERSIONS_IEDRIVER) + .option(VERSIONS_SELENIUM, versionsSeleniumOption) + .alias(VERSIONS_SELENIUM_ALIAS, VERSIONS_SELENIUM); }, (argv: yargs.Arguments) => { start.handler(argv); @@ -153,19 +199,34 @@ yargs 'update', 'Install or update selected binaries.', (yargs: yargs.Argv) => { return yargs.option(OUT_DIR, outDirOption) - .option(CHROME, chromeOption) - .option(GECKO, geckoOption) + .option(CHROMEDRIVER, chromedriverOption) + .alias(CHROMEDRIVER_ALIAS, CHROMEDRIVER) + .option(GECKODRIVER, geckodriverOption) + .alias(GECKODRIVER_ALIAS, GECKODRIVER) .option(GITHUB_TOKEN, githubTokenOption) - .option(IEDRIVER, ieOption) + .option(IEDRIVER, iedriverOption) + .alias(IEDRIVER_ALIAS, IEDRIVER) .option(IGNORE_SSL, ignoreSSLOption) .option(LOG_LEVEL, logLevelOption) + .option(MAX_VERSIONS_CHROMEDRIVER, maxVersionsChromedriverOption) + .alias(MAX_VERSIONS_CHROMEDRIVER_ALIAS, MAX_VERSIONS_CHROMEDRIVER) + .option(MAX_VERSIONS_GECKODRIVER, maxVersionsGeckodriverOption) + .alias(MAX_VERSIONS_GECKODRIVER_ALIAS, MAX_VERSIONS_GECKODRIVER) + .option(MAX_VERSIONS_IEDRIVER, maxVersionsIedriverOption) + .alias(MAX_VERSIONS_IEDRIVER_ALIAS, MAX_VERSIONS_IEDRIVER) + .option(MAX_VERSIONS_SELENIUM, maxVersionsSeleniumOption) .option(OUT_DIR, outDirOption) .option(PROXY, proxyOption) - .option(STANDALONE, standaloneOption) - .option(VERSIONS_CHROME, versionsChromeOption) - .option(VERSIONS_GECKO, versionsGeckoOption) - .option(VERSIONS_IE, versionsIeOption) - .option(VERSIONS_STANDALONE, versionsStandaloneOption); + .option(SELENIUM, seleniumOption) + .alias(SELENIUM_ALIAS, SELENIUM) + .option(VERSIONS_CHROMEDRIVER, versionsChromedriverOption) + .alias(VERSIONS_CHROMEDRIVER_ALIAS, VERSIONS_CHROMEDRIVER) + .option(VERSIONS_GECKODRIVER, versionsGeckodriverOption) + .alias(VERSIONS_GECKODRIVER_ALIAS, VERSIONS_GECKODRIVER) + .option(VERSIONS_IEDRIVER, versionsIedriverOption) + .alias(VERSIONS_IEDRIVER_ALIAS, VERSIONS_IEDRIVER) + .option(VERSIONS_SELENIUM, versionsSeleniumOption) + .alias(VERSIONS_SELENIUM_ALIAS, VERSIONS_SELENIUM); }, (argv: yargs.Arguments) => { update.handler(argv); diff --git a/lib/cmds/options.ts b/lib/cmds/options.ts index 0b8848ee..e2742957 100644 --- a/lib/cmds/options.ts +++ b/lib/cmds/options.ts @@ -16,14 +16,18 @@ export interface Options { githubToken?: string; } +export type BrowserDriverName = 'chromedriver'|'geckodriver'|'iedriver'; + /** * Contains information about a browser driver. */ export interface BrowserDriver { // The name of the browser driver. - name?: 'chromedriver'|'geckodriver'|'iedriver'; + name?: BrowserDriverName; // The version which does not have to follow semver. version?: string; + // A max version that either fully or partially matches the version. + maxVersion?: string; } /** @@ -35,6 +39,8 @@ export interface Server { name?: 'selenium'; // The version which does not have to follow semver. version?: string; + // A max version that either fully or partially matches the version. + maxVersion?: string; // Run as role = node option. runAsNode?: boolean; // The relative or full path to the chrome logs file. diff --git a/lib/cmds/update.ts b/lib/cmds/update.ts index 3853c828..b7bd95c8 100644 --- a/lib/cmds/update.ts +++ b/lib/cmds/update.ts @@ -11,7 +11,7 @@ const log = loglevel.getLogger('webdriver-manager'); * @param argv The argv from yargs. */ export async function handler(argv: yargs.Arguments) { - log.setLevel(argv.log_level); + log.setLevel(argv['log_level']); const options = convertArgs2Options(argv); await update(options); } @@ -35,12 +35,14 @@ export function updateBinary(optionsBinary: OptionsBinary): Promise { const promises = []; if (optionsBinary.browserDrivers) { for (const provider of optionsBinary.browserDrivers) { - promises.push(provider.binary.updateBinary(provider.version)); + promises.push(provider.binary.updateBinary(provider.version, + provider.maxVersion)); } } if (optionsBinary.server && optionsBinary.server.binary) { promises.push( - optionsBinary.server.binary.updateBinary(optionsBinary.server.version)); + optionsBinary.server.binary.updateBinary(optionsBinary.server.version, + optionsBinary.server.maxVersion)); } return Promise.all(promises); } \ No newline at end of file diff --git a/lib/cmds/utils.spec-unit.ts b/lib/cmds/utils.spec-unit.ts index 96ea951e..a30ef832 100644 --- a/lib/cmds/utils.spec-unit.ts +++ b/lib/cmds/utils.spec-unit.ts @@ -6,7 +6,7 @@ describe('utils', () => { const argv = { _: ['foobar'], proxy: 'http://some.proxy.com', - versions: {gecko: '0.16.0', chrome: '2.20'}, + versions: {geckodriver: '0.16.0', chromedriver: '2.20'}, out_dir: 'foobar_download', ignore_ssl: false, '$0': 'bin\\webdriver-manager' @@ -14,22 +14,8 @@ describe('utils', () => { const options = convertArgs2AllOptions(argv); expect(options.browserDrivers).toBeTruthy(); expect(options.browserDrivers.length).toBe(3); - for (const provider of options.browserDrivers) { - if (provider.name === 'geckodriver') { - expect(provider.version).toBe('0.16.0'); - } - if (provider.name === 'chromedriver') { - expect(provider.version).toBe('2.20'); - } - if (provider.name === 'iedriver') { - expect(provider.version).toBeUndefined(); - } - } expect(options.server).toBeTruthy(); expect(options.server.name).toBe('selenium'); - expect(options.server.version).toBeUndefined(); - expect(options.proxy).toBe('http://some.proxy.com'); - expect(options.ignoreSSL).toBeFalsy(); expect(options.outDir).toBe('foobar_download'); }); }); @@ -38,10 +24,10 @@ describe('utils', () => { it('should create the default providers', () => { const argv = { _: ['foobar'], - chrome: true, - gecko: true, - standalone: true, - versions: {gecko: '0.16.0', chrome: '2.20'}, + chromedriver: true, + geckodriver: true, + selenium: true, + versions: {geckodriver: '0.16.0', chromedriver: '2.20'}, out_dir: 'foobar_download', '$0': 'bin\\webdriver-manager' }; diff --git a/lib/cmds/utils.ts b/lib/cmds/utils.ts index 47c4b304..c6f81f0e 100644 --- a/lib/cmds/utils.ts +++ b/lib/cmds/utils.ts @@ -5,7 +5,7 @@ import {IEDriver} from '../provider/iedriver'; import {ProviderConfig} from '../provider/provider'; import {SeleniumServer, SeleniumServerProviderConfig} from '../provider/selenium_server'; -import {Options} from './options'; +import {BrowserDriver, BrowserDriverName, Options} from './options'; import {OptionsBinary} from './options_binary'; /** @@ -48,41 +48,25 @@ export function addOptionsBinary(options: Options): OptionsBinary { } /** - * Create the options with all providers. Used for clean and status commands. + * For the clean and status commands ONLY. + * Create the options with all providers. * @param argv */ export function convertArgs2AllOptions(argv: yargs.Arguments): Options { - let versionsChrome, versionsGecko, versionsIe, versionsStandalone = undefined; - if (argv.versions) { - versionsChrome = argv.versions.chrome as string; - versionsGecko = argv.versions.gecko as string; - versionsIe = argv.versions.ie as string; - versionsStandalone = argv.versions.standalone as string; - } return { browserDrivers: [ - {name: 'chromedriver', version: versionsChrome}, - {name: 'geckodriver', version: versionsGecko}, - {name: 'iedriver', version: versionsIe} + {name: 'chromedriver'}, + {name: 'geckodriver'}, + {name: 'iedriver'} ], - server: { - name: 'selenium', - version: versionsStandalone, - runAsNode: argv.standalone_node as boolean, - runAsDetach: argv.detach as boolean, - chromeLogs: argv.chrome_logs as string, - edge: argv.edge as string, - }, - ignoreSSL: argv.ignore_ssl as boolean, - outDir: argv.out_dir as string, - proxy: argv.proxy as string, - githubToken: argv.github_token as string, + server: {name: 'selenium'}, + outDir: argv['out_dir'] as string }; } /** - * Create the options with providers depending on argv's. Used for update and - * start commands. + * For the update and start commands ONLY. + * Create the options with providers depending on argv's. * @param argv */ export function convertArgs2Options(argv: yargs.Arguments): Options { @@ -95,31 +79,37 @@ export function convertArgs2Options(argv: yargs.Arguments): Options { githubToken: argv.github_token as string, }; - let versionsChrome, versionsGecko, versionsIe, versionsStandalone = undefined; - if (argv.versions) { - versionsChrome = argv.versions.chrome as string; - versionsGecko = argv.versions.gecko as string; - versionsIe = argv.versions.ie as string; - versionsStandalone = argv.versions.standalone as string; - } - if (argv.chrome as boolean) { - options.browserDrivers.push( - {name: 'chromedriver', version: versionsChrome}); + if (argv['chromedriver'] as boolean) { + setVersions('chromedriver', argv, options.browserDrivers); } - if (argv.gecko as boolean) { - options.browserDrivers.push({name: 'geckodriver', version: versionsGecko}); + if (argv['geckodriver'] as boolean) { + setVersions('geckodriver', argv, options.browserDrivers); } - if (argv.iedriver as boolean) { - options.browserDrivers.push({name: 'iedriver', version: versionsIe}); + if (argv['iedriver'] as boolean) { + setVersions('iedriver', argv, options.browserDrivers); } - if (argv.standalone as boolean) { + if (argv['selenium']) { options.server = {}; options.server.name = 'selenium'; options.server.runAsNode = argv.standalone_node as boolean; options.server.runAsDetach = argv.detach as boolean; - options.server.version = versionsStandalone; + options.server.version = argv['versions'] && argv['versions']['selenium'] ? + argv['versions']['selenium'] as string : undefined; + options.server.maxVersion = argv['max_versions'] + && argv['max_versions']['selenium'] ? + argv['versions']['selenium'] as string : undefined; options.server.chromeLogs = argv.chrome_logs as string; options.server.edge = argv.edge as string; } return options; +} + +function setVersions(name: BrowserDriverName, + argv: yargs.Arguments, browserDrivers: BrowserDriver[]): BrowserDriver[] { + const version = argv['versions'] && argv['versions'][name] ? + argv['versions'][name] as string : undefined; + const maxVersion = argv['max_versions'] && argv['max_versions'][name] ? + argv['max_versions'][name] as string : undefined; + browserDrivers.push({name, version, maxVersion}); + return browserDrivers; } \ No newline at end of file diff --git a/lib/provider/chromedriver.ts b/lib/provider/chromedriver.ts index 4f69d87b..269e1e67 100644 --- a/lib/provider/chromedriver.ts +++ b/lib/provider/chromedriver.ts @@ -18,6 +18,8 @@ export class ChromeDriver implements ProviderInterface { proxy: string = null; requestUrl = 'https://chromedriver.storage.googleapis.com/'; seleniumFlag = '-Dwebdriver.chrome.driver'; + version: string = null; + maxVersion: string = null; constructor(providerConfig?: ProviderConfig) { if (providerConfig) { @@ -43,6 +45,12 @@ export class ChromeDriver implements ProviderInterface { if (providerConfig.requestUrl) { this.requestUrl = providerConfig.requestUrl; } + if (providerConfig.version) { + this.version = providerConfig.version; + } + if (providerConfig.maxVersion) { + this.maxVersion = providerConfig.maxVersion; + } } } @@ -50,8 +58,15 @@ export class ChromeDriver implements ProviderInterface { * Should update the cache and download, find the version to download, * then download that binary. * @param version Optional to provide the version number or latest. + * @param maxVersion Optional to provide the max version. */ - async updateBinary(version?: string): Promise { + async updateBinary(version?: string, maxVersion?: string): Promise { + if (!version) { + version = this.version; + } + if (!maxVersion) { + maxVersion = this.maxVersion; + } await updateXml(this.requestUrl, { fileName: path.resolve(this.outDir, this.cacheFileName), ignoreSSL: this.ignoreSSL, @@ -63,7 +78,7 @@ export class ChromeDriver implements ProviderInterface { semanticVersionParser); const versionObj = getVersion( versionList, osHelper(this.osType, this.osArch), - formatVersion(version)); + formatVersion(version), maxVersion); const chromeDriverUrl = this.requestUrl + versionObj.url; const chromeDriverZip = path.resolve(this.outDir, versionObj.name); diff --git a/lib/provider/geckodriver.ts b/lib/provider/geckodriver.ts index d4bbf8c3..89fe64b4 100644 --- a/lib/provider/geckodriver.ts +++ b/lib/provider/geckodriver.ts @@ -23,6 +23,8 @@ export class GeckoDriver implements ProviderInterface { proxy: string = null; requestUrl = 'https://api.github.com/repos/mozilla/geckodriver/releases'; seleniumFlag = '-Dwebdriver.gecko.driver'; + version: string = null; + maxVersion: string = null; constructor(providerConfig?: GeckoDriverProviderConfig) { if (providerConfig) { @@ -51,6 +53,12 @@ export class GeckoDriver implements ProviderInterface { if (providerConfig.oauthToken) { this.oauthToken = providerConfig.oauthToken; } + if (providerConfig.version) { + this.version = providerConfig.version; + } + if (providerConfig.maxVersion) { + this.maxVersion = providerConfig.maxVersion; + } } } @@ -58,8 +66,15 @@ export class GeckoDriver implements ProviderInterface { * Should update the cache and download, find the version to download, * then download that binary. * @param version Optional to provide the version number or latest. + * @param maxVersion Optional to provide the max version. */ - async updateBinary(version?: string): Promise { + async updateBinary(version?: string, maxVersion?: string): Promise { + if (!version) { + version = this.version; + } + if (!maxVersion) { + maxVersion = this.maxVersion; + } await updateJson( this.requestUrl, { fileName: path.resolve(this.outDir, this.cacheFileName), @@ -71,7 +86,8 @@ export class GeckoDriver implements ProviderInterface { const versionList = convertJsonToVersionList(path.resolve(this.outDir, this.cacheFileName)); const versionObj = - getVersion(versionList, osHelper(this.osType, this.osArch), version); + getVersion(versionList, osHelper(this.osType, this.osArch), version, + maxVersion); const geckoDriverUrl = versionObj.url; const geckoDriverCompressed = path.resolve(this.outDir, versionObj.name); diff --git a/lib/provider/iedriver.ts b/lib/provider/iedriver.ts index 2af32b20..7ffcfb81 100644 --- a/lib/provider/iedriver.ts +++ b/lib/provider/iedriver.ts @@ -18,6 +18,8 @@ export class IEDriver implements ProviderInterface { proxy: string = null; requestUrl = 'https://selenium-release.storage.googleapis.com/'; seleniumFlag = '-Dwebdriver.ie.driver'; + version: string = null; + maxVersion: string = null; constructor(providerConfig?: ProviderConfig) { if (providerConfig) { @@ -43,6 +45,12 @@ export class IEDriver implements ProviderInterface { if (providerConfig.requestUrl) { this.requestUrl = providerConfig.requestUrl; } + if (providerConfig.version) { + this.version = providerConfig.version; + } + if (providerConfig.maxVersion) { + this.maxVersion = providerConfig.maxVersion; + } } } @@ -50,8 +58,15 @@ export class IEDriver implements ProviderInterface { * Should update the cache and download, find the version to download, * then download that binary. * @param version Optional to provide the version number or latest. + * @param maxVersion Optional to provide the max version. */ - async updateBinary(version?: string): Promise { + async updateBinary(version?: string, maxVersion?: string): Promise { + if (!version) { + version = this.version; + } + if (!maxVersion) { + maxVersion = this.maxVersion; + } await updateXml(this.requestUrl, { fileName: path.resolve(this.outDir, this.cacheFileName), ignoreSSL: this.ignoreSSL, @@ -61,7 +76,8 @@ export class IEDriver implements ProviderInterface { path.resolve(this.outDir, this.cacheFileName), '.zip', versionParser, semanticVersionParser); const versionObj = - getVersion(versionList, osHelper(this.osType, this.osArch), version); + getVersion(versionList, osHelper(this.osType, this.osArch), version, + maxVersion); const chromeDriverUrl = this.requestUrl + versionObj.url; const chromeDriverZip = path.resolve(this.outDir, versionObj.name); diff --git a/lib/provider/provider.ts b/lib/provider/provider.ts index 33779484..375268a4 100644 --- a/lib/provider/provider.ts +++ b/lib/provider/provider.ts @@ -11,9 +11,11 @@ export interface ProviderInterface { cleanFiles?: () => string; getBinaryPath?: (version?: string) => string | null; getStatus?: () => string | null; - updateBinary: (version?: string) => Promise; + updateBinary: (version?: string, maxVersion?: string) => Promise; seleniumFlag?: string; osType?: string; + version?: string; + maxVersion?: string; } /** @@ -41,6 +43,10 @@ export interface ProviderConfig { proxy?: string; // Set the requests to ignore SSL (optional). ignoreSSL?: boolean; + // The version number (optional). + version?: string; + // The max version number. Partially match is okay (optional). + maxVersion?: string; // Catch all for other things. [key: string]: string|boolean|number; } diff --git a/lib/provider/selenium_server.ts b/lib/provider/selenium_server.ts index 0fa2f783..de94f8e3 100644 --- a/lib/provider/selenium_server.ts +++ b/lib/provider/selenium_server.ts @@ -32,6 +32,8 @@ export class SeleniumServer implements ProviderInterface { seleniumProcess: childProcess.ChildProcess; runAsNode = false; runAsDetach = false; + version: string = null; + maxVersion: string = null; constructor(providerConfig?: SeleniumServerProviderConfig) { if (providerConfig) { @@ -67,6 +69,12 @@ export class SeleniumServer implements ProviderInterface { this.runAsDetach = providerConfig.runAsDetach; this.runAsNode = true; } + if (providerConfig.version) { + this.version = providerConfig.version; + } + if (providerConfig.maxVersion) { + this.maxVersion = providerConfig.maxVersion; + } } } @@ -74,8 +82,15 @@ export class SeleniumServer implements ProviderInterface { * Should update the cache and download, find the version to download, * then download that binary. * @param version Optional to provide the version number or latest. + * @param maxVersion Optional to provide the max version. */ - async updateBinary(version?: string): Promise { + async updateBinary(version?: string, maxVersion?: string): Promise { + if (!version) { + version = this.version; + } + if (!maxVersion) { + maxVersion = this.maxVersion; + } await updateXml(this.requestUrl, { fileName: path.resolve(this.outDir, this.cacheFileName), ignoreSSL: this.ignoreSSL, @@ -84,7 +99,7 @@ export class SeleniumServer implements ProviderInterface { const versionList = convertXmlToVersionList( path.resolve(this.outDir, this.cacheFileName), 'selenium-server-standalone', versionParser, semanticVersionParser); - const versionObj = getVersion(versionList, '', version); + const versionObj = getVersion(versionList, '', version, maxVersion); const seleniumServerUrl = this.requestUrl + versionObj.url; const seleniumServerJar = path.resolve(this.outDir, versionObj.name); diff --git a/lib/provider/utils/version_list.ts b/lib/provider/utils/version_list.ts index b869e62a..942e9123 100644 --- a/lib/provider/utils/version_list.ts +++ b/lib/provider/utils/version_list.ts @@ -39,12 +39,13 @@ export interface VersionObj { * @param versionList The version list object. * @param osMatch The OS name and architecture. * @param version Optional field for the semver version number or latest. - * * @returns Either a VersionObj or null. + * @param maxVersion Optional field to find the max version matching a value. + * @returns Either a VersionObj or null. */ export function getVersion( - versionList: VersionList, osMatch: string, version?: string): VersionObj| - null { - const versionObjs = getVersionObjs(versionList, version); + versionList: VersionList, osMatch: string, version?: string, + maxVersion?: string): VersionObj| null { + const versionObjs = getVersionObjs(versionList, version, maxVersion); return getVersionObj(versionObjs, osMatch); } @@ -55,21 +56,37 @@ export function getVersion( * @returns The object with paritial urls associated with the binary size. */ export function getVersionObjs( - versionList: VersionList, version?: string): {[key: string]: VersionObj} { + versionList: VersionList, version?: string, maxVersion?: string + ): {[key: string]: VersionObj} { if (version && version !== 'latest') { + // Exact matches are easy. return versionList[version]; } else { - let latestVersion = null; + // Either we want the latest or we want to match with the max version. + let retVersion = null; for (const versionKey of Object.keys(versionList)) { - if (!latestVersion) { - latestVersion = versionKey; + if (maxVersion) { + // Only find the greatest of the max version. + // An example: + // maxVersion = 0.1 might match 0.13, 0.1, 0.14, result is 0.14. + // if the user wants 0.1., then the maxVersion should be "0.1." + if (versionKey.startsWith(maxVersion)) { + if (!retVersion) { + retVersion = versionKey; + } else if (semver.gt(versionKey, retVersion)) { + retVersion = versionKey; + } + } } else { - if (semver.gt(versionKey, latestVersion)) { - latestVersion = versionKey; + // Always find the latest. + if (!retVersion) { + retVersion = versionKey; + } else if (semver.gt(versionKey, retVersion)) { + retVersion = versionKey; } } } - return versionList[latestVersion]; + return versionList[retVersion]; } }