'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.default = void 0; var _jestGetType = require('jest-get-type'); var _jestMatcherUtils = require('jest-matcher-utils'); var _jasmineUtils = require('./jasmineUtils'); var _utils = require('./utils'); /** * Copyright (c) Facebook, Inc. and its affiliates. 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. */ // The optional property of matcher context is true if undefined. const isExpand = expand => expand !== false; const PRINT_LIMIT = 3; const NO_ARGUMENTS = 'called with 0 arguments'; const printExpectedArgs = expected => expected.length === 0 ? NO_ARGUMENTS : expected.map(arg => (0, _jestMatcherUtils.printExpected)(arg)).join(', '); const printReceivedArgs = (received, expected) => received.length === 0 ? NO_ARGUMENTS : received .map((arg, i) => Array.isArray(expected) && i < expected.length && isEqualValue(expected[i], arg) ? printCommon(arg) : (0, _jestMatcherUtils.printReceived)(arg) ) .join(', '); const printCommon = val => (0, _jestMatcherUtils.DIM_COLOR)((0, _jestMatcherUtils.stringify)(val)); const isEqualValue = (expected, received) => (0, _jasmineUtils.equals)(expected, received, [_utils.iterableEquality]); const isEqualCall = (expected, received) => isEqualValue(expected, received); const isEqualReturn = (expected, result) => result.type === 'return' && isEqualValue(expected, result.value); const countReturns = results => results.reduce((n, result) => (result.type === 'return' ? n + 1 : n), 0); const printNumberOfReturns = (countReturns, countCalls) => `\nNumber of returns: ${(0, _jestMatcherUtils.printReceived)(countReturns)}` + (countCalls !== countReturns ? `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(countCalls)}` : ''); // Given a label, return a function which given a string, // right-aligns it preceding the colon in the label. const getRightAlignedPrinter = label => { // Assume that the label contains a colon. const index = label.indexOf(':'); const suffix = label.slice(index); return (string, isExpectedCall) => (isExpectedCall ? '->' + ' '.repeat(Math.max(0, index - 2 - string.length)) : ' '.repeat(Math.max(index - string.length))) + string + suffix; }; const printReceivedCallsNegative = ( expected, indexedCalls, isOnlyCall, iExpectedCall ) => { if (indexedCalls.length === 0) { return ''; } const label = 'Received: '; if (isOnlyCall) { return label + printReceivedArgs(indexedCalls[0], expected) + '\n'; } const printAligned = getRightAlignedPrinter(label); return ( 'Received\n' + indexedCalls.reduce( (printed, [i, args]) => printed + printAligned(String(i + 1), i === iExpectedCall) + printReceivedArgs(args, expected) + '\n', '' ) ); }; const printExpectedReceivedCallsPositive = ( expected, indexedCalls, expand, isOnlyCall, iExpectedCall ) => { const expectedLine = `Expected: ${printExpectedArgs(expected)}\n`; if (indexedCalls.length === 0) { return expectedLine; } const label = 'Received: '; if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) { const received = indexedCalls[0][1]; if (isLineDiffableCall(expected, received)) { // Display diff without indentation. const lines = [ (0, _jestMatcherUtils.EXPECTED_COLOR)('- Expected'), (0, _jestMatcherUtils.RECEIVED_COLOR)('+ Received'), '' ]; const length = Math.max(expected.length, received.length); for (let i = 0; i < length; i += 1) { if (i < expected.length && i < received.length) { if (isEqualValue(expected[i], received[i])) { lines.push(` ${printCommon(received[i])},`); continue; } if (isLineDiffableArg(expected[i], received[i])) { const difference = (0, _jestMatcherUtils.diff)( expected[i], received[i], { expand } ); if ( typeof difference === 'string' && difference.includes('- Expected') && difference.includes('+ Received') ) { // Omit annotation in case multiple args have diff. lines.push(difference.split('\n').slice(3).join('\n') + ','); continue; } } } if (i < expected.length) { lines.push( (0, _jestMatcherUtils.EXPECTED_COLOR)( '- ' + (0, _jestMatcherUtils.stringify)(expected[i]) ) + ',' ); } if (i < received.length) { lines.push( (0, _jestMatcherUtils.RECEIVED_COLOR)( '+ ' + (0, _jestMatcherUtils.stringify)(received[i]) ) + ',' ); } } return lines.join('\n') + '\n'; } return expectedLine + label + printReceivedArgs(received, expected) + '\n'; } const printAligned = getRightAlignedPrinter(label); return ( expectedLine + 'Received\n' + indexedCalls.reduce((printed, [i, received]) => { const aligned = printAligned(String(i + 1), i === iExpectedCall); return ( printed + ((i === iExpectedCall || iExpectedCall === undefined) && isLineDiffableCall(expected, received) ? aligned.replace(': ', '\n') + printDiffCall(expected, received, expand) : aligned + printReceivedArgs(received, expected)) + '\n' ); }, '') ); }; const indentation = 'Received'.replace(/\w/g, ' '); const printDiffCall = (expected, received, expand) => received .map((arg, i) => { if (i < expected.length) { if (isEqualValue(expected[i], arg)) { return indentation + ' ' + printCommon(arg) + ','; } if (isLineDiffableArg(expected[i], arg)) { const difference = (0, _jestMatcherUtils.diff)(expected[i], arg, { expand }); if ( typeof difference === 'string' && difference.includes('- Expected') && difference.includes('+ Received') ) { // Display diff with indentation. // Omit annotation in case multiple args have diff. return ( difference .split('\n') .slice(3) .map(line => indentation + line) .join('\n') + ',' ); } } } // Display + only if received arg has no corresponding expected arg. return ( indentation + (i < expected.length ? ' ' + (0, _jestMatcherUtils.printReceived)(arg) : (0, _jestMatcherUtils.RECEIVED_COLOR)( '+ ' + (0, _jestMatcherUtils.stringify)(arg) )) + ',' ); }) .join('\n'); const isLineDiffableCall = (expected, received) => expected.some( (arg, i) => i < received.length && isLineDiffableArg(arg, received[i]) ); // Almost redundant with function in jest-matcher-utils, // except no line diff for any strings. const isLineDiffableArg = (expected, received) => { const expectedType = (0, _jestGetType.getType)(expected); const receivedType = (0, _jestGetType.getType)(received); if (expectedType !== receivedType) { return false; } if ((0, _jestGetType.isPrimitive)(expected)) { return false; } if ( expectedType === 'date' || expectedType === 'function' || expectedType === 'regexp' ) { return false; } if (expected instanceof Error && received instanceof Error) { return false; } if ( expectedType === 'object' && typeof expected.asymmetricMatch === 'function' ) { return false; } if ( receivedType === 'object' && typeof received.asymmetricMatch === 'function' ) { return false; } return true; }; const printResult = (result, expected) => result.type === 'throw' ? 'function call threw an error' : result.type === 'incomplete' ? 'function call has not returned yet' : isEqualValue(expected, result.value) ? printCommon(result.value) : (0, _jestMatcherUtils.printReceived)(result.value); // Return either empty string or one line per indexed result, // so additional empty line can separate from `Number of returns` which follows. const printReceivedResults = ( label, expected, indexedResults, isOnlyCall, iExpectedCall ) => { if (indexedResults.length === 0) { return ''; } if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) { return label + printResult(indexedResults[0][1], expected) + '\n'; } const printAligned = getRightAlignedPrinter(label); return ( label.replace(':', '').trim() + '\n' + indexedResults.reduce( (printed, [i, result]) => printed + printAligned(String(i + 1), i === iExpectedCall) + printResult(result, expected) + '\n', '' ) ); }; const createToBeCalledMatcher = matcherName => function (received, expected) { const expectedArgument = ''; const options = { isNot: this.isNot, promise: this.promise }; (0, _jestMatcherUtils.ensureNoExpected)(expected, matcherName, options); ensureMockOrSpy(received, matcherName, expectedArgument, options); const receivedIsSpy = isSpy(received); const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); 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)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected number of calls: ${(0, _jestMatcherUtils.printExpected)( 0 )}\n` + `Received number of calls: ${(0, _jestMatcherUtils.printReceived)( count )}\n\n` + calls .reduce((lines, args, i) => { if (lines.length < PRINT_LIMIT) { lines.push(`${i + 1}: ${printReceivedArgs(args)}`); } return lines; }, []) .join('\n') : () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected number of calls: >= ${(0, _jestMatcherUtils.printExpected)( 1 )}\n` + `Received number of calls: ${(0, _jestMatcherUtils.printReceived)( count )}`; return { message, pass }; }; const createToReturnMatcher = matcherName => function (received, expected) { const expectedArgument = ''; const options = { isNot: this.isNot, promise: this.promise }; (0, _jestMatcherUtils.ensureNoExpected)(expected, matcherName, options); ensureMock(received, matcherName, expectedArgument, options); const receivedName = received.getMockName(); // Count return values that correspond only to calls that returned const count = received.mock.results.reduce( (n, result) => (result.type === 'return' ? n + 1 : n), 0 ); const pass = count > 0; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected number of returns: ${(0, _jestMatcherUtils.printExpected)( 0 )}\n` + `Received number of returns: ${(0, _jestMatcherUtils.printReceived)( count )}\n\n` + received.mock.results .reduce((lines, result, i) => { if (result.type === 'return' && lines.length < PRINT_LIMIT) { lines.push( `${i + 1}: ${(0, _jestMatcherUtils.printReceived)( result.value )}` ); } return lines; }, []) .join('\n') + (received.mock.calls.length !== count ? `\n\nReceived number of calls: ${(0, _jestMatcherUtils.printReceived)(received.mock.calls.length)}` : '') : () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected number of returns: >= ${(0, _jestMatcherUtils.printExpected)(1)}\n` + `Received number of returns: ${(0, _jestMatcherUtils.printReceived)(count)}` + (received.mock.calls.length !== count ? `\nReceived number of calls: ${(0, _jestMatcherUtils.printReceived)(received.mock.calls.length)}` : ''); return { message, pass }; }; const createToBeCalledTimesMatcher = matcherName => function (received, expected) { const expectedArgument = 'expected'; const options = { isNot: this.isNot, promise: this.promise }; (0, _jestMatcherUtils.ensureExpectedIsNonNegativeInteger)( expected, matcherName, options ); ensureMockOrSpy(received, matcherName, expectedArgument, options); const receivedIsSpy = isSpy(received); const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const count = receivedIsSpy ? received.calls.count() : received.mock.calls.length; const pass = count === expected; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + `\n\n` + `Expected number of calls: not ${(0, _jestMatcherUtils.printExpected)( expected )}` : () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected number of calls: ${(0, _jestMatcherUtils.printExpected)( expected )}\n` + `Received number of calls: ${(0, _jestMatcherUtils.printReceived)( count )}`; return { message, pass }; }; const createToReturnTimesMatcher = matcherName => function (received, expected) { const expectedArgument = 'expected'; const options = { isNot: this.isNot, promise: this.promise }; (0, _jestMatcherUtils.ensureExpectedIsNonNegativeInteger)( expected, matcherName, options ); ensureMock(received, matcherName, expectedArgument, options); const receivedName = received.getMockName(); // Count return values that correspond only to calls that returned const count = received.mock.results.reduce( (n, result) => (result.type === 'return' ? n + 1 : n), 0 ); const pass = count === expected; const message = pass ? () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + `\n\n` + `Expected number of returns: not ${(0, _jestMatcherUtils.printExpected)(expected)}` + (received.mock.calls.length !== count ? `\n\nReceived number of calls: ${(0, _jestMatcherUtils.printReceived)(received.mock.calls.length)}` : '') : () => (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected number of returns: ${(0, _jestMatcherUtils.printExpected)( expected )}\n` + `Received number of returns: ${(0, _jestMatcherUtils.printReceived)( count )}` + (received.mock.calls.length !== count ? `\nReceived number of calls: ${(0, _jestMatcherUtils.printReceived)(received.mock.calls.length)}` : ''); return { message, pass }; }; const createToBeCalledWithMatcher = matcherName => function (received, ...expected) { const expectedArgument = '...expected'; const options = { isNot: this.isNot, promise: this.promise }; ensureMockOrSpy(received, matcherName, expectedArgument, options); const receivedIsSpy = isSpy(received); const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; const pass = calls.some(call => isEqualCall(expected, call)); const message = pass ? () => { // Some examples of calls that are equal to expected value. const indexedCalls = []; let i = 0; while (i < calls.length && indexedCalls.length < PRINT_LIMIT) { if (isEqualCall(expected, calls[i])) { indexedCalls.push([i, calls[i]]); } i += 1; } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected: not ${printExpectedArgs(expected)}\n` + (calls.length === 1 && (0, _jestMatcherUtils.stringify)(calls[0]) === (0, _jestMatcherUtils.stringify)(expected) ? '' : printReceivedCallsNegative( expected, indexedCalls, calls.length === 1 )) + `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)( calls.length )}` ); } : () => { // Some examples of calls that are not equal to expected value. const indexedCalls = []; let i = 0; while (i < calls.length && indexedCalls.length < PRINT_LIMIT) { indexedCalls.push([i, calls[i]]); i += 1; } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + printExpectedReceivedCallsPositive( expected, indexedCalls, isExpand(this.expand), calls.length === 1 ) + `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)( calls.length )}` ); }; return { message, pass }; }; const createToReturnWithMatcher = matcherName => function (received, expected) { const expectedArgument = 'expected'; const options = { isNot: this.isNot, promise: this.promise }; ensureMock(received, matcherName, expectedArgument, options); const receivedName = received.getMockName(); const {calls, results} = received.mock; const pass = results.some(result => isEqualReturn(expected, result)); const message = pass ? () => { // Some examples of results that are equal to expected value. const indexedResults = []; let i = 0; while (i < results.length && indexedResults.length < PRINT_LIMIT) { if (isEqualReturn(expected, results[i])) { indexedResults.push([i, results[i]]); } i += 1; } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected: not ${(0, _jestMatcherUtils.printExpected)( expected )}\n` + (results.length === 1 && results[0].type === 'return' && (0, _jestMatcherUtils.stringify)(results[0].value) === (0, _jestMatcherUtils.stringify)(expected) ? '' : printReceivedResults( 'Received: ', expected, indexedResults, results.length === 1 )) + printNumberOfReturns(countReturns(results), calls.length) ); } : () => { // Some examples of results that are not equal to expected value. const indexedResults = []; let i = 0; while (i < results.length && indexedResults.length < PRINT_LIMIT) { indexedResults.push([i, results[i]]); i += 1; } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected: ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + printReceivedResults( 'Received: ', expected, indexedResults, results.length === 1 ) + printNumberOfReturns(countReturns(results), calls.length) ); }; return { message, pass }; }; const createLastCalledWithMatcher = matcherName => function (received, ...expected) { const expectedArgument = '...expected'; const options = { isNot: this.isNot, promise: this.promise }; ensureMockOrSpy(received, matcherName, expectedArgument, options); const receivedIsSpy = isSpy(received); const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; const iLast = calls.length - 1; const pass = iLast >= 0 && isEqualCall(expected, calls[iLast]); const message = pass ? () => { const indexedCalls = []; if (iLast > 0) { // Display preceding call as context. indexedCalls.push([iLast - 1, calls[iLast - 1]]); } indexedCalls.push([iLast, calls[iLast]]); return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected: not ${printExpectedArgs(expected)}\n` + (calls.length === 1 && (0, _jestMatcherUtils.stringify)(calls[0]) === (0, _jestMatcherUtils.stringify)(expected) ? '' : printReceivedCallsNegative( expected, indexedCalls, calls.length === 1, iLast )) + `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)( calls.length )}` ); } : () => { const indexedCalls = []; if (iLast >= 0) { if (iLast > 0) { let i = iLast - 1; // Is there a preceding call that is equal to expected args? while (i >= 0 && !isEqualCall(expected, calls[i])) { i -= 1; } if (i < 0) { i = iLast - 1; // otherwise, preceding call } indexedCalls.push([i, calls[i]]); } indexedCalls.push([iLast, calls[iLast]]); } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + printExpectedReceivedCallsPositive( expected, indexedCalls, isExpand(this.expand), calls.length === 1, iLast ) + `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)( calls.length )}` ); }; return { message, pass }; }; const createLastReturnedMatcher = matcherName => function (received, expected) { const expectedArgument = 'expected'; const options = { isNot: this.isNot, promise: this.promise }; ensureMock(received, matcherName, expectedArgument, options); const receivedName = received.getMockName(); const {calls, results} = received.mock; const iLast = results.length - 1; const pass = iLast >= 0 && isEqualReturn(expected, results[iLast]); const message = pass ? () => { const indexedResults = []; if (iLast > 0) { // Display preceding result as context. indexedResults.push([iLast - 1, results[iLast - 1]]); } indexedResults.push([iLast, results[iLast]]); return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected: not ${(0, _jestMatcherUtils.printExpected)( expected )}\n` + (results.length === 1 && results[0].type === 'return' && (0, _jestMatcherUtils.stringify)(results[0].value) === (0, _jestMatcherUtils.stringify)(expected) ? '' : printReceivedResults( 'Received: ', expected, indexedResults, results.length === 1, iLast )) + printNumberOfReturns(countReturns(results), calls.length) ); } : () => { const indexedResults = []; if (iLast >= 0) { if (iLast > 0) { let i = iLast - 1; // Is there a preceding result that is equal to expected value? while (i >= 0 && !isEqualReturn(expected, results[i])) { i -= 1; } if (i < 0) { i = iLast - 1; // otherwise, preceding result } indexedResults.push([i, results[i]]); } indexedResults.push([iLast, results[iLast]]); } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `Expected: ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + printReceivedResults( 'Received: ', expected, indexedResults, results.length === 1, iLast ) + printNumberOfReturns(countReturns(results), calls.length) ); }; return { message, pass }; }; const createNthCalledWithMatcher = matcherName => function (received, nth, ...expected) { const expectedArgument = 'n'; const options = { expectedColor: arg => arg, isNot: this.isNot, promise: this.promise, secondArgument: '...expected' }; ensureMockOrSpy(received, matcherName, expectedArgument, options); if (!Number.isSafeInteger(nth) || nth < 1) { throw new Error( (0, _jestMatcherUtils.matcherErrorMessage)( (0, _jestMatcherUtils.matcherHint)( matcherName, undefined, expectedArgument, options ), `${expectedArgument} must be a positive integer`, (0, _jestMatcherUtils.printWithType)( expectedArgument, nth, _jestMatcherUtils.stringify ) ) ); } const receivedIsSpy = isSpy(received); const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); const calls = receivedIsSpy ? received.calls.all().map(x => x.args) : received.mock.calls; const length = calls.length; const iNth = nth - 1; const pass = iNth < length && isEqualCall(expected, calls[iNth]); const message = pass ? () => { // Display preceding and following calls, // in case assertions fails because index is off by one. const indexedCalls = []; if (iNth - 1 >= 0) { indexedCalls.push([iNth - 1, calls[iNth - 1]]); } indexedCalls.push([iNth, calls[iNth]]); if (iNth + 1 < length) { indexedCalls.push([iNth + 1, calls[iNth + 1]]); } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `n: ${nth}\n` + `Expected: not ${printExpectedArgs(expected)}\n` + (calls.length === 1 && (0, _jestMatcherUtils.stringify)(calls[0]) === (0, _jestMatcherUtils.stringify)(expected) ? '' : printReceivedCallsNegative( expected, indexedCalls, calls.length === 1, iNth )) + `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)( calls.length )}` ); } : () => { // Display preceding and following calls: // * nearest call that is equal to expected args // * otherwise, adjacent call // in case assertions fails because of index, especially off by one. const indexedCalls = []; if (iNth < length) { if (iNth - 1 >= 0) { let i = iNth - 1; // Is there a preceding call that is equal to expected args? while (i >= 0 && !isEqualCall(expected, calls[i])) { i -= 1; } if (i < 0) { i = iNth - 1; // otherwise, adjacent call } indexedCalls.push([i, calls[i]]); } indexedCalls.push([iNth, calls[iNth]]); if (iNth + 1 < length) { let i = iNth + 1; // Is there a following call that is equal to expected args? while (i < length && !isEqualCall(expected, calls[i])) { i += 1; } if (i >= length) { i = iNth + 1; // otherwise, adjacent call } indexedCalls.push([i, calls[i]]); } } else if (length > 0) { // The number of received calls is fewer than the expected number. let i = length - 1; // Is there a call that is equal to expected args? while (i >= 0 && !isEqualCall(expected, calls[i])) { i -= 1; } if (i < 0) { i = length - 1; // otherwise, last call } indexedCalls.push([i, calls[i]]); } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `n: ${nth}\n` + printExpectedReceivedCallsPositive( expected, indexedCalls, isExpand(this.expand), calls.length === 1, iNth ) + `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)( calls.length )}` ); }; return { message, pass }; }; const createNthReturnedWithMatcher = matcherName => function (received, nth, expected) { const expectedArgument = 'n'; const options = { expectedColor: arg => arg, isNot: this.isNot, promise: this.promise, secondArgument: 'expected' }; ensureMock(received, matcherName, expectedArgument, options); if (!Number.isSafeInteger(nth) || nth < 1) { throw new Error( (0, _jestMatcherUtils.matcherErrorMessage)( (0, _jestMatcherUtils.matcherHint)( matcherName, undefined, expectedArgument, options ), `${expectedArgument} must be a positive integer`, (0, _jestMatcherUtils.printWithType)( expectedArgument, nth, _jestMatcherUtils.stringify ) ) ); } const receivedName = received.getMockName(); const {calls, results} = received.mock; const length = results.length; const iNth = nth - 1; const pass = iNth < length && isEqualReturn(expected, results[iNth]); const message = pass ? () => { // Display preceding and following results, // in case assertions fails because index is off by one. const indexedResults = []; if (iNth - 1 >= 0) { indexedResults.push([iNth - 1, results[iNth - 1]]); } indexedResults.push([iNth, results[iNth]]); if (iNth + 1 < length) { indexedResults.push([iNth + 1, results[iNth + 1]]); } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `n: ${nth}\n` + `Expected: not ${(0, _jestMatcherUtils.printExpected)( expected )}\n` + (results.length === 1 && results[0].type === 'return' && (0, _jestMatcherUtils.stringify)(results[0].value) === (0, _jestMatcherUtils.stringify)(expected) ? '' : printReceivedResults( 'Received: ', expected, indexedResults, results.length === 1, iNth )) + printNumberOfReturns(countReturns(results), calls.length) ); } : () => { // Display preceding and following results: // * nearest result that is equal to expected value // * otherwise, adjacent result // in case assertions fails because of index, especially off by one. const indexedResults = []; if (iNth < length) { if (iNth - 1 >= 0) { let i = iNth - 1; // Is there a preceding result that is equal to expected value? while (i >= 0 && !isEqualReturn(expected, results[i])) { i -= 1; } if (i < 0) { i = iNth - 1; // otherwise, adjacent result } indexedResults.push([i, results[i]]); } indexedResults.push([iNth, results[iNth]]); if (iNth + 1 < length) { let i = iNth + 1; // Is there a following result that is equal to expected value? while (i < length && !isEqualReturn(expected, results[i])) { i += 1; } if (i >= length) { i = iNth + 1; // otherwise, adjacent result } indexedResults.push([i, results[i]]); } } else if (length > 0) { // The number of received calls is fewer than the expected number. let i = length - 1; // Is there a result that is equal to expected value? while (i >= 0 && !isEqualReturn(expected, results[i])) { i -= 1; } if (i < 0) { i = length - 1; // otherwise, last result } indexedResults.push([i, results[i]]); } return ( (0, _jestMatcherUtils.matcherHint)( matcherName, receivedName, expectedArgument, options ) + '\n\n' + `n: ${nth}\n` + `Expected: ${(0, _jestMatcherUtils.printExpected)(expected)}\n` + printReceivedResults( 'Received: ', expected, indexedResults, results.length === 1, iNth ) + printNumberOfReturns(countReturns(results), calls.length) ); }; return { message, 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 isMock = received => received != null && received._isMockFunction === true; const isSpy = received => received != null && received.calls != null && typeof received.calls.all === 'function' && typeof received.calls.count === 'function'; const ensureMockOrSpy = (received, matcherName, expectedArgument, options) => { if (!isMock(received) && !isSpy(received)) { throw new Error( (0, _jestMatcherUtils.matcherErrorMessage)( (0, _jestMatcherUtils.matcherHint)( matcherName, undefined, expectedArgument, options ), `${(0, _jestMatcherUtils.RECEIVED_COLOR)( 'received' )} value must be a mock or spy function`, (0, _jestMatcherUtils.printWithType)( 'Received', received, _jestMatcherUtils.printReceived ) ) ); } }; const ensureMock = (received, matcherName, expectedArgument, options) => { if (!isMock(received)) { throw new Error( (0, _jestMatcherUtils.matcherErrorMessage)( (0, _jestMatcherUtils.matcherHint)( matcherName, undefined, expectedArgument, options ), `${(0, _jestMatcherUtils.RECEIVED_COLOR)( 'received' )} value must be a mock function`, (0, _jestMatcherUtils.printWithType)( 'Received', received, _jestMatcherUtils.printReceived ) ) ); } }; var _default = spyMatchers; exports.default = _default;