Skip to content

Commit

Permalink
[jest-each] Add pretty format (#6357)
Browse files Browse the repository at this point in the history
* Add support for %p pretty format placeholder

* Add pretty format interpolation to each docs

* Add pretty format to template each titles

* Update changelog

* Remove extra newline#

* Move %p pretty option higher up in the docs
  • Loading branch information
mattphillips authored and cpojer committed Jun 2, 2018
1 parent ddfa099 commit 6f5b2f9
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,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))
Expand Down
2 changes: 2 additions & 0 deletions docs/GlobalAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -477,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.
Expand Down
42 changes: 38 additions & 4 deletions e2e/__tests__/__snapshots__/each.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`formats args with pretty format when given %p 1`] = `
"PASS __tests__/pretty.test.js
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
"
`;

exports[`runs only the describe.only.each tests 1`] = `
"PASS __tests__/describe-only.test.js
passes all rows expected true == true
Expand Down Expand Up @@ -79,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
Expand Down Expand Up @@ -241,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
Expand All @@ -258,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
Expand Down
7 changes: 7 additions & 0 deletions e2e/__tests__/each.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
49 changes: 49 additions & 0 deletions e2e/each/__tests__/pretty.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* 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 = () => {};

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);
});
});
3 changes: 3 additions & 0 deletions packages/jest-each/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -100,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.
Expand All @@ -119,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.
Expand Down
47 changes: 47 additions & 0 deletions packages/jest-each/src/__tests__/array.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*
*/

import pretty from 'pretty-format';
import each from '../';

const noop = () => {};
Expand Down Expand Up @@ -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();
Expand Down
48 changes: 43 additions & 5 deletions packages/jest-each/src/bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ import chalk from 'chalk';
import pretty from 'pretty-format';

type Table = Array<Array<any>>;
type PrettyArgs = {
args: Array<mixed>,
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 {
Expand Down Expand Up @@ -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<any>, test: Function) => {
Expand Down Expand Up @@ -89,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,
);

Expand Down

0 comments on commit 6f5b2f9

Please sign in to comment.