spyMatchers.js 39 KB

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