diff --git a/CHANGELOG.md b/CHANGELOG.md index 66062e923d47..60c67811be0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - `[jest-snapshot]` Enable configurable snapshot paths ([#6143](https://github.com/facebook/jest/pull/6143)) - `[pretty-format]` Support HTMLCollection and NodeList in DOMCollection plugin ([#7125](https://github.com/facebook/jest/pull/7125)) - `[jest-runtime]` Pass the normalized configuration to script transformers ([#7148](https://github.com/facebook/jest/pull/7148)) +- `[expect]` Improve report when assertion fails, part 3 ([#7152](https://github.com/facebook/jest/pull/7152)) - `[jest-runtime]` If `require` fails without a file extension, print all files that match with one ([#7160](https://github.com/facebook/jest/pull/7160)) - `[jest-haste-map]` Make `ignorePattern` optional ([#7166](https://github.com/facebook/jest/pull/7166)) - `[jest-haste-map]` Add `getCacheFilePath` to get the path to the cache file for a `HasteMap` instance ([#7217](https://github.com/facebook/jest/pull/7217)) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index f1503dbd4ff4..19fe16e74e51 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -396,136 +396,136 @@ exports[`.toBeCloseTo() {pass: false} expect(-Infinity)toBeCloseTo( -1.23) 1`] = "expect(received).toBeCloseTo(expected) Precision: 2-digit -Expected: -1.23 -Received: -Infinity" +Expected: -1.23 +Received: -Infinity" `; exports[`.toBeCloseTo() {pass: false} expect(Infinity)toBeCloseTo( -Infinity) 1`] = ` "expect(received).toBeCloseTo(expected) Precision: 2-digit -Expected: -Infinity -Received: Infinity" +Expected: -Infinity +Received: Infinity" `; exports[`.toBeCloseTo() {pass: false} expect(Infinity)toBeCloseTo( 1.23) 1`] = ` "expect(received).toBeCloseTo(expected) Precision: 2-digit -Expected: 1.23 -Received: Infinity" +Expected: 1.23 +Received: Infinity" `; exports[`.toBeCloseTo() {pass: true} expect(-Infinity)toBeCloseTo( -Infinity) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: -Infinity -Received: -Infinity" +Expected: -Infinity +Received: -Infinity" `; exports[`.toBeCloseTo() {pass: true} expect(0)toBeCloseTo( 0) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: 0 -Received: 0" +Expected: 0 +Received: 0" `; exports[`.toBeCloseTo() {pass: true} expect(0)toBeCloseTo( 0.001) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: 0.001 -Received: 0" +Expected: 0.001 +Received: 0" `; exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.225) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: 1.225 -Received: 1.23" +Expected: 1.225 +Received: 1.23" `; exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.226) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: 1.226 -Received: 1.23" +Expected: 1.226 +Received: 1.23" `; exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.229) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: 1.229 -Received: 1.23" +Expected: 1.229 +Received: 1.23" `; exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.234) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: 1.234 -Received: 1.23" +Expected: 1.234 +Received: 1.23" `; exports[`.toBeCloseTo() {pass: true} expect(Infinity)toBeCloseTo( Infinity) 1`] = ` "expect(received).not.toBeCloseTo(expected) Precision: 2-digit -Expected: Infinity -Received: Infinity" +Expected: Infinity +Received: Infinity" `; exports[`.toBeCloseTo() accepts an optional precision argument: [0, 0.000004, 5] 1`] = ` "expect(received).not.toBeCloseTo(expected, precision) Precision: 5-digit -Expected: 0.000004 -Received: 0" +Expected: 0.000004 +Received: 0" `; exports[`.toBeCloseTo() accepts an optional precision argument: [0, 0.0001, 3] 1`] = ` "expect(received).not.toBeCloseTo(expected, precision) Precision: 3-digit -Expected: 0.0001 -Received: 0" +Expected: 0.0001 +Received: 0" `; exports[`.toBeCloseTo() accepts an optional precision argument: [0, 0.1, 0] 1`] = ` "expect(received).not.toBeCloseTo(expected, precision) Precision: 0-digit -Expected: 0.1 -Received: 0" +Expected: 0.1 +Received: 0" `; exports[`.toBeCloseTo() throws: [0, 0.01] 1`] = ` "expect(received).toBeCloseTo(expected) Precision: 2-digit -Expected: 0.01 -Received: 0" +Expected: 0.01 +Received: 0" `; exports[`.toBeCloseTo() throws: [1, 1.23] 1`] = ` "expect(received).toBeCloseTo(expected) Precision: 2-digit -Expected: 1.23 -Received: 1" +Expected: 1.23 +Received: 1" `; exports[`.toBeCloseTo() throws: [1.23, 1.2249999] 1`] = ` "expect(received).toBeCloseTo(expected) Precision: 2-digit -Expected: 1.2249999 -Received: 1.23" +Expected: 1.2249999 +Received: 1.23" `; exports[`.toBeDefined(), .toBeUndefined() '"a"' is defined 1`] = ` @@ -1537,222 +1537,161 @@ Expected has value: null" `; exports[`.toContain(), .toContainEqual() '"11112111"' contains '"2"' 1`] = ` -"expect(string).not.toContain(value) +"expect(string).not.toContain(value) // indexOf -Expected string: - \\"11112111\\" -Not to contain value: - \\"2\\" -" +Expected value: \\"2\\" +Received string: \\"11112111\\"" `; exports[`.toContain(), .toContainEqual() '"abcdef"' contains '"abc"' 1`] = ` -"expect(string).not.toContain(value) +"expect(string).not.toContain(value) // indexOf -Expected string: - \\"abcdef\\" -Not to contain value: - \\"abc\\" -" +Expected value: \\"abc\\" +Received string: \\"abcdef\\"" `; exports[`.toContain(), .toContainEqual() '["a", "b", "c", "d"]' contains '"a"' 1`] = ` -"expect(array).not.toContain(value) +"expect(array).not.toContain(value) // indexOf -Expected array: - [\\"a\\", \\"b\\", \\"c\\", \\"d\\"] -Not to contain value: - \\"a\\" -" +Expected value: \\"a\\" +Received array: [\\"a\\", \\"b\\", \\"c\\", \\"d\\"]" `; exports[`.toContain(), .toContainEqual() '["a", "b", "c", "d"]' contains a value equal to '"a"' 1`] = ` -"expect(array).not.toContainEqual(value) +"expect(array).not.toContainEqual(value) // deep equality -Expected array: - [\\"a\\", \\"b\\", \\"c\\", \\"d\\"] -Not to contain a value equal to: - \\"a\\" -" +Expected value: \\"a\\" +Received array: [\\"a\\", \\"b\\", \\"c\\", \\"d\\"]" `; exports[`.toContain(), .toContainEqual() '[{"a": "b"}, {"a": "c"}]' contains a value equal to '{"a": "b"}' 1`] = ` -"expect(array).not.toContainEqual(value) +"expect(array).not.toContainEqual(value) // deep equality -Expected array: - [{\\"a\\": \\"b\\"}, {\\"a\\": \\"c\\"}] -Not to contain a value equal to: - {\\"a\\": \\"b\\"} -" +Expected value: {\\"a\\": \\"b\\"} +Received array: [{\\"a\\": \\"b\\"}, {\\"a\\": \\"c\\"}]" `; exports[`.toContain(), .toContainEqual() '[{"a": "b"}, {"a": "c"}]' does not contain a value equal to'{"a": "d"}' 1`] = ` -"expect(array).toContainEqual(value) +"expect(array).toContainEqual(value) // deep equality -Expected array: - [{\\"a\\": \\"b\\"}, {\\"a\\": \\"c\\"}] -To contain a value equal to: - {\\"a\\": \\"d\\"}" +Expected value: {\\"a\\": \\"d\\"} +Received array: [{\\"a\\": \\"b\\"}, {\\"a\\": \\"c\\"}]" `; exports[`.toContain(), .toContainEqual() '[{}, []]' does not contain '[]' 1`] = ` -"expect(array).toContain(value) +"expect(array).toContain(value) // indexOf -Expected array: - [{}, []] -To contain value: - [] +Expected value: [] +Received array: [{}, []] Looks like you wanted to test for object/array equality with the stricter \`toContain\` matcher. You probably need to use \`toContainEqual\` instead." `; exports[`.toContain(), .toContainEqual() '[{}, []]' does not contain '{}' 1`] = ` -"expect(array).toContain(value) +"expect(array).toContain(value) // indexOf -Expected array: - [{}, []] -To contain value: - {} +Expected value: {} +Received array: [{}, []] Looks like you wanted to test for object/array equality with the stricter \`toContain\` matcher. You probably need to use \`toContainEqual\` instead." `; exports[`.toContain(), .toContainEqual() '[0, 1]' contains '1' 1`] = ` -"expect(object).not.toContain(value) +"expect(object).not.toContain(value) // indexOf -Expected object: - [0, 1] -Not to contain value: - 1 -" +Expected value: 1 +Received object: [0, 1]" `; exports[`.toContain(), .toContainEqual() '[0, 1]' contains a value equal to '1' 1`] = ` -"expect(object).not.toContainEqual(value) +"expect(object).not.toContainEqual(value) // deep equality -Expected object: - [0, 1] -Not to contain a value equal to: - 1 -" +Expected value: 1 +Received object: [0, 1]" `; exports[`.toContain(), .toContainEqual() '[1, 2, 3, 4]' contains '1' 1`] = ` -"expect(array).not.toContain(value) +"expect(array).not.toContain(value) // indexOf -Expected array: - [1, 2, 3, 4] -Not to contain value: - 1 -" +Expected value: 1 +Received array: [1, 2, 3, 4]" `; exports[`.toContain(), .toContainEqual() '[1, 2, 3, 4]' contains a value equal to '1' 1`] = ` -"expect(array).not.toContainEqual(value) +"expect(array).not.toContainEqual(value) // deep equality -Expected array: - [1, 2, 3, 4] -Not to contain a value equal to: - 1 -" +Expected value: 1 +Received array: [1, 2, 3, 4]" `; exports[`.toContain(), .toContainEqual() '[1, 2, 3]' does not contain '4' 1`] = ` -"expect(array).toContain(value) +"expect(array).toContain(value) // indexOf -Expected array: - [1, 2, 3] -To contain value: - 4" +Expected value: 4 +Received array: [1, 2, 3]" `; exports[`.toContain(), .toContainEqual() '[Symbol(a)]' contains 'Symbol(a)' 1`] = ` -"expect(array).not.toContain(value) +"expect(array).not.toContain(value) // indexOf -Expected array: - [Symbol(a)] -Not to contain value: - Symbol(a) -" +Expected value: Symbol(a) +Received array: [Symbol(a)]" `; exports[`.toContain(), .toContainEqual() '[Symbol(a)]' contains a value equal to 'Symbol(a)' 1`] = ` -"expect(array).not.toContainEqual(value) +"expect(array).not.toContainEqual(value) // deep equality -Expected array: - [Symbol(a)] -Not to contain a value equal to: - Symbol(a) -" +Expected value: Symbol(a) +Received array: [Symbol(a)]" `; exports[`.toContain(), .toContainEqual() '[null, undefined]' does not contain '1' 1`] = ` -"expect(array).toContain(value) +"expect(array).toContain(value) // indexOf -Expected array: - [null, undefined] -To contain value: - 1" +Expected value: 1 +Received array: [null, undefined]" `; exports[`.toContain(), .toContainEqual() '[undefined, null]' contains 'null' 1`] = ` -"expect(array).not.toContain(value) +"expect(array).not.toContain(value) // indexOf -Expected array: - [undefined, null] -Not to contain value: - null -" +Expected value: null +Received array: [undefined, null]" `; exports[`.toContain(), .toContainEqual() '[undefined, null]' contains 'undefined' 1`] = ` -"expect(array).not.toContain(value) +"expect(array).not.toContain(value) // indexOf -Expected array: - [undefined, null] -Not to contain value: - undefined -" +Expected value: undefined +Received array: [undefined, null]" `; exports[`.toContain(), .toContainEqual() '[undefined, null]' contains a value equal to 'null' 1`] = ` -"expect(array).not.toContainEqual(value) +"expect(array).not.toContainEqual(value) // deep equality -Expected array: - [undefined, null] -Not to contain a value equal to: - null -" +Expected value: null +Received array: [undefined, null]" `; exports[`.toContain(), .toContainEqual() '[undefined, null]' contains a value equal to 'undefined' 1`] = ` -"expect(array).not.toContainEqual(value) +"expect(array).not.toContainEqual(value) // deep equality -Expected array: - [undefined, null] -Not to contain a value equal to: - undefined -" +Expected value: undefined +Received array: [undefined, null]" `; exports[`.toContain(), .toContainEqual() 'Set {"abc", "def"}' contains '"abc"' 1`] = ` -"expect(set).not.toContain(value) +"expect(set).not.toContain(value) // indexOf -Expected set: - Set {\\"abc\\", \\"def\\"} -Not to contain value: - \\"abc\\" -" +Expected value: \\"abc\\" +Received set: Set {\\"abc\\", \\"def\\"}" `; exports[`.toContain(), .toContainEqual() 'Set {1, 2, 3, 4}' contains a value equal to '1' 1`] = ` -"expect(set).not.toContainEqual(value) +"expect(set).not.toContainEqual(value) // deep equality -Expected set: - Set {1, 2, 3, 4} -Not to contain a value equal to: - 1 -" +Expected value: 1 +Received set: Set {1, 2, 3, 4}" `; exports[`.toContain(), .toContainEqual() error cases 1`] = ` @@ -2812,111 +2751,81 @@ Received: exports[`.toHaveLength {pass: false} expect("").toHaveLength(1) 1`] = ` "expect(received).toHaveLength(length) -Expected value to have length: - 1 -Received: - \\"\\" -received.length: - 0" +Expected length: 1 +Received length: 0 +Received string: \\"\\"" `; exports[`.toHaveLength {pass: false} expect("abc").toHaveLength(66) 1`] = ` "expect(received).toHaveLength(length) -Expected value to have length: - 66 -Received: - \\"abc\\" -received.length: - 3" +Expected length: 66 +Received length: 3 +Received string: \\"abc\\"" `; exports[`.toHaveLength {pass: false} expect(["a", "b"]).toHaveLength(99) 1`] = ` "expect(received).toHaveLength(length) -Expected value to have length: - 99 -Received: - [\\"a\\", \\"b\\"] -received.length: - 2" +Expected length: 99 +Received length: 2 +Received array: [\\"a\\", \\"b\\"]" `; exports[`.toHaveLength {pass: false} expect([]).toHaveLength(1) 1`] = ` "expect(received).toHaveLength(length) -Expected value to have length: - 1 -Received: - [] -received.length: - 0" +Expected length: 1 +Received length: 0 +Received array: []" `; exports[`.toHaveLength {pass: false} expect([1, 2]).toHaveLength(3) 1`] = ` "expect(received).toHaveLength(length) -Expected value to have length: - 3 -Received: - [1, 2] -received.length: - 2" +Expected length: 3 +Received length: 2 +Received array: [1, 2]" `; exports[`.toHaveLength {pass: true} expect("").toHaveLength(0) 1`] = ` -"expect(received).not.toHaveLength(length) +"expect(received).not.toHaveLength(length) -Expected value to not have length: - 0 -Received: - \\"\\" -received.length: - 0" +Expected length: 0 +Received length: 0 +Received string: \\"\\"" `; exports[`.toHaveLength {pass: true} expect("abc").toHaveLength(3) 1`] = ` -"expect(received).not.toHaveLength(length) +"expect(received).not.toHaveLength(length) -Expected value to not have length: - 3 -Received: - \\"abc\\" -received.length: - 3" +Expected length: 3 +Received length: 3 +Received string: \\"abc\\"" `; exports[`.toHaveLength {pass: true} expect(["a", "b"]).toHaveLength(2) 1`] = ` -"expect(received).not.toHaveLength(length) +"expect(received).not.toHaveLength(length) -Expected value to not have length: - 2 -Received: - [\\"a\\", \\"b\\"] -received.length: - 2" +Expected length: 2 +Received length: 2 +Received array: [\\"a\\", \\"b\\"]" `; exports[`.toHaveLength {pass: true} expect([]).toHaveLength(0) 1`] = ` -"expect(received).not.toHaveLength(length) +"expect(received).not.toHaveLength(length) -Expected value to not have length: - 0 -Received: - [] -received.length: - 0" +Expected length: 0 +Received length: 0 +Received array: []" `; exports[`.toHaveLength {pass: true} expect([1, 2]).toHaveLength(2) 1`] = ` -"expect(received).not.toHaveLength(length) +"expect(received).not.toHaveLength(length) -Expected value to not have length: - 2 -Received: - [1, 2] -received.length: - 2" +Expected length: 2 +Received length: 2 +Received array: [1, 2]" `; exports[`.toHaveLength error cases 1`] = ` diff --git a/packages/expect/src/matchers.js b/packages/expect/src/matchers.js index adcbe91ae50e..1baa47fa44af 100644 --- a/packages/expect/src/matchers.js +++ b/packages/expect/src/matchers.js @@ -19,6 +19,7 @@ import { SUGGEST_TO_CONTAIN_EQUAL, ensureNoExpected, ensureNumbers, + getLabelPrinter, matcherErrorMessage, matcherHint, printReceived, @@ -102,8 +103,8 @@ const matchers: MatchersObject = { }) + '\n\n' + `Precision: ${printExpected(precision)}-digit\n` + - `Expected: ${printExpected(expected)}\n` + - `Received: ${printReceived(actual)}`; + `Expected: ${printExpected(expected)}\n` + + `Received: ${printReceived(actual)}`; return {message, pass}; }, @@ -305,32 +306,29 @@ const matchers: MatchersObject = { // At this point, we're either a string or an Array, // which was converted from an array-like structure. const pass = converted.indexOf(value) != -1; - const message = pass - ? () => - matcherHint('.not.toContain', collectionType, 'value') + - '\n\n' + - `Expected ${collectionType}:\n` + - ` ${printReceived(collection)}\n` + - `Not to contain value:\n` + - ` ${printExpected(value)}\n` - : () => { - const suggestToContainEqual = - converted !== null && - typeof converted !== 'string' && - converted instanceof Array && - converted.findIndex(item => - equals(item, value, [iterableEquality]), - ) !== -1; - return ( - matcherHint('.toContain', collectionType, 'value') + - '\n\n' + - `Expected ${collectionType}:\n` + - ` ${printReceived(collection)}\n` + - `To contain value:\n` + - ` ${printExpected(value)}` + - (suggestToContainEqual ? `\n\n${SUGGEST_TO_CONTAIN_EQUAL}` : '') - ); - }; + const message = () => { + const stringExpected = 'Expected value'; + const stringReceived = `Received ${collectionType}`; + const printLabel = getLabelPrinter(stringExpected, stringReceived); + const suggestToContainEqual = + !pass && + converted !== null && + typeof converted !== 'string' && + converted instanceof Array && + converted.findIndex(item => equals(item, value, [iterableEquality])) !== + -1; + + return ( + matcherHint('.toContain', collectionType, 'value', { + comment: 'indexOf', + isNot: this.isNot, + }) + + '\n\n' + + `${printLabel(stringExpected)}${printExpected(value)}\n` + + `${printLabel(stringReceived)}${printReceived(collection)}` + + (suggestToContainEqual ? `\n\n${SUGGEST_TO_CONTAIN_EQUAL}` : '') + ); + }; return {message, pass}; }, @@ -361,21 +359,21 @@ const matchers: MatchersObject = { const pass = converted.findIndex(item => equals(item, value, [iterableEquality])) !== -1; - const message = pass - ? () => - matcherHint('.not.toContainEqual', collectionType, 'value') + - '\n\n' + - `Expected ${collectionType}:\n` + - ` ${printReceived(collection)}\n` + - `Not to contain a value equal to:\n` + - ` ${printExpected(value)}\n` - : () => - matcherHint('.toContainEqual', collectionType, 'value') + - '\n\n' + - `Expected ${collectionType}:\n` + - ` ${printReceived(collection)}\n` + - `To contain a value equal to:\n` + - ` ${printExpected(value)}`; + const message = () => { + const stringExpected = 'Expected value'; + const stringReceived = `Received ${collectionType}`; + const printLabel = getLabelPrinter(stringExpected, stringReceived); + + return ( + matcherHint('.toContainEqual', collectionType, 'value', { + comment: 'deep equality', + isNot: this.isNot, + }) + + '\n\n' + + `${printLabel(stringExpected)}${printExpected(value)}\n` + + `${printLabel(stringReceived)}${printReceived(collection)}` + ); + }; return {message, pass}; }, @@ -443,25 +441,28 @@ const matchers: MatchersObject = { } const pass = received.length === length; - const message = pass - ? () => - matcherHint('.not.toHaveLength', 'received', 'length') + - '\n\n' + - `Expected value to not have length:\n` + - ` ${printExpected(length)}\n` + - `Received:\n` + - ` ${printReceived(received)}\n` + - `received.length:\n` + - ` ${printReceived(received.length)}` - : () => - matcherHint('.toHaveLength', 'received', 'length') + - '\n\n' + - `Expected value to have length:\n` + - ` ${printExpected(length)}\n` + - `Received:\n` + - ` ${printReceived(received)}\n` + - `received.length:\n` + - ` ${printReceived(received.length)}`; + const message = () => { + const stringExpected = 'Expected length'; + const stringReceivedLength = 'Received length'; + const stringReceivedValue = `Received ${getType(received)}`; + const printLabel = getLabelPrinter( + stringExpected, + stringReceivedLength, + stringReceivedValue, + ); + + return ( + matcherHint('.toHaveLength', 'received', 'length', { + isNot: this.isNot, + }) + + '\n\n' + + `${printLabel(stringExpected)}${printExpected(length)}\n` + + `${printLabel(stringReceivedLength)}${printReceived( + received.length, + )}\n` + + `${printLabel(stringReceivedValue)}${printReceived(received)}` + ); + }; return {message, pass}; }, diff --git a/packages/jest-matcher-utils/src/__tests__/index.test.js b/packages/jest-matcher-utils/src/__tests__/index.test.js index 9db8878662b1..b6ab75a5722c 100644 --- a/packages/jest-matcher-utils/src/__tests__/index.test.js +++ b/packages/jest-matcher-utils/src/__tests__/index.test.js @@ -6,9 +6,13 @@ * */ -'use strict'; - -import {ensureNoExpected, ensureNumbers, pluralize, stringify} from '../'; +import { + ensureNumbers, + ensureNoExpected, + getLabelPrinter, + pluralize, + stringify, +} from '../'; describe('.stringify()', () => { [ @@ -130,3 +134,53 @@ describe('.pluralize()', () => { test('two', () => expect(pluralize('apple', 2)).toEqual('two apples')); test('20', () => expect(pluralize('apple', 20)).toEqual('20 apples')); }); + +describe('getLabelPrinter', () => { + test('0 args', () => { + const printLabel = getLabelPrinter(); + expect(printLabel('')).toBe(': '); + }); + test('1 empty string', () => { + const printLabel = getLabelPrinter(); + expect(printLabel('')).toBe(': '); + }); + test('1 non-empty string', () => { + const string = 'Expected'; + const printLabel = getLabelPrinter(string); + expect(printLabel(string)).toBe('Expected: '); + }); + test('2 equal lengths', () => { + const stringExpected = 'Expected value'; + const collectionType = 'array'; + const stringReceived = `Received ${collectionType}`; + const printLabel = getLabelPrinter(stringExpected, stringReceived); + expect(printLabel(stringExpected)).toBe('Expected value: '); + expect(printLabel(stringReceived)).toBe('Received array: '); + }); + test('2 unequal lengths', () => { + const stringExpected = 'Expected value'; + const collectionType = 'set'; + const stringReceived = `Received ${collectionType}`; + const printLabel = getLabelPrinter(stringExpected, stringReceived); + expect(printLabel(stringExpected)).toBe('Expected value: '); + expect(printLabel(stringReceived)).toBe('Received set: '); + }); + test('returns incorrect padding if inconsistent arg is shorter', () => { + const stringConsistent = 'Expected'; + const stringInconsistent = 'Received value'; + const stringInconsistentShorter = 'Received set'; + const printLabel = getLabelPrinter(stringConsistent, stringInconsistent); + expect(printLabel(stringConsistent)).toBe('Expected: '); + expect(printLabel(stringInconsistentShorter)).toBe('Received set: '); + }); + test('throws if inconsistent arg is longer', () => { + const stringConsistent = 'Expected'; + const stringInconsistent = 'Received value'; + const stringInconsistentLonger = 'Received string'; + const printLabel = getLabelPrinter(stringConsistent, stringInconsistent); + expect(printLabel(stringConsistent)).toBe('Expected: '); + expect(() => { + printLabel(stringInconsistentLonger); + }).toThrow(); + }); +}); diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index 03f0e6369826..4b0b8be351fe 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -153,6 +153,21 @@ export const ensureNumbers = ( export const pluralize = (word: string, count: number) => (NUMBERS[count] || count) + ' ' + word + (count === 1 ? '' : 's'); +// To display lines of labeled values as two columns with monospace alignment: +// given the strings which will describe the values, +// return function which given each string, returns the label: +// string, colon, space, and enough padding spaces to align the value. + +type PrintLabel = string => string; + +export const getLabelPrinter = (...strings: Array): PrintLabel => { + const maxLength = strings.reduce( + (max, string) => (string.length > max ? string.length : max), + 0, + ); + return string => `${string}: ${' '.repeat(maxLength - string.length)}`; +}; + export const matcherErrorMessage = ( hint: string, // assertion returned from call to matcherHint generic: string, // condition which correct value must fulfill