spyMatchers.js 39 KB

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