From 9232dda5985df1a0e16230234b44f74fb3178e3d Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Sun, 23 Sep 2018 19:51:54 +0100 Subject: [PATCH 1/3] Add each array validation check --- .../__snapshots__/array.test.js.snap | 41 +++++++++++++++++++ .../jest-each/src/__tests__/array.test.js | 13 ++++++ packages/jest-each/src/bind.js | 32 +++++++++++---- 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap diff --git a/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap b/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap new file mode 100644 index 000000000000..558e8f8f4e3e --- /dev/null +++ b/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`jest-each .describe throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .describe.only throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .fdescribe throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .fit throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .it throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .it.only throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .test throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; + +exports[`jest-each .test.only throws an error when not called with an array 1`] = ` +"\`.each\` must be called with an Array or Tagged Template String. +" +`; diff --git a/packages/jest-each/src/__tests__/array.test.js b/packages/jest-each/src/__tests__/array.test.js index 1077ffecd629..594b25ef0161 100644 --- a/packages/jest-each/src/__tests__/array.test.js +++ b/packages/jest-each/src/__tests__/array.test.js @@ -47,6 +47,19 @@ describe('jest-each', () => { ['describe', 'only'], ].forEach(keyPath => { describe(`.${keyPath.join('.')}`, () => { + test('throws an error when not called with an array', () => { + const globalTestMocks = getGlobalTestMocks(); + const eachObject = each.withGlobal(globalTestMocks)(undefined); + const testFunction = get(eachObject, keyPath); + + testFunction('expected string', noop); + const globalMock = get(globalTestMocks, keyPath); + + expect(() => + globalMock.mock.calls[0][1](), + ).toThrowErrorMatchingSnapshot(); + }); + test('calls global with given title', () => { const globalTestMocks = getGlobalTestMocks(); const eachObject = each.withGlobal(globalTestMocks)([[]]); diff --git a/packages/jest-each/src/bind.js b/packages/jest-each/src/bind.js index fe4565b4c8c9..34e485fe6ad1 100644 --- a/packages/jest-each/src/bind.js +++ b/packages/jest-each/src/bind.js @@ -23,12 +23,31 @@ const SUPPORTED_PLACEHOLDERS = /%[sdifjoOp%]/g; const PRETTY_PLACEHOLDER = '%p'; const INDEX_PLACEHOLDER = '%#'; +const errorWithStack = (message, callsite) => { + const error = new Error(message); + if (Error.captureStackTrace) { + Error.captureStackTrace(error, callsite); + } + return error; +}; + export default (cb: Function, supportsDone: boolean = true) => (...args: any) => function eachBind(title: string, test: Function, timeout: number): void { if (args.length === 1) { - const table: Table = args[0].every(Array.isArray) - ? args[0] - : args[0].map(entry => [entry]); + const [tableArg] = args; + + if (!Array.isArray(tableArg)) { + const error = errorWithStack( + '`.each` must be called with an Array or Tagged Template String.\n', + eachBind, + ); + return cb(title, () => { + throw error; + }); + } + const table: Table = tableArg.every(Array.isArray) + ? tableArg + : tableArg.map(entry => [entry]); return table.forEach((row, i) => cb( arrayFormat(title, i, ...row), @@ -47,7 +66,7 @@ export default (cb: Function, supportsDone: boolean = true) => (...args: any) => const missingData = data.length % keys.length; if (missingData > 0) { - const error = new Error( + const error = errorWithStack( 'Not enough arguments supplied for given headings:\n' + EXPECTED_COLOR(keys.join(' | ')) + '\n\n' + @@ -58,12 +77,9 @@ export default (cb: Function, supportsDone: boolean = true) => (...args: any) => 'argument', missingData, )}`, + eachBind, ); - if (Error.captureStackTrace) { - Error.captureStackTrace(error, eachBind); - } - return cb(title, () => { throw error; }); From 2efc1e8c307312369533931096928818390c5fcc Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Sun, 23 Sep 2018 19:56:24 +0100 Subject: [PATCH 2/3] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a6ce07e7b5a..2f72957d6254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Fixes +- `[jest-each]` Add each array validation check ([#7033](https://github.com/facebook/jest/pull/7033)) - `[jest-haste-map]` [**BREAKING**] Replace internal data structures to improve performance ([#6960](https://github.com/facebook/jest/pull/6960)) - `[jest-haste-map]` Do not visit again files with the same sha-1 ([#6990](https://github.com/facebook/jest/pull/6990)) - `[jest-jasmine2]` Fix memory leak in Error objects hold by the framework ([#6965](https://github.com/facebook/jest/pull/6965)) From d1abdef9b1f1204ad3cf084cd7cd31135b126b8b Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Sun, 23 Sep 2018 23:00:10 +0100 Subject: [PATCH 3/3] Add called value to error message --- .../__tests__/__snapshots__/array.test.js.snap | 16 ++++++++++++++++ packages/jest-each/src/bind.js | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap b/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap index 558e8f8f4e3e..75cc81d64769 100644 --- a/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap +++ b/packages/jest-each/src/__tests__/__snapshots__/array.test.js.snap @@ -2,40 +2,56 @@ exports[`jest-each .describe throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .describe.only throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .fdescribe throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .fit throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .it throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .it.only throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .test throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; exports[`jest-each .test.only throws an error when not called with an array 1`] = ` "\`.each\` must be called with an Array or Tagged Template String. + +Instead was called with: undefined " `; diff --git a/packages/jest-each/src/bind.js b/packages/jest-each/src/bind.js index 34e485fe6ad1..88d68c11cecd 100644 --- a/packages/jest-each/src/bind.js +++ b/packages/jest-each/src/bind.js @@ -38,7 +38,11 @@ export default (cb: Function, supportsDone: boolean = true) => (...args: any) => if (!Array.isArray(tableArg)) { const error = errorWithStack( - '`.each` must be called with an Array or Tagged Template String.\n', + '`.each` must be called with an Array or Tagged Template String.\n\n' + + `Instead was called with: ${pretty(tableArg, { + maxDepth: 1, + min: true, + })}\n`, eachBind, ); return cb(title, () => {