From c6a5ad943df48cf8a75affdb5714bf71c5b5fe7f Mon Sep 17 00:00:00 2001 From: Craig Nishina Date: Tue, 3 Jan 2017 14:40:48 -0800 Subject: [PATCH] chore(cli): throw errors on unknown flags clsoes #3216 --- lib/cli.ts | 115 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 31 deletions(-) diff --git a/lib/cli.ts b/lib/cli.ts index c3eb2cde4..0a738d76d 100644 --- a/lib/cli.ts +++ b/lib/cli.ts @@ -31,42 +31,65 @@ process.argv.slice(2).forEach(function(arg: string) { } }); +export interface Option { + key: string; + value?: string; +} + +let describes: Option[] = [ + {key: 'help', value: 'Print Protractor help menu'}, + {key: 'version', value: 'Print Protractor version'}, + {key: 'browser', value: 'Browsername, e.g. chrome or firefox'}, + {key: 'seleniumAddress', value: 'A running selenium address to use'}, + {key: 'seleniumSessionId', value: 'Attaching an existing session id'}, + {key: 'seleniumServerJar', value: 'Location of the standalone selenium jar file'}, + {key: 'seleniumPort', value: 'Optional port for the selenium standalone server'}, + {key: 'baseUrl', value: 'URL to prepend to all relative paths'}, + {key: 'rootElement', value: 'Element housing ng-app, if not html or body'}, + {key: 'specs', value: 'Comma-separated list of files to test'}, + {key: 'exclude', value: 'Comma-separated list of files to exclude'}, + {key: 'verbose', value: 'Print full spec names'}, + {key: 'stackTrace', value: 'Print stack trace on error'}, + {key: 'params', value: 'Param object to be passed to the tests'}, + {key: 'framework', value: 'Test framework to use: jasmine, mocha, or custom'}, + {key: 'resultJsonOutputFile', value: 'Path to save JSON test result'}, + {key: 'troubleshoot', value: 'Turn on troubleshooting output'}, + {key: 'elementExplorer', value: 'Interactively test Protractor commands'}, + {key: 'debuggerServerPort', value: 'Start a debugger server at specified port instead of repl'} +]; + +let aliases: Option[] = [ + {key: 'browser', value: 'capabilities.browserName'}, + {key: 'name', value: 'capabilities.name'}, + {key: 'platform', value: 'capabilities.platform'}, + {key: 'platform-version', value: 'capabilities.version'}, + {key: 'tags', value: 'capabilities.tags'}, + {key: 'build', value: 'capabilities.build'}, + {key: 'grep', value: 'jasmineNodeOpts.grep'}, + {key: 'invert-grep', value: 'jasmineNodeOpts.invertGrep'}, + {key: 'explorer', value: 'elementExplorer'} +]; + +let strings: Option[] = [ + {key: 'capabilities.tunnel-identifier'} +] + optimist .usage( 'Usage: protractor [configFile] [options]\n' + 'configFile defaults to protractor.conf.js\n' + 'The [options] object will override values from the config file.\n' + - 'See the reference config for a full list of options.') - .describe('help', 'Print Protractor help menu') - .describe('version', 'Print Protractor version') - .describe('browser', 'Browsername, e.g. chrome or firefox') - .describe('seleniumAddress', 'A running selenium address to use') - .describe('seleniumSessionId', 'Attaching an existing session id') - .describe('seleniumServerJar', 'Location of the standalone selenium jar file') - .describe('seleniumPort', 'Optional port for the selenium standalone server') - .describe('baseUrl', 'URL to prepend to all relative paths') - .describe('rootElement', 'Element housing ng-app, if not html or body') - .describe('specs', 'Comma-separated list of files to test') - .describe('exclude', 'Comma-separated list of files to exclude') - .describe('verbose', 'Print full spec names') - .describe('stackTrace', 'Print stack trace on error') - .describe('params', 'Param object to be passed to the tests') - .describe('framework', 'Test framework to use: jasmine, mocha, or custom') - .describe('resultJsonOutputFile', 'Path to save JSON test result') - .describe('troubleshoot', 'Turn on troubleshooting output') - .describe('elementExplorer', 'Interactively test Protractor commands') - .describe('debuggerServerPort', 'Start a debugger server at specified port instead of repl') - .alias('browser', 'capabilities.browserName') - .alias('name', 'capabilities.name') - .alias('platform', 'capabilities.platform') - .alias('platform-version', 'capabilities.version') - .alias('tags', 'capabilities.tags') - .alias('build', 'capabilities.build') - .alias('grep', 'jasmineNodeOpts.grep') - .alias('invert-grep', 'jasmineNodeOpts.invertGrep') - .alias('explorer', 'elementExplorer') - .string('capabilities.tunnel-identifier') - .check(function(arg: any) { + 'See the reference config for a full list of options.'); +for (let desc of describes) { + optimist.describe(desc.key, desc.value); +} +for (let alias of aliases) { + optimist.alias(alias.key, alias.value); +} +for (let str of strings) { + optimist.string(str.key); +} +optimist.check(function(arg: any) { if (arg._.length > 1) { throw new Error('Error: more than one config file specified'); } @@ -74,6 +97,36 @@ optimist let argv: any = optimist.parse(args); +// Check to see if additional flags were used. +let unknownKeys: string[] = []; +for (let key of Object.keys(argv).slice(2)) { + if (key === '$0') { + continue; + } + let found = false; + for (let desc of describes) { + if (desc.key === key) { + found = true; + break; + } + } + for (let alias of aliases) { + if (found) { + break; + } + if (alias.key === key) { + found = true; + break; + } + } + if (!found) { + unknownKeys.push(key); + } +} +if (unknownKeys.length > 0) { + throw new Error('Found extra flags: ' + unknownKeys.join(', ')); +} + if (argv.help) { optimist.showHelp(); process.exit(0);