From 7c5adf1ac56121eb9b43ae702f47211541f19b30 Mon Sep 17 00:00:00 2001 From: rickhanlonii Date: Sun, 18 Mar 2018 16:24:18 -0400 Subject: [PATCH 1/2] Add .toBeCalledTimes and .toHaveBeenNthCalledWith --- docs/ExpectAPI.md | 10 +- .../__snapshots__/spy_matchers.test.js.snap | 634 +++++++++++------- .../expect/src/__tests__/spy_matchers.test.js | 479 +++++++------ packages/expect/src/spy_matchers.js | 143 ++-- 4 files changed, 740 insertions(+), 526 deletions(-) diff --git a/docs/ExpectAPI.md b/docs/ExpectAPI.md index 2549488517bd..29219f44877e 100644 --- a/docs/ExpectAPI.md +++ b/docs/ExpectAPI.md @@ -570,6 +570,7 @@ 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,9 +627,10 @@ 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 +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 @@ -640,8 +642,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 650e63d8826f..942ef92ab4a3 100644 --- a/packages/expect/src/__tests__/__snapshots__/spy_matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/spy_matchers.test.js.snap @@ -72,27 +72,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) @@ -100,27 +79,6 @@ 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 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`] = ` -"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 4`] = ` -"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 trailing undefined arguments 1`] = ` "expect(jest.fn()).lastCalledWith(expected) @@ -128,50 +86,10 @@ Expected mock function to have been last called with: Did not expect argument 2 but it was called with undefined." `; -exports[`nthCalledWith nthCalledWith 1`] = ` -"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) - -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" -`; - -exports[`nthCalledWith nthCalledWith 3`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) - -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" -`; - -exports[`nthCalledWith nthCalledWith 4`] = ` -"expect(jest.fn()).not.nthCalledWith(expected) - -Expected mock function first call to not have been called with: - [\\"foo1\\", \\"bar\\"]" -`; - 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 should reject non integer nth value 3`] = `"nth value 0.1 must be a positive integer greater than 0"`; - -exports[`nthCalledWith should reject non integer nth value 4`] = `"nth value 0.1 must be a positive integer greater than 0"`; - exports[`nthCalledWith should reject nth value smaller than 1 1`] = `"nth value 0 must be a positive integer greater than 0"`; -exports[`nthCalledWith should reject nth value smaller than 1 2`] = `"nth value 0 must be a positive integer greater than 0"`; - -exports[`nthCalledWith should reject nth value smaller than 1 3`] = `"nth value 0 must be a positive integer greater than 0"`; - -exports[`nthCalledWith should reject nth value smaller than 1 4`] = `"nth value 0 must be a positive integer greater than 0"`; - exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 1`] = ` "expect(jest.fn()).nthCalledWith(expected) @@ -186,46 +104,12 @@ Expected mock function first call to not have been called with: [\\"foo1\\", \\"bar\\"]" `; -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 3`] = ` -"expect(jest.fn()).nthCalledWith(expected) - -Expected mock function first call to have been called with: -" -`; - -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 4`] = ` -"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`] = ` -"expect(jest.fn()).nthCalledWith(expected) - -Expected mock function first call to have been called with: -" -`; - -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 6`] = ` -"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 7`] = ` -"expect(jest.fn()).nthCalledWith(expected) - -Expected mock function first call to have been called with: -" -`; - -exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 8`] = ` -"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 works when not called 1`] = ` @@ -285,6 +169,13 @@ Expected mock function first call to not have been called with: [\\"foo\\", \\"bar\\"]" `; +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 works with trailing undefined arguments 1`] = ` "expect(jest.fn()).nthCalledWith(expected) @@ -292,73 +183,293 @@ Expected mock function first call 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[`toBeCalled .not fails with any argument passed 1`] = ` +"expect(received)[.not].toBeCalled() -jest.fn() value must be a mock function or spy. -Received: - function: [Function fn]" +Matcher does not accept any arguments. +Got: + number: 555" `; -exports[`toBeCalled works with jest.fn 1`] = ` +exports[`toBeCalled .not passes when called 1`] = ` "expect(jest.fn()).toBeCalled() Expected mock function to have been called." `; -exports[`toBeCalled works with jest.fn 2`] = ` +exports[`toBeCalled fails with any argument passed 1`] = ` +"expect(received)[.not].toBeCalled() + +Matcher does not accept any arguments. +Got: + number: 555" +`; + +exports[`toBeCalled passes when called 1`] = ` "expect(jest.fn()).not.toBeCalled() Expected mock function not to be called but it was called with: []" `; -exports[`toBeCalled works with jest.fn 3`] = ` -"expect(received)[.not].toBeCalled() +exports[`toBeCalled works only on spies or jest.fn 1`] = ` +"expect(jest.fn())[.not].toBeCalled() -Matcher does not accept any arguments. +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: - number: 555" + object: {}" `; -exports[`toBeCalledWith works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toBeCalledWith() +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[`toHaveBeenCalled works only on spies or jest.fn 1`] = ` -"expect(jest.fn())[.not].toHaveBeenCalled() +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[`toHaveBeenCalled works with jest.fn 1`] = ` +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[`toBeCalledWith works with Immutable.js objects 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) + +Expected mock function not to have been called with: + [Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}, Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}]" +`; + +exports[`toBeCalledWith works with Map 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) + +Expected mock function not to have been called with: + [Map {1 => 2, 2 => 1}]" +`; + +exports[`toBeCalledWith works with Map 2`] = ` +"expect(jest.fn()).toBeCalledWith(expected) + +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}." +`; + +exports[`toBeCalledWith works with Set 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) + +Expected mock function not to have been called with: + [Set {1, 2}]" +`; + +exports[`toBeCalledWith works with Set 2`] = ` +"expect(jest.fn()).toBeCalledWith(expected) + +Expected mock function to have been called with: + Set {3, 4} as argument 1, but it was called with Set {1, 2}." +`; + +exports[`toBeCalledWith works with 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 \\"bar1\\"." +`; + +exports[`toBeCalledWith works with arguments that match 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) + +Expected mock function not to have been called with: + [\\"foo\\", \\"bar\\"]" +`; + +exports[`toBeCalledWith works with many arguments 1`] = ` +"expect(jest.fn()).not.toBeCalledWith(expected) + +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[`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 works with jest.fn 2`] = ` +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 with jest.fn 3`] = ` -"expect(received)[.not].toHaveBeenCalled() +exports[`toHaveBeenCalled works only on spies or jest.fn 1`] = ` +"expect(jest.fn())[.not].toHaveBeenCalled() -Matcher does not accept any arguments. -Got: - number: 555" +jest.fn() value must be a mock function or spy. +Received: + function: [Function fn]" `; -exports[`toHaveBeenCalledTimes accepts only numbers 1`] = ` +exports[`toHaveBeenCalledTimes .not only accepts a number argument 1`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -366,7 +477,7 @@ Got: object: {}" `; -exports[`toHaveBeenCalledTimes accepts only numbers 2`] = ` +exports[`toHaveBeenCalledTimes .not only accepts a number argument 2`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -374,7 +485,7 @@ Got: array: []" `; -exports[`toHaveBeenCalledTimes accepts only numbers 3`] = ` +exports[`toHaveBeenCalledTimes .not only accepts a number argument 3`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -382,7 +493,7 @@ Got: boolean: true" `; -exports[`toHaveBeenCalledTimes accepts only numbers 4`] = ` +exports[`toHaveBeenCalledTimes .not only accepts a number argument 4`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -390,7 +501,7 @@ Got: string: \\"a\\"" `; -exports[`toHaveBeenCalledTimes accepts only numbers 5`] = ` +exports[`toHaveBeenCalledTimes .not only accepts a number argument 5`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -398,7 +509,7 @@ Got: map: Map {}" `; -exports[`toHaveBeenCalledTimes accepts only numbers 6`] = ` +exports[`toHaveBeenCalledTimes .not only accepts a number argument 6`] = ` "expect(received)[.not].toHaveBeenCalledTimes(expected) Expected value must be a number. @@ -406,25 +517,73 @@ Got: function: [Function anonymous]" `; -exports[`toHaveBeenCalledTimes fails if function called less than expected times 1`] = ` +exports[`toHaveBeenCalledTimes .not passes 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`] = ` +exports[`toHaveBeenCalledTimes .not passes 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 only accepts a number argument 1`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) + +Expected value must be a number. +Got: + object: {}" +`; + +exports[`toHaveBeenCalledTimes only accepts a number argument 2`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) + +Expected value must be a number. +Got: + array: []" +`; + +exports[`toHaveBeenCalledTimes only accepts a number argument 3`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) + +Expected value must be a number. +Got: + boolean: true" +`; + +exports[`toHaveBeenCalledTimes only accepts a number argument 4`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) + +Expected value must be a number. +Got: + string: \\"a\\"" +`; + +exports[`toHaveBeenCalledTimes only accepts a number argument 5`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) + +Expected value must be a number. +Got: + map: Map {}" +`; + +exports[`toHaveBeenCalledTimes only accepts a number argument 6`] = ` +"expect(received)[.not].toHaveBeenCalledTimes(expected) + +Expected value must be a number. +Got: + function: [Function anonymous]" +`; + 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. @@ -504,27 +663,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) @@ -536,39 +674,6 @@ Expected mock function to have been called with: \\"bar\\" 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) @@ -648,58 +753,113 @@ 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: - \\"bar\\" as argument 2, but it was called with \\"bar3\\"." +Expected mock function first call to not have been called with: + [Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}, Immutable.Map {\\"a\\": {\\"b\\": \\"c\\"}}]" `; -exports[`toHaveBeenLastCalledWith works with trailing undefined arguments 1`] = ` -"expect(jest.fn()).toHaveBeenLastCalledWith(expected) +exports[`toHaveBeenNthCalledWith works with Map 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: + [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}." +`; + +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}." +`; + +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 \\"bar1\\"." +`; + +exports[`toHaveBeenNthCalledWith works with arguments that match 1`] = ` +"expect(jest.fn()).not.toHaveBeenNthCalledWith(expected) + +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 962febe48ac5..6dc8c135f486 100644 --- a/packages/expect/src/spy_matchers.js +++ b/packages/expect/src/spy_matchers.js @@ -53,6 +53,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 @@ -115,83 +146,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'; From 02d1c62a76d04291fe56deac5e40aaf781aa6f55 Mon Sep 17 00:00:00 2001 From: rickhanlonii Date: Sun, 18 Mar 2018 16:36:20 -0400 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++-- docs/ExpectAPI.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5fe04d618ee..b0486418f628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,12 +23,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) + ([#5706](https://github.com/facebook/jest/pull/5706)) +* `[expect]` Add `.toBeCalledTimes` and `toHaveBeenNthCalledWith` aliases + ([#5826](https://github.com/facebook/jest/pull/5826)) ### Fixes diff --git a/docs/ExpectAPI.md b/docs/ExpectAPI.md index 29219f44877e..2fc3e849d086 100644 --- a/docs/ExpectAPI.md +++ b/docs/ExpectAPI.md @@ -570,6 +570,7 @@ describe('drinkAll', () => { ``` ### `.toHaveBeenCalledTimes(number)` + Also under the alias: `.toBeCalledTimes(number)` Use `.toHaveBeenCalledTimes` to ensure that a mock function got called exact @@ -628,10 +629,11 @@ test('applying to all flavors does mango last', () => { ``` ### `.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)` + Also under the alias: `.nthCalledWith(arg1, arg2, ...)` -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 +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: