From a9a8d4365914f65a61f2ed0655426488dad1622f Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Wed, 30 May 2018 17:27:16 +0100 Subject: [PATCH 1/6] Add support for %p pretty format placeholder --- e2e/__tests__/__snapshots__/each.test.js.snap | 19 ++++++++ e2e/__tests__/each.test.js | 7 +++ e2e/each/__tests__/pretty.test.js | 26 ++++++++++ .../jest-each/src/__tests__/array.test.js | 47 +++++++++++++++++++ packages/jest-each/src/bind.js | 45 ++++++++++++++++-- 5 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 e2e/each/__tests__/pretty.test.js diff --git a/e2e/__tests__/__snapshots__/each.test.js.snap b/e2e/__tests__/__snapshots__/each.test.js.snap index 5d3a38d5d10c..60183561b7ef 100644 --- a/e2e/__tests__/__snapshots__/each.test.js.snap +++ b/e2e/__tests__/__snapshots__/each.test.js.snap @@ -1,5 +1,24 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`formats args with pretty format when given %p 1`] = ` +"PASS __tests__/pretty.test.js + ✓ \\"hello\\" == \\"hello\\" + ✓ 1 == 1 + ✓ null == null + ✓ undefined == undefined + ✓ 1.2 == 1.2 + ✓ {\\"foo\\": \\"bar\\"} == {\\"foo\\": \\"bar\\"} + ✓ {\\"foo\\": [Object]} == {\\"foo\\": [Object]} + ✓ [Function noop] == [Function noop] + ✓ [] == [] + ✓ [[Object]] == [[Object]] + ✓ Infinity == Infinity + ✓ -Infinity == -Infinity + ✓ NaN == NaN + +" +`; + exports[`runs only the describe.only.each tests 1`] = ` "PASS __tests__/describe-only.test.js passes all rows expected true == true diff --git a/e2e/__tests__/each.test.js b/e2e/__tests__/each.test.js index b311ef9265d0..dbf20e10bc8c 100644 --- a/e2e/__tests__/each.test.js +++ b/e2e/__tests__/each.test.js @@ -56,3 +56,10 @@ test('runs only the describe.only.each tests', () => { expect(rest).toMatchSnapshot(); expect(result.status).toBe(0); }); + +test('formats args with pretty format when given %p', () => { + const result = runJest(dir, ['pretty.test.js']); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); + expect(result.status).toBe(0); +}); diff --git a/e2e/each/__tests__/pretty.test.js b/e2e/each/__tests__/pretty.test.js new file mode 100644 index 000000000000..0a0d9ab9c37b --- /dev/null +++ b/e2e/each/__tests__/pretty.test.js @@ -0,0 +1,26 @@ +/** + * 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. + */ + +const noop = () => {}; + +it.each([ + ['hello', 'hello'], + [1, 1], + [null, null], + [undefined, undefined], + [1.2, 1.2], + [{foo: 'bar'}, {foo: 'bar'}], + [{foo: {bar: 'baz'}}, {foo: {bar: 'baz'}}], + [noop, noop], + [[], []], + [[{foo: {bar: 'baz'}}], [{foo: {bar: 'baz'}}]], + [Infinity, Infinity], + [-Infinity, -Infinity], + [NaN, NaN], +])('%p == %p', (left, right) => { + expect(left).toEqual(right); +}); diff --git a/packages/jest-each/src/__tests__/array.test.js b/packages/jest-each/src/__tests__/array.test.js index c10e16ad4dae..6b8fb1ef1adc 100644 --- a/packages/jest-each/src/__tests__/array.test.js +++ b/packages/jest-each/src/__tests__/array.test.js @@ -6,6 +6,7 @@ * */ +import pretty from 'pretty-format'; import each from '../'; const noop = () => {}; @@ -140,6 +141,52 @@ describe('jest-each', () => { ); }); + test('calls global test title with %p placeholder injected at the correct positions', () => { + const globalTestMocks = getGlobalTestMocks(); + const eachObject = each.withGlobal(globalTestMocks)([ + ['string1', 'pretty1', 'string2', 'pretty2'], + ['string1', 'pretty1', 'string2', 'pretty2'], + ]); + const testFunction = get(eachObject, keyPath); + testFunction('expected string: %s %p %s %p', noop); + + const globalMock = get(globalTestMocks, keyPath); + expect(globalMock).toHaveBeenCalledTimes(2); + expect(globalMock).toHaveBeenCalledWith( + `expected string: string1 ${pretty('pretty1')} string2 ${pretty( + 'pretty2', + )}`, + expectFunction, + ); + expect(globalMock).toHaveBeenCalledWith( + `expected string: string1 ${pretty('pretty1')} string2 ${pretty( + 'pretty2', + )}`, + expectFunction, + ); + }); + + test('does not calls global test title with %p placeholder when no data is supplied at given position', () => { + const globalTestMocks = getGlobalTestMocks(); + const eachObject = each.withGlobal(globalTestMocks)([ + ['string1', 'pretty1', 'string2'], + ['string1', 'pretty1', 'string2'], + ]); + const testFunction = get(eachObject, keyPath); + testFunction('expected string: %s %p %s %p', noop); + + const globalMock = get(globalTestMocks, keyPath); + expect(globalMock).toHaveBeenCalledTimes(2); + expect(globalMock).toHaveBeenCalledWith( + `expected string: string1 ${pretty('pretty1')} string2 %p`, + expectFunction, + ); + expect(globalMock).toHaveBeenCalledWith( + `expected string: string1 ${pretty('pretty1')} string2 %p`, + expectFunction, + ); + }); + test('calls global with cb function containing all parameters of each test case when given 1d array', () => { const globalTestMocks = getGlobalTestMocks(); const testCallBack = jest.fn(); diff --git a/packages/jest-each/src/bind.js b/packages/jest-each/src/bind.js index fc3103ce8a62..761593fac336 100644 --- a/packages/jest-each/src/bind.js +++ b/packages/jest-each/src/bind.js @@ -12,10 +12,15 @@ import chalk from 'chalk'; import pretty from 'pretty-format'; type Table = Array>; +type PrettyArgs = { + args: Array, + title: string, +}; const EXPECTED_COLOR = chalk.green; const RECEIVED_COLOR = chalk.red; -const SUPPORTED_PLACEHOLDERS = /%[sdifjoO%]/g; +const SUPPORTED_PLACEHOLDERS = /%[sdifjoOp%]/g; +const PRETTY_PLACEHOLDER = '%p'; export default (cb: Function) => (...args: any) => function eachBind(title: string, test: Function): void { @@ -59,9 +64,41 @@ export default (cb: Function) => (...args: any) => ); }; -const arrayFormat = (str, ...args) => { - const matches = (str.match(SUPPORTED_PLACEHOLDERS) || []).length; - return util.format(str, ...args.slice(0, matches)); +const getPrettyIndexes = placeholders => + placeholders.reduce( + (indexes, placeholder, index) => + placeholder === PRETTY_PLACEHOLDER ? indexes.concat(index) : indexes, + [], + ); + +const arrayFormat = (title, ...args) => { + const placeholders = title.match(SUPPORTED_PLACEHOLDERS) || []; + const prettyIndexes = getPrettyIndexes(placeholders); + + const {title: prettyTitle, args: remainingArgs} = args.reduce( + (acc: PrettyArgs, arg, index) => { + if (prettyIndexes.indexOf(index) !== -1) { + return { + args: acc.args, + title: acc.title.replace( + PRETTY_PLACEHOLDER, + pretty(arg, {maxDepth: 1, min: true}), + ), + }; + } + + return { + args: acc.args.concat([arg]), + title: acc.title, + }; + }, + {args: [], title}, + ); + + return util.format( + prettyTitle, + ...remainingArgs.slice(0, placeholders.length - prettyIndexes.length), + ); }; const applyRestParams = (params: Array, test: Function) => { From 70b997bce32c67c27a35bb76a743efd252b985d6 Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Wed, 30 May 2018 17:29:22 +0100 Subject: [PATCH 2/6] Add pretty format interpolation to each docs --- docs/GlobalAPI.md | 2 ++ packages/jest-each/README.md | 3 +++ 2 files changed, 5 insertions(+) diff --git a/docs/GlobalAPI.md b/docs/GlobalAPI.md index 78c1208c95e3..ce407a0842cf 100644 --- a/docs/GlobalAPI.md +++ b/docs/GlobalAPI.md @@ -240,6 +240,7 @@ Use `describe.each` if you keep duplicating the same test suites with different * `%j` - JSON. * `%o` - Object. * `%%` - single percent sign ('%'). This does not consume an argument. + * `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). * `fn`: `Function` the suite of tests to be ran, this is the function that will receive the parameters in each row as function arguments. Example: @@ -484,6 +485,7 @@ Use `test.each` if you keep duplicating the same test with different data. `test * `%j` - JSON. * `%o` - Object. * `%%` - single percent sign ('%'). This does not consume an argument. + * `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). * `fn`: `Function` the test to be ran, this is the function that will receive the parameters in each row as function arguments. Example: diff --git a/packages/jest-each/README.md b/packages/jest-each/README.md index d0ed999de85b..9c5c7b7cffb7 100644 --- a/packages/jest-each/README.md +++ b/packages/jest-each/README.md @@ -33,6 +33,7 @@ jest-each allows you to provide multiple arguments to your `test`/`describe` whi * `%j` - JSON. * `%o` - Object. * `%%` - single percent sign ('%'). This does not consume an argument. + * `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). * 🖖 Spock like data tables with [Tagged Template Literals](#tagged-template-literal-of-rows) --- @@ -107,6 +108,7 @@ const each = require('jest-each'); * `%j` - JSON. * `%o` - Object. * `%%` - single percent sign ('%'). This does not consume an argument. + * `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). * testFn: `Function` the test logic, this is the function that will receive the parameters of each row as function arguments #### `each([parameters]).describe(name, suiteFn)` @@ -126,6 +128,7 @@ const each = require('jest-each'); * `%j` - JSON. * `%o` - Object. * `%%` - single percent sign ('%'). This does not consume an argument. + * `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). * suiteFn: `Function` the suite of `test`/`it`s to be ran, this is the function that will receive the parameters in each row as function arguments ### Usage From 2cac11bc5deebb51d6f7f8bf7a90bda52b21433c Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Wed, 30 May 2018 17:39:44 +0100 Subject: [PATCH 3/6] Add pretty format to template each titles --- e2e/__tests__/__snapshots__/each.test.js.snap | 49 +++++++++++------ e2e/each/__tests__/pretty.test.js | 55 +++++++++++++------ packages/jest-each/src/bind.js | 3 +- 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/e2e/__tests__/__snapshots__/each.test.js.snap b/e2e/__tests__/__snapshots__/each.test.js.snap index 60183561b7ef..aa30ac869404 100644 --- a/e2e/__tests__/__snapshots__/each.test.js.snap +++ b/e2e/__tests__/__snapshots__/each.test.js.snap @@ -2,19 +2,34 @@ exports[`formats args with pretty format when given %p 1`] = ` "PASS __tests__/pretty.test.js - ✓ \\"hello\\" == \\"hello\\" - ✓ 1 == 1 - ✓ null == null - ✓ undefined == undefined - ✓ 1.2 == 1.2 - ✓ {\\"foo\\": \\"bar\\"} == {\\"foo\\": \\"bar\\"} - ✓ {\\"foo\\": [Object]} == {\\"foo\\": [Object]} - ✓ [Function noop] == [Function noop] - ✓ [] == [] - ✓ [[Object]] == [[Object]] - ✓ Infinity == Infinity - ✓ -Infinity == -Infinity - ✓ NaN == NaN + array + ✓ \\"hello\\" == \\"hello\\" + ✓ 1 == 1 + ✓ null == null + ✓ undefined == undefined + ✓ 1.2 == 1.2 + ✓ {\\"foo\\": \\"bar\\"} == {\\"foo\\": \\"bar\\"} + ✓ {\\"foo\\": [Object]} == {\\"foo\\": [Object]} + ✓ [Function noop] == [Function noop] + ✓ [] == [] + ✓ [[Object]] == [[Object]] + ✓ Infinity == Infinity + ✓ -Infinity == -Infinity + ✓ NaN == NaN + template + ✓ \\"hello\\" == \\"hello\\" + ✓ 1 == 1 + ✓ null == null + ✓ undefined == undefined + ✓ 1.2 == 1.2 + ✓ {\\"foo\\": \\"bar\\"} == {\\"foo\\": \\"bar\\"} + ✓ {\\"foo\\": [Object]} == {\\"foo\\": [Object]} + ✓ [Function noop] == [Function noop] + ✓ [] == [] + ✓ [[Object]] == [[Object]] + ✓ Infinity == Infinity + ✓ -Infinity == -Infinity + ✓ NaN == NaN " `; @@ -98,9 +113,9 @@ exports[`shows the correct errors in stderr when failing tests 1`] = ` ✕ The word red contains the letter 'z' ✕ The word green contains the letter 'z' ✕ The word bean contains the letter 'z' - template table describe fails on all rows expected a == b + template table describe fails on all rows expected \\"a\\" == \\"b\\" ✕ fails - template table describe fails on all rows expected c == d + template table describe fails on all rows expected \\"c\\" == \\"d\\" ✕ fails array table describe fails on all rows expected a == b ✕ fails @@ -260,7 +275,7 @@ exports[`shows the correct errors in stderr when failing tests 1`] = ` at __tests__/failure.test.js:47:28 - ● template table describe fails on all rows expected a == b › fails + ● template table describe fails on all rows expected \\"a\\" == \\"b\\" › fails expect(received).toBe(expected) // Object.is equality @@ -277,7 +292,7 @@ exports[`shows the correct errors in stderr when failing tests 1`] = ` at __tests__/failure.test.js:59:20 - ● template table describe fails on all rows expected c == d › fails + ● template table describe fails on all rows expected \\"c\\" == \\"d\\" › fails expect(received).toBe(expected) // Object.is equality diff --git a/e2e/each/__tests__/pretty.test.js b/e2e/each/__tests__/pretty.test.js index 0a0d9ab9c37b..97e045b30542 100644 --- a/e2e/each/__tests__/pretty.test.js +++ b/e2e/each/__tests__/pretty.test.js @@ -7,20 +7,43 @@ const noop = () => {}; -it.each([ - ['hello', 'hello'], - [1, 1], - [null, null], - [undefined, undefined], - [1.2, 1.2], - [{foo: 'bar'}, {foo: 'bar'}], - [{foo: {bar: 'baz'}}, {foo: {bar: 'baz'}}], - [noop, noop], - [[], []], - [[{foo: {bar: 'baz'}}], [{foo: {bar: 'baz'}}]], - [Infinity, Infinity], - [-Infinity, -Infinity], - [NaN, NaN], -])('%p == %p', (left, right) => { - expect(left).toEqual(right); +describe('array', () => { + it.each([ + ['hello', 'hello'], + [1, 1], + [null, null], + [undefined, undefined], + [1.2, 1.2], + [{foo: 'bar'}, {foo: 'bar'}], + [{foo: {bar: 'baz'}}, {foo: {bar: 'baz'}}], + [noop, noop], + [[], []], + [[{foo: {bar: 'baz'}}], [{foo: {bar: 'baz'}}]], + [Infinity, Infinity], + [-Infinity, -Infinity], + [NaN, NaN], + ])('%p == %p', (left, right) => { + expect(left).toEqual(right); + }); +}); + +describe('template', () => { + it.each` + left | right + ${'hello'} | ${'hello'} + ${1} | ${1} + ${null} | ${null} + ${undefined} | ${undefined} + ${1.2} | ${1.2} + ${{foo: 'bar'}} | ${{foo: 'bar'}} + ${{foo: {bar: 'baz'}}} | ${{foo: {bar: 'baz'}}} + ${noop} | ${noop} + ${[]} | ${[]} + ${[{foo: {bar: 'baz'}}]} | ${[{foo: {bar: 'baz'}}]} + ${Infinity} | ${Infinity} + ${-Infinity} | ${-Infinity} + ${NaN} | ${NaN} + `('$left == $right', ({left, right}) => { + expect(left).toEqual(right); + }); }); diff --git a/packages/jest-each/src/bind.js b/packages/jest-each/src/bind.js index 761593fac336..544f21b9e056 100644 --- a/packages/jest-each/src/bind.js +++ b/packages/jest-each/src/bind.js @@ -126,7 +126,8 @@ const buildTable = ( const interpolate = (title: string, data: any) => Object.keys(data).reduce( - (acc, key) => acc.replace('$' + key, data[key]), + (acc, key) => + acc.replace('$' + key, pretty(data[key], {maxDepth: 1, min: true})), title, ); From 7ea7aa89017f54c7d6cc9e292c5ff917b4678cde Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Wed, 30 May 2018 17:51:17 +0100 Subject: [PATCH 4/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d31a12b9c823..e818ab6bc642 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +* `[jest-each]` Add pretty-format serialising to each titles ([#6357](https://github.com/facebook/jest/pull/6357)) * `[jest-cli]` shouldRunTestSuite watch hook now receives an object with `config`, `testPath` and `duration` ([#6350](https://github.com/facebook/jest/pull/6350)) * `[jest-each]` Support one dimensional array of data ([#6351](https://github.com/facebook/jest/pull/6351)) * `[jest-watch]` create new package `jest-watch` to ease custom watch plugin development ([#6318](https://github.com/facebook/jest/pull/6318)) From dafcb5b7f783eaac729787728861993913f34ad9 Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Thu, 31 May 2018 18:35:26 +0100 Subject: [PATCH 5/6] Remove extra newline# --- packages/jest-each/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-each/README.md b/packages/jest-each/README.md index d6b8f7fec455..6028004425b7 100644 --- a/packages/jest-each/README.md +++ b/packages/jest-each/README.md @@ -432,4 +432,3 @@ each` ## License MIT - From e416ebed8383223141a5db68fb03ae0bccb36a07 Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Fri, 1 Jun 2018 10:13:02 +0100 Subject: [PATCH 6/6] Move %p pretty option higher up in the docs --- docs/GlobalAPI.md | 4 ++-- packages/jest-each/README.md | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/GlobalAPI.md b/docs/GlobalAPI.md index ebba86d108b2..049cf3ec692f 100644 --- a/docs/GlobalAPI.md +++ b/docs/GlobalAPI.md @@ -233,6 +233,7 @@ Use `describe.each` if you keep duplicating the same test suites with different - `table`: `Array` of Arrays with the arguments that are passed into the `fn` for each row. - `name`: `String` the title of the test suite. - Generate unique test titles by positionally injecting parameters with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args): + - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `%s`- String. - `%d`- Number. - `%i` - Integer. @@ -240,7 +241,6 @@ Use `describe.each` if you keep duplicating the same test suites with different - `%j` - JSON. - `%o` - Object. - `%%` - single percent sign ('%'). This does not consume an argument. - - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `fn`: `Function` the suite of tests to be ran, this is the function that will receive the parameters in each row as function arguments. Example: @@ -478,6 +478,7 @@ Use `test.each` if you keep duplicating the same test with different data. `test - `table`: `Array` of Arrays with the arguments that are passed into the test `fn` for each row. - `name`: `String` the title of the test block. - Generate unique test titles by positionally injecting parameters with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args): + - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `%s`- String. - `%d`- Number. - `%i` - Integer. @@ -485,7 +486,6 @@ Use `test.each` if you keep duplicating the same test with different data. `test - `%j` - JSON. - `%o` - Object. - `%%` - single percent sign ('%'). This does not consume an argument. - - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `fn`: `Function` the test to be ran, this is the function that will receive the parameters in each row as function arguments. Example: diff --git a/packages/jest-each/README.md b/packages/jest-each/README.md index 6028004425b7..08b2994837f5 100644 --- a/packages/jest-each/README.md +++ b/packages/jest-each/README.md @@ -26,6 +26,7 @@ jest-each allows you to provide multiple arguments to your `test`/`describe` whi - Also under the aliases: `.xdescribe` - Asynchronous tests with `done` - Unique test titles with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args): + - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `%s`- String. - `%d`- Number. - `%i` - Integer. @@ -33,7 +34,6 @@ jest-each allows you to provide multiple arguments to your `test`/`describe` whi - `%j` - JSON. - `%o` - Object. - `%%` - single percent sign ('%'). This does not consume an argument. - - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - 🖖 Spock like data tables with [Tagged Template Literals](#tagged-template-literal-of-rows) --- @@ -101,6 +101,7 @@ const each = require('jest-each'); - name: `String` the title of the `test`. - Generate unique test titles by positionally injecting parameters with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args): + - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `%s`- String. - `%d`- Number. - `%i` - Integer. @@ -120,6 +121,7 @@ const each = require('jest-each'); - name: `String` the title of the `describe` - Generate unique test titles by positionally injecting parameters with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args): + - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format). - `%s`- String. - `%d`- Number. - `%i` - Integer.