UNPKG

40.1 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.default = void 0;
7
8var _jestGetType = require('jest-get-type');
9
10var _jestMatcherUtils = require('jest-matcher-utils');
11
12var _jasmineUtils = require('./jasmineUtils');
13
14var _utils = require('./utils');
15
16/**
17 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
18 *
19 * This source code is licensed under the MIT license found in the
20 * LICENSE file in the root directory of this source tree.
21 */
22// The optional property of matcher context is true if undefined.
23const isExpand = expand => expand !== false;
24
25const PRINT_LIMIT = 3;
26const NO_ARGUMENTS = 'called with 0 arguments';
27
28const printExpectedArgs = expected =>
29 expected.length === 0
30 ? NO_ARGUMENTS
31 : expected.map(arg => (0, _jestMatcherUtils.printExpected)(arg)).join(', ');
32
33const printReceivedArgs = (received, expected) =>
34 received.length === 0
35 ? NO_ARGUMENTS
36 : received
37 .map((arg, i) =>
38 Array.isArray(expected) &&
39 i < expected.length &&
40 isEqualValue(expected[i], arg)
41 ? printCommon(arg)
42 : (0, _jestMatcherUtils.printReceived)(arg)
43 )
44 .join(', ');
45
46const printCommon = val =>
47 (0, _jestMatcherUtils.DIM_COLOR)((0, _jestMatcherUtils.stringify)(val));
48
49const isEqualValue = (expected, received) =>
50 (0, _jasmineUtils.equals)(expected, received, [_utils.iterableEquality]);
51
52const isEqualCall = (expected, received) => isEqualValue(expected, received);
53
54const isEqualReturn = (expected, result) =>
55 result.type === 'return' && isEqualValue(expected, result.value);
56
57const countReturns = results =>
58 results.reduce((n, result) => (result.type === 'return' ? n + 1 : n), 0);
59
60const printNumberOfReturns = (countReturns, countCalls) =>
61 `\nNumber of returns: ${(0, _jestMatcherUtils.printReceived)(countReturns)}` +
62 (countCalls !== countReturns
63 ? `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(countCalls)}`
64 : '');
65
66// Given a label, return a function which given a string,
67// right-aligns it preceding the colon in the label.
68const getRightAlignedPrinter = label => {
69 // Assume that the label contains a colon.
70 const index = label.indexOf(':');
71 const suffix = label.slice(index);
72 return (string, isExpectedCall) =>
73 (isExpectedCall
74 ? '->' + ' '.repeat(Math.max(0, index - 2 - string.length))
75 : ' '.repeat(Math.max(index - string.length))) +
76 string +
77 suffix;
78};
79
80const printReceivedCallsNegative = (
81 expected,
82 indexedCalls,
83 isOnlyCall,
84 iExpectedCall
85) => {
86 if (indexedCalls.length === 0) {
87 return '';
88 }
89
90 const label = 'Received: ';
91
92 if (isOnlyCall) {
93 return label + printReceivedArgs(indexedCalls[0], expected) + '\n';
94 }
95
96 const printAligned = getRightAlignedPrinter(label);
97 return (
98 'Received\n' +
99 indexedCalls.reduce(
100 (printed, [i, args]) =>
101 printed +
102 printAligned(String(i + 1), i === iExpectedCall) +
103 printReceivedArgs(args, expected) +
104 '\n',
105 ''
106 )
107 );
108};
109
110const printExpectedReceivedCallsPositive = (
111 expected,
112 indexedCalls,
113 expand,
114 isOnlyCall,
115 iExpectedCall
116) => {
117 const expectedLine = `Expected: ${printExpectedArgs(expected)}\n`;
118
119 if (indexedCalls.length === 0) {
120 return expectedLine;
121 }
122
123 const label = 'Received: ';
124
125 if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) {
126 const received = indexedCalls[0][1];
127
128 if (isLineDiffableCall(expected, received)) {
129 // Display diff without indentation.
130 const lines = [
131 (0, _jestMatcherUtils.EXPECTED_COLOR)('- Expected'),
132 (0, _jestMatcherUtils.RECEIVED_COLOR)('+ Received'),
133 ''
134 ];
135 const length = Math.max(expected.length, received.length);
136
137 for (let i = 0; i < length; i += 1) {
138 if (i < expected.length && i < received.length) {
139 if (isEqualValue(expected[i], received[i])) {
140 lines.push(` ${printCommon(received[i])},`);
141 continue;
142 }
143
144 if (isLineDiffableArg(expected[i], received[i])) {
145 const difference = (0, _jestMatcherUtils.diff)(
146 expected[i],
147 received[i],
148 {
149 expand
150 }
151 );
152
153 if (
154 typeof difference === 'string' &&
155 difference.includes('- Expected') &&
156 difference.includes('+ Received')
157 ) {
158 // Omit annotation in case multiple args have diff.
159 lines.push(difference.split('\n').slice(3).join('\n') + ',');
160 continue;
161 }
162 }
163 }
164
165 if (i < expected.length) {
166 lines.push(
167 (0, _jestMatcherUtils.EXPECTED_COLOR)(
168 '- ' + (0, _jestMatcherUtils.stringify)(expected[i])
169 ) + ','
170 );
171 }
172
173 if (i < received.length) {
174 lines.push(
175 (0, _jestMatcherUtils.RECEIVED_COLOR)(
176 '+ ' + (0, _jestMatcherUtils.stringify)(received[i])
177 ) + ','
178 );
179 }
180 }
181
182 return lines.join('\n') + '\n';
183 }
184
185 return expectedLine + label + printReceivedArgs(received, expected) + '\n';
186 }
187
188 const printAligned = getRightAlignedPrinter(label);
189 return (
190 expectedLine +
191 'Received\n' +
192 indexedCalls.reduce((printed, [i, received]) => {
193 const aligned = printAligned(String(i + 1), i === iExpectedCall);
194 return (
195 printed +
196 ((i === iExpectedCall || iExpectedCall === undefined) &&
197 isLineDiffableCall(expected, received)
198 ? aligned.replace(': ', '\n') +
199 printDiffCall(expected, received, expand)
200 : aligned + printReceivedArgs(received, expected)) +
201 '\n'
202 );
203 }, '')
204 );
205};
206
207const indentation = 'Received'.replace(/\w/g, ' ');
208
209const printDiffCall = (expected, received, expand) =>
210 received
211 .map((arg, i) => {
212 if (i < expected.length) {
213 if (isEqualValue(expected[i], arg)) {
214 return indentation + ' ' + printCommon(arg) + ',';
215 }
216
217 if (isLineDiffableArg(expected[i], arg)) {
218 const difference = (0, _jestMatcherUtils.diff)(expected[i], arg, {
219 expand
220 });
221
222 if (
223 typeof difference === 'string' &&
224 difference.includes('- Expected') &&
225 difference.includes('+ Received')
226 ) {
227 // Display diff with indentation.
228 // Omit annotation in case multiple args have diff.
229 return (
230 difference
231 .split('\n')
232 .slice(3)
233 .map(line => indentation + line)
234 .join('\n') + ','
235 );
236 }
237 }
238 } // Display + only if received arg has no corresponding expected arg.
239
240 return (
241 indentation +
242 (i < expected.length
243 ? ' ' + (0, _jestMatcherUtils.printReceived)(arg)
244 : (0, _jestMatcherUtils.RECEIVED_COLOR)(
245 '+ ' + (0, _jestMatcherUtils.stringify)(arg)
246 )) +
247 ','
248 );
249 })
250 .join('\n');
251
252const isLineDiffableCall = (expected, received) =>
253 expected.some(
254 (arg, i) => i < received.length && isLineDiffableArg(arg, received[i])
255 ); // Almost redundant with function in jest-matcher-utils,
256// except no line diff for any strings.
257
258const isLineDiffableArg = (expected, received) => {
259 const expectedType = (0, _jestGetType.getType)(expected);
260 const receivedType = (0, _jestGetType.getType)(received);
261
262 if (expectedType !== receivedType) {
263 return false;
264 }
265
266 if ((0, _jestGetType.isPrimitive)(expected)) {
267 return false;
268 }
269
270 if (
271 expectedType === 'date' ||
272 expectedType === 'function' ||
273 expectedType === 'regexp'
274 ) {
275 return false;
276 }
277
278 if (expected instanceof Error && received instanceof Error) {
279 return false;
280 }
281
282 if (
283 expectedType === 'object' &&
284 typeof expected.asymmetricMatch === 'function'
285 ) {
286 return false;
287 }
288
289 if (
290 receivedType === 'object' &&
291 typeof received.asymmetricMatch === 'function'
292 ) {
293 return false;
294 }
295
296 return true;
297};
298
299const printResult = (result, expected) =>
300 result.type === 'throw'
301 ? 'function call threw an error'
302 : result.type === 'incomplete'
303 ? 'function call has not returned yet'
304 : isEqualValue(expected, result.value)
305 ? printCommon(result.value)
306 : (0, _jestMatcherUtils.printReceived)(result.value);
307
308// Return either empty string or one line per indexed result,
309// so additional empty line can separate from `Number of returns` which follows.
310const printReceivedResults = (
311 label,
312 expected,
313 indexedResults,
314 isOnlyCall,
315 iExpectedCall
316) => {
317 if (indexedResults.length === 0) {
318 return '';
319 }
320
321 if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) {
322 return label + printResult(indexedResults[0][1], expected) + '\n';
323 }
324
325 const printAligned = getRightAlignedPrinter(label);
326 return (
327 label.replace(':', '').trim() +
328 '\n' +
329 indexedResults.reduce(
330 (printed, [i, result]) =>
331 printed +
332 printAligned(String(i + 1), i === iExpectedCall) +
333 printResult(result, expected) +
334 '\n',
335 ''
336 )
337 );
338};
339
340const createToBeCalledMatcher = matcherName =>
341 function (received, expected) {
342 const expectedArgument = '';
343 const options = {
344 isNot: this.isNot,
345 promise: this.promise
346 };
347 (0, _jestMatcherUtils.ensureNoExpected)(expected, matcherName, options);
348 ensureMockOrSpy(received, matcherName, expectedArgument, options);
349 const receivedIsSpy = isSpy(received);
350 const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
351 const count = receivedIsSpy
352 ? received.calls.count()
353 : received.mock.calls.length;
354 const calls = receivedIsSpy
355 ? received.calls.all().map(x => x.args)
356 : received.mock.calls;
357 const pass = count > 0;
358 const message = pass
359 ? () =>
360 (0, _jestMatcherUtils.matcherHint)(
361 matcherName,
362 receivedName,
363 expectedArgument,
364 options
365 ) +
366 '\n\n' +
367 `Expected number of calls: ${(0, _jestMatcherUtils.printExpected)(
368 0
369 )}\n` +
370 `Received number of calls: ${(0, _jestMatcherUtils.printReceived)(
371 count
372 )}\n\n` +
373 calls
374 .reduce((lines, args, i) => {
375 if (lines.length < PRINT_LIMIT) {
376 lines.push(`${i + 1}: ${printReceivedArgs(args)}`);
377 }
378
379 return lines;
380 }, [])
381 .join('\n')
382 : () =>
383 (0, _jestMatcherUtils.matcherHint)(
384 matcherName,
385 receivedName,
386 expectedArgument,
387 options
388 ) +
389 '\n\n' +
390 `Expected number of calls: >= ${(0, _jestMatcherUtils.printExpected)(
391 1
392 )}\n` +
393 `Received number of calls: ${(0, _jestMatcherUtils.printReceived)(
394 count
395 )}`;
396 return {
397 message,
398 pass
399 };
400 };
401
402const createToReturnMatcher = matcherName =>
403 function (received, expected) {
404 const expectedArgument = '';
405 const options = {
406 isNot: this.isNot,
407 promise: this.promise
408 };
409 (0, _jestMatcherUtils.ensureNoExpected)(expected, matcherName, options);
410 ensureMock(received, matcherName, expectedArgument, options);
411 const receivedName = received.getMockName(); // Count return values that correspond only to calls that returned
412
413 const count = received.mock.results.reduce(
414 (n, result) => (result.type === 'return' ? n + 1 : n),
415 0
416 );
417 const pass = count > 0;
418 const message = pass
419 ? () =>
420 (0, _jestMatcherUtils.matcherHint)(
421 matcherName,
422 receivedName,
423 expectedArgument,
424 options
425 ) +
426 '\n\n' +
427 `Expected number of returns: ${(0, _jestMatcherUtils.printExpected)(
428 0
429 )}\n` +
430 `Received number of returns: ${(0, _jestMatcherUtils.printReceived)(
431 count
432 )}\n\n` +
433 received.mock.results
434 .reduce((lines, result, i) => {
435 if (result.type === 'return' && lines.length < PRINT_LIMIT) {
436 lines.push(
437 `${i + 1}: ${(0, _jestMatcherUtils.printReceived)(
438 result.value
439 )}`
440 );
441 }
442
443 return lines;
444 }, [])
445 .join('\n') +
446 (received.mock.calls.length !== count
447 ? `\n\nReceived number of calls: ${(0,
448 _jestMatcherUtils.printReceived)(received.mock.calls.length)}`
449 : '')
450 : () =>
451 (0, _jestMatcherUtils.matcherHint)(
452 matcherName,
453 receivedName,
454 expectedArgument,
455 options
456 ) +
457 '\n\n' +
458 `Expected number of returns: >= ${(0,
459 _jestMatcherUtils.printExpected)(1)}\n` +
460 `Received number of returns: ${(0,
461 _jestMatcherUtils.printReceived)(count)}` +
462 (received.mock.calls.length !== count
463 ? `\nReceived number of calls: ${(0,
464 _jestMatcherUtils.printReceived)(received.mock.calls.length)}`
465 : '');
466 return {
467 message,
468 pass
469 };
470 };
471
472const createToBeCalledTimesMatcher = matcherName =>
473 function (received, expected) {
474 const expectedArgument = 'expected';
475 const options = {
476 isNot: this.isNot,
477 promise: this.promise
478 };
479 (0, _jestMatcherUtils.ensureExpectedIsNonNegativeInteger)(
480 expected,
481 matcherName,
482 options
483 );
484 ensureMockOrSpy(received, matcherName, expectedArgument, options);
485 const receivedIsSpy = isSpy(received);
486 const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
487 const count = receivedIsSpy
488 ? received.calls.count()
489 : received.mock.calls.length;
490 const pass = count === expected;
491 const message = pass
492 ? () =>
493 (0, _jestMatcherUtils.matcherHint)(
494 matcherName,
495 receivedName,
496 expectedArgument,
497 options
498 ) +
499 `\n\n` +
500 `Expected number of calls: not ${(0, _jestMatcherUtils.printExpected)(
501 expected
502 )}`
503 : () =>
504 (0, _jestMatcherUtils.matcherHint)(
505 matcherName,
506 receivedName,
507 expectedArgument,
508 options
509 ) +
510 '\n\n' +
511 `Expected number of calls: ${(0, _jestMatcherUtils.printExpected)(
512 expected
513 )}\n` +
514 `Received number of calls: ${(0, _jestMatcherUtils.printReceived)(
515 count
516 )}`;
517 return {
518 message,
519 pass
520 };
521 };
522
523const createToReturnTimesMatcher = matcherName =>
524 function (received, expected) {
525 const expectedArgument = 'expected';
526 const options = {
527 isNot: this.isNot,
528 promise: this.promise
529 };
530 (0, _jestMatcherUtils.ensureExpectedIsNonNegativeInteger)(
531 expected,
532 matcherName,
533 options
534 );
535 ensureMock(received, matcherName, expectedArgument, options);
536 const receivedName = received.getMockName(); // Count return values that correspond only to calls that returned
537
538 const count = received.mock.results.reduce(
539 (n, result) => (result.type === 'return' ? n + 1 : n),
540 0
541 );
542 const pass = count === expected;
543 const message = pass
544 ? () =>
545 (0, _jestMatcherUtils.matcherHint)(
546 matcherName,
547 receivedName,
548 expectedArgument,
549 options
550 ) +
551 `\n\n` +
552 `Expected number of returns: not ${(0,
553 _jestMatcherUtils.printExpected)(expected)}` +
554 (received.mock.calls.length !== count
555 ? `\n\nReceived number of calls: ${(0,
556 _jestMatcherUtils.printReceived)(received.mock.calls.length)}`
557 : '')
558 : () =>
559 (0, _jestMatcherUtils.matcherHint)(
560 matcherName,
561 receivedName,
562 expectedArgument,
563 options
564 ) +
565 '\n\n' +
566 `Expected number of returns: ${(0, _jestMatcherUtils.printExpected)(
567 expected
568 )}\n` +
569 `Received number of returns: ${(0, _jestMatcherUtils.printReceived)(
570 count
571 )}` +
572 (received.mock.calls.length !== count
573 ? `\nReceived number of calls: ${(0,
574 _jestMatcherUtils.printReceived)(received.mock.calls.length)}`
575 : '');
576 return {
577 message,
578 pass
579 };
580 };
581
582const createToBeCalledWithMatcher = matcherName =>
583 function (received, ...expected) {
584 const expectedArgument = '...expected';
585 const options = {
586 isNot: this.isNot,
587 promise: this.promise
588 };
589 ensureMockOrSpy(received, matcherName, expectedArgument, options);
590 const receivedIsSpy = isSpy(received);
591 const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
592 const calls = receivedIsSpy
593 ? received.calls.all().map(x => x.args)
594 : received.mock.calls;
595 const pass = calls.some(call => isEqualCall(expected, call));
596 const message = pass
597 ? () => {
598 // Some examples of calls that are equal to expected value.
599 const indexedCalls = [];
600 let i = 0;
601
602 while (i < calls.length && indexedCalls.length < PRINT_LIMIT) {
603 if (isEqualCall(expected, calls[i])) {
604 indexedCalls.push([i, calls[i]]);
605 }
606
607 i += 1;
608 }
609
610 return (
611 (0, _jestMatcherUtils.matcherHint)(
612 matcherName,
613 receivedName,
614 expectedArgument,
615 options
616 ) +
617 '\n\n' +
618 `Expected: not ${printExpectedArgs(expected)}\n` +
619 (calls.length === 1 &&
620 (0, _jestMatcherUtils.stringify)(calls[0]) ===
621 (0, _jestMatcherUtils.stringify)(expected)
622 ? ''
623 : printReceivedCallsNegative(
624 expected,
625 indexedCalls,
626 calls.length === 1
627 )) +
628 `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(
629 calls.length
630 )}`
631 );
632 }
633 : () => {
634 // Some examples of calls that are not equal to expected value.
635 const indexedCalls = [];
636 let i = 0;
637
638 while (i < calls.length && indexedCalls.length < PRINT_LIMIT) {
639 indexedCalls.push([i, calls[i]]);
640 i += 1;
641 }
642
643 return (
644 (0, _jestMatcherUtils.matcherHint)(
645 matcherName,
646 receivedName,
647 expectedArgument,
648 options
649 ) +
650 '\n\n' +
651 printExpectedReceivedCallsPositive(
652 expected,
653 indexedCalls,
654 isExpand(this.expand),
655 calls.length === 1
656 ) +
657 `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(
658 calls.length
659 )}`
660 );
661 };
662 return {
663 message,
664 pass
665 };
666 };
667
668const createToReturnWithMatcher = matcherName =>
669 function (received, expected) {
670 const expectedArgument = 'expected';
671 const options = {
672 isNot: this.isNot,
673 promise: this.promise
674 };
675 ensureMock(received, matcherName, expectedArgument, options);
676 const receivedName = received.getMockName();
677 const {calls, results} = received.mock;
678 const pass = results.some(result => isEqualReturn(expected, result));
679 const message = pass
680 ? () => {
681 // Some examples of results that are equal to expected value.
682 const indexedResults = [];
683 let i = 0;
684
685 while (i < results.length && indexedResults.length < PRINT_LIMIT) {
686 if (isEqualReturn(expected, results[i])) {
687 indexedResults.push([i, results[i]]);
688 }
689
690 i += 1;
691 }
692
693 return (
694 (0, _jestMatcherUtils.matcherHint)(
695 matcherName,
696 receivedName,
697 expectedArgument,
698 options
699 ) +
700 '\n\n' +
701 `Expected: not ${(0, _jestMatcherUtils.printExpected)(
702 expected
703 )}\n` +
704 (results.length === 1 &&
705 results[0].type === 'return' &&
706 (0, _jestMatcherUtils.stringify)(results[0].value) ===
707 (0, _jestMatcherUtils.stringify)(expected)
708 ? ''
709 : printReceivedResults(
710 'Received: ',
711 expected,
712 indexedResults,
713 results.length === 1
714 )) +
715 printNumberOfReturns(countReturns(results), calls.length)
716 );
717 }
718 : () => {
719 // Some examples of results that are not equal to expected value.
720 const indexedResults = [];
721 let i = 0;
722
723 while (i < results.length && indexedResults.length < PRINT_LIMIT) {
724 indexedResults.push([i, results[i]]);
725 i += 1;
726 }
727
728 return (
729 (0, _jestMatcherUtils.matcherHint)(
730 matcherName,
731 receivedName,
732 expectedArgument,
733 options
734 ) +
735 '\n\n' +
736 `Expected: ${(0, _jestMatcherUtils.printExpected)(expected)}\n` +
737 printReceivedResults(
738 'Received: ',
739 expected,
740 indexedResults,
741 results.length === 1
742 ) +
743 printNumberOfReturns(countReturns(results), calls.length)
744 );
745 };
746 return {
747 message,
748 pass
749 };
750 };
751
752const createLastCalledWithMatcher = matcherName =>
753 function (received, ...expected) {
754 const expectedArgument = '...expected';
755 const options = {
756 isNot: this.isNot,
757 promise: this.promise
758 };
759 ensureMockOrSpy(received, matcherName, expectedArgument, options);
760 const receivedIsSpy = isSpy(received);
761 const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
762 const calls = receivedIsSpy
763 ? received.calls.all().map(x => x.args)
764 : received.mock.calls;
765 const iLast = calls.length - 1;
766 const pass = iLast >= 0 && isEqualCall(expected, calls[iLast]);
767 const message = pass
768 ? () => {
769 const indexedCalls = [];
770
771 if (iLast > 0) {
772 // Display preceding call as context.
773 indexedCalls.push([iLast - 1, calls[iLast - 1]]);
774 }
775
776 indexedCalls.push([iLast, calls[iLast]]);
777 return (
778 (0, _jestMatcherUtils.matcherHint)(
779 matcherName,
780 receivedName,
781 expectedArgument,
782 options
783 ) +
784 '\n\n' +
785 `Expected: not ${printExpectedArgs(expected)}\n` +
786 (calls.length === 1 &&
787 (0, _jestMatcherUtils.stringify)(calls[0]) ===
788 (0, _jestMatcherUtils.stringify)(expected)
789 ? ''
790 : printReceivedCallsNegative(
791 expected,
792 indexedCalls,
793 calls.length === 1,
794 iLast
795 )) +
796 `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(
797 calls.length
798 )}`
799 );
800 }
801 : () => {
802 const indexedCalls = [];
803
804 if (iLast >= 0) {
805 if (iLast > 0) {
806 let i = iLast - 1; // Is there a preceding call that is equal to expected args?
807
808 while (i >= 0 && !isEqualCall(expected, calls[i])) {
809 i -= 1;
810 }
811
812 if (i < 0) {
813 i = iLast - 1; // otherwise, preceding call
814 }
815
816 indexedCalls.push([i, calls[i]]);
817 }
818
819 indexedCalls.push([iLast, calls[iLast]]);
820 }
821
822 return (
823 (0, _jestMatcherUtils.matcherHint)(
824 matcherName,
825 receivedName,
826 expectedArgument,
827 options
828 ) +
829 '\n\n' +
830 printExpectedReceivedCallsPositive(
831 expected,
832 indexedCalls,
833 isExpand(this.expand),
834 calls.length === 1,
835 iLast
836 ) +
837 `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(
838 calls.length
839 )}`
840 );
841 };
842 return {
843 message,
844 pass
845 };
846 };
847
848const createLastReturnedMatcher = matcherName =>
849 function (received, expected) {
850 const expectedArgument = 'expected';
851 const options = {
852 isNot: this.isNot,
853 promise: this.promise
854 };
855 ensureMock(received, matcherName, expectedArgument, options);
856 const receivedName = received.getMockName();
857 const {calls, results} = received.mock;
858 const iLast = results.length - 1;
859 const pass = iLast >= 0 && isEqualReturn(expected, results[iLast]);
860 const message = pass
861 ? () => {
862 const indexedResults = [];
863
864 if (iLast > 0) {
865 // Display preceding result as context.
866 indexedResults.push([iLast - 1, results[iLast - 1]]);
867 }
868
869 indexedResults.push([iLast, results[iLast]]);
870 return (
871 (0, _jestMatcherUtils.matcherHint)(
872 matcherName,
873 receivedName,
874 expectedArgument,
875 options
876 ) +
877 '\n\n' +
878 `Expected: not ${(0, _jestMatcherUtils.printExpected)(
879 expected
880 )}\n` +
881 (results.length === 1 &&
882 results[0].type === 'return' &&
883 (0, _jestMatcherUtils.stringify)(results[0].value) ===
884 (0, _jestMatcherUtils.stringify)(expected)
885 ? ''
886 : printReceivedResults(
887 'Received: ',
888 expected,
889 indexedResults,
890 results.length === 1,
891 iLast
892 )) +
893 printNumberOfReturns(countReturns(results), calls.length)
894 );
895 }
896 : () => {
897 const indexedResults = [];
898
899 if (iLast >= 0) {
900 if (iLast > 0) {
901 let i = iLast - 1; // Is there a preceding result that is equal to expected value?
902
903 while (i >= 0 && !isEqualReturn(expected, results[i])) {
904 i -= 1;
905 }
906
907 if (i < 0) {
908 i = iLast - 1; // otherwise, preceding result
909 }
910
911 indexedResults.push([i, results[i]]);
912 }
913
914 indexedResults.push([iLast, results[iLast]]);
915 }
916
917 return (
918 (0, _jestMatcherUtils.matcherHint)(
919 matcherName,
920 receivedName,
921 expectedArgument,
922 options
923 ) +
924 '\n\n' +
925 `Expected: ${(0, _jestMatcherUtils.printExpected)(expected)}\n` +
926 printReceivedResults(
927 'Received: ',
928 expected,
929 indexedResults,
930 results.length === 1,
931 iLast
932 ) +
933 printNumberOfReturns(countReturns(results), calls.length)
934 );
935 };
936 return {
937 message,
938 pass
939 };
940 };
941
942const createNthCalledWithMatcher = matcherName =>
943 function (received, nth, ...expected) {
944 const expectedArgument = 'n';
945 const options = {
946 expectedColor: arg => arg,
947 isNot: this.isNot,
948 promise: this.promise,
949 secondArgument: '...expected'
950 };
951 ensureMockOrSpy(received, matcherName, expectedArgument, options);
952
953 if (!Number.isSafeInteger(nth) || nth < 1) {
954 throw new Error(
955 (0, _jestMatcherUtils.matcherErrorMessage)(
956 (0, _jestMatcherUtils.matcherHint)(
957 matcherName,
958 undefined,
959 expectedArgument,
960 options
961 ),
962 `${expectedArgument} must be a positive integer`,
963 (0, _jestMatcherUtils.printWithType)(
964 expectedArgument,
965 nth,
966 _jestMatcherUtils.stringify
967 )
968 )
969 );
970 }
971
972 const receivedIsSpy = isSpy(received);
973 const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
974 const calls = receivedIsSpy
975 ? received.calls.all().map(x => x.args)
976 : received.mock.calls;
977 const length = calls.length;
978 const iNth = nth - 1;
979 const pass = iNth < length && isEqualCall(expected, calls[iNth]);
980 const message = pass
981 ? () => {
982 // Display preceding and following calls,
983 // in case assertions fails because index is off by one.
984 const indexedCalls = [];
985
986 if (iNth - 1 >= 0) {
987 indexedCalls.push([iNth - 1, calls[iNth - 1]]);
988 }
989
990 indexedCalls.push([iNth, calls[iNth]]);
991
992 if (iNth + 1 < length) {
993 indexedCalls.push([iNth + 1, calls[iNth + 1]]);
994 }
995
996 return (
997 (0, _jestMatcherUtils.matcherHint)(
998 matcherName,
999 receivedName,
1000 expectedArgument,
1001 options
1002 ) +
1003 '\n\n' +
1004 `n: ${nth}\n` +
1005 `Expected: not ${printExpectedArgs(expected)}\n` +
1006 (calls.length === 1 &&
1007 (0, _jestMatcherUtils.stringify)(calls[0]) ===
1008 (0, _jestMatcherUtils.stringify)(expected)
1009 ? ''
1010 : printReceivedCallsNegative(
1011 expected,
1012 indexedCalls,
1013 calls.length === 1,
1014 iNth
1015 )) +
1016 `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(
1017 calls.length
1018 )}`
1019 );
1020 }
1021 : () => {
1022 // Display preceding and following calls:
1023 // * nearest call that is equal to expected args
1024 // * otherwise, adjacent call
1025 // in case assertions fails because of index, especially off by one.
1026 const indexedCalls = [];
1027
1028 if (iNth < length) {
1029 if (iNth - 1 >= 0) {
1030 let i = iNth - 1; // Is there a preceding call that is equal to expected args?
1031
1032 while (i >= 0 && !isEqualCall(expected, calls[i])) {
1033 i -= 1;
1034 }
1035
1036 if (i < 0) {
1037 i = iNth - 1; // otherwise, adjacent call
1038 }
1039
1040 indexedCalls.push([i, calls[i]]);
1041 }
1042
1043 indexedCalls.push([iNth, calls[iNth]]);
1044
1045 if (iNth + 1 < length) {
1046 let i = iNth + 1; // Is there a following call that is equal to expected args?
1047
1048 while (i < length && !isEqualCall(expected, calls[i])) {
1049 i += 1;
1050 }
1051
1052 if (i >= length) {
1053 i = iNth + 1; // otherwise, adjacent call
1054 }
1055
1056 indexedCalls.push([i, calls[i]]);
1057 }
1058 } else if (length > 0) {
1059 // The number of received calls is fewer than the expected number.
1060 let i = length - 1; // Is there a call that is equal to expected args?
1061
1062 while (i >= 0 && !isEqualCall(expected, calls[i])) {
1063 i -= 1;
1064 }
1065
1066 if (i < 0) {
1067 i = length - 1; // otherwise, last call
1068 }
1069
1070 indexedCalls.push([i, calls[i]]);
1071 }
1072
1073 return (
1074 (0, _jestMatcherUtils.matcherHint)(
1075 matcherName,
1076 receivedName,
1077 expectedArgument,
1078 options
1079 ) +
1080 '\n\n' +
1081 `n: ${nth}\n` +
1082 printExpectedReceivedCallsPositive(
1083 expected,
1084 indexedCalls,
1085 isExpand(this.expand),
1086 calls.length === 1,
1087 iNth
1088 ) +
1089 `\nNumber of calls: ${(0, _jestMatcherUtils.printReceived)(
1090 calls.length
1091 )}`
1092 );
1093 };
1094 return {
1095 message,
1096 pass
1097 };
1098 };
1099
1100const createNthReturnedWithMatcher = matcherName =>
1101 function (received, nth, expected) {
1102 const expectedArgument = 'n';
1103 const options = {
1104 expectedColor: arg => arg,
1105 isNot: this.isNot,
1106 promise: this.promise,
1107 secondArgument: 'expected'
1108 };
1109 ensureMock(received, matcherName, expectedArgument, options);
1110
1111 if (!Number.isSafeInteger(nth) || nth < 1) {
1112 throw new Error(
1113 (0, _jestMatcherUtils.matcherErrorMessage)(
1114 (0, _jestMatcherUtils.matcherHint)(
1115 matcherName,
1116 undefined,
1117 expectedArgument,
1118 options
1119 ),
1120 `${expectedArgument} must be a positive integer`,
1121 (0, _jestMatcherUtils.printWithType)(
1122 expectedArgument,
1123 nth,
1124 _jestMatcherUtils.stringify
1125 )
1126 )
1127 );
1128 }
1129
1130 const receivedName = received.getMockName();
1131 const {calls, results} = received.mock;
1132 const length = results.length;
1133 const iNth = nth - 1;
1134 const pass = iNth < length && isEqualReturn(expected, results[iNth]);
1135 const message = pass
1136 ? () => {
1137 // Display preceding and following results,
1138 // in case assertions fails because index is off by one.
1139 const indexedResults = [];
1140
1141 if (iNth - 1 >= 0) {
1142 indexedResults.push([iNth - 1, results[iNth - 1]]);
1143 }
1144
1145 indexedResults.push([iNth, results[iNth]]);
1146
1147 if (iNth + 1 < length) {
1148 indexedResults.push([iNth + 1, results[iNth + 1]]);
1149 }
1150
1151 return (
1152 (0, _jestMatcherUtils.matcherHint)(
1153 matcherName,
1154 receivedName,
1155 expectedArgument,
1156 options
1157 ) +
1158 '\n\n' +
1159 `n: ${nth}\n` +
1160 `Expected: not ${(0, _jestMatcherUtils.printExpected)(
1161 expected
1162 )}\n` +
1163 (results.length === 1 &&
1164 results[0].type === 'return' &&
1165 (0, _jestMatcherUtils.stringify)(results[0].value) ===
1166 (0, _jestMatcherUtils.stringify)(expected)
1167 ? ''
1168 : printReceivedResults(
1169 'Received: ',
1170 expected,
1171 indexedResults,
1172 results.length === 1,
1173 iNth
1174 )) +
1175 printNumberOfReturns(countReturns(results), calls.length)
1176 );
1177 }
1178 : () => {
1179 // Display preceding and following results:
1180 // * nearest result that is equal to expected value
1181 // * otherwise, adjacent result
1182 // in case assertions fails because of index, especially off by one.
1183 const indexedResults = [];
1184
1185 if (iNth < length) {
1186 if (iNth - 1 >= 0) {
1187 let i = iNth - 1; // Is there a preceding result that is equal to expected value?
1188
1189 while (i >= 0 && !isEqualReturn(expected, results[i])) {
1190 i -= 1;
1191 }
1192
1193 if (i < 0) {
1194 i = iNth - 1; // otherwise, adjacent result
1195 }
1196
1197 indexedResults.push([i, results[i]]);
1198 }
1199
1200 indexedResults.push([iNth, results[iNth]]);
1201
1202 if (iNth + 1 < length) {
1203 let i = iNth + 1; // Is there a following result that is equal to expected value?
1204
1205 while (i < length && !isEqualReturn(expected, results[i])) {
1206 i += 1;
1207 }
1208
1209 if (i >= length) {
1210 i = iNth + 1; // otherwise, adjacent result
1211 }
1212
1213 indexedResults.push([i, results[i]]);
1214 }
1215 } else if (length > 0) {
1216 // The number of received calls is fewer than the expected number.
1217 let i = length - 1; // Is there a result that is equal to expected value?
1218
1219 while (i >= 0 && !isEqualReturn(expected, results[i])) {
1220 i -= 1;
1221 }
1222
1223 if (i < 0) {
1224 i = length - 1; // otherwise, last result
1225 }
1226
1227 indexedResults.push([i, results[i]]);
1228 }
1229
1230 return (
1231 (0, _jestMatcherUtils.matcherHint)(
1232 matcherName,
1233 receivedName,
1234 expectedArgument,
1235 options
1236 ) +
1237 '\n\n' +
1238 `n: ${nth}\n` +
1239 `Expected: ${(0, _jestMatcherUtils.printExpected)(expected)}\n` +
1240 printReceivedResults(
1241 'Received: ',
1242 expected,
1243 indexedResults,
1244 results.length === 1,
1245 iNth
1246 ) +
1247 printNumberOfReturns(countReturns(results), calls.length)
1248 );
1249 };
1250 return {
1251 message,
1252 pass
1253 };
1254 };
1255
1256const spyMatchers = {
1257 lastCalledWith: createLastCalledWithMatcher('lastCalledWith'),
1258 lastReturnedWith: createLastReturnedMatcher('lastReturnedWith'),
1259 nthCalledWith: createNthCalledWithMatcher('nthCalledWith'),
1260 nthReturnedWith: createNthReturnedWithMatcher('nthReturnedWith'),
1261 toBeCalled: createToBeCalledMatcher('toBeCalled'),
1262 toBeCalledTimes: createToBeCalledTimesMatcher('toBeCalledTimes'),
1263 toBeCalledWith: createToBeCalledWithMatcher('toBeCalledWith'),
1264 toHaveBeenCalled: createToBeCalledMatcher('toHaveBeenCalled'),
1265 toHaveBeenCalledTimes: createToBeCalledTimesMatcher('toHaveBeenCalledTimes'),
1266 toHaveBeenCalledWith: createToBeCalledWithMatcher('toHaveBeenCalledWith'),
1267 toHaveBeenLastCalledWith: createLastCalledWithMatcher(
1268 'toHaveBeenLastCalledWith'
1269 ),
1270 toHaveBeenNthCalledWith: createNthCalledWithMatcher(
1271 'toHaveBeenNthCalledWith'
1272 ),
1273 toHaveLastReturnedWith: createLastReturnedMatcher('toHaveLastReturnedWith'),
1274 toHaveNthReturnedWith: createNthReturnedWithMatcher('toHaveNthReturnedWith'),
1275 toHaveReturned: createToReturnMatcher('toHaveReturned'),
1276 toHaveReturnedTimes: createToReturnTimesMatcher('toHaveReturnedTimes'),
1277 toHaveReturnedWith: createToReturnWithMatcher('toHaveReturnedWith'),
1278 toReturn: createToReturnMatcher('toReturn'),
1279 toReturnTimes: createToReturnTimesMatcher('toReturnTimes'),
1280 toReturnWith: createToReturnWithMatcher('toReturnWith')
1281};
1282
1283const isMock = received =>
1284 received != null && received._isMockFunction === true;
1285
1286const isSpy = received =>
1287 received != null &&
1288 received.calls != null &&
1289 typeof received.calls.all === 'function' &&
1290 typeof received.calls.count === 'function';
1291
1292const ensureMockOrSpy = (received, matcherName, expectedArgument, options) => {
1293 if (!isMock(received) && !isSpy(received)) {
1294 throw new Error(
1295 (0, _jestMatcherUtils.matcherErrorMessage)(
1296 (0, _jestMatcherUtils.matcherHint)(
1297 matcherName,
1298 undefined,
1299 expectedArgument,
1300 options
1301 ),
1302 `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
1303 'received'
1304 )} value must be a mock or spy function`,
1305 (0, _jestMatcherUtils.printWithType)(
1306 'Received',
1307 received,
1308 _jestMatcherUtils.printReceived
1309 )
1310 )
1311 );
1312 }
1313};
1314
1315const ensureMock = (received, matcherName, expectedArgument, options) => {
1316 if (!isMock(received)) {
1317 throw new Error(
1318 (0, _jestMatcherUtils.matcherErrorMessage)(
1319 (0, _jestMatcherUtils.matcherHint)(
1320 matcherName,
1321 undefined,
1322 expectedArgument,
1323 options
1324 ),
1325 `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
1326 'received'
1327 )} value must be a mock function`,
1328 (0, _jestMatcherUtils.printWithType)(
1329 'Received',
1330 received,
1331 _jestMatcherUtils.printReceived
1332 )
1333 )
1334 );
1335 }
1336};
1337
1338var _default = spyMatchers;
1339exports.default = _default;