From 7c3e1ef846481b8e1772adb68e6b7fe38925734d Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Tue, 11 Dec 2018 05:57:48 -0500 Subject: [PATCH 1/5] added dashed arg support to fix #7424 --- e2e/__tests__/supports-dashed-args.js | 52 +++++++++++++++++++ packages/jest-cli/src/cli/index.js | 6 ++- .../jest-validate/src/validateCLIOptions.js | 19 +++++-- 3 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 e2e/__tests__/supports-dashed-args.js diff --git a/e2e/__tests__/supports-dashed-args.js b/e2e/__tests__/supports-dashed-args.js new file mode 100644 index 000000000000..e3903a4703bb --- /dev/null +++ b/e2e/__tests__/supports-dashed-args.js @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +import path from 'path'; +import runJest from '../runJest'; + +const consoleDir = path.resolve(__dirname, '../console'); +const eachDir = path.resolve(__dirname, '../each'); + +expect.addSnapshotSerializer({ + print: value => value, + test: received => typeof received === 'string', +}); + +test('works with passing tests', () => { + const result = runJest(eachDir, [ + 'success.test.js', + '--runInBand', + '--collect-coverage', + '--coverageReporters', + 'text-summary', + '--detect-open-handles', + ]); + expect(result.status).toBe(0); +}); + +test('throws error for unknown dashed & camelcase args', () => { + const result = runJest(consoleDir, [ + '--doesNotExist', + '--also-does-not-exist', + ]); + expect(result.status).toBe(1); + expect(result.stderr).toMatchInlineSnapshot(` +● Unrecognized CLI Parameters: + + Following options were not recognized: + ["doesNotExist", "also-does-not-exist"] + + CLI Options Documentation: + https://jestjs.io/docs/en/cli.html + + +`); +}); diff --git a/packages/jest-cli/src/cli/index.js b/packages/jest-cli/src/cli/index.js index 1738d86776b4..a45ec7226e84 100644 --- a/packages/jest-cli/src/cli/index.js +++ b/packages/jest-cli/src/cli/index.js @@ -175,7 +175,8 @@ const readResultsAndExit = ( }; const buildArgv = (maybeArgv: ?Argv, project: ?Path) => { - const argv: Argv = yargs(maybeArgv || process.argv.slice(2)) + const rawArgv: Argv | string[] = maybeArgv || process.argv.slice(2); + const argv: Argv = yargs(rawArgv) .usage(args.usage) .alias('help', 'h') .options(args.options) @@ -185,6 +186,9 @@ const buildArgv = (maybeArgv: ?Argv, project: ?Path) => { validateCLIOptions( argv, Object.assign({}, args.options, {deprecationEntries}), + Array.isArray(rawArgv) + ? rawArgv.map(rawArgv => rawArgv.replace(/^--?/, '')) + : Object.keys(rawArgv), ); return argv; diff --git a/packages/jest-validate/src/validateCLIOptions.js b/packages/jest-validate/src/validateCLIOptions.js index 255093959030..67d0e8704242 100644 --- a/packages/jest-validate/src/validateCLIOptions.js +++ b/packages/jest-validate/src/validateCLIOptions.js @@ -65,16 +65,27 @@ const logDeprecatedOptions = ( }); }; -export default function validateCLIOptions(argv: Argv, options: Object) { +export default function validateCLIOptions( + argv: Argv, + options: Object, + rawArgv: string[] = [], +) { const yargsSpecialOptions = ['$0', '_', 'help', 'h']; const deprecationEntries = options.deprecationEntries || {}; const allowedOptions = Object.keys(options).reduce( (acc, option) => acc.add(option).add(options[option].alias || option), new Set(yargsSpecialOptions), ); - const unrecognizedOptions = Object.keys(argv).filter( - arg => !allowedOptions.has(arg), - ); + const unrecognizedOptions = Object.keys(argv).filter(arg => { + const camelCased = arg.replace(/-([^-])/g, (a, b) => b.toUpperCase()); + if ( + !allowedOptions.has(camelCased) && + (!rawArgv.length || rawArgv.includes(arg)) + ) { + return true; + } + return false; + }, []); if (unrecognizedOptions.length) { throw createCLIValidationError(unrecognizedOptions, allowedOptions); From a9999f6c2be66aab89f7de186b42cd66075fed0d Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Tue, 11 Dec 2018 07:18:12 -0500 Subject: [PATCH 2/5] update docs & changelog --- CHANGELOG.md | 1 + docs/CLI.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69eea7572b77..ac52cd11e957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ ### Fixes +- `[jest-cli]` Support dashed args ([#7497](https://github.com/facebook/jest/pull/7497)) - `[jest-cli]` [**BREAKING**] Do not use `text-summary` coverage reporter by default if other reporters are configured ([#7058](https://github.com/facebook/jest/pull/7058)) - `[jest-mock]` [**BREAKING**] Fix bugs with mock/spy result tracking of recursive functions ([#6381](https://github.com/facebook/jest/pull/6381)) - `[jest-haste-map]` [**BREAKING**] Recover files correctly after haste name collisions are fixed ([#7329](https://github.com/facebook/jest/pull/7329)) diff --git a/docs/CLI.md b/docs/CLI.md index f19cf7579a1a..44a8adc6ad5d 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -81,6 +81,21 @@ you can use: npm test -- -u -t="ColorPicker" ``` +## Camelcase & dashed args support + +Jest supports both camelcase and dashed arg formats. Which means the following examples will have equal result: + +```bash +jest --collect-coverage +jest --collectCoverage +``` + +They can also be mixed: + +```bash +jest --update-snapshot --detectOpenHandles +``` + ## Options _Note: CLI options take precedence over values from the [Configuration](Configuration.md)._ From ec9ba733bd2176c34f7d95fba4169c10f0ce2be1 Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Wed, 12 Dec 2018 08:35:49 -0500 Subject: [PATCH 3/5] fix dashed arg support tests --- e2e/__tests__/supports-dashed-args.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/e2e/__tests__/supports-dashed-args.js b/e2e/__tests__/supports-dashed-args.js index e3903a4703bb..a0c18a22ebbe 100644 --- a/e2e/__tests__/supports-dashed-args.js +++ b/e2e/__tests__/supports-dashed-args.js @@ -27,17 +27,27 @@ test('works with passing tests', () => { '--collect-coverage', '--coverageReporters', 'text-summary', - '--detect-open-handles', + '--clear-mocks', + '--useStderr', ]); + if (result.status !== 0) { + console.error(result.stderr); + } expect(result.status).toBe(0); }); test('throws error for unknown dashed & camelcase args', () => { const result = runJest(consoleDir, [ + 'success.test.js', + '--runInBand', + '--collect-coverage', + '--coverageReporters', + 'text-summary', + '--clear-mocks', '--doesNotExist', '--also-does-not-exist', + '--useStderr', ]); - expect(result.status).toBe(1); expect(result.stderr).toMatchInlineSnapshot(` ● Unrecognized CLI Parameters: @@ -49,4 +59,5 @@ test('throws error for unknown dashed & camelcase args', () => { `); + expect(result.status).toBe(1); }); From 3f45e1167df8b435f6d4b41ef2890d65b7314b9d Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Wed, 12 Dec 2018 15:59:16 -0500 Subject: [PATCH 4/5] move changelog item to correct location, small edit to docs --- CHANGELOG.md | 2 +- docs/CLI.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac52cd11e957..ea3b7209941f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,6 @@ ### Fixes -- `[jest-cli]` Support dashed args ([#7497](https://github.com/facebook/jest/pull/7497)) - `[jest-cli]` [**BREAKING**] Do not use `text-summary` coverage reporter by default if other reporters are configured ([#7058](https://github.com/facebook/jest/pull/7058)) - `[jest-mock]` [**BREAKING**] Fix bugs with mock/spy result tracking of recursive functions ([#6381](https://github.com/facebook/jest/pull/6381)) - `[jest-haste-map]` [**BREAKING**] Recover files correctly after haste name collisions are fixed ([#7329](https://github.com/facebook/jest/pull/7329)) @@ -81,6 +80,7 @@ - `[jest-haste-map]` Remove legacy condition for duplicate module detection ([#7333](https://github.com/facebook/jest/pull/7333)) - `[jest-haste-map]` Fix `require` detection with trailing commas and ignore `import typeof` modules ([#7385](https://github.com/facebook/jest/pull/7385)) - `[jest-cli]` Fix to set prettierPath via config file ([#7412](https://github.com/facebook/jest/pull/7412)) +- `[jest-cli]` Support dashed args ([#7497](https://github.com/facebook/jest/pull/7497)) ### Chore & Maintenance diff --git a/docs/CLI.md b/docs/CLI.md index 44a8adc6ad5d..f5e1a1347758 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -83,14 +83,14 @@ npm test -- -u -t="ColorPicker" ## Camelcase & dashed args support -Jest supports both camelcase and dashed arg formats. Which means the following examples will have equal result: +Jest supports both camelcase and dashed arg formats. The following examples will have equal result: ```bash jest --collect-coverage jest --collectCoverage ``` -They can also be mixed: +Arguments can also be mixed: ```bash jest --update-snapshot --detectOpenHandles From bad4999a1439d3e03ade3daee4d89dc8d74e50cb Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Thu, 13 Dec 2018 08:14:49 -0500 Subject: [PATCH 5/5] use camelcase, filter dashed args on returns config --- .../jest-cli/src/__tests__/cli/args.test.js | 13 +++++++++++++ packages/jest-cli/src/cli/index.js | 13 +++++++++++-- packages/jest-validate/package.json | 1 + .../jest-validate/src/validateCLIOptions.js | 17 +++++++---------- yarn.lock | 5 +++++ 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/packages/jest-cli/src/__tests__/cli/args.test.js b/packages/jest-cli/src/__tests__/cli/args.test.js index 88f3faf1c4c5..88d16dc43591 100644 --- a/packages/jest-cli/src/__tests__/cli/args.test.js +++ b/packages/jest-cli/src/__tests__/cli/args.test.js @@ -10,6 +10,7 @@ import type {Argv} from 'types/Argv'; import {check} from '../../cli/args'; +import {buildArgv} from '../../cli'; describe('check', () => { it('returns true if the arguments are valid', () => { @@ -59,3 +60,15 @@ describe('check', () => { ); }); }); + +describe('buildArgv', () => { + it('should return only camelcased args ', () => { + const mockProcessArgv = jest + .spyOn(process.argv, 'slice') + .mockImplementation(() => ['--clear-mocks']); + const actual = buildArgv(null); + expect(actual).not.toHaveProperty('clear-mocks'); + expect(actual).toHaveProperty('clearMocks', true); + mockProcessArgv.mockRestore(); + }); +}); diff --git a/packages/jest-cli/src/cli/index.js b/packages/jest-cli/src/cli/index.js index a45ec7226e84..65de1406434e 100644 --- a/packages/jest-cli/src/cli/index.js +++ b/packages/jest-cli/src/cli/index.js @@ -35,6 +35,7 @@ import logDebugMessages from '../lib/log_debug_messages'; export async function run(maybeArgv?: Argv, project?: Path) { try { + // $FlowFixMe:`allow reduced return const argv: Argv = buildArgv(maybeArgv, project); if (argv.init) { @@ -174,7 +175,7 @@ const readResultsAndExit = ( } }; -const buildArgv = (maybeArgv: ?Argv, project: ?Path) => { +export const buildArgv = (maybeArgv: ?Argv, project: ?Path) => { const rawArgv: Argv | string[] = maybeArgv || process.argv.slice(2); const argv: Argv = yargs(rawArgv) .usage(args.usage) @@ -186,12 +187,20 @@ const buildArgv = (maybeArgv: ?Argv, project: ?Path) => { validateCLIOptions( argv, Object.assign({}, args.options, {deprecationEntries}), + // strip leading dashes Array.isArray(rawArgv) ? rawArgv.map(rawArgv => rawArgv.replace(/^--?/, '')) : Object.keys(rawArgv), ); - return argv; + // strip dashed args + return Object.keys(argv).reduce((result, key) => { + if (!key.includes('-')) { + // $FlowFixMe:`allow reduced return + result[key] = argv[key]; + } + return result; + }, {}); }; const getProjectListFromCLIArgs = (argv, project: ?Path) => { diff --git a/packages/jest-validate/package.json b/packages/jest-validate/package.json index 33a9d90b4bb4..6ea5a6e5b68f 100644 --- a/packages/jest-validate/package.json +++ b/packages/jest-validate/package.json @@ -8,6 +8,7 @@ "license": "MIT", "main": "build/index.js", "dependencies": { + "camelcase": "^5.0.0", "chalk": "^2.0.1", "jest-get-type": "^22.1.0", "leven": "^2.1.0", diff --git a/packages/jest-validate/src/validateCLIOptions.js b/packages/jest-validate/src/validateCLIOptions.js index 67d0e8704242..006af5162fcf 100644 --- a/packages/jest-validate/src/validateCLIOptions.js +++ b/packages/jest-validate/src/validateCLIOptions.js @@ -10,6 +10,7 @@ import type {Argv} from 'types/Argv'; import chalk from 'chalk'; +import camelcase from 'camelcase'; import {createDidYouMeanMessage, format, ValidationError} from './utils'; import {deprecationWarning} from './deprecated'; import defaultConfig from './defaultConfig'; @@ -76,16 +77,12 @@ export default function validateCLIOptions( (acc, option) => acc.add(option).add(options[option].alias || option), new Set(yargsSpecialOptions), ); - const unrecognizedOptions = Object.keys(argv).filter(arg => { - const camelCased = arg.replace(/-([^-])/g, (a, b) => b.toUpperCase()); - if ( - !allowedOptions.has(camelCased) && - (!rawArgv.length || rawArgv.includes(arg)) - ) { - return true; - } - return false; - }, []); + const unrecognizedOptions = Object.keys(argv).filter( + arg => + !allowedOptions.has(camelcase(arg)) && + (!rawArgv.length || rawArgv.includes(arg)), + [], + ); if (unrecognizedOptions.length) { throw createCLIValidationError(unrecognizedOptions, allowedOptions); diff --git a/yarn.lock b/yarn.lock index e41514cbff50..191ce9c9d96f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3437,6 +3437,11 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= +camelcase@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"