From 80f97b3cdebe9f5e4d15593031ed65d897bdb15d Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Thu, 27 Dec 2018 17:25:12 -0500 Subject: [PATCH 01/11] expect/jest-matcher-utils: Improve report when assertion fails, part 5 --- .../__snapshots__/failures.test.js.snap | 10 +- .../assertionCounts.test.js.snap | 2 +- .../__snapshots__/matchers.test.js.snap | 282 +++++++++--------- .../__snapshots__/spyMatchers.test.js.snap | 100 +++---- .../toThrowMatchers.test.js.snap | 4 +- .../expect/src/__tests__/matchers.test.js | 10 +- packages/expect/src/index.js | 54 ++-- packages/expect/src/matchers.js | 113 ++++--- .../__snapshots__/index.test.js.snap | 8 +- .../src/__tests__/index.test.js | 8 +- packages/jest-matcher-utils/src/index.js | 94 ++++-- types/Matchers.js | 8 + 12 files changed, 398 insertions(+), 295 deletions(-) diff --git a/e2e/__tests__/__snapshots__/failures.test.js.snap b/e2e/__tests__/__snapshots__/failures.test.js.snap index b202ca4340d4..3f03b03af34a 100644 --- a/e2e/__tests__/__snapshots__/failures.test.js.snap +++ b/e2e/__tests__/__snapshots__/failures.test.js.snap @@ -360,8 +360,9 @@ exports[`works with async failures 1`] = ` expect(received).rejects.toEqual() - Expected received Promise to reject, instead it resolved to value - {\\"foo\\": \\"bar\\"} + Received promise resolves instead of rejects + + Received value: {\\"foo\\": \\"bar\\"} 16 | 17 | test('expect reject', () => @@ -377,8 +378,9 @@ exports[`works with async failures 1`] = ` expect(received).resolves.toEqual() - Expected received Promise to resolve, instead it rejected to value - {\\"foo\\": \\"bar\\"} + Received promise rejects instead of resolves + + Received value: {\\"foo\\": \\"bar\\"} 19 | 20 | test('expect resolve', () => diff --git a/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap b/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap index c7474a6ec766..ca1bc099e9df 100644 --- a/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`.hasAssertions() throws if expected is not undefined 1`] = ` -"expect(received)[.not].hasAssertions() +"expect(received)[.not].hasAssertions() Matcher error: expected value must be omitted or undefined diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index f1503dbd4ff4..069a29f662f2 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -1,225 +1,227 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`.rejects fails for promise that resolves 1`] = ` -"expect(received).rejects.toBe() +"expect(received).rejects.toBe() -Expected received Promise to reject, instead it resolved to value - 4" +Received promise resolves instead of rejects + +Received value: 4" `; exports[`.rejects fails non-promise value "a" 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: string Received has value: \\"a\\"" `; exports[`.rejects fails non-promise value [1] 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: array Received has value: [1]" `; exports[`.rejects fails non-promise value [Function anonymous] 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: function Received has value: [Function anonymous]" `; exports[`.rejects fails non-promise value {"a": 1} 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: object Received has value: {\\"a\\": 1}" `; exports[`.rejects fails non-promise value 4 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: number Received has value: 4" `; exports[`.rejects fails non-promise value null 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has value: null" `; exports[`.rejects fails non-promise value true 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: boolean Received has value: true" `; exports[`.rejects fails non-promise value undefined 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has value: undefined" `; exports[`.resolves fails for promise that rejects 1`] = ` -"expect(received).resolves.toBe() +"expect(received).resolves.toBe() + +Received promise rejects instead of resolves -Expected received Promise to resolve, instead it rejected to value - 4" +Received value: 4" `; exports[`.resolves fails non-promise value "a" 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: string Received has value: \\"a\\"" `; exports[`.resolves fails non-promise value "a" synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: string Received has value: \\"a\\"" `; exports[`.resolves fails non-promise value [1] 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: array Received has value: [1]" `; exports[`.resolves fails non-promise value [1] synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: array Received has value: [1]" `; exports[`.resolves fails non-promise value [Function anonymous] 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: function Received has value: [Function anonymous]" `; exports[`.resolves fails non-promise value [Function anonymous] synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: function Received has value: [Function anonymous]" `; exports[`.resolves fails non-promise value {"a": 1} 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: object Received has value: {\\"a\\": 1}" `; exports[`.resolves fails non-promise value {"a": 1} synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: object Received has value: {\\"a\\": 1}" `; exports[`.resolves fails non-promise value 4 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: number Received has value: 4" `; exports[`.resolves fails non-promise value 4 synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: number Received has value: 4" `; exports[`.resolves fails non-promise value null 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has value: null" `; exports[`.resolves fails non-promise value null synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has value: null" `; exports[`.resolves fails non-promise value true 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: boolean Received has value: true" `; exports[`.resolves fails non-promise value true synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has type: boolean Received has value: true" `; exports[`.resolves fails non-promise value undefined 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has value: undefined" `; exports[`.resolves fails non-promise value undefined synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.toBeDefined() -Matcher error: received value must be a Promise +Matcher error: received value must be a promise Received has value: undefined" `; @@ -529,121 +531,121 @@ Received: 1.23" `; exports[`.toBeDefined(), .toBeUndefined() '"a"' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: \\"a\\"" `; exports[`.toBeDefined(), .toBeUndefined() '"a"' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: \\"a\\"" `; exports[`.toBeDefined(), .toBeUndefined() '[]' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: []" `; exports[`.toBeDefined(), .toBeUndefined() '[]' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: []" `; exports[`.toBeDefined(), .toBeUndefined() '[Function anonymous]' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: [Function anonymous]" `; exports[`.toBeDefined(), .toBeUndefined() '[Function anonymous]' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: [Function anonymous]" `; exports[`.toBeDefined(), .toBeUndefined() '{}' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: {}" `; exports[`.toBeDefined(), .toBeUndefined() '{}' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: {}" `; exports[`.toBeDefined(), .toBeUndefined() '0.5' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: 0.5" `; exports[`.toBeDefined(), .toBeUndefined() '0.5' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: 0.5" `; exports[`.toBeDefined(), .toBeUndefined() '1' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: 1" `; exports[`.toBeDefined(), .toBeUndefined() '1' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: 1" `; exports[`.toBeDefined(), .toBeUndefined() 'Infinity' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: Infinity" `; exports[`.toBeDefined(), .toBeUndefined() 'Infinity' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: Infinity" `; exports[`.toBeDefined(), .toBeUndefined() 'Map {}' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: Map {}" `; exports[`.toBeDefined(), .toBeUndefined() 'Map {}' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: Map {}" `; exports[`.toBeDefined(), .toBeUndefined() 'true' is defined 1`] = ` -"expect(received).not.toBeDefined() +"expect(received).not.toBeDefined() Received: true" `; exports[`.toBeDefined(), .toBeUndefined() 'true' is defined 2`] = ` -"expect(received).toBeUndefined() +"expect(received).toBeUndefined() Received: true" `; exports[`.toBeDefined(), .toBeUndefined() undefined is undefined 1`] = ` -"expect(received).toBeDefined() +"expect(received).toBeDefined() Received: undefined" `; exports[`.toBeDefined(), .toBeUndefined() undefined is undefined 2`] = ` -"expect(received).not.toBeUndefined() +"expect(received).not.toBeUndefined() Received: undefined" `; @@ -1197,331 +1199,331 @@ Expected has value: 4" `; exports[`.toBeNaN() {pass: true} expect(NaN).toBeNaN() 1`] = ` -"expect(received).not.toBeNaN() +"expect(received).not.toBeNaN() Received: NaN" `; exports[`.toBeNaN() {pass: true} expect(NaN).toBeNaN() 2`] = ` -"expect(received).not.toBeNaN() +"expect(received).not.toBeNaN() Received: NaN" `; exports[`.toBeNaN() {pass: true} expect(NaN).toBeNaN() 3`] = ` -"expect(received).not.toBeNaN() +"expect(received).not.toBeNaN() Received: NaN" `; exports[`.toBeNaN() {pass: true} expect(NaN).toBeNaN() 4`] = ` -"expect(received).not.toBeNaN() +"expect(received).not.toBeNaN() Received: NaN" `; exports[`.toBeNaN() throws 1`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: 1" `; exports[`.toBeNaN() throws 2`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: \\"\\"" `; exports[`.toBeNaN() throws 3`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: null" `; exports[`.toBeNaN() throws 4`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: undefined" `; exports[`.toBeNaN() throws 5`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: {}" `; exports[`.toBeNaN() throws 6`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: []" `; exports[`.toBeNaN() throws 7`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: 0.2" `; exports[`.toBeNaN() throws 8`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: 0" `; exports[`.toBeNaN() throws 9`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: Infinity" `; exports[`.toBeNaN() throws 10`] = ` -"expect(received).toBeNaN() +"expect(received).toBeNaN() Received: -Infinity" `; -exports[`.toBeNull() fails for '"a"' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for '"a"' 1`] = ` +"expect(received).toBeNull() Received: \\"a\\"" `; -exports[`.toBeNull() fails for '[]' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for '[]' 1`] = ` +"expect(received).toBeNull() Received: []" `; -exports[`.toBeNull() fails for '[Function anonymous]' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for '[Function anonymous]' 1`] = ` +"expect(received).toBeNull() Received: [Function anonymous]" `; -exports[`.toBeNull() fails for '{}' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for '{}' 1`] = ` +"expect(received).toBeNull() Received: {}" `; -exports[`.toBeNull() fails for '0.5' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for '0.5' 1`] = ` +"expect(received).toBeNull() Received: 0.5" `; -exports[`.toBeNull() fails for '1' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for '1' 1`] = ` +"expect(received).toBeNull() Received: 1" `; -exports[`.toBeNull() fails for 'Infinity' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for 'Infinity' 1`] = ` +"expect(received).toBeNull() Received: Infinity" `; -exports[`.toBeNull() fails for 'Map {}' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for 'Map {}' 1`] = ` +"expect(received).toBeNull() Received: Map {}" `; -exports[`.toBeNull() fails for 'true' with .not 1`] = ` -"expect(received).toBeNull() +exports[`.toBeNull() fails for 'true' 1`] = ` +"expect(received).toBeNull() Received: true" `; -exports[`.toBeNull() pass for null 1`] = ` -"expect(received).not.toBeNull() +exports[`.toBeNull() fails for null with .not 1`] = ` +"expect(received).not.toBeNull() Received: null" `; exports[`.toBeTruthy(), .toBeFalsy() '""' is falsy 1`] = ` -"expect(received).toBeTruthy() +"expect(received).toBeTruthy() Received: \\"\\"" `; exports[`.toBeTruthy(), .toBeFalsy() '""' is falsy 2`] = ` -"expect(received).not.toBeFalsy() +"expect(received).not.toBeFalsy() Received: \\"\\"" `; exports[`.toBeTruthy(), .toBeFalsy() '"a"' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: \\"a\\"" `; exports[`.toBeTruthy(), .toBeFalsy() '"a"' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: \\"a\\"" `; exports[`.toBeTruthy(), .toBeFalsy() '[]' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: []" `; exports[`.toBeTruthy(), .toBeFalsy() '[]' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: []" `; exports[`.toBeTruthy(), .toBeFalsy() '[Function anonymous]' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: [Function anonymous]" `; exports[`.toBeTruthy(), .toBeFalsy() '[Function anonymous]' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: [Function anonymous]" `; exports[`.toBeTruthy(), .toBeFalsy() '{}' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: {}" `; exports[`.toBeTruthy(), .toBeFalsy() '{}' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: {}" `; exports[`.toBeTruthy(), .toBeFalsy() '0' is falsy 1`] = ` -"expect(received).toBeTruthy() +"expect(received).toBeTruthy() Received: 0" `; exports[`.toBeTruthy(), .toBeFalsy() '0' is falsy 2`] = ` -"expect(received).not.toBeFalsy() +"expect(received).not.toBeFalsy() Received: 0" `; exports[`.toBeTruthy(), .toBeFalsy() '0.5' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: 0.5" `; exports[`.toBeTruthy(), .toBeFalsy() '0.5' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: 0.5" `; exports[`.toBeTruthy(), .toBeFalsy() '1' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: 1" `; exports[`.toBeTruthy(), .toBeFalsy() '1' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: 1" `; exports[`.toBeTruthy(), .toBeFalsy() 'Infinity' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: Infinity" `; exports[`.toBeTruthy(), .toBeFalsy() 'Infinity' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: Infinity" `; exports[`.toBeTruthy(), .toBeFalsy() 'Map {}' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: Map {}" `; exports[`.toBeTruthy(), .toBeFalsy() 'Map {}' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: Map {}" `; exports[`.toBeTruthy(), .toBeFalsy() 'NaN' is falsy 1`] = ` -"expect(received).toBeTruthy() +"expect(received).toBeTruthy() Received: NaN" `; exports[`.toBeTruthy(), .toBeFalsy() 'NaN' is falsy 2`] = ` -"expect(received).not.toBeFalsy() +"expect(received).not.toBeFalsy() Received: NaN" `; exports[`.toBeTruthy(), .toBeFalsy() 'false' is falsy 1`] = ` -"expect(received).toBeTruthy() +"expect(received).toBeTruthy() Received: false" `; exports[`.toBeTruthy(), .toBeFalsy() 'false' is falsy 2`] = ` -"expect(received).not.toBeFalsy() +"expect(received).not.toBeFalsy() Received: false" `; exports[`.toBeTruthy(), .toBeFalsy() 'null' is falsy 1`] = ` -"expect(received).toBeTruthy() +"expect(received).toBeTruthy() Received: null" `; exports[`.toBeTruthy(), .toBeFalsy() 'null' is falsy 2`] = ` -"expect(received).not.toBeFalsy() +"expect(received).not.toBeFalsy() Received: null" `; exports[`.toBeTruthy(), .toBeFalsy() 'true' is truthy 1`] = ` -"expect(received).not.toBeTruthy() +"expect(received).not.toBeTruthy() Received: true" `; exports[`.toBeTruthy(), .toBeFalsy() 'true' is truthy 2`] = ` -"expect(received).toBeFalsy() +"expect(received).toBeFalsy() Received: true" `; exports[`.toBeTruthy(), .toBeFalsy() 'undefined' is falsy 1`] = ` -"expect(received).toBeTruthy() +"expect(received).toBeTruthy() Received: undefined" `; exports[`.toBeTruthy(), .toBeFalsy() 'undefined' is falsy 2`] = ` -"expect(received).not.toBeFalsy() +"expect(received).not.toBeFalsy() Received: undefined" `; exports[`.toBeTruthy(), .toBeFalsy() does not accept arguments 1`] = ` -"expect(received)[.not].toBeTruthy() +"expect(received).toBeTruthy() Matcher error: expected value must be omitted or undefined @@ -1529,7 +1531,7 @@ Expected has value: null" `; exports[`.toBeTruthy(), .toBeFalsy() does not accept arguments 2`] = ` -"expect(received)[.not].toBeFalsy() +"expect(received).toBeFalsy() Matcher error: expected value must be omitted or undefined diff --git a/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap index 6a64d8650306..0ffe77b4172c 100644 --- a/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap @@ -8,7 +8,7 @@ Expected mock function \\"named-mock\\" to not have been last called with: `; exports[`lastCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].lastCalledWith() +"expect(jest.fn())[.not].lastCalledWith() Matcher error: received value must be a mock or spy function @@ -159,7 +159,7 @@ But the last call has not returned yet" `; exports[`lastReturnedWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].lastReturnedWith() +"expect(jest.fn())[.not].lastReturnedWith() Matcher error: received value must be a mock or spy function @@ -293,7 +293,7 @@ Expected mock function first call to not have been called with: `; exports[`nthCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].nthCalledWith() +"expect(jest.fn())[.not].nthCalledWith() Matcher error: received value must be a mock or spy function @@ -491,7 +491,7 @@ But the first call returned exactly: `; exports[`nthReturnedWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].nthReturnedWith() +"expect(jest.fn())[.not].nthReturnedWith() Matcher error: received value must be a mock or spy function @@ -598,7 +598,7 @@ But the first call returned exactly: `; exports[`toBeCalled .not fails with any argument passed 1`] = ` -"expect(received)[.not].toBeCalled() +"expect(received)[.not].toBeCalled() Matcher error: expected value must be omitted or undefined @@ -607,13 +607,13 @@ Expected has value: 555" `; exports[`toBeCalled .not passes when called 1`] = ` -"expect(jest.fn()).toBeCalled() +"expect(jest.fn()).toBeCalled() Expected mock function to have been called, but it was not called." `; exports[`toBeCalled fails with any argument passed 1`] = ` -"expect(received)[.not].toBeCalled() +"expect(received)[.not].toBeCalled() Matcher error: expected value must be omitted or undefined @@ -622,21 +622,21 @@ Expected has value: 555" `; exports[`toBeCalled includes the custom mock name in the error message 1`] = ` -"expect(named-mock).not.toBeCalled() +"expect(named-mock).not.toBeCalled() Expected mock function \\"named-mock\\" not to be called but it was called with: []" `; exports[`toBeCalled passes when called 1`] = ` -"expect(jest.fn()).not.toBeCalled() +"expect(jest.fn()).not.toBeCalled() Expected mock function not to be called but it was called with: []" `; exports[`toBeCalled works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toBeCalled() +"expect(jest.fn())[.not].toBeCalled() Matcher error: received value must be a mock or spy function @@ -777,7 +777,7 @@ Expected mock function not to be called two times, but it was called e `; exports[`toBeCalledTimes works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toBeCalledTimes() +"expect(jest.fn())[.not].toBeCalledTimes() Matcher error: received value must be a mock or spy function @@ -793,7 +793,7 @@ Expected mock function \\"named-mock\\" not to have been called with: `; exports[`toBeCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toBeCalledWith() +"expect(jest.fn())[.not].toBeCalledWith() Matcher error: received value must be a mock or spy function @@ -920,7 +920,7 @@ Expected mock function to have been called with: `; exports[`toHaveBeenCalled .not fails with any argument passed 1`] = ` -"expect(received)[.not].toHaveBeenCalled() +"expect(received)[.not].toHaveBeenCalled() Matcher error: expected value must be omitted or undefined @@ -929,13 +929,13 @@ Expected has value: 555" `; exports[`toHaveBeenCalled .not passes when called 1`] = ` -"expect(jest.fn()).toHaveBeenCalled() +"expect(jest.fn()).toHaveBeenCalled() Expected mock function to have been called, but it was not called." `; exports[`toHaveBeenCalled fails with any argument passed 1`] = ` -"expect(received)[.not].toHaveBeenCalled() +"expect(received)[.not].toHaveBeenCalled() Matcher error: expected value must be omitted or undefined @@ -944,21 +944,21 @@ Expected has value: 555" `; exports[`toHaveBeenCalled includes the custom mock name in the error message 1`] = ` -"expect(named-mock).not.toHaveBeenCalled() +"expect(named-mock).not.toHaveBeenCalled() Expected mock function \\"named-mock\\" not to be called but it was called with: []" `; exports[`toHaveBeenCalled passes when called 1`] = ` -"expect(jest.fn()).not.toHaveBeenCalled() +"expect(jest.fn()).not.toHaveBeenCalled() Expected mock function not to be called but it was called with: []" `; exports[`toHaveBeenCalled works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenCalled() +"expect(jest.fn())[.not].toHaveBeenCalled() Matcher error: received value must be a mock or spy function @@ -1099,7 +1099,7 @@ Expected mock function not to be called two times, but it was called e `; exports[`toHaveBeenCalledTimes works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenCalledTimes() +"expect(jest.fn())[.not].toHaveBeenCalledTimes() Matcher error: received value must be a mock or spy function @@ -1115,7 +1115,7 @@ Expected mock function \\"named-mock\\" not to have been called with: `; exports[`toHaveBeenCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenCalledWith() +"expect(jest.fn())[.not].toHaveBeenCalledWith() Matcher error: received value must be a mock or spy function @@ -1249,7 +1249,7 @@ Expected mock function \\"named-mock\\" to not have been last called with: `; exports[`toHaveBeenLastCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenLastCalledWith() +"expect(jest.fn())[.not].toHaveBeenLastCalledWith() Matcher error: received value must be a mock or spy function @@ -1395,7 +1395,7 @@ Expected mock function first call to not have been called with: `; exports[`toHaveBeenNthCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenNthCalledWith() +"expect(jest.fn())[.not].toHaveBeenNthCalledWith() Matcher error: received value must be a mock or spy function @@ -1537,7 +1537,7 @@ But the last call has not returned yet" `; exports[`toHaveLastReturnedWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveLastReturnedWith() +"expect(jest.fn())[.not].toHaveLastReturnedWith() Matcher error: received value must be a mock or spy function @@ -1732,7 +1732,7 @@ But the first call returned exactly: `; exports[`toHaveNthReturnedWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveNthReturnedWith() +"expect(jest.fn())[.not].toHaveNthReturnedWith() Matcher error: received value must be a mock or spy function @@ -1839,7 +1839,7 @@ But the first call returned exactly: `; exports[`toHaveReturned .not fails with any argument passed 1`] = ` -"expect(received)[.not].toHaveReturned() +"expect(received)[.not].toHaveReturned() Matcher error: expected value must be omitted or undefined @@ -1848,25 +1848,25 @@ Expected has value: 555" `; exports[`toHaveReturned .not passes when a call throws undefined 1`] = ` -"expect(jest.fn()).toHaveReturned() +"expect(jest.fn()).toHaveReturned() Expected mock function to have returned." `; exports[`toHaveReturned .not passes when all calls throw 1`] = ` -"expect(jest.fn()).toHaveReturned() +"expect(jest.fn()).toHaveReturned() Expected mock function to have returned." `; exports[`toHaveReturned .not passes when not returned 1`] = ` -"expect(jest.fn()).toHaveReturned() +"expect(jest.fn()).toHaveReturned() Expected mock function to have returned." `; exports[`toHaveReturned fails with any argument passed 1`] = ` -"expect(received)[.not].toHaveReturned() +"expect(received)[.not].toHaveReturned() Matcher error: expected value must be omitted or undefined @@ -1875,20 +1875,20 @@ Expected has value: 555" `; exports[`toHaveReturned includes the custom mock name in the error message 1`] = ` -"expect(named-mock).not.toHaveReturned() +"expect(named-mock).not.toHaveReturned() Expected mock function \\"named-mock\\" not to have returned, but it returned: 42" `; exports[`toHaveReturned incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).toHaveReturned() +"expect(jest.fn()).toHaveReturned() Expected mock function to have returned." `; exports[`toHaveReturned passes when at least one call does not throw 1`] = ` -"expect(jest.fn()).not.toHaveReturned() +"expect(jest.fn()).not.toHaveReturned() Expected mock function not to have returned, but it returned: 42 @@ -1897,21 +1897,21 @@ Expected mock function not to have returned, but it returned: `; exports[`toHaveReturned passes when returned 1`] = ` -"expect(jest.fn()).not.toHaveReturned() +"expect(jest.fn()).not.toHaveReturned() Expected mock function not to have returned, but it returned: 42" `; exports[`toHaveReturned passes when undefined is returned 1`] = ` -"expect(jest.fn()).not.toHaveReturned() +"expect(jest.fn()).not.toHaveReturned() Expected mock function not to have returned, but it returned: undefined" `; exports[`toHaveReturned works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveReturned() +"expect(jest.fn())[.not].toHaveReturned() Matcher error: received value must be a mock or spy function @@ -2076,7 +2076,7 @@ Expected mock function not to have returned two times, but it returned `; exports[`toHaveReturnedTimes works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveReturnedTimes() +"expect(jest.fn())[.not].toHaveReturnedTimes() Matcher error: received value must be a mock or spy function @@ -2117,7 +2117,7 @@ But it did not return." `; exports[`toHaveReturnedWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveReturnedWith() +"expect(jest.fn())[.not].toHaveReturnedWith() Matcher error: received value must be a mock or spy function @@ -2234,7 +2234,7 @@ But it returned exactly: `; exports[`toReturn .not fails with any argument passed 1`] = ` -"expect(received)[.not].toReturn() +"expect(received)[.not].toReturn() Matcher error: expected value must be omitted or undefined @@ -2243,25 +2243,25 @@ Expected has value: 555" `; exports[`toReturn .not passes when a call throws undefined 1`] = ` -"expect(jest.fn()).toReturn() +"expect(jest.fn()).toReturn() Expected mock function to have returned." `; exports[`toReturn .not passes when all calls throw 1`] = ` -"expect(jest.fn()).toReturn() +"expect(jest.fn()).toReturn() Expected mock function to have returned." `; exports[`toReturn .not passes when not returned 1`] = ` -"expect(jest.fn()).toReturn() +"expect(jest.fn()).toReturn() Expected mock function to have returned." `; exports[`toReturn fails with any argument passed 1`] = ` -"expect(received)[.not].toReturn() +"expect(received)[.not].toReturn() Matcher error: expected value must be omitted or undefined @@ -2270,20 +2270,20 @@ Expected has value: 555" `; exports[`toReturn includes the custom mock name in the error message 1`] = ` -"expect(named-mock).not.toReturn() +"expect(named-mock).not.toReturn() Expected mock function \\"named-mock\\" not to have returned, but it returned: 42" `; exports[`toReturn incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).toReturn() +"expect(jest.fn()).toReturn() Expected mock function to have returned." `; exports[`toReturn passes when at least one call does not throw 1`] = ` -"expect(jest.fn()).not.toReturn() +"expect(jest.fn()).not.toReturn() Expected mock function not to have returned, but it returned: 42 @@ -2292,21 +2292,21 @@ Expected mock function not to have returned, but it returned: `; exports[`toReturn passes when returned 1`] = ` -"expect(jest.fn()).not.toReturn() +"expect(jest.fn()).not.toReturn() Expected mock function not to have returned, but it returned: 42" `; exports[`toReturn passes when undefined is returned 1`] = ` -"expect(jest.fn()).not.toReturn() +"expect(jest.fn()).not.toReturn() Expected mock function not to have returned, but it returned: undefined" `; exports[`toReturn works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toReturn() +"expect(jest.fn())[.not].toReturn() Matcher error: received value must be a mock or spy function @@ -2471,7 +2471,7 @@ Expected mock function not to have returned two times, but it returned `; exports[`toReturnTimes works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toReturnTimes() +"expect(jest.fn())[.not].toReturnTimes() Matcher error: received value must be a mock or spy function @@ -2512,7 +2512,7 @@ But it did not return." `; exports[`toReturnWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toReturnWith() +"expect(jest.fn())[.not].toReturnWith() Matcher error: received value must be a mock or spy function diff --git a/packages/expect/src/__tests__/__snapshots__/toThrowMatchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/toThrowMatchers.test.js.snap index 8ce9e200485f..f02f4d14a79c 100644 --- a/packages/expect/src/__tests__/__snapshots__/toThrowMatchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/toThrowMatchers.test.js.snap @@ -64,7 +64,7 @@ Instead, it threw: `; exports[`.toThrow() promise/async throws if Error-like object is returned threw, but should not have 1`] = ` -[Error: expect(function).not.toThrow() +[Error: expect(function).not.toThrow() Expected the function not to throw an error. Instead, it threw: @@ -192,7 +192,7 @@ Instead, it threw: `; exports[`.toThrowError() promise/async throws if Error-like object is returned threw, but should not have 1`] = ` -[Error: expect(function).not.toThrow() +[Error: expect(function).not.toThrow() Expected the function not to throw an error. Instead, it threw: diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index c32b1d4856ba..95e7f6398f59 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -614,20 +614,22 @@ describe('.toBeNaN()', () => { describe('.toBeNull()', () => { [{}, [], true, 1, 'a', 0.5, new Map(), () => {}, Infinity].forEach(v => { - test(`fails for '${stringify(v)}' with .not`, () => { + test(`fails for '${stringify(v)}'`, () => { jestExpect(v).not.toBeNull(); expect(() => jestExpect(v).toBeNull()).toThrowErrorMatchingSnapshot(); }); }); - it('pass for null', () => { - jestExpect(null).toBeNull(); - + it('fails for null with .not', () => { expect(() => jestExpect(null).not.toBeNull(), ).toThrowErrorMatchingSnapshot(); }); + + it('pass for null', () => { + jestExpect(null).toBeNull(); + }); }); describe('.toBeDefined(), .toBeUndefined()', () => { diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index ac2644672c48..af98196a25b0 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -94,8 +94,8 @@ const expect = (actual: any, ...rest: Array): ExpectationObject => { Object.keys(allMatchers).forEach(name => { const matcher = allMatchers[name]; const promiseMatcher = getPromiseMatcher(name, matcher) || matcher; - expectation[name] = makeThrowingMatcher(matcher, false, actual); - expectation.not[name] = makeThrowingMatcher(matcher, true, actual); + expectation[name] = makeThrowingMatcher(matcher, false, '', actual); + expectation.not[name] = makeThrowingMatcher(matcher, true, '', actual); expectation.resolves[name] = makeResolveMatcher( name, @@ -142,12 +142,16 @@ const makeResolveMatcher = ( actual: Promise, outerErr: JestAssertionError, ): PromiseMatcherFn => (...args) => { - const matcherStatement = `.resolves.${isNot ? 'not.' : ''}${matcherName}`; + const options = { + isNot, + promise: 'resolves', + }; + if (!isPromise(actual)) { throw new JestAssertionError( matcherUtils.matcherErrorMessage( - matcherUtils.matcherHint(matcherStatement, undefined, ''), - `${matcherUtils.RECEIVED_COLOR('received')} value must be a Promise`, + matcherUtils.matcherHint(matcherName, undefined, '', options), + `${matcherUtils.RECEIVED_COLOR('received')} value must be a promise`, matcherUtils.printWithType( 'Received', actual, @@ -161,16 +165,16 @@ const makeResolveMatcher = ( return actual.then( result => - makeThrowingMatcher(matcher, isNot, result, innerErr).apply(null, args), + makeThrowingMatcher(matcher, isNot, 'resolves', result, innerErr).apply( + null, + args, + ), reason => { outerErr.message = - matcherUtils.matcherHint(matcherStatement, 'received', '') + + matcherUtils.matcherHint(matcherName, undefined, '', options) + '\n\n' + - `Expected ${matcherUtils.RECEIVED_COLOR( - 'received', - )} Promise to resolve, ` + - 'instead it rejected to value\n' + - ` ${matcherUtils.printReceived(reason)}`; + `Received promise rejects instead of resolves\n\n` + + `Received value: ${matcherUtils.printReceived(reason)}`; return Promise.reject(outerErr); }, ); @@ -183,12 +187,16 @@ const makeRejectMatcher = ( actual: Promise, outerErr: JestAssertionError, ): PromiseMatcherFn => (...args) => { - const matcherStatement = `.rejects.${isNot ? 'not.' : ''}${matcherName}`; + const options = { + isNot, + promise: 'rejects', + }; + if (!isPromise(actual)) { throw new JestAssertionError( matcherUtils.matcherErrorMessage( - matcherUtils.matcherHint(matcherStatement, undefined, ''), - `${matcherUtils.RECEIVED_COLOR('received')} value must be a Promise`, + matcherUtils.matcherHint(matcherName, undefined, '', options), + `${matcherUtils.RECEIVED_COLOR('received')} value must be a promise`, matcherUtils.printWithType( 'Received', actual, @@ -203,23 +211,24 @@ const makeRejectMatcher = ( return actual.then( result => { outerErr.message = - matcherUtils.matcherHint(matcherStatement, 'received', '') + + matcherUtils.matcherHint(matcherName, undefined, '', options) + '\n\n' + - `Expected ${matcherUtils.RECEIVED_COLOR( - 'received', - )} Promise to reject, ` + - 'instead it resolved to value\n' + - ` ${matcherUtils.printReceived(result)}`; + `Received promise resolves instead of rejects\n\n` + + `Received value: ${matcherUtils.printReceived(result)}`; return Promise.reject(outerErr); }, reason => - makeThrowingMatcher(matcher, isNot, reason, innerErr).apply(null, args), + makeThrowingMatcher(matcher, isNot, 'rejects', reason, innerErr).apply( + null, + args, + ), ); }; const makeThrowingMatcher = ( matcher: RawMatcherFn, isNot: boolean, + promise: string, actual: any, err?: JestAssertionError, ): ThrowingMatcherFn => @@ -242,6 +251,7 @@ const makeThrowingMatcher = ( equals, error: err, isNot, + promise, utils, }, ); diff --git a/packages/expect/src/matchers.js b/packages/expect/src/matchers.js index adcbe91ae50e..4be38c872c79 100644 --- a/packages/expect/src/matchers.js +++ b/packages/expect/src/matchers.js @@ -108,27 +108,37 @@ const matchers: MatchersObject = { return {message, pass}; }, - toBeDefined(actual: any, expected: void) { - ensureNoExpected(expected, '.toBeDefined'); - const pass = actual !== void 0; + toBeDefined(received: any, expected: void) { + const options = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, 'toBeDefined', options); + + const pass = received !== void 0; + const message = () => - matcherHint('.toBeDefined', 'received', '', { - isNot: this.isNot, - }) + + matcherHint('toBeDefined', undefined, '', options) + '\n\n' + - `Received: ${printReceived(actual)}`; + `Received: ${printReceived(received)}`; + return {message, pass}; }, - toBeFalsy(actual: any, expected: void) { - ensureNoExpected(expected, '.toBeFalsy'); - const pass = !actual; + toBeFalsy(received: any, expected: void) { + const options = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, 'toBeFalsy', options); + + const pass = !received; + const message = () => - matcherHint('.toBeFalsy', 'received', '', { - isNot: this.isNot, - }) + + matcherHint('toBeFalsy', undefined, '', options) + '\n\n' + - `Received: ${printReceived(actual)}`; + `Received: ${printReceived(received)}`; + return {message, pass}; }, @@ -228,51 +238,70 @@ const matchers: MatchersObject = { return {message, pass}; }, - toBeNaN(actual: any, expected: void) { - ensureNoExpected(expected, '.toBeNaN'); - const pass = Number.isNaN(actual); + toBeNaN(received: any, expected: void) { + const options = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, 'toBeNaN', options); + + const pass = Number.isNaN(received); + const message = () => - matcherHint('.toBeNaN', 'received', '', { - isNot: this.isNot, - }) + + matcherHint('toBeNaN', undefined, '', options) + '\n\n' + - `Received: ${printReceived(actual)}`; + `Received: ${printReceived(received)}`; + return {message, pass}; }, - toBeNull(actual: any, expected: void) { - ensureNoExpected(expected, '.toBeNull'); - const pass = actual === null; + toBeNull(received: any, expected: void) { + const options = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, 'toBeNull', options); + + const pass = received === null; + const message = () => - matcherHint('.toBeNull', 'received', '', { - isNot: this.isNot, - }) + + matcherHint('toBeNull', undefined, '', options) + '\n\n' + - `Received: ${printReceived(actual)}`; + `Received: ${printReceived(received)}`; + return {message, pass}; }, - toBeTruthy(actual: any, expected: void) { - ensureNoExpected(expected, '.toBeTruthy'); - const pass = !!actual; + toBeTruthy(received: any, expected: void) { + const options = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, 'toBeTruthy', options); + + const pass = !!received; + const message = () => - matcherHint('.toBeTruthy', 'received', '', { - isNot: this.isNot, - }) + + matcherHint('toBeTruthy', undefined, '', options) + '\n\n' + - `Received: ${printReceived(actual)}`; + `Received: ${printReceived(received)}`; + return {message, pass}; }, - toBeUndefined(actual: any, expected: void) { - ensureNoExpected(expected, '.toBeUndefined'); - const pass = actual === void 0; + toBeUndefined(received: any, expected: void) { + const options = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, 'toBeUndefined', options); + + const pass = received === void 0; + const message = () => - matcherHint('.toBeUndefined', 'received', '', { - isNot: this.isNot, - }) + + matcherHint('toBeUndefined', undefined, '', options) + '\n\n' + - `Received: ${printReceived(actual)}`; + `Received: ${printReceived(received)}`; return {message, pass}; }, diff --git a/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap b/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap index fb80b64d1896..638d58870326 100644 --- a/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap +++ b/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`.ensureNoExpected() throws error when expected is not undefined 1`] = ` -"expect(received)[.not]This() +exports[`.ensureNoExpected() throws error when expected is not undefined with matcherName 1`] = ` +"expect(received)[.not].toBeDefined() Matcher error: expected value must be omitted or undefined @@ -9,8 +9,8 @@ Expected has type: object Expected has value: {\\"a\\": 1}" `; -exports[`.ensureNoExpected() throws error when expected is not undefined with matcherName 1`] = ` -"expect(received)[.not].toBeDefined() +exports[`.ensureNoExpected() throws error when expected is not undefined with matcherName and options 1`] = ` +"expect(received).not.toBeDefined() Matcher error: expected value must be omitted or undefined diff --git a/packages/jest-matcher-utils/src/__tests__/index.test.js b/packages/jest-matcher-utils/src/__tests__/index.test.js index 9db8878662b1..739caee6d081 100644 --- a/packages/jest-matcher-utils/src/__tests__/index.test.js +++ b/packages/jest-matcher-utils/src/__tests__/index.test.js @@ -112,15 +112,15 @@ describe('.ensureNoExpected()', () => { }).not.toThrow(); }); - test('throws error when expected is not undefined', () => { + test('throws error when expected is not undefined with matcherName', () => { expect(() => { - ensureNoExpected({a: 1}); + ensureNoExpected({a: 1}, '.toBeDefined'); }).toThrowErrorMatchingSnapshot(); }); - test('throws error when expected is not undefined with matcherName', () => { + test('throws error when expected is not undefined with matcherName and options', () => { expect(() => { - ensureNoExpected({a: 1}, '.toBeDefined'); + ensureNoExpected({a: 1}, 'toBeDefined', {isNot: true}); }).toThrowErrorMatchingSnapshot(); }); }); diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index 03f0e6369826..6f90558c6d89 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -7,6 +7,8 @@ * @flow */ +import type {MatcherHintOptions} from 'types/Matchers'; + import chalk from 'chalk'; import getType from 'jest-get-type'; import prettyFormat from 'pretty-format'; @@ -30,6 +32,7 @@ const PLUGINS = [ export const EXPECTED_COLOR = chalk.green; export const RECEIVED_COLOR = chalk.red; +const DIM_COLOR = chalk.dim; const NUMBERS = [ 'zero', @@ -102,12 +105,20 @@ export const printWithType = ( return hasType + hasValue; }; -export const ensureNoExpected = (expected: any, matcherName: string) => { - matcherName || (matcherName = 'This'); +export const ensureNoExpected = ( + expected: any, + matcherName: string, // required because optional was probably non-use case + options?: MatcherHintOptions, +) => { if (typeof expected !== 'undefined') { throw new Error( matcherErrorMessage( - matcherHint('[.not]' + matcherName, undefined, ''), + matcherHint( + (options ? '' : '[.not]') + matcherName, // backward compatibility + undefined, + '', + options, + ), `${EXPECTED_COLOR('expected')} value must be omitted or undefined`, printWithType('Expected', expected, printExpected), ), @@ -159,28 +170,67 @@ export const matcherErrorMessage = ( specific: string, // incorrect value returned from call to printWithType ) => `${hint}\n\n${chalk.bold('Matcher error')}: ${generic}\n\n${specific}`; +// Display assertion for the report when a test fails. +// New format: rejects/resolves, not, and matcher name have black color +// Old format: matcher name has dim color export const matcherHint = ( matcherName: string, received: string = 'received', expected: string = 'expected', - options: { - comment?: string, - isDirectExpectCall?: boolean, - isNot?: boolean, - secondArgument?: ?string, - } = {}, + options: MatcherHintOptions = {}, ) => { - const {comment, isDirectExpectCall, isNot, secondArgument} = options; - return ( - chalk.dim('expect' + (isDirectExpectCall ? '' : '(')) + - RECEIVED_COLOR(received) + - (isNot - ? `${chalk.dim(').')}not${chalk.dim(matcherName + '(')}` - : chalk.dim((isDirectExpectCall ? '' : ')') + matcherName + '(')) + - EXPECTED_COLOR(expected) + - (secondArgument - ? `${chalk.dim(', ')}${EXPECTED_COLOR(secondArgument)}` - : '') + - chalk.dim(`)${comment ? ` // ${comment}` : ''}`) - ); + const { + comment = '', + isDirectExpectCall = false, + isNot = false, + promise = '', + secondArgument = '', + } = options; + let hint = ''; + let dimString = 'expect'; // concatenate adjacent dim substrings + + if (!isDirectExpectCall && received !== '') { + hint += DIM_COLOR(dimString + '(') + RECEIVED_COLOR(received); + dimString = ')'; + } + + if (promise !== '') { + hint += DIM_COLOR(dimString + '.') + promise; + dimString = ''; + } + + if (isNot) { + hint += DIM_COLOR(dimString + '.') + 'not'; + dimString = ''; + } + + if (matcherName.includes('.')) { + // Old format: for backward compatibility, + // especially without promise or isNot options + dimString += matcherName; + } else { + // New format: omit period from matcherName arg + hint += DIM_COLOR(dimString + '.') + matcherName; + dimString = ''; + } + + if (expected === '') { + dimString += '()'; + } else { + hint += DIM_COLOR(dimString + '(') + EXPECTED_COLOR(expected); + if (secondArgument) { + hint += DIM_COLOR(', ') + EXPECTED_COLOR(secondArgument); + } + dimString = ')'; + } + + if (comment !== '') { + dimString += ' // ' + comment; + } + + if (dimString !== '') { + hint += DIM_COLOR(dimString); + } + + return hint; }; diff --git a/types/Matchers.js b/types/Matchers.js index 79e89d433fb8..016af0c82001 100644 --- a/types/Matchers.js +++ b/types/Matchers.js @@ -80,3 +80,11 @@ export type ExpectationObject = { }, not: {[id: string]: ThrowingMatcherFn}, }; + +export type MatcherHintOptions = { + comment?: string, + isDirectExpectCall?: boolean, + isNot?: boolean, + promise?: string, + secondArgument?: ?string, +}; From c26d8eca52eb42404bccdff715f04e0934c93248 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Thu, 27 Dec 2018 19:14:11 -0500 Subject: [PATCH 02/11] Edit utils and improve one snapshot --- .../__tests__/__snapshots__/matchers.test.js.snap | 2 +- packages/expect/src/__tests__/matchers.test.js | 4 +++- packages/jest-matcher-utils/src/index.js | 13 +++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 069a29f662f2..2c0200863cab 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -1531,7 +1531,7 @@ Expected has value: null" `; exports[`.toBeTruthy(), .toBeFalsy() does not accept arguments 2`] = ` -"expect(received).toBeFalsy() +"expect(received).not.toBeFalsy() Matcher error: expected value must be omitted or undefined diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index 95e7f6398f59..c62d75818887 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -564,7 +564,9 @@ describe('.toBeTruthy(), .toBeFalsy()', () => { it('does not accept arguments', () => { expect(() => jestExpect(0).toBeTruthy(null)).toThrowErrorMatchingSnapshot(); - expect(() => jestExpect(0).toBeFalsy(null)).toThrowErrorMatchingSnapshot(); + expect(() => + jestExpect(0).not.toBeFalsy(null), + ).toThrowErrorMatchingSnapshot(); }); [{}, [], true, 1, 'a', 0.5, new Map(), () => {}, Infinity].forEach(v => { diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index 6f90558c6d89..d22ed7063d8d 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -107,18 +107,15 @@ export const printWithType = ( export const ensureNoExpected = ( expected: any, - matcherName: string, // required because optional was probably non-use case + matcherName: string, options?: MatcherHintOptions, ) => { if (typeof expected !== 'undefined') { + // Prepend maybe not only for backward compatibility. + const matcherString = (options ? '' : '[.not]') + matcherName; throw new Error( matcherErrorMessage( - matcherHint( - (options ? '' : '[.not]') + matcherName, // backward compatibility - undefined, - '', - options, - ), + matcherHint(matcherString, undefined, '', options), `${EXPECTED_COLOR('expected')} value must be omitted or undefined`, printWithType('Expected', expected, printExpected), ), @@ -181,7 +178,7 @@ export const matcherHint = ( ) => { const { comment = '', - isDirectExpectCall = false, + isDirectExpectCall = false, // seems redundant with received === '' isNot = false, promise = '', secondArgument = '', From 5debacd4a877734a47e811f2cc904d0cd5c23f94 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Thu, 27 Dec 2018 19:34:49 -0500 Subject: [PATCH 03/11] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66062e923d47..247d152a2ae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - `[jest-validate]` Add syntax to validate multiple permitted types ([#7207](https://github.com/facebook/jest/pull/7207)) - `[jest-config]` Accept an array as as well as a string for `testRegex`([#7209]https://github.com/facebook/jest/pull/7209)) - `[expect/jest-matcher-utils]` Improve report when assertion fails, part 4 ([#7241](https://github.com/facebook/jest/pull/7241)) +- `[expect/jest-matcher-utils]` Improve report when assertion fails, part 5 ([#7557](https://github.com/facebook/jest/pull/7557)) - `[expect]` Check constructor equality in .toStrictEqual() ([#7005](https://github.com/facebook/jest/pull/7005)) - `[jest-util]` Add `jest.getTimerCount()` to get the count of scheduled fake timers ([#7285](https://github.com/facebook/jest/pull/7285)) - `[jest-config]` Add `dependencyExtractor` option to use a custom module to extract dependencies from files ([#7313](https://github.com/facebook/jest/pull/7313), [#7349](https://github.com/facebook/jest/pull/7349), [#7350](https://github.com/facebook/jest/pull/7350)) From 9f2e7e9a17429dbddc58bd9c6d518473607c10a7 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Sat, 29 Dec 2018 11:39:46 -0500 Subject: [PATCH 04/11] Improve message for ensureNoExpected --- .../__snapshots__/assertionCounts.test.js.snap | 2 +- .../__snapshots__/matchers.test.js.snap | 4 ++-- .../__snapshots__/spyMatchers.test.js.snap | 16 ++++++++-------- .../__tests__/__snapshots__/index.test.js.snap | 4 ++-- packages/jest-matcher-utils/src/index.js | 4 +++- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap b/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap index ca1bc099e9df..8f2f6f1f5eb0 100644 --- a/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/assertionCounts.test.js.snap @@ -3,7 +3,7 @@ exports[`.hasAssertions() throws if expected is not undefined 1`] = ` "expect(received)[.not].hasAssertions() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 2" diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 2c0200863cab..7f66fea9ba58 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -1525,7 +1525,7 @@ Received: undefined" exports[`.toBeTruthy(), .toBeFalsy() does not accept arguments 1`] = ` "expect(received).toBeTruthy() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has value: null" `; @@ -1533,7 +1533,7 @@ Expected has value: null" exports[`.toBeTruthy(), .toBeFalsy() does not accept arguments 2`] = ` "expect(received).not.toBeFalsy() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has value: null" `; diff --git a/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap index 0ffe77b4172c..4015f9948b3b 100644 --- a/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap @@ -600,7 +600,7 @@ But the first call returned exactly: exports[`toBeCalled .not fails with any argument passed 1`] = ` "expect(received)[.not].toBeCalled() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -615,7 +615,7 @@ Expected mock function to have been called, but it was not called." exports[`toBeCalled fails with any argument passed 1`] = ` "expect(received)[.not].toBeCalled() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -922,7 +922,7 @@ Expected mock function to have been called with: exports[`toHaveBeenCalled .not fails with any argument passed 1`] = ` "expect(received)[.not].toHaveBeenCalled() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -937,7 +937,7 @@ Expected mock function to have been called, but it was not called." exports[`toHaveBeenCalled fails with any argument passed 1`] = ` "expect(received)[.not].toHaveBeenCalled() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -1841,7 +1841,7 @@ But the first call returned exactly: exports[`toHaveReturned .not fails with any argument passed 1`] = ` "expect(received)[.not].toHaveReturned() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -1868,7 +1868,7 @@ Expected mock function to have returned." exports[`toHaveReturned fails with any argument passed 1`] = ` "expect(received)[.not].toHaveReturned() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -2236,7 +2236,7 @@ But it returned exactly: exports[`toReturn .not fails with any argument passed 1`] = ` "expect(received)[.not].toReturn() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" @@ -2263,7 +2263,7 @@ Expected mock function to have returned." exports[`toReturn fails with any argument passed 1`] = ` "expect(received)[.not].toReturn() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: number Expected has value: 555" diff --git a/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap b/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap index 638d58870326..32ae2ce0d013 100644 --- a/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap +++ b/packages/jest-matcher-utils/src/__tests__/__snapshots__/index.test.js.snap @@ -3,7 +3,7 @@ exports[`.ensureNoExpected() throws error when expected is not undefined with matcherName 1`] = ` "expect(received)[.not].toBeDefined() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: object Expected has value: {\\"a\\": 1}" @@ -12,7 +12,7 @@ Expected has value: {\\"a\\": 1}" exports[`.ensureNoExpected() throws error when expected is not undefined with matcherName and options 1`] = ` "expect(received).not.toBeDefined() -Matcher error: expected value must be omitted or undefined +Matcher error: this matcher must not have an expected argument Expected has type: object Expected has value: {\\"a\\": 1}" diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index d22ed7063d8d..4f1e1f22a930 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -116,7 +116,9 @@ export const ensureNoExpected = ( throw new Error( matcherErrorMessage( matcherHint(matcherString, undefined, '', options), - `${EXPECTED_COLOR('expected')} value must be omitted or undefined`, + // Because expected is omitted in hint above, + // expected is black instead of green in message below. + 'this matcher must not have an expected argument', printWithType('Expected', expected, printExpected), ), ); From 159e2163316a5cb72439654e77850f39fda9d652 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Sat, 29 Dec 2018 16:10:40 -0500 Subject: [PATCH 05/11] Rewrite promise instead message --- e2e/__tests__/__snapshots__/failures.test.js.snap | 8 ++++---- .../__tests__/__snapshots__/matchers.test.js.snap | 8 ++++---- packages/expect/src/index.js | 12 ++++++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/e2e/__tests__/__snapshots__/failures.test.js.snap b/e2e/__tests__/__snapshots__/failures.test.js.snap index 3f03b03af34a..69d99cd678a4 100644 --- a/e2e/__tests__/__snapshots__/failures.test.js.snap +++ b/e2e/__tests__/__snapshots__/failures.test.js.snap @@ -360,9 +360,9 @@ exports[`works with async failures 1`] = ` expect(received).rejects.toEqual() - Received promise resolves instead of rejects + Received promise resolved instead of rejected - Received value: {\\"foo\\": \\"bar\\"} + Received promise resolved to value: {\\"foo\\": \\"bar\\"} 16 | 17 | test('expect reject', () => @@ -378,9 +378,9 @@ exports[`works with async failures 1`] = ` expect(received).resolves.toEqual() - Received promise rejects instead of resolves + Received promise rejected instead of resolved - Received value: {\\"foo\\": \\"bar\\"} + Received promise rejected to value: {\\"foo\\": \\"bar\\"} 19 | 20 | test('expect resolve', () => diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 7f66fea9ba58..ea182bd0fbaf 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -3,9 +3,9 @@ exports[`.rejects fails for promise that resolves 1`] = ` "expect(received).rejects.toBe() -Received promise resolves instead of rejects +Received promise resolved instead of rejected -Received value: 4" +Received promise resolved to value: 4" `; exports[`.rejects fails non-promise value "a" 1`] = ` @@ -81,9 +81,9 @@ Received has value: undefined" exports[`.resolves fails for promise that rejects 1`] = ` "expect(received).resolves.toBe() -Received promise rejects instead of resolves +Received promise rejected instead of resolved -Received value: 4" +Received promise rejected to value: 4" `; exports[`.resolves fails non-promise value "a" 1`] = ` diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index af98196a25b0..0564760e5bd3 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -173,8 +173,10 @@ const makeResolveMatcher = ( outerErr.message = matcherUtils.matcherHint(matcherName, undefined, '', options) + '\n\n' + - `Received promise rejects instead of resolves\n\n` + - `Received value: ${matcherUtils.printReceived(reason)}`; + `Received promise rejected instead of resolved\n\n` + + `Received promise rejected to value: ${matcherUtils.printReceived( + reason, + )}`; return Promise.reject(outerErr); }, ); @@ -213,8 +215,10 @@ const makeRejectMatcher = ( outerErr.message = matcherUtils.matcherHint(matcherName, undefined, '', options) + '\n\n' + - `Received promise resolves instead of rejects\n\n` + - `Received value: ${matcherUtils.printReceived(result)}`; + `Received promise resolved instead of rejected\n\n` + + `Received promise resolved to value: ${matcherUtils.printReceived( + result, + )}`; return Promise.reject(outerErr); }, reason => From a8965662f022c517bc19dabd76f39508f8236314 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Mon, 31 Dec 2018 16:18:35 -0500 Subject: [PATCH 06/11] Rewrite half of non-promise value tests with not --- .../__snapshots__/matchers.test.js.snap | 24 ++++---- .../expect/src/__tests__/matchers.test.js | 55 +++++++++++++++++-- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 3801e9223d3f..f5108aef297b 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -45,7 +45,7 @@ Received has value: {\\"a\\": 1}" `; exports[`.rejects fails non-promise value 4 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.not.toBeDefined() Matcher error: received value must be a promise @@ -54,7 +54,7 @@ Received has value: 4" `; exports[`.rejects fails non-promise value null 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.not.toBeDefined() Matcher error: received value must be a promise @@ -62,7 +62,7 @@ Received has value: null" `; exports[`.rejects fails non-promise value true 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.not.toBeDefined() Matcher error: received value must be a promise @@ -71,7 +71,7 @@ Received has value: true" `; exports[`.rejects fails non-promise value undefined 1`] = ` -"expect(received).rejects.toBeDefined() +"expect(received).rejects.not.toBeDefined() Matcher error: received value must be a promise @@ -159,7 +159,7 @@ Received has value: {\\"a\\": 1}" `; exports[`.resolves fails non-promise value 4 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -168,7 +168,7 @@ Received has value: 4" `; exports[`.resolves fails non-promise value 4 synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -177,7 +177,7 @@ Received has value: 4" `; exports[`.resolves fails non-promise value null 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -185,7 +185,7 @@ Received has value: null" `; exports[`.resolves fails non-promise value null synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -193,7 +193,7 @@ Received has value: null" `; exports[`.resolves fails non-promise value true 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -202,7 +202,7 @@ Received has value: true" `; exports[`.resolves fails non-promise value true synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -211,7 +211,7 @@ Received has value: true" `; exports[`.resolves fails non-promise value undefined 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise @@ -219,7 +219,7 @@ Received has value: undefined" `; exports[`.resolves fails non-promise value undefined synchronously 1`] = ` -"expect(received).resolves.toBeDefined() +"expect(received).resolves.not.toBeDefined() Matcher error: received value must be a promise diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index c62d75818887..faaf78e4782e 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -52,7 +52,7 @@ describe('.rejects', () => { await jestExpect(fn()).rejects.toThrow('some error'); }); - [4, [1], {a: 1}, 'a', true, null, undefined, () => {}].forEach(value => { + ['a', [1], () => {}, {a: 1}].forEach(value => { it(`fails non-promise value ${stringify(value)} synchronously`, () => { let error; try { @@ -62,9 +62,7 @@ describe('.rejects', () => { } expect(error).toBeDefined(); }); - }); - [4, [1], {a: 1}, 'a', true, null, undefined, () => {}].forEach(value => { it(`fails non-promise value ${stringify(value)}`, async () => { let error; try { @@ -77,6 +75,29 @@ describe('.rejects', () => { }); }); + [4, null, true, undefined].forEach(value => { + it(`fails non-promise value ${stringify(value)} synchronously`, () => { + let error; + try { + jestExpect(value).rejects.not.toBe(111); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + }); + + it(`fails non-promise value ${stringify(value)}`, async () => { + let error; + try { + await jestExpect(value).rejects.not.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + }); + it('fails for promise that resolves', async () => { let error; try { @@ -108,7 +129,7 @@ describe('.resolves', () => { ).resolves.toThrow(); }); - [4, [1], {a: 1}, 'a', true, null, undefined, () => {}].forEach(value => { + ['a', [1], () => {}, {a: 1}].forEach(value => { it(`fails non-promise value ${stringify(value)} synchronously`, () => { let error; try { @@ -119,9 +140,7 @@ describe('.resolves', () => { expect(error).toBeDefined(); expect(error.message).toMatchSnapshot(); }); - }); - [4, [1], {a: 1}, 'a', true, null, undefined, () => {}].forEach(value => { it(`fails non-promise value ${stringify(value)}`, async () => { let error; try { @@ -134,6 +153,30 @@ describe('.resolves', () => { }); }); + [4, null, true, undefined].forEach(value => { + it(`fails non-promise value ${stringify(value)} synchronously`, () => { + let error; + try { + jestExpect(value).resolves.not.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + + it(`fails non-promise value ${stringify(value)}`, async () => { + let error; + try { + await jestExpect(value).resolves.not.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + }); + it('fails for promise that rejects', async () => { let error; try { From e3b7d02c1c6e91819d504a1f7854145a747dec59 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Fri, 4 Jan 2019 12:09:07 -0500 Subject: [PATCH 07/11] Delete empty line and duplicated words --- .../__tests__/__snapshots__/matchers.test.js.snap | 6 ++---- packages/expect/src/index.js | 12 ++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index f5108aef297b..2fd4578e636e 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -4,8 +4,7 @@ exports[`.rejects fails for promise that resolves 1`] = ` "expect(received).rejects.toBe() Received promise resolved instead of rejected - -Received promise resolved to value: 4" +Resolved to value: 4" `; exports[`.rejects fails non-promise value "a" 1`] = ` @@ -82,8 +81,7 @@ exports[`.resolves fails for promise that rejects 1`] = ` "expect(received).resolves.toBe() Received promise rejected instead of resolved - -Received promise rejected to value: 4" +Rejected to value: 4" `; exports[`.resolves fails non-promise value "a" 1`] = ` diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index 0564760e5bd3..67e6883f7b06 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -173,10 +173,8 @@ const makeResolveMatcher = ( outerErr.message = matcherUtils.matcherHint(matcherName, undefined, '', options) + '\n\n' + - `Received promise rejected instead of resolved\n\n` + - `Received promise rejected to value: ${matcherUtils.printReceived( - reason, - )}`; + `Received promise rejected instead of resolved\n` + + `Rejected to value: ${matcherUtils.printReceived(reason)}`; return Promise.reject(outerErr); }, ); @@ -215,10 +213,8 @@ const makeRejectMatcher = ( outerErr.message = matcherUtils.matcherHint(matcherName, undefined, '', options) + '\n\n' + - `Received promise resolved instead of rejected\n\n` + - `Received promise resolved to value: ${matcherUtils.printReceived( - result, - )}`; + `Received promise resolved instead of rejected\n` + + `Resolved to value: ${matcherUtils.printReceived(result)}`; return Promise.reject(outerErr); }, reason => From de47699663ef2a54f93291f3b6562424d3bd8695 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Fri, 4 Jan 2019 12:27:48 -0500 Subject: [PATCH 08/11] Rebuild and update e2e snapshot --- e2e/__tests__/__snapshots__/failures.test.js.snap | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/e2e/__tests__/__snapshots__/failures.test.js.snap b/e2e/__tests__/__snapshots__/failures.test.js.snap index 69d99cd678a4..08a7abceff5d 100644 --- a/e2e/__tests__/__snapshots__/failures.test.js.snap +++ b/e2e/__tests__/__snapshots__/failures.test.js.snap @@ -361,8 +361,7 @@ exports[`works with async failures 1`] = ` expect(received).rejects.toEqual() Received promise resolved instead of rejected - - Received promise resolved to value: {\\"foo\\": \\"bar\\"} + Resolved to value: {\\"foo\\": \\"bar\\"} 16 | 17 | test('expect reject', () => @@ -379,8 +378,7 @@ exports[`works with async failures 1`] = ` expect(received).resolves.toEqual() Received promise rejected instead of resolved - - Received promise rejected to value: {\\"foo\\": \\"bar\\"} + Rejected to value: {\\"foo\\": \\"bar\\"} 19 | 20 | test('expect resolve', () => From 7f67e2120e7f49c82dd3cf5b5a35454da98eabbf Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Wed, 9 Jan 2019 15:16:53 -0500 Subject: [PATCH 09/11] Add section about promise property to ExpectAPI.md --- docs/ExpectAPI.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/ExpectAPI.md b/docs/ExpectAPI.md index c362734a8f8f..56fad8f3c2d7 100644 --- a/docs/ExpectAPI.md +++ b/docs/ExpectAPI.md @@ -117,7 +117,15 @@ These helper functions and properties can be found on `this` inside a custom mat #### `this.isNot` -A boolean to let you know this matcher was called with the negated `.not` modifier allowing you to flip your assertion. +A boolean to let you know this matcher was called with the negated `.not` modifier allowing you to flip your assertion and display a clear and correct matcher hint. + +#### `this.promise` + +A string allowing you to display a clear and correct matcher hint: + +- `'rejects'` if matcher was called with the promise `.rejects` modifier +- `'resolves'` if matcher was called with the promise `.resolves` modifier +- `''` if matcher was not called with a promise modifier #### `this.equals(a, b)` From fabe202b68aef9083ad40c6e43638435dc51149c Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Wed, 9 Jan 2019 15:46:21 -0500 Subject: [PATCH 10/11] Update example code to use options in ExpectAPI.md --- docs/ExpectAPI.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/ExpectAPI.md b/docs/ExpectAPI.md index 56fad8f3c2d7..f9946e51c2b6 100644 --- a/docs/ExpectAPI.md +++ b/docs/ExpectAPI.md @@ -117,7 +117,7 @@ These helper functions and properties can be found on `this` inside a custom mat #### `this.isNot` -A boolean to let you know this matcher was called with the negated `.not` modifier allowing you to flip your assertion and display a clear and correct matcher hint. +A boolean to let you know this matcher was called with the negated `.not` modifier allowing you to flip your assertion and display a clear and correct matcher hint (see example code). #### `this.promise` @@ -145,28 +145,31 @@ The most useful ones are `matcherHint`, `printExpected` and `printReceived` to f const diff = require('jest-diff'); expect.extend({ toBe(received, expected) { + const options = { + comment: 'Object.is equality', + isNot: this.isNot, + promise: this.promise, + }; + const pass = Object.is(received, expected); const message = pass ? () => - this.utils.matcherHint('.not.toBe') + + this.utils.matcherHint('toBe', undefined, undefined, options) + '\n\n' + - `Expected value to not be (using Object.is):\n` + - ` ${this.utils.printExpected(expected)}\n` + - `Received:\n` + - ` ${this.utils.printReceived(received)}` + `Expected: ${this.utils.printExpected(expected)}\n` + + `Received: ${this.utils.printReceived(received)}` : () => { - const diffString = diff(expected, received, { + const difference = diff(expected, received, { expand: this.expand, }); return ( - this.utils.matcherHint('.toBe') + + this.utils.matcherHint('toBe', undefined, undefined, options) + '\n\n' + - `Expected value to be (using Object.is):\n` + - ` ${this.utils.printExpected(expected)}\n` + - `Received:\n` + - ` ${this.utils.printReceived(received)}` + - (diffString ? `\n\nDifference:\n\n${diffString}` : '') + (difference && difference.includes('- Expect') + ? `Difference:\n\n${diffString}` + : `Expected: ${this.utils.printExpected(expected)}\n` + + `Received: ${this.utils.printReceived(received)}`) ); }; From e949202f825db3a9a7255935dcc8fe4df7645b32 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Fri, 11 Jan 2019 16:02:36 -0500 Subject: [PATCH 11/11] Added promise property to MatcherState --- types/Matchers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/types/Matchers.js b/types/Matchers.js index 016af0c82001..768bb12c2725 100644 --- a/types/Matchers.js +++ b/types/Matchers.js @@ -36,6 +36,7 @@ export type MatcherState = { expectedAssertionsNumber: ?number, isExpectingAssertions: ?boolean, isNot: boolean, + promise: string, snapshotState: SnapshotState, suppressedErrors: Array, testPath?: Path,