diff --git a/CHANGELOG.md b/CHANGELOG.md index be3d9a539a64..862db3c3d283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,12 +28,14 @@ * `[jest-mock]` Add tracking of return values in the `mock` property ([#5752](https://github.com/facebook/jest/pull/5752)) * `[jest-mock]` Add tracking of thrown errors in the `mock` property - ([5764](https://github.com/facebook/jest/pull/5764)) + ([#5764](https://github.com/facebook/jest/pull/5764)) * `[expect]`Add nthCalledWith spy matcher ([#5605](https://github.com/facebook/jest/pull/5605)) * `[jest-cli]` Add `isSerial` property that runners can expose to specify that they can not run in parallel ([#5706](https://github.com/facebook/jest/pull/5706)) +* `[expect]` Add `.toBeCalledTimes` and `toHaveBeenNthCalledWith` aliases + ([#5826](https://github.com/facebook/jest/pull/5826)) * `[jest-cli]` Interactive Snapshot Mode improvements ([#5864](https://github.com/facebook/jest/pull/5864)) diff --git a/docs/ExpectAPI.md b/docs/ExpectAPI.md index 2549488517bd..2fc3e849d086 100644 --- a/docs/ExpectAPI.md +++ b/docs/ExpectAPI.md @@ -571,6 +571,8 @@ describe('drinkAll', () => { ### `.toHaveBeenCalledTimes(number)` +Also under the alias: `.toBeCalledTimes(number)` + Use `.toHaveBeenCalledTimes` to ensure that a mock function got called exact number of times. @@ -626,10 +628,12 @@ test('applying to all flavors does mango last', () => { }); ``` -### `.nthCalledWith(nthCall, arg1, arg2, ....)` +### `.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)` + +Also under the alias: `.nthCalledWith(arg1, arg2, ...)` -If you have a mock function, you can use `.nthCalledWith` to test what arguments -it was nth called with. For example, let's say you have a +If you have a mock function, you can use `.toHaveBeenNthCalledWith` to test what +arguments it was nth called with. For example, let's say you have a `drinkEach(drink, Array)` function that applies `f` to a bunch of flavors, and you want to ensure that when you call it, the first flavor it operates on is `'lemon'` and the second one is `'octopus'`. You can write: @@ -640,8 +644,8 @@ Note that, nth argument must be positive integer starting from 1. test('drinkEach drinks each drink', () => { const drink = jest.fn(); drinkEach(drink, ['lemon', 'octopus']); - expect(drink).nthCalledWith(1, 'lemon'); - expect(drink).nthCalledWith(2, 'octopus'); + expect(drink).toHaveBeenNthCalledWith(1, 'lemon'); + expect(drink).toHaveBeenNthCalledWith(2, 'octopus'); }); ``` diff --git a/packages/expect/src/__tests__/__snapshots__/spy_matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/spy_matchers.test.js.snap index 8487cb972281..fd64c30e1931 100644 --- a/packages/expect/src/__tests__/__snapshots__/spy_matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/spy_matchers.test.js.snap @@ -102,27 +102,6 @@ Expected mock function to not have been last called with: [\\"foo\\", \\"bar\\"]" `; -exports[`lastCalledWith works with many arguments 2`] = ` -"expect(jest.fn()).not.lastCalledWith(expected) - -Expected mock function to not have been last called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`lastCalledWith works with many arguments 3`] = ` -"expect(jest.fn()).not.lastCalledWith(expected) - -Expected mock function to not have been last called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`lastCalledWith works with many arguments 4`] = ` -"expect(jest.fn()).not.lastCalledWith(expected) - -Expected mock function to not have been last called with: - [\\"foo\\", \\"bar\\"]" -`; - exports[`lastCalledWith works with many arguments that don't match 1`] = ` "expect(jest.fn()).lastCalledWith(expected) @@ -132,166 +111,333 @@ as argument 2, but it was called with \\"bar3\\"." `; -exports[`lastCalledWith works with many arguments that don't match 2`] = ` -"expect(jest.fn()).lastCalledWith(expected) - -Expected mock function to have been last called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\"." -`; - -exports[`lastCalledWith works with many arguments that don't match 3`] = ` +exports[`lastCalledWith works with trailing undefined arguments 1`] = ` "expect(jest.fn()).lastCalledWith(expected) Expected mock function to have been last called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\"." + Did not expect argument 2 but it was called with undefined." `; -exports[`lastCalledWith works with many arguments that don't match 4`] = ` -"expect(jest.fn()).lastCalledWith(expected) +exports[`nthCalledWith should reject non integer nth value 1`] = `"nth value 0.1 must be a positive integer greater than 0"`; -Expected mock function to have been last called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\"." -`; +exports[`nthCalledWith should reject nth value smaller than 1 1`] = `"nth value 0 must be a positive integer greater than 0"`; -exports[`lastCalledWith works with trailing undefined arguments 1`] = ` -"expect(jest.fn()).lastCalledWith(expected) +exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 1`] = ` +"expect(jest.fn()).nthCalledWith(expected) -Expected mock function to have been last called with: - Did not expect argument 2 but it was called with undefined." +Expected mock function first call to have been called with: +" `; -exports[`nthCalledWith nthCalledWith 1`] = ` +exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 2`] = ` "expect(jest.fn()).not.nthCalledWith(expected) Expected mock function first call to not have been called with: [\\"foo1\\", \\"bar\\"]" `; -exports[`nthCalledWith nthCalledWith 2`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`nthCalledWith works only on spies or jest.fn 1`] = ` +"expect(jest.fn())[.not].nthCalledWith() -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" +jest.fn() value must be a mock function or spy. +Received: + function: [Function fn]" `; -exports[`nthCalledWith nthCalledWith 3`] = ` +exports[`nthCalledWith works when not called 1`] = ` +"expect(jest.fn()).nthCalledWith(expected) + +Expected mock function first call to have been called with: + [\\"foo\\", \\"bar\\"] +But it was not called." +`; + +exports[`nthCalledWith works with Immutable.js objects 1`] = ` "expect(jest.fn()).not.nthCalledWith(expected) Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" + [Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}, Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}]" `; -exports[`nthCalledWith nthCalledWith 4`] = ` +exports[`nthCalledWith works with Map 1`] = ` "expect(jest.fn()).not.nthCalledWith(expected) Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" + [Map {1 => 2, 2 => 1}]" `; -exports[`nthCalledWith should reject non integer nth value 1`] = `"nth value 0.1 must be a positive integer greater than 0"`; - -exports[`nthCalledWith should reject non integer nth value 2`] = `"nth value 0.1 must be a positive integer greater than 0"`; +exports[`nthCalledWith works with Map 2`] = ` +"expect(jest.fn()).nthCalledWith(expected) -exports[`nthCalledWith should reject non integer nth value 3`] = `"nth value 0.1 must be a positive integer greater than 0"`; +Expected mock function first call to have been called with: + Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +as argument 1, but it was called with + Map {1 => 2, 2 => 1}. -exports[`nthCalledWith should reject non integer nth value 4`] = `"nth value 0.1 must be a positive integer greater than 0"`; +Difference: -exports[`nthCalledWith should reject nth value smaller than 1 1`] = `"nth value 0 must be a positive integer greater than 0"`; +- Expected ++ Received -exports[`nthCalledWith should reject nth value smaller than 1 2`] = `"nth value 0 must be a positive integer greater than 0"`; + Map { +- \\"a\\" => \\"b\\", +- \\"b\\" => \\"a\\", ++ 1 => 2, ++ 2 => 1, + }" +`; -exports[`nthCalledWith should reject nth value smaller than 1 3`] = `"nth value 0 must be a positive integer greater than 0"`; +exports[`nthCalledWith works with Set 1`] = ` +"expect(jest.fn()).not.nthCalledWith(expected) -exports[`nthCalledWith should reject nth value smaller than 1 4`] = `"nth value 0 must be a positive integer greater than 0"`; +Expected mock function first call to not have been called with: + [Set {1, 2}]" +`; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 1`] = ` +exports[`nthCalledWith works with Set 2`] = ` "expect(jest.fn()).nthCalledWith(expected) Expected mock function first call to have been called with: -" -`; + Set {3, 4} +as argument 1, but it was called with + Set {1, 2}. -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 2`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +Difference: -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }" `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 3`] = ` +exports[`nthCalledWith works with arguments that don't match 1`] = ` "expect(jest.fn()).nthCalledWith(expected) Expected mock function first call to have been called with: -" + \\"bar\\" +as argument 2, but it was called with + \\"bar1\\"." +`; + +exports[`nthCalledWith works with arguments that match 1`] = ` +"expect(jest.fn()).not.nthCalledWith(expected) + +Expected mock function first call to not have been called with: + [\\"foo\\", \\"bar\\"]" `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 4`] = ` +exports[`nthCalledWith works with three calls 1`] = ` "expect(jest.fn()).not.nthCalledWith(expected) Expected mock function first call to not have been called with: [\\"foo1\\", \\"bar\\"]" `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 5`] = ` +exports[`nthCalledWith works with trailing undefined arguments 1`] = ` "expect(jest.fn()).nthCalledWith(expected) Expected mock function first call to have been called with: -" + Did not expect argument 2 but it was called with undefined." `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 6`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`toBeCalled .not fails with any argument passed 1`] = ` +"expect(received)[.not].toBeCalled() -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" +Matcher does not accept any arguments. +Got: + number: 555" `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 7`] = ` -"expect(jest.fn()).nthCalledWith(expected) +exports[`toBeCalled .not passes when called 1`] = ` +"expect(jest.fn()).toBeCalled() -Expected mock function first call to have been called with: -" +Expected mock function to have been called." `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 8`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`toBeCalled fails with any argument passed 1`] = ` +"expect(received)[.not].toBeCalled() -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" +Matcher does not accept any arguments. +Got: + number: 555" `; -exports[`nthCalledWith works when not called 1`] = ` -"expect(jest.fn()).nthCalledWith(expected) +exports[`toBeCalled passes when called 1`] = ` +"expect(jest.fn()).not.toBeCalled() -Expected mock function first call to have been called with: +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() + +jest.fn() value must be a mock function or spy. +Received: + function: [Function fn]" +`; + +exports[`toBeCalledTimes .not only accepts a number argument 1`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + object: {}" +`; + +exports[`toBeCalledTimes .not only accepts a number argument 2`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + array: []" +`; + +exports[`toBeCalledTimes .not only accepts a number argument 3`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + boolean: true" +`; + +exports[`toBeCalledTimes .not only accepts a number argument 4`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + string: \\"a\\"" +`; + +exports[`toBeCalledTimes .not only accepts a number argument 5`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + map: Map {}" +`; + +exports[`toBeCalledTimes .not only accepts a number argument 6`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + function: [Function anonymous]" +`; + +exports[`toBeCalledTimes .not passes if function called less than expected times 1`] = ` +"expect(jest.fn()).toBeCalledTimes(2) + +Expected mock function to have been called two times, but it was called one time." +`; + +exports[`toBeCalledTimes .not passes if function called more than expected times 1`] = ` +"expect(jest.fn()).toBeCalledTimes(2) + +Expected mock function to have been called two times, but it was called three times." +`; + +exports[`toBeCalledTimes only accepts a number argument 1`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + object: {}" +`; + +exports[`toBeCalledTimes only accepts a number argument 2`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + array: []" +`; + +exports[`toBeCalledTimes only accepts a number argument 3`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + boolean: true" +`; + +exports[`toBeCalledTimes only accepts a number argument 4`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + string: \\"a\\"" +`; + +exports[`toBeCalledTimes only accepts a number argument 5`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + map: Map {}" +`; + +exports[`toBeCalledTimes only accepts a number argument 6`] = ` +"expect(received)[.not].toBeCalledTimes(expected) + +Expected value must be a number. +Got: + function: [Function anonymous]" +`; + +exports[`toBeCalledTimes passes if function called equal to expected times 1`] = ` +"expect(jest.fn()).not.toBeCalledTimes(2) + +Expected mock function not to be called two times, but it was called exactly two times." +`; + +exports[`toBeCalledTimes works only on spies or jest.fn 1`] = ` +"expect(jest.fn())[.not].toBeCalledTimes() + +jest.fn() value must be a mock function or spy. +Received: + function: [Function fn]" +`; + +exports[`toBeCalledWith works only on spies or jest.fn 1`] = ` +"expect(jest.fn())[.not].toBeCalledWith() + +jest.fn() value must be a mock function or spy. +Received: + function: [Function fn]" +`; + +exports[`toBeCalledWith works when not called 1`] = ` +"expect(jest.fn()).toBeCalledWith(expected) + +Expected mock function to have been called with: [\\"foo\\", \\"bar\\"] But it was not called." `; -exports[`nthCalledWith works with Immutable.js objects 1`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`toBeCalledWith works with Immutable.js objects 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) -Expected mock function first call to not have been called with: +Expected mock function not to have been called with: [Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}, Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}]" `; -exports[`nthCalledWith works with Map 1`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`toBeCalledWith works with Map 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) -Expected mock function first call to not have been called with: +Expected mock function not to have been called with: [Map {1 => 2, 2 => 1}]" `; -exports[`nthCalledWith works with Map 2`] = ` -"expect(jest.fn()).nthCalledWith(expected) +exports[`toBeCalledWith works with Map 2`] = ` +"expect(jest.fn()).toBeCalledWith(expected) -Expected mock function first call to have been called with: +Expected mock function to have been called with: Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} as argument 1, but it was called with Map {1 => 2, 2 => 1}. @@ -309,17 +455,17 @@ Difference: }" `; -exports[`nthCalledWith works with Set 1`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`toBeCalledWith works with Set 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) -Expected mock function first call to not have been called with: +Expected mock function not to have been called with: [Set {1, 2}]" `; -exports[`nthCalledWith works with Set 2`] = ` -"expect(jest.fn()).nthCalledWith(expected) +exports[`toBeCalledWith works with Set 2`] = ` +"expect(jest.fn()).toBeCalledWith(expected) -Expected mock function first call to have been called with: +Expected mock function to have been called with: Set {3, 4} as argument 1, but it was called with Set {1, 2}. @@ -337,96 +483,151 @@ Difference: }" `; -exports[`nthCalledWith works with arguments that don't match 1`] = ` -"expect(jest.fn()).nthCalledWith(expected) +exports[`toBeCalledWith works with arguments that don't match 1`] = ` +"expect(jest.fn()).toBeCalledWith(expected) -Expected mock function first call to have been called with: +Expected mock function to have been called with: \\"bar\\" as argument 2, but it was called with \\"bar1\\"." `; -exports[`nthCalledWith works with arguments that match 1`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) +exports[`toBeCalledWith works with arguments that match 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) -Expected mock function first call to not have been called with: +Expected mock function not to have been called with: [\\"foo\\", \\"bar\\"]" `; -exports[`nthCalledWith works with trailing undefined arguments 1`] = ` -"expect(jest.fn()).nthCalledWith(expected) +exports[`toBeCalledWith works with many arguments 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) -Expected mock function first call to have been called with: +Expected mock function not to have been called with: + [\\"foo\\", \\"bar\\"]" +`; + +exports[`toBeCalledWith works with many arguments that don't match 1`] = ` +"expect(jest.fn()).toBeCalledWith(expected) + +Expected mock function to have been called with: + \\"bar\\" +as argument 2, but it was called with + \\"bar3\\". + + \\"bar\\" +as argument 2, but it was called with + \\"bar2\\". + + \\"bar\\" +as argument 2, but it was called with + \\"bar1\\"." +`; + +exports[`toBeCalledWith works with trailing undefined arguments 1`] = ` +"expect(jest.fn()).toBeCalledWith(expected) + +Expected mock function to have been called with: Did not expect argument 2 but it was called with undefined." `; -exports[`toBeCalled works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toBeCalled() +exports[`toHaveBeenCalled .not fails with any argument passed 1`] = ` +"expect(received)[.not].toHaveBeenCalled() + +Matcher does not accept any arguments. +Got: + number: 555" +`; + +exports[`toHaveBeenCalled .not passes when called 1`] = ` +"expect(jest.fn()).toHaveBeenCalled() + +Expected mock function to have been called." +`; + +exports[`toHaveBeenCalled fails with any argument passed 1`] = ` +"expect(received)[.not].toHaveBeenCalled() + +Matcher does not accept any arguments. +Got: + number: 555" +`; + +exports[`toHaveBeenCalled passes when called 1`] = ` +"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() jest.fn() value must be a mock function or spy. Received: function: [Function fn]" `; -exports[`toBeCalled works with jest.fn 1`] = ` -"expect(jest.fn()).toBeCalled() +exports[`toHaveBeenCalledTimes .not only accepts a number argument 1`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) -Expected mock function to have been called." +Expected value must be a number. +Got: + object: {}" `; -exports[`toBeCalled works with jest.fn 2`] = ` -"expect(jest.fn()).not.toBeCalled() +exports[`toHaveBeenCalledTimes .not only accepts a number argument 2`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) -Expected mock function not to be called but it was called with: - []" +Expected value must be a number. +Got: + array: []" `; -exports[`toBeCalled works with jest.fn 3`] = ` -"expect(received)[.not].toBeCalled() +exports[`toHaveBeenCalledTimes .not only accepts a number argument 3`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) -Matcher does not accept any arguments. +Expected value must be a number. Got: - number: 555" + boolean: true" `; -exports[`toBeCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toBeCalledWith() +exports[`toHaveBeenCalledTimes .not only accepts a number argument 4`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) -jest.fn() value must be a mock function or spy. -Received: - function: [Function fn]" +Expected value must be a number. +Got: + string: \\"a\\"" `; -exports[`toHaveBeenCalled works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenCalled() +exports[`toHaveBeenCalledTimes .not only accepts a number argument 5`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) -jest.fn() value must be a mock function or spy. -Received: - function: [Function fn]" +Expected value must be a number. +Got: + map: Map {}" `; -exports[`toHaveBeenCalled works with jest.fn 1`] = ` -"expect(jest.fn()).toHaveBeenCalled() +exports[`toHaveBeenCalledTimes .not only accepts a number argument 6`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) -Expected mock function to have been called." +Expected value must be a number. +Got: + function: [Function anonymous]" `; -exports[`toHaveBeenCalled works with jest.fn 2`] = ` -"expect(jest.fn()).not.toHaveBeenCalled() +exports[`toHaveBeenCalledTimes .not passes if function called less than expected times 1`] = ` +"expect(jest.fn()).toHaveBeenCalledTimes(2) -Expected mock function not to be called but it was called with: - []" +Expected mock function to have been called two times, but it was called one time." `; -exports[`toHaveBeenCalled works with jest.fn 3`] = ` -"expect(received)[.not].toHaveBeenCalled() +exports[`toHaveBeenCalledTimes .not passes if function called more than expected times 1`] = ` +"expect(jest.fn()).toHaveBeenCalledTimes(2) -Matcher does not accept any arguments. -Got: - number: 555" +Expected mock function to have been called two times, but it was called three times." `; -exports[`toHaveBeenCalledTimes accepts only numbers 1`] = ` +exports[`toHaveBeenCalledTimes only accepts a number argument 1`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -434,7 +635,7 @@ Got: object: {}" `; -exports[`toHaveBeenCalledTimes accepts only numbers 2`] = ` +exports[`toHaveBeenCalledTimes only accepts a number argument 2`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -442,7 +643,7 @@ Got: array: []" `; -exports[`toHaveBeenCalledTimes accepts only numbers 3`] = ` +exports[`toHaveBeenCalledTimes only accepts a number argument 3`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -450,7 +651,7 @@ Got: boolean: true" `; -exports[`toHaveBeenCalledTimes accepts only numbers 4`] = ` +exports[`toHaveBeenCalledTimes only accepts a number argument 4`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -458,7 +659,7 @@ Got: string: \\"a\\"" `; -exports[`toHaveBeenCalledTimes accepts only numbers 5`] = ` +exports[`toHaveBeenCalledTimes only accepts a number argument 5`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -466,7 +667,7 @@ Got: map: Map {}" `; -exports[`toHaveBeenCalledTimes accepts only numbers 6`] = ` +exports[`toHaveBeenCalledTimes only accepts a number argument 6`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -474,25 +675,13 @@ Got: function: [Function anonymous]" `; -exports[`toHaveBeenCalledTimes fails if function called less than expected times 1`] = ` -"expect(jest.fn()).toHaveBeenCalledTimes(2) - -Expected mock function to have been called two times, but it was called one time." -`; - -exports[`toHaveBeenCalledTimes fails if function called more than expected times 1`] = ` -"expect(jest.fn()).toHaveBeenCalledTimes(2) - -Expected mock function to have been called two times, but it was called three times." -`; - exports[`toHaveBeenCalledTimes passes if function called equal to expected times 1`] = ` "expect(jest.fn()).not.toHaveBeenCalledTimes(2) Expected mock function not to be called two times, but it was called exactly two times." `; -exports[`toHaveBeenCalledTimes verifies that actual is a Spy 1`] = ` +exports[`toHaveBeenCalledTimes works only on spies or jest.fn 1`] = ` "expect(jest.fn())[.not].toHaveBeenCalledTimes() jest.fn() value must be a mock function or spy. @@ -602,27 +791,6 @@ Expected mock function not to have been called with: [\\"foo\\", \\"bar\\"]" `; -exports[`toHaveBeenCalledWith works with many arguments 2`] = ` -"expect(jest.fn()).not.toHaveBeenCalledWith(expected) - -Expected mock function not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toHaveBeenCalledWith works with many arguments 3`] = ` -"expect(jest.fn()).not.toHaveBeenCalledWith(expected) - -Expected mock function not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - -exports[`toHaveBeenCalledWith works with many arguments 4`] = ` -"expect(jest.fn()).not.toHaveBeenCalledWith(expected) - -Expected mock function not to have been called with: - [\\"foo\\", \\"bar\\"]" -`; - exports[`toHaveBeenCalledWith works with many arguments that don't match 1`] = ` "expect(jest.fn()).toHaveBeenCalledWith(expected) @@ -640,57 +808,6 @@ as argument 2, but it was called with \\"bar1\\"." `; -exports[`toHaveBeenCalledWith works with many arguments that don't match 2`] = ` -"expect(jest.fn()).toHaveBeenCalledWith(expected) - -Expected mock function to have been called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\". - - \\"bar\\" -as argument 2, but it was called with - \\"bar2\\". - - \\"bar\\" -as argument 2, but it was called with - \\"bar1\\"." -`; - -exports[`toHaveBeenCalledWith works with many arguments that don't match 3`] = ` -"expect(jest.fn()).toHaveBeenCalledWith(expected) - -Expected mock function to have been called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\". - - \\"bar\\" -as argument 2, but it was called with - \\"bar2\\". - - \\"bar\\" -as argument 2, but it was called with - \\"bar1\\"." -`; - -exports[`toHaveBeenCalledWith works with many arguments that don't match 4`] = ` -"expect(jest.fn()).toHaveBeenCalledWith(expected) - -Expected mock function to have been called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\". - - \\"bar\\" -as argument 2, but it was called with - \\"bar2\\". - - \\"bar\\" -as argument 2, but it was called with - \\"bar1\\"." -`; - exports[`toHaveBeenCalledWith works with trailing undefined arguments 1`] = ` "expect(jest.fn()).toHaveBeenCalledWith(expected) @@ -800,66 +917,145 @@ Expected mock function to not have been last called with: [\\"foo\\", \\"bar\\"]" `; -exports[`toHaveBeenLastCalledWith works with many arguments 2`] = ` -"expect(jest.fn()).not.toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenLastCalledWith works with many arguments that don't match 1`] = ` +"expect(jest.fn()).toHaveBeenLastCalledWith(expected) -Expected mock function to not have been last called with: - [\\"foo\\", \\"bar\\"]" +Expected mock function to have been last called with: + \\"bar\\" +as argument 2, but it was called with + \\"bar3\\"." `; -exports[`toHaveBeenLastCalledWith works with many arguments 3`] = ` -"expect(jest.fn()).not.toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenLastCalledWith works with trailing undefined arguments 1`] = ` +"expect(jest.fn()).toHaveBeenLastCalledWith(expected) -Expected mock function to not have been last called with: - [\\"foo\\", \\"bar\\"]" +Expected mock function to have been last called with: + Did not expect argument 2 but it was called with undefined." `; -exports[`toHaveBeenLastCalledWith works with many arguments 4`] = ` -"expect(jest.fn()).not.toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith should reject non integer nth value 1`] = `"nth value 0.1 must be a positive integer greater than 0"`; -Expected mock function to not have been last called with: - [\\"foo\\", \\"bar\\"]" +exports[`toHaveBeenNthCalledWith should reject nth value smaller than 1 1`] = `"nth value 0 must be a positive integer greater than 0"`; + +exports[`toHaveBeenNthCalledWith should replace 1st, 2nd, 3rd with first, second, third 1`] = ` +"expect(jest.fn()).toHaveBeenNthCalledWith(expected) + +Expected mock function first call to have been called with: +" `; -exports[`toHaveBeenLastCalledWith works with many arguments that don't match 1`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith should replace 1st, 2nd, 3rd with first, second, third 2`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) -Expected mock function to have been last called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\"." +Expected mock function first call to not have been called with: + [\\"foo1\\", \\"bar\\"]" `; -exports[`toHaveBeenLastCalledWith works with many arguments that don't match 2`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith works only on spies or jest.fn 1`] = ` +"expect(jest.fn())[.not].toHaveBeenNthCalledWith() -Expected mock function to have been last called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\"." +jest.fn() value must be a mock function or spy. +Received: + function: [Function fn]" `; -exports[`toHaveBeenLastCalledWith works with many arguments that don't match 3`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith works when not called 1`] = ` +"expect(jest.fn()).toHaveBeenNthCalledWith(expected) -Expected mock function to have been last called with: - \\"bar\\" -as argument 2, but it was called with - \\"bar3\\"." +Expected mock function first call to have been called with: + [\\"foo\\", \\"bar\\"] +But it was not called." `; -exports[`toHaveBeenLastCalledWith works with many arguments that don't match 4`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith works with Immutable.js objects 1`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) -Expected mock function to have been last called with: +Expected mock function first call to not have been called with: + [Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}, Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}]" +`; + +exports[`toHaveBeenNthCalledWith works with Map 1`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) + +Expected mock function first call to not have been called with: + [Map {1 => 2, 2 => 1}]" +`; + +exports[`toHaveBeenNthCalledWith works with Map 2`] = ` +"expect(jest.fn()).toHaveBeenNthCalledWith(expected) + +Expected mock function first call to have been called with: + Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"} +as argument 1, but it was called with + Map {1 => 2, 2 => 1}. + +Difference: + +- Expected ++ Received + + Map { +- \\"a\\" => \\"b\\", +- \\"b\\" => \\"a\\", ++ 1 => 2, ++ 2 => 1, + }" +`; + +exports[`toHaveBeenNthCalledWith works with Set 1`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) + +Expected mock function first call to not have been called with: + [Set {1, 2}]" +`; + +exports[`toHaveBeenNthCalledWith works with Set 2`] = ` +"expect(jest.fn()).toHaveBeenNthCalledWith(expected) + +Expected mock function first call to have been called with: + Set {3, 4} +as argument 1, but it was called with + Set {1, 2}. + +Difference: + +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }" +`; + +exports[`toHaveBeenNthCalledWith works with arguments that don't match 1`] = ` +"expect(jest.fn()).toHaveBeenNthCalledWith(expected) + +Expected mock function first call to have been called with: \\"bar\\" as argument 2, but it was called with - \\"bar3\\"." + \\"bar1\\"." `; -exports[`toHaveBeenLastCalledWith works with trailing undefined arguments 1`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith works with arguments that match 1`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) -Expected mock function to have been last called with: +Expected mock function first call to not have been called with: + [\\"foo\\", \\"bar\\"]" +`; + +exports[`toHaveBeenNthCalledWith works with three calls 1`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) + +Expected mock function first call to not have been called with: + [\\"foo1\\", \\"bar\\"]" +`; + +exports[`toHaveBeenNthCalledWith works with trailing undefined arguments 1`] = ` +"expect(jest.fn()).toHaveBeenNthCalledWith(expected) + +Expected mock function first call to have been called with: Did not expect argument 2 but it was called with undefined." `; diff --git a/packages/expect/src/__tests__/spy_matchers.test.js b/packages/expect/src/__tests__/spy_matchers.test.js index 52cb3d1d29e9..91624ef28515 100644 --- a/packages/expect/src/__tests__/spy_matchers.test.js +++ b/packages/expect/src/__tests__/spy_matchers.test.js @@ -9,297 +9,336 @@ const Immutable = require('immutable'); const jestExpect = require('../'); -['toHaveBeenCalled', 'toBeCalled'].forEach(called => { - test(`${called} works with jest.fn`, () => { - const fn = jest.fn(); +['toBeCalled', 'toHaveBeenCalled'].forEach(called => { + describe(`${called}`, () => { + test(`works only on spies or jest.fn`, () => { + const fn = function fn() {}; - jestExpect(fn).not[called](); - expect(() => jestExpect(fn)[called]()).toThrowErrorMatchingSnapshot(); + expect(() => jestExpect(fn)[called]()).toThrowErrorMatchingSnapshot(); + }); - fn(); - jestExpect(fn)[called](); - expect(() => jestExpect(fn).not[called]()).toThrowErrorMatchingSnapshot(); + test(`passes when called`, () => { + const fn = jest.fn(); + fn(); + jestExpect(fn)[called](); + expect(() => jestExpect(fn).not[called]()).toThrowErrorMatchingSnapshot(); + }); - expect(() => jestExpect(fn)[called](555)).toThrowErrorMatchingSnapshot(); - }); -}); + test(`.not passes when called`, () => { + const fn = jest.fn(); + + jestExpect(fn).not[called](); + expect(() => jestExpect(fn)[called]()).toThrowErrorMatchingSnapshot(); + }); + + test(`fails with any argument passed`, () => { + const fn = jest.fn(); -describe('toHaveBeenCalledTimes', () => { - it('accepts only numbers', () => { - const fn = jest.fn(); - fn(); - jestExpect(fn).toHaveBeenCalledTimes(1); + fn(); + expect(() => jestExpect(fn)[called](555)).toThrowErrorMatchingSnapshot(); + }); + + test(`.not fails with any argument passed`, () => { + const fn = jest.fn(); - [{}, [], true, 'a', new Map(), () => {}].forEach(value => { expect(() => - jestExpect(fn).toHaveBeenCalledTimes(value), + jestExpect(fn).not[called](555), ).toThrowErrorMatchingSnapshot(); }); }); +}); - it('verifies that actual is a Spy', () => { - const fn = function fn() {}; +['toBeCalledTimes', 'toHaveBeenCalledTimes'].forEach(calledTimes => { + describe(`${calledTimes}`, () => { + test('works only on spies or jest.fn', () => { + const fn = function fn() {}; - expect(() => - jestExpect(fn).toHaveBeenCalledTimes(2), - ).toThrowErrorMatchingSnapshot(); - }); + expect(() => + jestExpect(fn)[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); - it('passes if function called equal to expected times', () => { - const fn = jest.fn(); - fn(); - fn(); + test('only accepts a number argument', () => { + const fn = jest.fn(); + fn(); + jestExpect(fn)[calledTimes](1); + + [{}, [], true, 'a', new Map(), () => {}].forEach(value => { + expect(() => + jestExpect(fn)[calledTimes](value), + ).toThrowErrorMatchingSnapshot(); + }); + }); - jestExpect(fn).toHaveBeenCalledTimes(2); + test('.not only accepts a number argument', () => { + const fn = jest.fn(); + jestExpect(fn).not[calledTimes](1); - expect(() => - jestExpect(fn).not.toHaveBeenCalledTimes(2), - ).toThrowErrorMatchingSnapshot(); - }); + [{}, [], true, 'a', new Map(), () => {}].forEach(value => { + expect(() => + jestExpect(fn).not[calledTimes](value), + ).toThrowErrorMatchingSnapshot(); + }); + }); - it('fails if function called more than expected times', () => { - const fn = jest.fn(); - fn(); - fn(); - fn(); + test('passes if function called equal to expected times', () => { + const fn = jest.fn(); + fn(); + fn(); - jestExpect(fn).toHaveBeenCalledTimes(3); - jestExpect(fn).not.toHaveBeenCalledTimes(2); + jestExpect(fn)[calledTimes](2); - expect(() => - jestExpect(fn).toHaveBeenCalledTimes(2), - ).toThrowErrorMatchingSnapshot(); - }); + expect(() => + jestExpect(fn).not[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); - it('fails if function called less than expected times', () => { - const fn = jest.fn(); - fn(); + test('.not passes if function called more than expected times', () => { + const fn = jest.fn(); + fn(); + fn(); + fn(); - jestExpect(fn).toHaveBeenCalledTimes(1); - jestExpect(fn).not.toHaveBeenCalledTimes(2); + jestExpect(fn)[calledTimes](3); + jestExpect(fn).not[calledTimes](2); - expect(() => - jestExpect(fn).toHaveBeenCalledTimes(2), - ).toThrowErrorMatchingSnapshot(); - }); -}); + expect(() => + jestExpect(fn)[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); -[ - 'lastCalledWith', - 'toBeCalled', - 'toBeCalledWith', - 'toHaveBeenCalled', - 'toHaveBeenCalledWith', - 'toHaveBeenLastCalledWith', -].forEach(calledWith => { - test(`${calledWith} works only on spies or jest.fn`, () => { - const fn = function fn() {}; + test('.not passes if function called less than expected times', () => { + const fn = jest.fn(); + fn(); + + jestExpect(fn)[calledTimes](1); + jestExpect(fn).not[calledTimes](2); - expect(() => jestExpect(fn)[calledWith]()).toThrowErrorMatchingSnapshot(); + expect(() => + jestExpect(fn)[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); }); }); [ 'lastCalledWith', + 'toHaveBeenLastCalledWith', 'nthCalledWith', + 'toHaveBeenNthCalledWith', + 'toBeCalledWith', 'toHaveBeenCalledWith', - 'toHaveBeenLastCalledWith', ].forEach(calledWith => { const caller = function(callee, ...args) { - if (calledWith == 'nthCalledWith') { + if ( + calledWith === 'nthCalledWith' || + calledWith === 'toHaveBeenNthCalledWith' + ) { callee(1, ...args); } else { callee(...args); } }; - test(`${calledWith} works when not called`, () => { - const fn = jest.fn(); - caller(jestExpect(fn).not[calledWith], 'foo', 'bar'); - - expect(() => - caller(jestExpect(fn)[calledWith], 'foo', 'bar'), - ).toThrowErrorMatchingSnapshot(); - }); - - test(`${calledWith} works with no arguments`, () => { - const fn = jest.fn(); - fn(); - caller(jestExpect(fn)[calledWith]); - }); - - test(`${calledWith} works with arguments that don't match`, () => { - const fn = jest.fn(); - fn('foo', 'bar1'); - - caller(jestExpect(fn).not[calledWith], 'foo', 'bar'); - - expect(() => - caller(jestExpect(fn)[calledWith], 'foo', 'bar'), - ).toThrowErrorMatchingSnapshot(); - }); - - test(`${calledWith} works with arguments that match`, () => { - const fn = jest.fn(); - fn('foo', 'bar'); - - caller(jestExpect(fn)[calledWith], 'foo', 'bar'); - - expect(() => - caller(jestExpect(fn).not[calledWith], 'foo', 'bar'), - ).toThrowErrorMatchingSnapshot(); - }); - - test(`${calledWith} works with trailing undefined arguments`, () => { - const fn = jest.fn(); - fn('foo', undefined); - - expect(() => - caller(jestExpect(fn)[calledWith], 'foo'), - ).toThrowErrorMatchingSnapshot(); - }); - - test(`${calledWith} works with Map`, () => { - const fn = jest.fn(); - - const m1 = new Map([[1, 2], [2, 1]]); - const m2 = new Map([[1, 2], [2, 1]]); - const m3 = new Map([['a', 'b'], ['b', 'a']]); - - fn(m1); + describe(`${calledWith}`, () => { + test(`works only on spies or jest.fn`, () => { + const fn = function fn() {}; - caller(jestExpect(fn)[calledWith], m2); - caller(jestExpect(fn).not[calledWith], m3); - - expect(() => - caller(jestExpect(fn).not[calledWith], m2), - ).toThrowErrorMatchingSnapshot(); - expect(() => - caller(jestExpect(fn)[calledWith], m3), - ).toThrowErrorMatchingSnapshot(); - }); + expect(() => jestExpect(fn)[calledWith]()).toThrowErrorMatchingSnapshot(); + }); - test(`${calledWith} works with Set`, () => { - const fn = jest.fn(); + test(`works when not called`, () => { + const fn = jest.fn(); + caller(jestExpect(fn).not[calledWith], 'foo', 'bar'); - const s1 = new Set([1, 2]); - const s2 = new Set([1, 2]); - const s3 = new Set([3, 4]); + expect(() => + caller(jestExpect(fn)[calledWith], 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + }); - fn(s1); + test(`works with no arguments`, () => { + const fn = jest.fn(); + fn(); + caller(jestExpect(fn)[calledWith]); + }); - caller(jestExpect(fn)[calledWith], s2); - caller(jestExpect(fn).not[calledWith], s3); + test(`works with arguments that don't match`, () => { + const fn = jest.fn(); + fn('foo', 'bar1'); - expect(() => - caller(jestExpect(fn).not[calledWith], s2), - ).toThrowErrorMatchingSnapshot(); - expect(() => - caller(jestExpect(fn)[calledWith], s3), - ).toThrowErrorMatchingSnapshot(); - }); + caller(jestExpect(fn).not[calledWith], 'foo', 'bar'); - test(`${calledWith} works with Immutable.js objects`, () => { - const fn = jest.fn(); - const directlyCreated = new Immutable.Map([['a', {b: 'c'}]]); - const indirectlyCreated = new Immutable.Map().set('a', {b: 'c'}); - fn(directlyCreated, indirectlyCreated); - - caller(jestExpect(fn)[calledWith], indirectlyCreated, directlyCreated); - - expect(() => - caller( - jestExpect(fn).not[calledWith], - indirectlyCreated, - directlyCreated, - ), - ).toThrowErrorMatchingSnapshot(); - }); + expect(() => + caller(jestExpect(fn)[calledWith], 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + }); - [ - 'lastCalledWith', - 'toHaveBeenCalledWith', - 'toHaveBeenLastCalledWith', - ].forEach(calledWith => { - test(`${calledWith} works with many arguments`, () => { + test(`works with arguments that match`, () => { const fn = jest.fn(); - fn('foo1', 'bar'); - fn('foo', 'bar1'); fn('foo', 'bar'); - jestExpect(fn)[calledWith]('foo', 'bar'); + caller(jestExpect(fn)[calledWith], 'foo', 'bar'); expect(() => - jestExpect(fn).not[calledWith]('foo', 'bar'), + caller(jestExpect(fn).not[calledWith], 'foo', 'bar'), ).toThrowErrorMatchingSnapshot(); }); - test(`${calledWith} works with many arguments that don't match`, () => { + test(`works with trailing undefined arguments`, () => { const fn = jest.fn(); - fn('foo', 'bar1'); - fn('foo', 'bar2'); - fn('foo', 'bar3'); - - jestExpect(fn).not[calledWith]('foo', 'bar'); + fn('foo', undefined); expect(() => - jestExpect(fn)[calledWith]('foo', 'bar'), + caller(jestExpect(fn)[calledWith], 'foo'), ).toThrowErrorMatchingSnapshot(); }); - }); - describe('nthCalledWith', () => { - test(`nthCalledWith`, () => { + test(`works with Map`, () => { const fn = jest.fn(); - fn('foo1', 'bar'); - fn('foo', 'bar1'); - fn('foo', 'bar'); - jestExpect(fn).nthCalledWith(1, 'foo1', 'bar'); - jestExpect(fn).nthCalledWith(2, 'foo', 'bar1'); - jestExpect(fn).nthCalledWith(3, 'foo', 'bar'); + const m1 = new Map([[1, 2], [2, 1]]); + const m2 = new Map([[1, 2], [2, 1]]); + const m3 = new Map([['a', 'b'], ['b', 'a']]); - expect(() => { - jestExpect(fn).not.nthCalledWith(1, 'foo1', 'bar'); - jestExpect(fn).not.nthCalledWith(2, 'foo', 'bar1'); - jestExpect(fn).not.nthCalledWith(3, 'foo', 'bar'); - }).toThrowErrorMatchingSnapshot(); - }); + fn(m1); - it('should replace 1st, 2nd, 3rd with first, second, third', async () => { - const fn = jest.fn(); - fn('foo1', 'bar'); - fn('foo', 'bar1'); - fn('foo', 'bar'); + caller(jestExpect(fn)[calledWith], m2); + caller(jestExpect(fn).not[calledWith], m3); - expect(() => { - jestExpect(fn).nthCalledWith(1, 'foo', 'bar'); - jestExpect(fn).nthCalledWith(2, 'foo', 'bar'); - jestExpect(fn).nthCalledWith(3, 'foo1', 'bar'); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - jestExpect(fn).not.nthCalledWith(1, 'foo1', 'bar'); - jestExpect(fn).not.nthCalledWith(2, 'foo', 'bar1'); - jestExpect(fn).not.nthCalledWith(3, 'foo', 'bar'); - }).toThrowErrorMatchingSnapshot(); + expect(() => + caller(jestExpect(fn).not[calledWith], m2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + caller(jestExpect(fn)[calledWith], m3), + ).toThrowErrorMatchingSnapshot(); }); - it('should reject nth value smaller than 1', async () => { + test(`works with Set`, () => { const fn = jest.fn(); - fn('foo1', 'bar'); - expect(() => { - jestExpect(fn).nthCalledWith(0, 'foo1', 'bar'); - }).toThrowErrorMatchingSnapshot(); + const s1 = new Set([1, 2]); + const s2 = new Set([1, 2]); + const s3 = new Set([3, 4]); + + fn(s1); + + caller(jestExpect(fn)[calledWith], s2); + caller(jestExpect(fn).not[calledWith], s3); + + expect(() => + caller(jestExpect(fn).not[calledWith], s2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + caller(jestExpect(fn)[calledWith], s3), + ).toThrowErrorMatchingSnapshot(); }); - it('should reject non integer nth value', async () => { + test(`works with Immutable.js objects`, () => { const fn = jest.fn(); - fn('foo1', 'bar'); + const directlyCreated = new Immutable.Map([['a', {b: 'c'}]]); + const indirectlyCreated = new Immutable.Map().set('a', {b: 'c'}); + fn(directlyCreated, indirectlyCreated); + + caller(jestExpect(fn)[calledWith], indirectlyCreated, directlyCreated); - expect(() => { - jestExpect(fn).nthCalledWith(0.1, 'foo1', 'bar'); - }).toThrowErrorMatchingSnapshot(); + expect(() => + caller( + jestExpect(fn).not[calledWith], + indirectlyCreated, + directlyCreated, + ), + ).toThrowErrorMatchingSnapshot(); }); + + const basicCalledWith = [ + 'lastCalledWith', + 'toHaveBeenLastCalledWith', + 'toBeCalledWith', + 'toHaveBeenCalledWith', + ]; + + if (basicCalledWith.indexOf(calledWith) >= 0) { + test(`works with many arguments`, () => { + const fn = jest.fn(); + fn('foo1', 'bar'); + fn('foo', 'bar1'); + fn('foo', 'bar'); + + jestExpect(fn)[calledWith]('foo', 'bar'); + + expect(() => + jestExpect(fn).not[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + }); + + test(`works with many arguments that don't match`, () => { + const fn = jest.fn(); + fn('foo', 'bar1'); + fn('foo', 'bar2'); + fn('foo', 'bar3'); + + jestExpect(fn).not[calledWith]('foo', 'bar'); + + expect(() => + jestExpect(fn)[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + }); + } + + const nthCalled = ['toHaveBeenNthCalledWith', 'nthCalledWith']; + if (nthCalled.indexOf(calledWith) >= 0) { + test(`works with three calls`, () => { + const fn = jest.fn(); + fn('foo1', 'bar'); + fn('foo', 'bar1'); + fn('foo', 'bar'); + + jestExpect(fn)[calledWith](1, 'foo1', 'bar'); + jestExpect(fn)[calledWith](2, 'foo', 'bar1'); + jestExpect(fn)[calledWith](3, 'foo', 'bar'); + + expect(() => { + jestExpect(fn).not[calledWith](1, 'foo1', 'bar'); + jestExpect(fn).not[calledWith](2, 'foo', 'bar1'); + jestExpect(fn).not[calledWith](3, 'foo', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('should replace 1st, 2nd, 3rd with first, second, third', async () => { + const fn = jest.fn(); + fn('foo1', 'bar'); + fn('foo', 'bar1'); + fn('foo', 'bar'); + + expect(() => { + jestExpect(fn)[calledWith](1, 'foo', 'bar'); + jestExpect(fn)[calledWith](2, 'foo', 'bar'); + jestExpect(fn)[calledWith](3, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + jestExpect(fn).not[calledWith](1, 'foo1', 'bar'); + jestExpect(fn).not[calledWith](2, 'foo', 'bar1'); + jestExpect(fn).not[calledWith](3, 'foo', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('should reject nth value smaller than 1', async () => { + const fn = jest.fn(); + fn('foo1', 'bar'); + + expect(() => { + jestExpect(fn)[calledWith](0, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('should reject non integer nth value', async () => { + const fn = jest.fn(); + fn('foo1', 'bar'); + + expect(() => { + jestExpect(fn)[calledWith](0.1, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + } }); }); diff --git a/packages/expect/src/spy_matchers.js b/packages/expect/src/spy_matchers.js index f3fc7d817e67..f1e4e7585dd4 100644 --- a/packages/expect/src/spy_matchers.js +++ b/packages/expect/src/spy_matchers.js @@ -54,6 +54,37 @@ const createToBeCalledMatcher = matcherName => (received, expected) => { return {message, pass}; }; +const createToBeCalledTimesMatcher = (matcherName: string) => ( + received: any, + expected: number, +) => { + ensureExpectedIsNumber(expected, matcherName); + ensureMock(received, matcherName); + + const receivedIsSpy = isSpy(received); + const type = receivedIsSpy ? 'spy' : 'mock function'; + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + const count = receivedIsSpy + ? received.calls.count() + : received.mock.calls.length; + const pass = count === expected; + const message = pass + ? () => + matcherHint('.not' + matcherName, receivedName, String(expected)) + + `\n\n` + + `Expected ${type} not to be called ` + + `${EXPECTED_COLOR(pluralize('time', expected))}, but it was` + + ` called exactly ${RECEIVED_COLOR(pluralize('time', count))}.` + : () => + matcherHint(matcherName, receivedName, String(expected)) + + '\n\n' + + `Expected ${type} to have been called ` + + `${EXPECTED_COLOR(pluralize('time', expected))},` + + ` but it was called ${RECEIVED_COLOR(pluralize('time', count))}.`; + + return {message, pass}; +}; + const createToBeCalledWithMatcher = matcherName => ( received: any, ...expected: any @@ -116,83 +147,65 @@ const createLastCalledWithMatcher = matcherName => ( return {message, pass}; }; -const spyMatchers: MatchersObject = { - lastCalledWith: createLastCalledWithMatcher('.lastCalledWith'), - nthCalledWith(received: any, nth: number, ...expected: any) { - const matcherName = '.nthCalledWith'; - ensureMock(received, matcherName); +const createNthCalledWithMatcher = (matcherName: string) => ( + received: any, + nth: number, + ...expected: any +) => { + ensureMock(received, matcherName); + + const receivedIsSpy = isSpy(received); + const type = receivedIsSpy ? 'spy' : 'mock function'; + + if (typeof nth !== 'number' || parseInt(nth, 10) !== nth || nth < 1) { + const message = () => + `nth value ${printReceived( + nth, + )} must be a positive integer greater than ${printExpected(0)}`; + const pass = false; + return {message, pass}; + } - const receivedIsSpy = isSpy(received); - const type = receivedIsSpy ? 'spy' : 'mock function'; + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + const calls = receivedIsSpy + ? received.calls.all().map(x => x.args) + : received.mock.calls; + const pass = equals(calls[nth - 1], expected, [iterableEquality]); - if (typeof nth !== 'number' || parseInt(nth, 10) !== nth || nth < 1) { - const message = () => - `nth value ${printReceived( + const message = pass + ? () => + matcherHint('.not' + matcherName, receivedName) + + '\n\n' + + `Expected ${type} ${nthToString( nth, - )} must be a positive integer greater than ${printExpected(0)}`; - const pass = false; - return {message, pass}; - } + )} call to not have been called with:\n` + + ` ${printExpected(expected)}` + : () => + matcherHint(matcherName, receivedName) + + '\n\n' + + `Expected ${type} ${nthToString( + nth, + )} call to have been called with:\n` + + formatMismatchedCalls(calls, expected, LAST_CALL_PRINT_LIMIT); - const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); - const calls = receivedIsSpy - ? received.calls.all().map(x => x.args) - : received.mock.calls; - const pass = equals(calls[nth - 1], expected, [iterableEquality]); - - const message = pass - ? () => - matcherHint('.not' + matcherName, receivedName) + - '\n\n' + - `Expected ${type} ${nthToString( - nth, - )} call to not have been called with:\n` + - ` ${printExpected(expected)}` - : () => - matcherHint(matcherName, receivedName) + - '\n\n' + - `Expected ${type} ${nthToString( - nth, - )} call to have been called with:\n` + - formatMismatchedCalls(calls, expected, LAST_CALL_PRINT_LIMIT); + return {message, pass}; +}; - return {message, pass}; - }, +const spyMatchers: MatchersObject = { + lastCalledWith: createLastCalledWithMatcher('.lastCalledWith'), + nthCalledWith: createNthCalledWithMatcher('.nthCalledWith'), toBeCalled: createToBeCalledMatcher('.toBeCalled'), + toBeCalledTimes: createToBeCalledTimesMatcher('.toBeCalledTimes'), toBeCalledWith: createToBeCalledWithMatcher('.toBeCalledWith'), toHaveBeenCalled: createToBeCalledMatcher('.toHaveBeenCalled'), - toHaveBeenCalledTimes(received: any, expected: number) { - const matcherName = '.toHaveBeenCalledTimes'; - ensureExpectedIsNumber(expected, matcherName); - ensureMock(received, matcherName); - - const receivedIsSpy = isSpy(received); - const type = receivedIsSpy ? 'spy' : 'mock function'; - const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); - const count = receivedIsSpy - ? received.calls.count() - : received.mock.calls.length; - const pass = count === expected; - const message = pass - ? () => - matcherHint('.not' + matcherName, receivedName, String(expected)) + - `\n\n` + - `Expected ${type} not to be called ` + - `${EXPECTED_COLOR(pluralize('time', expected))}, but it was` + - ` called exactly ${RECEIVED_COLOR(pluralize('time', count))}.` - : () => - matcherHint(matcherName, receivedName, String(expected)) + - '\n\n' + - `Expected ${type} to have been called ` + - `${EXPECTED_COLOR(pluralize('time', expected))},` + - ` but it was called ${RECEIVED_COLOR(pluralize('time', count))}.`; - - return {message, pass}; - }, + toHaveBeenCalledTimes: createToBeCalledTimesMatcher('.toHaveBeenCalledTimes'), toHaveBeenCalledWith: createToBeCalledWithMatcher('.toHaveBeenCalledWith'), toHaveBeenLastCalledWith: createLastCalledWithMatcher( '.toHaveBeenLastCalledWith', ), + toHaveBeenNthCalledWith: createNthCalledWithMatcher( + '.toHaveBeenNthCalledWith', + ), }; const isSpy = spy => spy.calls && typeof spy.calls.count === 'function';