'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _slicedToArray = (function() { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for ( var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true ) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError( 'Invalid attempt to destructure non-iterable instance' ); } }; })(); var _jestMatcherUtils = require('jest-matcher-utils'); var _jasmine_utils = require('./jasmine_utils'); var _utils = require('./utils'); var _jestDiff = require('jest-diff'); var _jestDiff2 = _interopRequireDefault(_jestDiff); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : {default: obj}; } const CALL_PRINT_LIMIT = 3; /** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * */ const RETURN_PRINT_LIMIT = 5; const LAST_CALL_PRINT_LIMIT = 1; const createToBeCalledMatcher = matcherName => (received, expected) => { (0, _jestMatcherUtils.ensureNoExpected)(expected, matcherName); ensureMock(received, matcherName); const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const identifier = receivedIsSpy || receivedName === 'jest.fn()' ? type : `${type} "${receivedName}"`; const count = receivedIsSpy ? received.calls.count() : received.mock.calls.length; const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; const pass = count > 0; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName, '' ) + '\n\n' + `Expected ${identifier} not to be called ` + formatReceivedCalls(calls, CALL_PRINT_LIMIT, {sameSentence: true}) : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName, '') + '\n\n' + `Expected ${identifier} to have been called, but it was not called.`; return {message: message, pass: pass}; }; const createToReturnMatcher = matcherName => (received, expected) => { (0, _jestMatcherUtils.ensureNoExpected)(expected, matcherName); ensureMock(received, matcherName); const receivedName = received.getMockName(); const identifier = receivedName === 'jest.fn()' ? 'mock function' : `mock function "${receivedName}"`; // List of return values that correspond only to calls that did not throw // an error const returnValues = received.mock.results .filter(result => !result.isThrow) .map(result => result.value); const count = returnValues.length; const pass = count > 0; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName, '' ) + '\n\n' + `Expected ${identifier} not to have returned, but it returned:\n` + ` ${getPrintedReturnValues(returnValues, RETURN_PRINT_LIMIT)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName, '') + '\n\n' + `Expected ${identifier} to have returned.`; return {message: message, pass: pass}; }; const createToBeCalledTimesMatcher = matcherName => (received, expected) => { (0, _jestMatcherUtils.ensureExpectedIsNumber)(expected, matcherName); ensureMock(received, matcherName); const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const identifier = receivedIsSpy || receivedName === 'jest.fn()' ? type : `${type} "${receivedName}"`; const count = receivedIsSpy ? received.calls.count() : received.mock.calls.length; const pass = count === expected; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName, String(expected) ) + `\n\n` + `Expected ${identifier} not to be called ` + `${(0, _jestMatcherUtils.EXPECTED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', expected) )}, but it was` + ` called exactly ${(0, _jestMatcherUtils.RECEIVED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', count) )}.` : () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, String(expected) ) + '\n\n' + `Expected ${identifier} to have been called ` + `${(0, _jestMatcherUtils.EXPECTED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', expected) )},` + ` but it was called ${(0, _jestMatcherUtils.RECEIVED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', count) )}.`; return {message: message, pass: pass}; }; const createToReturnTimesMatcher = matcherName => (received, expected) => { (0, _jestMatcherUtils.ensureExpectedIsNumber)(expected, matcherName); ensureMock(received, matcherName); const receivedName = received.getMockName(); const identifier = receivedName === 'jest.fn()' ? 'mock function' : `mock function "${receivedName}"`; // List of return results that correspond only to calls that did not throw // an error const returnResults = received.mock.results.filter(result => !result.isThrow); const count = returnResults.length; const pass = count === expected; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName, String(expected) ) + `\n\n` + `Expected ${identifier} not to have returned ` + `${(0, _jestMatcherUtils.EXPECTED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', expected) )}, but it` + ` returned exactly ${(0, _jestMatcherUtils.RECEIVED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', count) )}.` : () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, String(expected) ) + '\n\n' + `Expected ${identifier} to have returned ` + `${(0, _jestMatcherUtils.EXPECTED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', expected) )},` + ` but it returned ${(0, _jestMatcherUtils.RECEIVED_COLOR)( (0, _jestMatcherUtils.pluralize)('time', count) )}.`; return {message: message, pass: pass}; }; const createToBeCalledWithMatcher = matcherName => function(received) { for ( var _len = arguments.length, expected = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++ ) { expected[_key - 1] = arguments[_key]; } ensureMock(received, matcherName); const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const identifier = receivedIsSpy || receivedName === 'jest.fn()' ? type : `${type} "${receivedName}"`; const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; var _partition = (0, _utils.partition)(calls, call => (0, _jasmine_utils.equals)(call, expected, [_utils.iterableEquality]) ), _partition2 = _slicedToArray(_partition, 2); const match = _partition2[0], fail = _partition2[1]; const pass = match.length > 0; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName ) + '\n\n' + `Expected ${identifier} not to have been called with:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName) + '\n\n' + `Expected ${identifier} to have been called with:\n` + formatMismatchedCalls(fail, expected, CALL_PRINT_LIMIT); return {message: message, pass: pass}; }; const createToReturnWithMatcher = matcherName => (received, expected) => { ensureMock(received, matcherName); const receivedName = received.getMockName(); const identifier = receivedName === 'jest.fn()' ? 'mock function' : `mock function "${receivedName}"`; // List of return values that correspond only to calls that did not throw // an error const returnValues = received.mock.results .filter(result => !result.isThrow) .map(result => result.value); var _partition3 = (0, _utils.partition)(returnValues, value => (0, _jasmine_utils.equals)(expected, value, [_utils.iterableEquality]) ), _partition4 = _slicedToArray(_partition3, 1); const match = _partition4[0]; const pass = match.length > 0; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)('.not' + matcherName, receivedName) + '\n\n' + `Expected ${identifier} not to have returned:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + `But it returned exactly:\n` + ` ${(0, _jestMatcherUtils.printReceived)(expected)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName) + '\n\n' + `Expected ${identifier} to have returned:\n` + formatMismatchedReturnValues( returnValues, expected, RETURN_PRINT_LIMIT ); return {message: message, pass: pass}; }; const createLastCalledWithMatcher = matcherName => function(received) { for ( var _len2 = arguments.length, expected = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++ ) { expected[_key2 - 1] = arguments[_key2]; } ensureMock(received, matcherName); const receivedIsSpy = isSpy(received); const type = receivedIsSpy ? 'spy' : 'mock function'; const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const identifier = receivedIsSpy || receivedName === 'jest.fn()' ? type : `${type} "${receivedName}"`; const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; const pass = (0, _jasmine_utils.equals)(calls[calls.length - 1], expected, [ _utils.iterableEquality ]); const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName ) + '\n\n' + `Expected ${identifier} to not have been last called with:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName) + '\n\n' + `Expected ${identifier} to have been last called with:\n` + formatMismatchedCalls(calls, expected, LAST_CALL_PRINT_LIMIT); return {message: message, pass: pass}; }; const createLastReturnedMatcher = matcherName => (received, expected) => { ensureMock(received, matcherName); const receivedName = received.getMockName(); const identifier = receivedName === 'jest.fn()' ? 'mock function' : `mock function "${receivedName}"`; const results = received.mock.results; const lastResult = results[results.length - 1]; const pass = !!lastResult && !lastResult.isThrow && (0, _jasmine_utils.equals)(lastResult.value, expected, [ _utils.iterableEquality ]); const message = pass ? () => (0, _jestMatcherUtils.matcherHint)('.not' + matcherName, receivedName) + '\n\n' + `Expected ${identifier} to not have last returned:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + `But it last returned exactly:\n` + ` ${(0, _jestMatcherUtils.printReceived)(lastResult.value)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName) + '\n\n' + `Expected ${identifier} to have last returned:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + (!lastResult ? `But it was ${(0, _jestMatcherUtils.RECEIVED_COLOR)('not called')}` : lastResult.isThrow ? `But the last call ${(0, _jestMatcherUtils.RECEIVED_COLOR)( 'threw an error' )}` : `But the last call returned:\n ${(0, _jestMatcherUtils.printReceived)(lastResult.value)}`); return {message: message, pass: pass}; }; const createNthCalledWithMatcher = matcherName => function(received, nth) { for ( var _len3 = arguments.length, expected = Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++ ) { expected[_key3 - 2] = arguments[_key3]; } 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 ${(0, _jestMatcherUtils.printReceived)( nth )} must be a positive integer greater than ${(0, _jestMatcherUtils.printExpected)(0)}`; const pass = false; return {message: message, pass: pass}; } const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const identifier = receivedIsSpy || receivedName === 'jest.fn()' ? type : `${type} "${receivedName}"`; const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; const pass = (0, _jasmine_utils.equals)(calls[nth - 1], expected, [ _utils.iterableEquality ]); const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( '.not' + matcherName, receivedName ) + '\n\n' + `Expected ${identifier} ${nthToString( nth )} call to not have been called with:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName) + '\n\n' + `Expected ${identifier} ${nthToString( nth )} call to have been called with:\n` + formatMismatchedCalls( calls[nth - 1] ? [calls[nth - 1]] : [], expected, LAST_CALL_PRINT_LIMIT ); return {message: message, pass: pass}; }; const createNthReturnedWithMatcher = matcherName => ( received, nth, expected ) => { ensureMock(received, matcherName); if (typeof nth !== 'number' || parseInt(nth, 10) !== nth || nth < 1) { const message = () => `nth value ${(0, _jestMatcherUtils.printReceived)( nth )} must be a positive integer greater than ${(0, _jestMatcherUtils.printExpected)(0)}`; const pass = false; return {message: message, pass: pass}; } const receivedName = received.getMockName(); const identifier = receivedName === 'jest.fn()' ? 'mock function' : `mock function "${receivedName}"`; const results = received.mock.results; const nthResult = results[nth - 1]; const pass = !!nthResult && !nthResult.isThrow && (0, _jasmine_utils.equals)(nthResult.value, expected, [ _utils.iterableEquality ]); const nthString = nthToString(nth); const message = pass ? () => (0, _jestMatcherUtils.matcherHint)('.not' + matcherName, receivedName) + '\n\n' + `Expected ${identifier} ${nthString} call to not have returned with:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + `But the ${nthString} call returned exactly:\n` + ` ${(0, _jestMatcherUtils.printReceived)(nthResult.value)}` : () => (0, _jestMatcherUtils.matcherHint)(matcherName, receivedName) + '\n\n' + `Expected ${identifier} ${nthString} call to have returned with:\n` + ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + (results.length === 0 ? `But it was ${(0, _jestMatcherUtils.RECEIVED_COLOR)('not called')}` : nth > results.length ? `But it was only called ${(0, _jestMatcherUtils.printReceived)( results.length )} times` : nthResult.isThrow ? `But the ${nthString} call ${(0, _jestMatcherUtils.RECEIVED_COLOR)('threw an error')}` : `But the ${nthString} call returned with:\n ${(0, _jestMatcherUtils.printReceived)(nthResult.value)}`); return {message: message, pass: pass}; }; const spyMatchers = { lastCalledWith: createLastCalledWithMatcher('.lastCalledWith'), lastReturnedWith: createLastReturnedMatcher('.lastReturnedWith'), nthCalledWith: createNthCalledWithMatcher('.nthCalledWith'), nthReturnedWith: createNthReturnedWithMatcher('.nthReturnedWith'), toBeCalled: createToBeCalledMatcher('.toBeCalled'), toBeCalledTimes: createToBeCalledTimesMatcher('.toBeCalledTimes'), toBeCalledWith: createToBeCalledWithMatcher('.toBeCalledWith'), toHaveBeenCalled: createToBeCalledMatcher('.toHaveBeenCalled'), toHaveBeenCalledTimes: createToBeCalledTimesMatcher('.toHaveBeenCalledTimes'), toHaveBeenCalledWith: createToBeCalledWithMatcher('.toHaveBeenCalledWith'), toHaveBeenLastCalledWith: createLastCalledWithMatcher( '.toHaveBeenLastCalledWith' ), toHaveBeenNthCalledWith: createNthCalledWithMatcher( '.toHaveBeenNthCalledWith' ), toHaveLastReturnedWith: createLastReturnedMatcher('.toHaveLastReturnedWith'), toHaveNthReturnedWith: createNthReturnedWithMatcher('.toHaveNthReturnedWith'), toHaveReturned: createToReturnMatcher('.toHaveReturned'), toHaveReturnedTimes: createToReturnTimesMatcher('.toHaveReturnedTimes'), toHaveReturnedWith: createToReturnWithMatcher('.toHaveReturnedWith'), toReturn: createToReturnMatcher('.toReturn'), toReturnTimes: createToReturnTimesMatcher('.toReturnTimes'), toReturnWith: createToReturnWithMatcher('.toReturnWith') }; const isSpy = spy => spy.calls && typeof spy.calls.count === 'function'; const ensureMock = (mockOrSpy, matcherName) => { if ( !mockOrSpy || ((mockOrSpy.calls === undefined || mockOrSpy.calls.all === undefined) && mockOrSpy._isMockFunction !== true) ) { throw new Error( (0, _jestMatcherUtils.matcherHint)( '[.not]' + matcherName, 'jest.fn()', '' ) + '\n\n' + `${(0, _jestMatcherUtils.RECEIVED_COLOR)( 'jest.fn()' )} value must be a mock function ` + `or spy.\n` + (0, _jestMatcherUtils.printWithType)( 'Received', mockOrSpy, _jestMatcherUtils.printReceived ) ); } }; const getPrintedCalls = (calls, limit, sep, fn) => { const result = []; let i = calls.length; while (--i >= 0 && --limit >= 0) { result.push(fn(calls[i])); } return result.join(sep); }; const getPrintedReturnValues = (calls, limit) => { const result = []; for (let i = 0; i < calls.length && i < limit; i += 1) { result.push((0, _jestMatcherUtils.printReceived)(calls[i])); } if (calls.length > limit) { result.push( `...and ${(0, _jestMatcherUtils.printReceived)( calls.length - limit )} more` ); } return result.join('\n\n '); }; const formatReceivedCalls = (calls, limit, options) => { if (calls.length) { const but = options && options.sameSentence ? 'but' : 'But'; const count = calls.length - limit; const printedCalls = getPrintedCalls( calls, limit, ', ', _jestMatcherUtils.printReceived ); return ( `${but} it was called ` + `with:\n ` + printedCalls + (count > 0 ? '\nand ' + (0, _jestMatcherUtils.RECEIVED_COLOR)( (0, _jestMatcherUtils.pluralize)('more call', count) ) + '.' : '') ); } else { return `But it was ${(0, _jestMatcherUtils.RECEIVED_COLOR)('not called')}.`; } }; const formatMismatchedCalls = (calls, expected, limit) => { if (calls.length) { return getPrintedCalls( calls, limit, '\n\n', formatMismatchedArgs.bind(null, expected) ); } else { return ( ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + `But it was ${(0, _jestMatcherUtils.RECEIVED_COLOR)('not called')}.` ); } }; const formatMismatchedReturnValues = (returnValues, expected, limit) => { if (returnValues.length) { return ( ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + `But it returned:\n` + ` ${getPrintedReturnValues(returnValues, limit)}` ); } else { return ( ` ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + `But it did ${(0, _jestMatcherUtils.RECEIVED_COLOR)('not return')}.` ); } }; const formatMismatchedArgs = (expected, received) => { const length = Math.max(expected.length, received.length); const printedArgs = []; for (let i = 0; i < length; i++) { if ( !(0, _jasmine_utils.equals)(expected[i], received[i], [ _utils.iterableEquality ]) ) { const oneline = (0, _utils.isOneline)(expected[i], received[i]); const diffString = (0, _jestDiff2.default)(expected[i], received[i]); printedArgs.push( ` ${(0, _jestMatcherUtils.printExpected)(expected[i])}\n` + `as argument ${i + 1}, but it was called with\n` + ` ${(0, _jestMatcherUtils.printReceived)(received[i])}.` + (diffString && !oneline ? `\n\nDifference:\n\n${diffString}` : '') ); } else if (i >= expected.length) { printedArgs.push( ` Did not expect argument ${i + 1} ` + `but it was called with ${(0, _jestMatcherUtils.printReceived)( received[i] )}.` ); } } return printedArgs.join('\n'); }; const nthToString = nth => { switch (nth) { case 1: return 'first'; case 2: return 'second'; case 3: return 'third'; } return `${nth}th`; }; exports.default = spyMatchers;