diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d13a1c27a04..aa34e1685ea9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - `[expect]` Improve report when mock-spy matcher fails, part 1 ([#8640](https://github.com/facebook/jest/pull/8640)) - `[expect]` Improve report when mock-spy matcher fails, part 2 ([#8649](https://github.com/facebook/jest/pull/8649)) - `[expect]` Improve report when mock-spy matcher fails, part 3 ([#8697](https://github.com/facebook/jest/pull/8697)) +- `[expect]` Improve report when mock-spy matcher fails, part 4 ([#8710](https://github.com/facebook/jest/pull/8710)) - `[jest-snapshot]` Highlight substring differences when matcher fails, part 3 ([#8569](https://github.com/facebook/jest/pull/8569)) - `[jest-cli]` Improve chai support (with detailed output, to match jest exceptions) ([#8454](https://github.com/facebook/jest/pull/8454)) - `[*]` Manage the global timeout with `--testTimeout` command line argument. ([#8456](https://github.com/facebook/jest/pull/8456)) diff --git a/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap index 8b42aa51913b..bf6a4cf1042d 100644 --- a/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap @@ -127,44 +127,54 @@ Expected mock function to have been last called with: `; exports[`lastReturnedWith a call that throws is not considered to have returned 1`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) -Expected mock function to have last returned: - undefined -But the last call threw an error" +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1" `; exports[`lastReturnedWith a call that throws undefined is not considered to have returned 1`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) + +Expected: undefined +Received: function call threw an error -Expected mock function to have last returned: - undefined -But the last call threw an error" +Number of returns: 0 +Number of calls: 1" `; exports[`lastReturnedWith includes the custom mock name in the error message 1`] = ` -"expect(named-mock).lastReturnedWith(expected) +"expect(named-mock).lastReturnedWith(expected) -Expected mock function \\"named-mock\\" to have last returned: - \\"foo\\" -But it was not called" +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`lastReturnedWith lastReturnedWith incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) + +Expected: 0 +Received + 3: function call has not returned yet +-> 4: function call has not returned yet -Expected mock function to have last returned: - 0 -But the last call has not returned yet" +Number of returns: 0 +Number of calls: 4" `; exports[`lastReturnedWith lastReturnedWith works with three calls 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) -Expected mock function to not have last returned: - \\"foo3\\" -But it last returned exactly: - \\"foo3\\"" +Expected: not \\"foo3\\" +Received + 2: \\"foo2\\" +-> 3: \\"foo3\\" + +Number of returns: 3" `; exports[`lastReturnedWith works only on spies or jest.fn 1`] = ` @@ -177,92 +187,86 @@ Received has value: [Function fn]" `; exports[`lastReturnedWith works when not called 1`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) -Expected mock function to have last returned: - \\"foo\\" -But it was not called" +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`lastReturnedWith works with Immutable.js objects directly created 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) -Expected mock function to not have last returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it last returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} + +Number of returns: 1" `; exports[`lastReturnedWith works with Immutable.js objects indirectly created 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function to not have last returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it last returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`lastReturnedWith works with Map 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) -Expected mock function to not have last returned: - Map {1 => 2, 2 => 1} -But it last returned exactly: - Map {1 => 2, 2 => 1}" +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`lastReturnedWith works with Map 2`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) -Expected mock function to have last returned: - Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} -But the last call returned: - Map {1 => 2, 2 => 1}" +Expected: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`lastReturnedWith works with Set 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) -Expected mock function to not have last returned: - Set {1, 2} -But it last returned exactly: - Set {1, 2}" +Expected: not Set {1, 2} + +Number of returns: 1" `; exports[`lastReturnedWith works with Set 2`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) -Expected mock function to have last returned: - Set {3, 4} -But the last call returned: - Set {1, 2}" +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1" `; exports[`lastReturnedWith works with argument that does match 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) -Expected mock function to not have last returned: - \\"foo\\" -But it last returned exactly: - \\"foo\\"" +Expected: not \\"foo\\" + +Number of returns: 1" `; exports[`lastReturnedWith works with argument that does not match 1`] = ` -"expect(jest.fn()).lastReturnedWith(expected) +"expect(jest.fn()).lastReturnedWith(expected) -Expected mock function to have last returned: - \\"bar\\" -But the last call returned: - \\"foo\\"" +Expected: \\"bar\\" +Received: \\"foo\\" + +Number of returns: 1" `; exports[`lastReturnedWith works with undefined 1`] = ` -"expect(jest.fn()).not.lastReturnedWith(expected) +"expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not undefined -Expected mock function to not have last returned: - undefined -But it last returned exactly: - undefined" +Number of returns: 1" `; exports[`nthCalledWith includes the custom mock name in the error message 1`] = ` @@ -426,61 +430,88 @@ Expected mock function first call to have been called with: `; exports[`nthReturnedWith a call that throws is not considered to have returned 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: undefined +Received: function call threw an error -Expected mock function first call to have returned with: - undefined -But the first call threw an error" +Number of returns: 0 +Number of calls: 1" `; exports[`nthReturnedWith a call that throws undefined is not considered to have returned 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function first call to have returned with: - undefined -But the first call threw an error" +n: 1 +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1" `; exports[`nthReturnedWith includes the custom mock name in the error message 1`] = ` -"expect(named-mock).nthReturnedWith(expected) +"expect(named-mock).nthReturnedWith(n, expected) -Expected mock function \\"named-mock\\" first call to have returned with: - \\"foo\\" -But it was not called" +n: 1 +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: 6 +Received +-> 1: function call has not returned yet + 2: function call has not returned yet -Expected mock function first call to have returned with: - 6 -But the first call has not returned yet" +Number of returns: 2 +Number of calls: 4" `; exports[`nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 2`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function second call to have returned with: - 3 -But the second call has not returned yet" +n: 2 +Expected: 3 +Received + 1: function call has not returned yet +-> 2: function call has not returned yet + 3: 1 + +Number of returns: 2 +Number of calls: 4" `; exports[`nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 3`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 3 +Expected: not 1 +Received + 2: function call has not returned yet +-> 3: 1 + 4: 0 -Expected mock function third call to not have returned with: - 1 -But the third call returned exactly: - 1" +Number of returns: 2 +Number of calls: 4" `; exports[`nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 4`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) -Expected mock function 4th call to not have returned with: - 0 -But the 4th call returned exactly: - 0" +n: 4 +Expected: not 0 +Received + 3: 1 +-> 4: 0 + +Number of returns: 2 +Number of calls: 4" `; exports[`nthReturnedWith nthReturnedWith negative throw matcher error for n that is not number 1`] = ` @@ -510,38 +541,50 @@ n has value: 0" `; exports[`nthReturnedWith nthReturnedWith should reject nth value greater than number of calls 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function 4th call to have returned with: - \\"foo\\" -But it was only called 3 times" +n: 4 +Expected: \\"foo\\" +Received + 3: \\"foo\\" + +Number of returns: 3" `; exports[`nthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function first call to have returned with: - \\"bar1\\" -But the first call returned with: - \\"foo1\\"" +n: 1 +Expected: \\"bar1\\" +Received +-> 1: \\"foo1\\" + 2: \\"foo2\\" + +Number of returns: 3" `; exports[`nthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third 2`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not \\"foo1\\" +Received +-> 1: \\"foo1\\" + 2: \\"foo2\\" -Expected mock function first call to not have returned with: - \\"foo1\\" -But the first call returned exactly: - \\"foo1\\"" +Number of returns: 3" `; exports[`nthReturnedWith nthReturnedWith works with three calls 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) -Expected mock function first call to not have returned with: - \\"foo1\\" -But the first call returned exactly: - \\"foo1\\"" +n: 1 +Expected: not \\"foo1\\" +Received +-> 1: \\"foo1\\" + 2: \\"foo2\\" + +Number of returns: 3" `; exports[`nthReturnedWith works only on spies or jest.fn 1`] = ` @@ -554,92 +597,96 @@ Received has value: [Function fn]" `; exports[`nthReturnedWith works when not called 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function first call to have returned with: - \\"foo\\" -But it was not called" +n: 1 +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`nthReturnedWith works with Immutable.js objects directly created 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function first call to not have returned with: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But the first call returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`nthReturnedWith works with Immutable.js objects indirectly created 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) -Expected mock function first call to not have returned with: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But the first call returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +n: 1 +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} + +Number of returns: 1" `; exports[`nthReturnedWith works with Map 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Map {1 => 2, 2 => 1} -Expected mock function first call to not have returned with: - Map {1 => 2, 2 => 1} -But the first call returned exactly: - Map {1 => 2, 2 => 1}" +Number of returns: 1" `; exports[`nthReturnedWith works with Map 2`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function first call to have returned with: - Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} -But the first call returned with: - Map {1 => 2, 2 => 1}" +n: 1 +Expected: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`nthReturnedWith works with Set 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Set {1, 2} -Expected mock function first call to not have returned with: - Set {1, 2} -But the first call returned exactly: - Set {1, 2}" +Number of returns: 1" `; exports[`nthReturnedWith works with Set 2`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function first call to have returned with: - Set {3, 4} -But the first call returned with: - Set {1, 2}" +n: 1 +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1" `; exports[`nthReturnedWith works with argument that does match 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) -Expected mock function first call to not have returned with: - \\"foo\\" -But the first call returned exactly: - \\"foo\\"" +n: 1 +Expected: not \\"foo\\" + +Number of returns: 1" `; exports[`nthReturnedWith works with argument that does not match 1`] = ` -"expect(jest.fn()).nthReturnedWith(expected) +"expect(jest.fn()).nthReturnedWith(n, expected) -Expected mock function first call to have returned with: - \\"bar\\" -But the first call returned with: - \\"foo\\"" +n: 1 +Expected: \\"bar\\" +Received: \\"foo\\" + +Number of returns: 1" `; exports[`nthReturnedWith works with undefined 1`] = ` -"expect(jest.fn()).not.nthReturnedWith(expected) +"expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not undefined -Expected mock function first call to not have returned with: - undefined -But the first call returned exactly: - undefined" +Number of returns: 1" `; exports[`toBeCalled .not fails with any argument passed 1`] = ` @@ -1589,44 +1636,54 @@ Expected mock function first call to have been called with: `; exports[`toHaveLastReturnedWith a call that throws is not considered to have returned 1`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: undefined +Received: function call threw an error -Expected mock function to have last returned: - undefined -But the last call threw an error" +Number of returns: 0 +Number of calls: 1" `; exports[`toHaveLastReturnedWith a call that throws undefined is not considered to have returned 1`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) -Expected mock function to have last returned: - undefined -But the last call threw an error" +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1" `; exports[`toHaveLastReturnedWith includes the custom mock name in the error message 1`] = ` -"expect(named-mock).toHaveLastReturnedWith(expected) +"expect(named-mock).toHaveLastReturnedWith(expected) -Expected mock function \\"named-mock\\" to have last returned: - \\"foo\\" -But it was not called" +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toHaveLastReturnedWith lastReturnedWith incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: 0 +Received + 3: function call has not returned yet +-> 4: function call has not returned yet -Expected mock function to have last returned: - 0 -But the last call has not returned yet" +Number of returns: 0 +Number of calls: 4" `; exports[`toHaveLastReturnedWith lastReturnedWith works with three calls 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) -Expected mock function to not have last returned: - \\"foo3\\" -But it last returned exactly: - \\"foo3\\"" +Expected: not \\"foo3\\" +Received + 2: \\"foo2\\" +-> 3: \\"foo3\\" + +Number of returns: 3" `; exports[`toHaveLastReturnedWith works only on spies or jest.fn 1`] = ` @@ -1639,150 +1696,171 @@ Received has value: [Function fn]" `; exports[`toHaveLastReturnedWith works when not called 1`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) -Expected mock function to have last returned: - \\"foo\\" -But it was not called" +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toHaveLastReturnedWith works with Immutable.js objects directly created 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function to not have last returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it last returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with Immutable.js objects indirectly created 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function to not have last returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it last returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with Map 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) -Expected mock function to not have last returned: - Map {1 => 2, 2 => 1} -But it last returned exactly: - Map {1 => 2, 2 => 1}" +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with Map 2`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) -Expected mock function to have last returned: - Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} -But the last call returned: - Map {1 => 2, 2 => 1}" +Expected: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with Set 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Set {1, 2} -Expected mock function to not have last returned: - Set {1, 2} -But it last returned exactly: - Set {1, 2}" +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with Set 2`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) -Expected mock function to have last returned: - Set {3, 4} -But the last call returned: - Set {1, 2}" +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with argument that does match 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) -Expected mock function to not have last returned: - \\"foo\\" -But it last returned exactly: - \\"foo\\"" +Expected: not \\"foo\\" + +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with argument that does not match 1`] = ` -"expect(jest.fn()).toHaveLastReturnedWith(expected) +"expect(jest.fn()).toHaveLastReturnedWith(expected) -Expected mock function to have last returned: - \\"bar\\" -But the last call returned: - \\"foo\\"" +Expected: \\"bar\\" +Received: \\"foo\\" + +Number of returns: 1" `; exports[`toHaveLastReturnedWith works with undefined 1`] = ` -"expect(jest.fn()).not.toHaveLastReturnedWith(expected) +"expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not undefined -Expected mock function to not have last returned: - undefined -But it last returned exactly: - undefined" +Number of returns: 1" `; exports[`toHaveNthReturnedWith a call that throws is not considered to have returned 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function first call to have returned with: - undefined -But the first call threw an error" +n: 1 +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1" `; exports[`toHaveNthReturnedWith a call that throws undefined is not considered to have returned 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: undefined +Received: function call threw an error -Expected mock function first call to have returned with: - undefined -But the first call threw an error" +Number of returns: 0 +Number of calls: 1" `; exports[`toHaveNthReturnedWith includes the custom mock name in the error message 1`] = ` -"expect(named-mock).toHaveNthReturnedWith(expected) +"expect(named-mock).toHaveNthReturnedWith(n, expected) -Expected mock function \\"named-mock\\" first call to have returned with: - \\"foo\\" -But it was not called" +n: 1 +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function first call to have returned with: - 6 -But the first call has not returned yet" +n: 1 +Expected: 6 +Received +-> 1: function call has not returned yet + 2: function call has not returned yet + +Number of returns: 2 +Number of calls: 4" `; exports[`toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 2`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 2 +Expected: 3 +Received + 1: function call has not returned yet +-> 2: function call has not returned yet + 3: 1 -Expected mock function second call to have returned with: - 3 -But the second call has not returned yet" +Number of returns: 2 +Number of calls: 4" `; exports[`toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 3`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 3 +Expected: not 1 +Received + 2: function call has not returned yet +-> 3: 1 + 4: 0 -Expected mock function third call to not have returned with: - 1 -But the third call returned exactly: - 1" +Number of returns: 2 +Number of calls: 4" `; exports[`toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly 4`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) -Expected mock function 4th call to not have returned with: - 0 -But the 4th call returned exactly: - 0" +n: 4 +Expected: not 0 +Received + 3: 1 +-> 4: 0 + +Number of returns: 2 +Number of calls: 4" `; exports[`toHaveNthReturnedWith nthReturnedWith negative throw matcher error for n that is not number 1`] = ` @@ -1812,38 +1890,50 @@ n has value: 0" `; exports[`toHaveNthReturnedWith nthReturnedWith should reject nth value greater than number of calls 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function 4th call to have returned with: - \\"foo\\" -But it was only called 3 times" +n: 4 +Expected: \\"foo\\" +Received + 3: \\"foo\\" + +Number of returns: 3" `; exports[`toHaveNthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: \\"bar1\\" +Received +-> 1: \\"foo1\\" + 2: \\"foo2\\" -Expected mock function first call to have returned with: - \\"bar1\\" -But the first call returned with: - \\"foo1\\"" +Number of returns: 3" `; exports[`toHaveNthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third 2`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not \\"foo1\\" +Received +-> 1: \\"foo1\\" + 2: \\"foo2\\" -Expected mock function first call to not have returned with: - \\"foo1\\" -But the first call returned exactly: - \\"foo1\\"" +Number of returns: 3" `; exports[`toHaveNthReturnedWith nthReturnedWith works with three calls 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) -Expected mock function first call to not have returned with: - \\"foo1\\" -But the first call returned exactly: - \\"foo1\\"" +n: 1 +Expected: not \\"foo1\\" +Received +-> 1: \\"foo1\\" + 2: \\"foo2\\" + +Number of returns: 3" `; exports[`toHaveNthReturnedWith works only on spies or jest.fn 1`] = ` @@ -1856,92 +1946,96 @@ Received has value: [Function fn]" `; exports[`toHaveNthReturnedWith works when not called 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function first call to have returned with: - \\"foo\\" -But it was not called" +n: 1 +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toHaveNthReturnedWith works with Immutable.js objects directly created 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function first call to not have returned with: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But the first call returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with Immutable.js objects indirectly created 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function first call to not have returned with: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But the first call returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with Map 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) -Expected mock function first call to not have returned with: - Map {1 => 2, 2 => 1} -But the first call returned exactly: - Map {1 => 2, 2 => 1}" +n: 1 +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with Map 2`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function first call to have returned with: - Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} -But the first call returned with: - Map {1 => 2, 2 => 1}" +n: 1 +Expected: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with Set 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Set {1, 2} -Expected mock function first call to not have returned with: - Set {1, 2} -But the first call returned exactly: - Set {1, 2}" +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with Set 2`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function first call to have returned with: - Set {3, 4} -But the first call returned with: - Set {1, 2}" +n: 1 +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with argument that does match 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) -Expected mock function first call to not have returned with: - \\"foo\\" -But the first call returned exactly: - \\"foo\\"" +n: 1 +Expected: not \\"foo\\" + +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with argument that does not match 1`] = ` -"expect(jest.fn()).toHaveNthReturnedWith(expected) +"expect(jest.fn()).toHaveNthReturnedWith(n, expected) -Expected mock function first call to have returned with: - \\"bar\\" -But the first call returned with: - \\"foo\\"" +n: 1 +Expected: \\"bar\\" +Received: \\"foo\\" + +Number of returns: 1" `; exports[`toHaveNthReturnedWith works with undefined 1`] = ` -"expect(jest.fn()).not.toHaveNthReturnedWith(expected) +"expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not undefined -Expected mock function first call to not have returned with: - undefined -But the first call returned exactly: - undefined" +Number of returns: 1" `; exports[`toHaveReturned .not fails with any argument passed 1`] = ` @@ -2216,54 +2310,56 @@ Received has value: [Function fn]" `; exports[`toHaveReturnedWith a call that throws is not considered to have returned 1`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) -Expected mock function to have returned: - undefined -But it did not return." +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1" `; exports[`toHaveReturnedWith a call that throws undefined is not considered to have returned 1`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: undefined +Received: function call threw an error -Expected mock function to have returned: - undefined -But it did not return." +Number of returns: 0 +Number of calls: 1" `; exports[`toHaveReturnedWith includes the custom mock name in the error message 1`] = ` -"expect(named-mock).toHaveReturnedWith(expected) +"expect(named-mock).toHaveReturnedWith(expected) -Expected mock function \\"named-mock\\" to have returned: - \\"foo\\" -But it did not return." +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toHaveReturnedWith returnedWith incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) -Expected mock function to have returned: - undefined -But it did not return." +Expected: undefined +Received + 1: function call has not returned yet + 2: function call has not returned yet + 3: function call has not returned yet + +Number of returns: 0 +Number of calls: 4" `; exports[`toHaveReturnedWith returnedWith works with more calls than the limit 1`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) - -Expected mock function to have returned: - \\"bar\\" -But it returned: - \\"foo1\\" - - \\"foo2\\" - - \\"foo3\\" +"expect(jest.fn()).toHaveReturnedWith(expected) - \\"foo4\\" +Expected: \\"bar\\" +Received + 1: \\"foo1\\" + 2: \\"foo2\\" + 3: \\"foo3\\" - \\"foo5\\" - - ...and 1 more" +Number of returns: 6" `; exports[`toHaveReturnedWith works only on spies or jest.fn 1`] = ` @@ -2276,92 +2372,86 @@ Received has value: [Function fn]" `; exports[`toHaveReturnedWith works when not called 1`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) -Expected mock function to have returned: - \\"foo\\" -But it did not return." +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toHaveReturnedWith works with Immutable.js objects directly created 1`] = ` -"expect(jest.fn()).not.toHaveReturnedWith(expected) +"expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function not to have returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`toHaveReturnedWith works with Immutable.js objects indirectly created 1`] = ` -"expect(jest.fn()).not.toHaveReturnedWith(expected) +"expect(jest.fn()).not.toHaveReturnedWith(expected) -Expected mock function not to have returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} + +Number of returns: 1" `; exports[`toHaveReturnedWith works with Map 1`] = ` -"expect(jest.fn()).not.toHaveReturnedWith(expected) +"expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Map {1 => 2, 2 => 1} -Expected mock function not to have returned: - Map {1 => 2, 2 => 1} -But it returned exactly: - Map {1 => 2, 2 => 1}" +Number of returns: 1" `; exports[`toHaveReturnedWith works with Map 2`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) -Expected mock function to have returned: - Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} -But it returned: - Map {1 => 2, 2 => 1}" +Expected: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toHaveReturnedWith works with Set 1`] = ` -"expect(jest.fn()).not.toHaveReturnedWith(expected) +"expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Set {1, 2} -Expected mock function not to have returned: - Set {1, 2} -But it returned exactly: - Set {1, 2}" +Number of returns: 1" `; exports[`toHaveReturnedWith works with Set 2`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) -Expected mock function to have returned: - Set {3, 4} -But it returned: - Set {1, 2}" +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1" `; exports[`toHaveReturnedWith works with argument that does match 1`] = ` -"expect(jest.fn()).not.toHaveReturnedWith(expected) +"expect(jest.fn()).not.toHaveReturnedWith(expected) -Expected mock function not to have returned: - \\"foo\\" -But it returned exactly: - \\"foo\\"" +Expected: not \\"foo\\" + +Number of returns: 1" `; exports[`toHaveReturnedWith works with argument that does not match 1`] = ` -"expect(jest.fn()).toHaveReturnedWith(expected) +"expect(jest.fn()).toHaveReturnedWith(expected) -Expected mock function to have returned: - \\"bar\\" -But it returned: - \\"foo\\"" +Expected: \\"bar\\" +Received: \\"foo\\" + +Number of returns: 1" `; exports[`toHaveReturnedWith works with undefined 1`] = ` -"expect(jest.fn()).not.toHaveReturnedWith(expected) +"expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not undefined -Expected mock function not to have returned: - undefined -But it returned exactly: - undefined" +Number of returns: 1" `; exports[`toReturn .not fails with any argument passed 1`] = ` @@ -2636,54 +2726,56 @@ Received has value: [Function fn]" `; exports[`toReturnWith a call that throws is not considered to have returned 1`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) + +Expected: undefined +Received: function call threw an error -Expected mock function to have returned: - undefined -But it did not return." +Number of returns: 0 +Number of calls: 1" `; exports[`toReturnWith a call that throws undefined is not considered to have returned 1`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) -Expected mock function to have returned: - undefined -But it did not return." +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1" `; exports[`toReturnWith includes the custom mock name in the error message 1`] = ` -"expect(named-mock).toReturnWith(expected) +"expect(named-mock).toReturnWith(expected) -Expected mock function \\"named-mock\\" to have returned: - \\"foo\\" -But it did not return." +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toReturnWith returnedWith incomplete recursive calls are handled properly 1`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) + +Expected: undefined +Received + 1: function call has not returned yet + 2: function call has not returned yet + 3: function call has not returned yet -Expected mock function to have returned: - undefined -But it did not return." +Number of returns: 0 +Number of calls: 4" `; exports[`toReturnWith returnedWith works with more calls than the limit 1`] = ` -"expect(jest.fn()).toReturnWith(expected) - -Expected mock function to have returned: - \\"bar\\" -But it returned: - \\"foo1\\" +"expect(jest.fn()).toReturnWith(expected) - \\"foo2\\" +Expected: \\"bar\\" +Received + 1: \\"foo1\\" + 2: \\"foo2\\" + 3: \\"foo3\\" - \\"foo3\\" - - \\"foo4\\" - - \\"foo5\\" - - ...and 1 more" +Number of returns: 6" `; exports[`toReturnWith works only on spies or jest.fn 1`] = ` @@ -2696,90 +2788,84 @@ Received has value: [Function fn]" `; exports[`toReturnWith works when not called 1`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) -Expected mock function to have returned: - \\"foo\\" -But it did not return." +Expected: \\"foo\\" + +Number of returns: 0" `; exports[`toReturnWith works with Immutable.js objects directly created 1`] = ` -"expect(jest.fn()).not.toReturnWith(expected) +"expect(jest.fn()).not.toReturnWith(expected) -Expected mock function not to have returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} + +Number of returns: 1" `; exports[`toReturnWith works with Immutable.js objects indirectly created 1`] = ` -"expect(jest.fn()).not.toReturnWith(expected) +"expect(jest.fn()).not.toReturnWith(expected) + +Expected: not Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -Expected mock function not to have returned: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}} -But it returned exactly: - Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}" +Number of returns: 1" `; exports[`toReturnWith works with Map 1`] = ` -"expect(jest.fn()).not.toReturnWith(expected) +"expect(jest.fn()).not.toReturnWith(expected) -Expected mock function not to have returned: - Map {1 => 2, 2 => 1} -But it returned exactly: - Map {1 => 2, 2 => 1}" +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toReturnWith works with Map 2`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) -Expected mock function to have returned: - Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} -But it returned: - Map {1 => 2, 2 => 1}" +Expected: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1" `; exports[`toReturnWith works with Set 1`] = ` -"expect(jest.fn()).not.toReturnWith(expected) +"expect(jest.fn()).not.toReturnWith(expected) + +Expected: not Set {1, 2} -Expected mock function not to have returned: - Set {1, 2} -But it returned exactly: - Set {1, 2}" +Number of returns: 1" `; exports[`toReturnWith works with Set 2`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) -Expected mock function to have returned: - Set {3, 4} -But it returned: - Set {1, 2}" +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1" `; exports[`toReturnWith works with argument that does match 1`] = ` -"expect(jest.fn()).not.toReturnWith(expected) +"expect(jest.fn()).not.toReturnWith(expected) -Expected mock function not to have returned: - \\"foo\\" -But it returned exactly: - \\"foo\\"" +Expected: not \\"foo\\" + +Number of returns: 1" `; exports[`toReturnWith works with argument that does not match 1`] = ` -"expect(jest.fn()).toReturnWith(expected) +"expect(jest.fn()).toReturnWith(expected) -Expected mock function to have returned: - \\"bar\\" -But it returned: - \\"foo\\"" +Expected: \\"bar\\" +Received: \\"foo\\" + +Number of returns: 1" `; exports[`toReturnWith works with undefined 1`] = ` -"expect(jest.fn()).not.toReturnWith(expected) +"expect(jest.fn()).not.toReturnWith(expected) + +Expected: not undefined -Expected mock function not to have returned: - undefined -But it returned exactly: - undefined" +Number of returns: 1" `; diff --git a/packages/expect/src/spyMatchers.ts b/packages/expect/src/spyMatchers.ts index f55e4e2be21b..94079de8a117 100644 --- a/packages/expect/src/spyMatchers.ts +++ b/packages/expect/src/spyMatchers.ts @@ -17,6 +17,7 @@ import { printReceived, printWithType, RECEIVED_COLOR, + stringify, } from 'jest-matcher-utils'; import {MatchersObject, MatcherState, SyncExpectationResult} from './types'; import {equals} from './jasmineUtils'; @@ -24,7 +25,6 @@ import {iterableEquality, partition, isOneline} from './utils'; const PRINT_LIMIT = 3; const CALL_PRINT_LIMIT = 3; -const RETURN_PRINT_LIMIT = 5; const LAST_CALL_PRINT_LIMIT = 1; const printReceivedArgs = (args: Array): string => @@ -32,6 +32,83 @@ const printReceivedArgs = (args: Array): string => ? 'called with no arguments' : args.map(arg => printReceived(arg)).join(', '); +const isEqualReturn = (expected: unknown, result: any): boolean => + result.type === 'return' && + equals(expected, result.value, [iterableEquality]); + +const countReturns = (results: Array): number => + results.reduce( + (n: number, result: any) => (result.type === 'return' ? n + 1 : n), + 0, + ); + +const printNumberOfReturns = ( + countReturns: number, + countCalls: number, +): string => + `\nNumber of returns: ${printReceived(countReturns)}` + + (countCalls !== countReturns + ? `\nNumber of calls: ${printReceived(countCalls)}` + : ''); + +type PrintLabel = (string: string, isExpectedCall: boolean) => string; + +// Given a label, return a function which given a string, +// right-aligns it preceding the colon in the label. +const getRightAlignedPrinter = (label: string): PrintLabel => { + // Assume that the label contains a colon. + const index = label.indexOf(':'); + const suffix = label.slice(index); + + return (string: string, isExpectedCall: boolean) => + (isExpectedCall + ? '->' + ' '.repeat(Math.max(0, index - 2 - string.length)) + : ' '.repeat(Math.max(index - string.length))) + + string + + suffix; +}; + +const printResult = (result: any) => + result.type === 'throw' + ? 'function call threw an error' + : result.type === 'incomplete' + ? 'function call has not returned yet' + : printReceived(result.value); + +type IndexedResult = [number, any]; + +// Return either empty string or one line per indexed result, +// so additional empty line can separate from `Number of returns` which follows. +const printReceivedResults = ( + label: string, + indexedResults: Array, + isOnlyCall: boolean, + iExpectedCall?: number, +) => { + if (indexedResults.length === 0) { + return ''; + } + + if (isOnlyCall) { + return label + printResult(indexedResults[0][1]) + '\n'; + } + + const printAligned = getRightAlignedPrinter(label); + + return ( + label.replace(':', '').trim() + + '\n' + + indexedResults.reduce( + (printed: string, [i, result]: IndexedResult) => + printed + + printAligned(String(i + 1), i === iExpectedCall) + + printResult(result) + + '\n', + '', + ) + ); +}; + const createToBeCalledMatcher = (matcherName: string) => function( this: MatcherState, @@ -277,41 +354,62 @@ const createToReturnWithMatcher = (matcherName: string) => isNot: this.isNot, promise: this.promise, }; - ensureMock(received, matcherName.slice(1), expectedArgument, options); + ensureMock(received, matcherName, expectedArgument, options); const receivedName = received.getMockName(); - const identifier = - receivedName === 'jest.fn()' - ? 'mock function' - : `mock function "${receivedName}"`; - - // List of return values that correspond only to calls that returned - const returnValues = received.mock.results - .filter((result: any) => result.type === 'return') - .map((result: any) => result.value); + const {calls, results} = received.mock; - const [match] = partition(returnValues, value => - equals(expected, value, [iterableEquality]), - ); - const pass = match.length > 0; + const pass = results.some((result: any) => isEqualReturn(expected, result)); const message = pass - ? () => - matcherHint('.not' + matcherName, receivedName) + - '\n\n' + - `Expected ${identifier} not to have returned:\n` + - ` ${printExpected(expected)}\n` + - `But it returned exactly:\n` + - ` ${printReceived(expected)}` - : () => - matcherHint(matcherName, receivedName) + - '\n\n' + - `Expected ${identifier} to have returned:\n` + - formatMismatchedReturnValues( - returnValues, - expected, - RETURN_PRINT_LIMIT, + ? () => { + // Some examples of results that are equal to expected value. + const indexedResults: Array = []; + let i = 0; + while (i < results.length && indexedResults.length < PRINT_LIMIT) { + if (isEqualReturn(expected, results[i])) { + indexedResults.push([i, results[i]]); + } + i += 1; + } + + return ( + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: not ${printExpected(expected)}\n` + + (results.length === 1 && + results[0].type === 'return' && + stringify(results[0].value) === stringify(expected) + ? '' + : printReceivedResults( + 'Received: ', + indexedResults, + results.length === 1, + )) + + printNumberOfReturns(countReturns(results), calls.length) ); + } + : () => { + // Some examples of results that are not equal to expected value. + const indexedResults: Array = []; + let i = 0; + while (i < results.length && indexedResults.length < PRINT_LIMIT) { + indexedResults.push([i, results[i]]); + i += 1; + } + + return ( + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: ${printExpected(expected)}\n` + + printReceivedResults( + 'Received: ', + indexedResults, + results.length === 1, + ) + + printNumberOfReturns(countReturns(results), calls.length) + ); + }; return {message, pass}; }; @@ -367,43 +465,73 @@ const createLastReturnedMatcher = (matcherName: string) => isNot: this.isNot, promise: this.promise, }; - ensureMock(received, matcherName.slice(1), expectedArgument, options); + ensureMock(received, matcherName, expectedArgument, options); const receivedName = received.getMockName(); - const identifier = - receivedName === 'jest.fn()' - ? 'mock function' - : `mock function "${receivedName}"`; - const results = received.mock.results; - const lastResult = results[results.length - 1]; - const pass = - !!lastResult && - lastResult.type === 'return' && - equals(lastResult.value, expected, [iterableEquality]); + const {calls, results} = received.mock; + const iLast = results.length - 1; + + const pass = iLast >= 0 && isEqualReturn(expected, results[iLast]); const message = pass - ? () => - matcherHint('.not' + matcherName, receivedName) + - '\n\n' + - `Expected ${identifier} to not have last returned:\n` + - ` ${printExpected(expected)}\n` + - `But it last returned exactly:\n` + - ` ${printReceived(lastResult.value)}` - : () => - matcherHint(matcherName, receivedName) + - '\n\n' + - `Expected ${identifier} to have last returned:\n` + - ` ${printExpected(expected)}\n` + - (!lastResult - ? `But it was ${RECEIVED_COLOR('not called')}` - : lastResult.type === 'incomplete' - ? `But the last call ${RECEIVED_COLOR('has not returned yet')}` - : lastResult.type === 'throw' - ? `But the last call ${RECEIVED_COLOR('threw an error')}` - : `But the last call returned:\n ${printReceived( - lastResult.value, - )}`); + ? () => { + const indexedResults: Array = []; + if (iLast > 0) { + // Display preceding result as context. + indexedResults.push([iLast - 1, results[iLast - 1]]); + } + indexedResults.push([iLast, results[iLast]]); + + return ( + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: not ${printExpected(expected)}\n` + + (results.length === 1 && + results[0].type === 'return' && + stringify(results[0].value) === stringify(expected) + ? '' + : printReceivedResults( + 'Received: ', + indexedResults, + results.length === 1, + iLast, + )) + + printNumberOfReturns(countReturns(results), calls.length) + ); + } + : () => { + const indexedResults: Array = []; + if (iLast >= 0) { + if (iLast > 0) { + let i = iLast - 1; + // Is there a preceding result that is equal to expected value? + while (i >= 0 && !isEqualReturn(expected, results[i])) { + i -= 1; + } + if (i < 0) { + i = iLast - 1; // otherwise, preceding result + } + + indexedResults.push([i, results[i]]); + } + + indexedResults.push([iLast, results[iLast]]); + } + + return ( + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: ${printExpected(expected)}\n` + + printReceivedResults( + 'Received: ', + indexedResults, + results.length === 1, + iLast, + ) + + printNumberOfReturns(countReturns(results), calls.length) + ); + }; return {message, pass}; }; @@ -487,17 +615,12 @@ const createNthReturnedWithMatcher = (matcherName: string) => promise: this.promise, secondArgument: 'expected', }; - ensureMock(received, matcherName.slice(1), expectedArgument, options); + ensureMock(received, matcherName, expectedArgument, options); if (!Number.isSafeInteger(nth) || nth < 1) { throw new Error( matcherErrorMessage( - matcherHint( - matcherName.slice(1), - undefined, - expectedArgument, - options, - ), + matcherHint(matcherName, undefined, expectedArgument, options), `${EXPECTED_COLOR(expectedArgument)} must be a positive integer`, printWithType(expectedArgument, nth, printExpected), ), @@ -505,53 +628,112 @@ const createNthReturnedWithMatcher = (matcherName: string) => } const receivedName = received.getMockName(); - const identifier = - receivedName === 'jest.fn()' - ? 'mock function' - : `mock function "${receivedName}"`; - - const results = received.mock.results; - const nthResult = results[nth - 1]; - const pass = - !!nthResult && - nthResult.type === 'return' && - equals(nthResult.value, expected, [iterableEquality]); - const nthString = nthToString(nth); + const {calls, results} = received.mock; + const length = results.length; + const iNth = nth - 1; + + const pass = iNth < length && isEqualReturn(expected, results[iNth]); + const message = pass - ? () => - matcherHint('.not' + matcherName, receivedName) + - '\n\n' + - `Expected ${identifier} ${nthString} call to not have returned with:\n` + - ` ${printExpected(expected)}\n` + - `But the ${nthString} call returned exactly:\n` + - ` ${printReceived(nthResult.value)}` - : () => - matcherHint(matcherName, receivedName) + - '\n\n' + - `Expected ${identifier} ${nthString} call to have returned with:\n` + - ` ${printExpected(expected)}\n` + - (results.length === 0 - ? `But it was ${RECEIVED_COLOR('not called')}` - : nth > results.length - ? `But it was only called ${printReceived(results.length)} times` - : nthResult.type === 'incomplete' - ? `But the ${nthString} call ${RECEIVED_COLOR( - 'has not returned yet', - )}` - : nthResult.type === 'throw' - ? `But the ${nthString} call ${RECEIVED_COLOR('threw an error')}` - : `But the ${nthString} call returned with:\n ${printReceived( - nthResult.value, - )}`); + ? () => { + // Display preceding and following results, + // in case assertions fails because index is off by one. + const indexedResults: Array = []; + if (iNth - 1 >= 0) { + indexedResults.push([iNth - 1, results[iNth - 1]]); + } + indexedResults.push([iNth, results[iNth]]); + if (iNth + 1 < length) { + indexedResults.push([iNth + 1, results[iNth + 1]]); + } + + return ( + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `n: ${nth}\n` + + `Expected: not ${printExpected(expected)}\n` + + (results.length === 1 && + results[0].type === 'return' && + stringify(results[0].value) === stringify(expected) + ? '' + : printReceivedResults( + 'Received: ', + indexedResults, + results.length === 1, + iNth, + )) + + printNumberOfReturns(countReturns(results), calls.length) + ); + } + : () => { + // Display preceding and following results: + // * nearest result that is equal to expected value + // * otherwise, adjacent result + // in case assertions fails because of index, especially off by one. + const indexedResults: Array = []; + if (iNth < length) { + if (iNth - 1 >= 0) { + let i = iNth - 1; + // Is there a preceding result that is equal to expected value? + while (i >= 0 && !isEqualReturn(expected, results[i])) { + i -= 1; + } + if (i < 0) { + i = iNth - 1; // otherwise, adjacent result + } + + indexedResults.push([i, results[i]]); + } + indexedResults.push([iNth, results[iNth]]); + if (iNth + 1 < length) { + let i = iNth + 1; + // Is there a following result that is equal to expected value? + while (i < length && !isEqualReturn(expected, results[i])) { + i += 1; + } + if (i >= length) { + i = iNth + 1; // otherwise, adjacent result + } + + indexedResults.push([i, results[i]]); + } + } else if (length > 0) { + // The number of received calls is fewer than the expected number. + let i = length - 1; + // Is there a result that is equal to expected value? + while (i >= 0 && !isEqualReturn(expected, results[i])) { + i -= 1; + } + if (i < 0) { + i = length - 1; // otherwise, last result + } + + indexedResults.push([i, results[i]]); + } + + return ( + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `n: ${nth}\n` + + `Expected: ${printExpected(expected)}\n` + + printReceivedResults( + 'Received: ', + indexedResults, + results.length === 1, + iNth, + ) + + printNumberOfReturns(countReturns(results), calls.length) + ); + }; return {message, pass}; }; const spyMatchers: MatchersObject = { lastCalledWith: createLastCalledWithMatcher('.lastCalledWith'), - lastReturnedWith: createLastReturnedMatcher('.lastReturnedWith'), + lastReturnedWith: createLastReturnedMatcher('lastReturnedWith'), nthCalledWith: createNthCalledWithMatcher('.nthCalledWith'), - nthReturnedWith: createNthReturnedWithMatcher('.nthReturnedWith'), + nthReturnedWith: createNthReturnedWithMatcher('nthReturnedWith'), toBeCalled: createToBeCalledMatcher('toBeCalled'), toBeCalledTimes: createToBeCalledTimesMatcher('toBeCalledTimes'), toBeCalledWith: createToBeCalledWithMatcher('.toBeCalledWith'), @@ -564,14 +746,14 @@ const spyMatchers: MatchersObject = { toHaveBeenNthCalledWith: createNthCalledWithMatcher( '.toHaveBeenNthCalledWith', ), - toHaveLastReturnedWith: createLastReturnedMatcher('.toHaveLastReturnedWith'), - toHaveNthReturnedWith: createNthReturnedWithMatcher('.toHaveNthReturnedWith'), + toHaveLastReturnedWith: createLastReturnedMatcher('toHaveLastReturnedWith'), + toHaveNthReturnedWith: createNthReturnedWithMatcher('toHaveNthReturnedWith'), toHaveReturned: createToReturnMatcher('toHaveReturned'), toHaveReturnedTimes: createToReturnTimesMatcher('toHaveReturnedTimes'), - toHaveReturnedWith: createToReturnWithMatcher('.toHaveReturnedWith'), + toHaveReturnedWith: createToReturnWithMatcher('toHaveReturnedWith'), toReturn: createToReturnMatcher('toReturn'), toReturnTimes: createToReturnTimesMatcher('toReturnTimes'), - toReturnWith: createToReturnWithMatcher('.toReturnWith'), + toReturnWith: createToReturnWithMatcher('toReturnWith'), }; const isSpy = (spy: any) => spy.calls && typeof spy.calls.count === 'function'; @@ -613,20 +795,6 @@ const getPrintedCalls = ( return result.join(sep); }; -const getPrintedReturnValues = (calls: Array, limit: number): string => { - const result = []; - - for (let i = 0; i < calls.length && i < limit; i += 1) { - result.push(printReceived(calls[i])); - } - - if (calls.length > limit) { - result.push(`...and ${printReceived(calls.length - limit)} more`); - } - - return result.join('\n\n '); -}; - const formatMismatchedCalls = ( calls: Array, expected: any, @@ -647,25 +815,6 @@ const formatMismatchedCalls = ( } }; -const formatMismatchedReturnValues = ( - returnValues: Array, - expected: any, - limit: number, -): string => { - if (returnValues.length) { - return ( - ` ${printExpected(expected)}\n` + - `But it returned:\n` + - ` ${getPrintedReturnValues(returnValues, limit)}` - ); - } else { - return ( - ` ${printExpected(expected)}\n` + - `But it did ${RECEIVED_COLOR('not return')}.` - ); - } -}; - const formatMismatchedArgs = (expected: any, received: any): string => { const length = Math.max(expected.length, received.length);