@casual-simulation/expect 2.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -0
  3. package/index.d.ts +6 -0
  4. package/index.js +5 -0
  5. package/index.js.map +1 -0
  6. package/package.json +35 -0
  7. package/src/asymmetricMatchers.d.ts +67 -0
  8. package/src/asymmetricMatchers.js +188 -0
  9. package/src/asymmetricMatchers.js.map +1 -0
  10. package/src/diff/cleanupSemantic.d.ts +58 -0
  11. package/src/diff/cleanupSemantic.js +526 -0
  12. package/src/diff/cleanupSemantic.js.map +1 -0
  13. package/src/diff/constants.d.ts +9 -0
  14. package/src/diff/constants.js +10 -0
  15. package/src/diff/constants.js.map +1 -0
  16. package/src/diff/diffLines.d.ts +13 -0
  17. package/src/diff/diffLines.js +138 -0
  18. package/src/diff/diffLines.js.map +1 -0
  19. package/src/diff/diffStrings.d.ts +10 -0
  20. package/src/diff/diffStrings.js +36 -0
  21. package/src/diff/diffStrings.js.map +1 -0
  22. package/src/diff/getAlignedDiffs.d.ts +11 -0
  23. package/src/diff/getAlignedDiffs.js +187 -0
  24. package/src/diff/getAlignedDiffs.js.map +1 -0
  25. package/src/diff/index.d.ts +16 -0
  26. package/src/diff/index.js +139 -0
  27. package/src/diff/index.js.map +1 -0
  28. package/src/diff/joinAlignedDiffs.d.ts +11 -0
  29. package/src/diff/joinAlignedDiffs.js +191 -0
  30. package/src/diff/joinAlignedDiffs.js.map +1 -0
  31. package/src/diff/normalizeDiffOptions.d.ts +10 -0
  32. package/src/diff/normalizeDiffOptions.js +40 -0
  33. package/src/diff/normalizeDiffOptions.js.map +1 -0
  34. package/src/diff/printDiffs.d.ts +11 -0
  35. package/src/diff/printDiffs.js +46 -0
  36. package/src/diff/printDiffs.js.map +1 -0
  37. package/src/diff/types.d.ts +49 -0
  38. package/src/diff/types.js +2 -0
  39. package/src/diff/types.js.map +1 -0
  40. package/src/diff-sequences/index.d.ts +19 -0
  41. package/src/diff-sequences/index.js +506 -0
  42. package/src/diff-sequences/index.js.map +1 -0
  43. package/src/extractExpectedAssertionsErrors.d.ts +11 -0
  44. package/src/extractExpectedAssertionsErrors.js +58 -0
  45. package/src/extractExpectedAssertionsErrors.js.map +1 -0
  46. package/src/get-type/index.d.ts +11 -0
  47. package/src/get-type/index.js +57 -0
  48. package/src/get-type/index.js.map +1 -0
  49. package/src/index.d.ts +16 -0
  50. package/src/index.js +247 -0
  51. package/src/index.js.map +1 -0
  52. package/src/jasmineUtils.d.ts +9 -0
  53. package/src/jasmineUtils.js +218 -0
  54. package/src/jasmineUtils.js.map +1 -0
  55. package/src/jestMatchersObject.d.ts +14 -0
  56. package/src/jestMatchersObject.js +78 -0
  57. package/src/jestMatchersObject.js.map +1 -0
  58. package/src/matcher-utils/Replaceable.d.ts +18 -0
  59. package/src/matcher-utils/Replaceable.js +57 -0
  60. package/src/matcher-utils/Replaceable.js.map +1 -0
  61. package/src/matcher-utils/deepCyclicCopyReplaceable.d.ts +8 -0
  62. package/src/matcher-utils/deepCyclicCopyReplaceable.js +96 -0
  63. package/src/matcher-utils/deepCyclicCopyReplaceable.js.map +1 -0
  64. package/src/matcher-utils/index.d.ts +53 -0
  65. package/src/matcher-utils/index.js +341 -0
  66. package/src/matcher-utils/index.js.map +1 -0
  67. package/src/matchers.d.ts +11 -0
  68. package/src/matchers.js +575 -0
  69. package/src/matchers.js.map +1 -0
  70. package/src/message-util/index.d.ts +11 -0
  71. package/src/message-util/index.js +34 -0
  72. package/src/message-util/index.js.map +1 -0
  73. package/src/pretty-format/collections.d.ts +33 -0
  74. package/src/pretty-format/collections.js +130 -0
  75. package/src/pretty-format/collections.js.map +1 -0
  76. package/src/pretty-format/index.d.ts +25 -0
  77. package/src/pretty-format/index.js +390 -0
  78. package/src/pretty-format/index.js.map +1 -0
  79. package/src/pretty-format/plugins/AsymmetricMatcher.d.ts +12 -0
  80. package/src/pretty-format/plugins/AsymmetricMatcher.js +53 -0
  81. package/src/pretty-format/plugins/AsymmetricMatcher.js.map +1 -0
  82. package/src/pretty-format/plugins/ConvertAnsi.d.ts +12 -0
  83. package/src/pretty-format/plugins/ConvertAnsi.js +58 -0
  84. package/src/pretty-format/plugins/ConvertAnsi.js.map +1 -0
  85. package/src/pretty-format/plugins/DOMCollection.d.ts +12 -0
  86. package/src/pretty-format/plugins/DOMCollection.js +39 -0
  87. package/src/pretty-format/plugins/DOMCollection.js.map +1 -0
  88. package/src/pretty-format/plugins/DOMElement.d.ts +12 -0
  89. package/src/pretty-format/plugins/DOMElement.js +68 -0
  90. package/src/pretty-format/plugins/DOMElement.js.map +1 -0
  91. package/src/pretty-format/plugins/Immutable.d.ts +12 -0
  92. package/src/pretty-format/plugins/Immutable.js +113 -0
  93. package/src/pretty-format/plugins/Immutable.js.map +1 -0
  94. package/src/pretty-format/plugins/ReactTestComponent.d.ts +19 -0
  95. package/src/pretty-format/plugins/ReactTestComponent.js +29 -0
  96. package/src/pretty-format/plugins/ReactTestComponent.js.map +1 -0
  97. package/src/pretty-format/plugins/lib/escapeHTML.d.ts +8 -0
  98. package/src/pretty-format/plugins/lib/escapeHTML.js +10 -0
  99. package/src/pretty-format/plugins/lib/escapeHTML.js.map +1 -0
  100. package/src/pretty-format/plugins/lib/markup.d.ts +14 -0
  101. package/src/pretty-format/plugins/lib/markup.js +98 -0
  102. package/src/pretty-format/plugins/lib/markup.js.map +1 -0
  103. package/src/pretty-format/types.d.ts +109 -0
  104. package/src/pretty-format/types.js +8 -0
  105. package/src/pretty-format/types.js.map +1 -0
  106. package/src/print.d.ts +16 -0
  107. package/src/print.js +71 -0
  108. package/src/print.js.map +1 -0
  109. package/src/spyMatchers.d.ts +10 -0
  110. package/src/spyMatchers.js +766 -0
  111. package/src/spyMatchers.js.map +1 -0
  112. package/src/test-utils/ConditionalTest.d.ts +10 -0
  113. package/src/test-utils/ConditionalTest.js +25 -0
  114. package/src/test-utils/ConditionalTest.js.map +1 -0
  115. package/src/test-utils/alignedAnsiStyleSerializer.d.ts +9 -0
  116. package/src/test-utils/alignedAnsiStyleSerializer.js +46 -0
  117. package/src/test-utils/alignedAnsiStyleSerializer.js.map +1 -0
  118. package/src/test-utils/config.d.ts +10 -0
  119. package/src/test-utils/config.js +143 -0
  120. package/src/test-utils/config.js.map +1 -0
  121. package/src/test-utils/index.d.ts +10 -0
  122. package/src/test-utils/index.js +10 -0
  123. package/src/test-utils/index.js.map +1 -0
  124. package/src/toThrowMatchers.d.ts +12 -0
  125. package/src/toThrowMatchers.js +258 -0
  126. package/src/toThrowMatchers.js.map +1 -0
  127. package/src/types.d.ts +327 -0
  128. package/src/types.js +9 -0
  129. package/src/types.js.map +1 -0
  130. package/src/utils.d.ts +26 -0
  131. package/src/utils.js +303 -0
  132. package/src/utils.js.map +1 -0
@@ -0,0 +1,766 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { getType, isPrimitive } from './get-type';
8
+ import { DIM_COLOR, EXPECTED_COLOR, RECEIVED_COLOR, diff, ensureExpectedIsNonNegativeInteger, ensureNoExpected, matcherErrorMessage, matcherHint, printExpected, printReceived, printWithType, stringify, } from './matcher-utils';
9
+ import { equals } from './jasmineUtils';
10
+ import { iterableEquality } from './utils';
11
+ // The optional property of matcher context is true if undefined.
12
+ const isExpand = (expand) => expand !== false;
13
+ const PRINT_LIMIT = 3;
14
+ const NO_ARGUMENTS = 'called with 0 arguments';
15
+ const printExpectedArgs = (expected) => expected.length === 0
16
+ ? NO_ARGUMENTS
17
+ : expected.map((arg) => printExpected(arg)).join(', ');
18
+ const printReceivedArgs = (received, expected) => received.length === 0
19
+ ? NO_ARGUMENTS
20
+ : received
21
+ .map((arg, i) => Array.isArray(expected) &&
22
+ i < expected.length &&
23
+ isEqualValue(expected[i], arg)
24
+ ? printCommon(arg)
25
+ : printReceived(arg))
26
+ .join(', ');
27
+ const printCommon = (val) => DIM_COLOR(stringify(val));
28
+ const isEqualValue = (expected, received) => equals(expected, received, [iterableEquality]);
29
+ const isEqualCall = (expected, received) => isEqualValue(expected, received);
30
+ const isEqualReturn = (expected, result) => result.type === 'return' && isEqualValue(expected, result.value);
31
+ const countReturns = (results) => results.reduce((n, result) => (result.type === 'return' ? n + 1 : n), 0);
32
+ const printNumberOfReturns = (countReturns, countCalls) => `\nNumber of returns: ${printReceived(countReturns)}` +
33
+ (countCalls !== countReturns
34
+ ? `\nNumber of calls: ${printReceived(countCalls)}`
35
+ : '');
36
+ // Given a label, return a function which given a string,
37
+ // right-aligns it preceding the colon in the label.
38
+ const getRightAlignedPrinter = (label) => {
39
+ // Assume that the label contains a colon.
40
+ const index = label.indexOf(':');
41
+ const suffix = label.slice(index);
42
+ return (string, isExpectedCall) => (isExpectedCall
43
+ ? '->' + ' '.repeat(Math.max(0, index - 2 - string.length))
44
+ : ' '.repeat(Math.max(index - string.length))) +
45
+ string +
46
+ suffix;
47
+ };
48
+ const printReceivedCallsNegative = (expected, indexedCalls, isOnlyCall, iExpectedCall) => {
49
+ if (indexedCalls.length === 0) {
50
+ return '';
51
+ }
52
+ const label = 'Received: ';
53
+ if (isOnlyCall) {
54
+ return label + printReceivedArgs(indexedCalls[0], expected) + '\n';
55
+ }
56
+ const printAligned = getRightAlignedPrinter(label);
57
+ return ('Received\n' +
58
+ indexedCalls.reduce((printed, [i, args]) => printed +
59
+ printAligned(String(i + 1), i === iExpectedCall) +
60
+ printReceivedArgs(args, expected) +
61
+ '\n', ''));
62
+ };
63
+ const printExpectedReceivedCallsPositive = (expected, indexedCalls, expand, isOnlyCall, iExpectedCall) => {
64
+ const expectedLine = `Expected: ${printExpectedArgs(expected)}\n`;
65
+ if (indexedCalls.length === 0) {
66
+ return expectedLine;
67
+ }
68
+ const label = 'Received: ';
69
+ if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) {
70
+ const received = indexedCalls[0][1];
71
+ if (isLineDiffableCall(expected, received)) {
72
+ // Display diff without indentation.
73
+ const lines = [
74
+ EXPECTED_COLOR('- Expected'),
75
+ RECEIVED_COLOR('+ Received'),
76
+ '',
77
+ ];
78
+ const length = Math.max(expected.length, received.length);
79
+ for (let i = 0; i < length; i += 1) {
80
+ if (i < expected.length && i < received.length) {
81
+ if (isEqualValue(expected[i], received[i])) {
82
+ lines.push(` ${printCommon(received[i])},`);
83
+ continue;
84
+ }
85
+ if (isLineDiffableArg(expected[i], received[i])) {
86
+ const difference = diff(expected[i], received[i], {
87
+ expand,
88
+ });
89
+ if (typeof difference === 'string' &&
90
+ difference.includes('- Expected') &&
91
+ difference.includes('+ Received')) {
92
+ // Omit annotation in case multiple args have diff.
93
+ lines.push(difference.split('\n').slice(3).join('\n') + ',');
94
+ continue;
95
+ }
96
+ }
97
+ }
98
+ if (i < expected.length) {
99
+ lines.push(EXPECTED_COLOR('- ' + stringify(expected[i])) + ',');
100
+ }
101
+ if (i < received.length) {
102
+ lines.push(RECEIVED_COLOR('+ ' + stringify(received[i])) + ',');
103
+ }
104
+ }
105
+ return lines.join('\n') + '\n';
106
+ }
107
+ return (expectedLine + label + printReceivedArgs(received, expected) + '\n');
108
+ }
109
+ const printAligned = getRightAlignedPrinter(label);
110
+ return (expectedLine +
111
+ 'Received\n' +
112
+ indexedCalls.reduce((printed, [i, received]) => {
113
+ const aligned = printAligned(String(i + 1), i === iExpectedCall);
114
+ return (printed +
115
+ ((i === iExpectedCall || iExpectedCall === undefined) &&
116
+ isLineDiffableCall(expected, received)
117
+ ? aligned.replace(': ', '\n') +
118
+ printDiffCall(expected, received, expand)
119
+ : aligned + printReceivedArgs(received, expected)) +
120
+ '\n');
121
+ }, ''));
122
+ };
123
+ const indentation = 'Received'.replace(/\w/g, ' ');
124
+ const printDiffCall = (expected, received, expand) => received
125
+ .map((arg, i) => {
126
+ if (i < expected.length) {
127
+ if (isEqualValue(expected[i], arg)) {
128
+ return indentation + ' ' + printCommon(arg) + ',';
129
+ }
130
+ if (isLineDiffableArg(expected[i], arg)) {
131
+ const difference = diff(expected[i], arg, { expand });
132
+ if (typeof difference === 'string' &&
133
+ difference.includes('- Expected') &&
134
+ difference.includes('+ Received')) {
135
+ // Display diff with indentation.
136
+ // Omit annotation in case multiple args have diff.
137
+ return (difference
138
+ .split('\n')
139
+ .slice(3)
140
+ .map((line) => indentation + line)
141
+ .join('\n') + ',');
142
+ }
143
+ }
144
+ }
145
+ // Display + only if received arg has no corresponding expected arg.
146
+ return (indentation +
147
+ (i < expected.length
148
+ ? ' ' + printReceived(arg)
149
+ : RECEIVED_COLOR('+ ' + stringify(arg))) +
150
+ ',');
151
+ })
152
+ .join('\n');
153
+ const isLineDiffableCall = (expected, received) => expected.some((arg, i) => i < received.length && isLineDiffableArg(arg, received[i]));
154
+ // Almost redundant with function in jest-matcher-utils,
155
+ // except no line diff for any strings.
156
+ const isLineDiffableArg = (expected, received) => {
157
+ const expectedType = getType(expected);
158
+ const receivedType = getType(received);
159
+ if (expectedType !== receivedType) {
160
+ return false;
161
+ }
162
+ if (isPrimitive(expected)) {
163
+ return false;
164
+ }
165
+ if (expectedType === 'date' ||
166
+ expectedType === 'function' ||
167
+ expectedType === 'regexp') {
168
+ return false;
169
+ }
170
+ if (expected instanceof Error && received instanceof Error) {
171
+ return false;
172
+ }
173
+ if (expectedType === 'object' &&
174
+ typeof expected.asymmetricMatch === 'function') {
175
+ return false;
176
+ }
177
+ if (receivedType === 'object' &&
178
+ typeof received.asymmetricMatch === 'function') {
179
+ return false;
180
+ }
181
+ return true;
182
+ };
183
+ const printResult = (result, expected) => result.type === 'throw'
184
+ ? 'function call threw an error'
185
+ : result.type === 'incomplete'
186
+ ? 'function call has not returned yet'
187
+ : isEqualValue(expected, result.value)
188
+ ? printCommon(result.value)
189
+ : printReceived(result.value);
190
+ // Return either empty string or one line per indexed result,
191
+ // so additional empty line can separate from `Number of returns` which follows.
192
+ const printReceivedResults = (label, expected, indexedResults, isOnlyCall, iExpectedCall) => {
193
+ if (indexedResults.length === 0) {
194
+ return '';
195
+ }
196
+ if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) {
197
+ return label + printResult(indexedResults[0][1], expected) + '\n';
198
+ }
199
+ const printAligned = getRightAlignedPrinter(label);
200
+ return (label.replace(':', '').trim() +
201
+ '\n' +
202
+ indexedResults.reduce((printed, [i, result]) => printed +
203
+ printAligned(String(i + 1), i === iExpectedCall) +
204
+ printResult(result, expected) +
205
+ '\n', ''));
206
+ };
207
+ const createToBeCalledMatcher = (matcherName) => function (received, expected) {
208
+ const expectedArgument = '';
209
+ const options = {
210
+ isNot: this.isNot,
211
+ promise: this.promise,
212
+ };
213
+ ensureNoExpected(expected, matcherName, options);
214
+ ensureMockOrSpy(received, matcherName, expectedArgument, options);
215
+ const receivedIsSpy = isSpy(received);
216
+ const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
217
+ const count = receivedIsSpy
218
+ ? received.calls.count()
219
+ : received.mock.calls.length;
220
+ const calls = receivedIsSpy
221
+ ? received.calls.all().map((x) => x.args)
222
+ : received.mock.calls;
223
+ const pass = count > 0;
224
+ const message = pass
225
+ ? () => matcherHint(matcherName, receivedName, expectedArgument, options) +
226
+ '\n\n' +
227
+ `Expected number of calls: ${printExpected(0)}\n` +
228
+ `Received number of calls: ${printReceived(count)}\n\n` +
229
+ calls
230
+ .reduce((lines, args, i) => {
231
+ if (lines.length < PRINT_LIMIT) {
232
+ lines.push(`${i + 1}: ${printReceivedArgs(args)}`);
233
+ }
234
+ return lines;
235
+ }, [])
236
+ .join('\n')
237
+ : () => matcherHint(matcherName, receivedName, expectedArgument, options) +
238
+ '\n\n' +
239
+ `Expected number of calls: >= ${printExpected(1)}\n` +
240
+ `Received number of calls: ${printReceived(count)}`;
241
+ return { message, pass };
242
+ };
243
+ const createToReturnMatcher = (matcherName) => function (received, expected) {
244
+ const expectedArgument = '';
245
+ const options = {
246
+ isNot: this.isNot,
247
+ promise: this.promise,
248
+ };
249
+ ensureNoExpected(expected, matcherName, options);
250
+ ensureMock(received, matcherName, expectedArgument, options);
251
+ const receivedName = received.getMockName();
252
+ // Count return values that correspond only to calls that returned
253
+ const count = received.mock.results.reduce((n, result) => (result.type === 'return' ? n + 1 : n), 0);
254
+ const pass = count > 0;
255
+ const message = pass
256
+ ? () => matcherHint(matcherName, receivedName, expectedArgument, options) +
257
+ '\n\n' +
258
+ `Expected number of returns: ${printExpected(0)}\n` +
259
+ `Received number of returns: ${printReceived(count)}\n\n` +
260
+ received.mock.results
261
+ .reduce((lines, result, i) => {
262
+ if (result.type === 'return' &&
263
+ lines.length < PRINT_LIMIT) {
264
+ lines.push(`${i + 1}: ${printReceived(result.value)}`);
265
+ }
266
+ return lines;
267
+ }, [])
268
+ .join('\n') +
269
+ (received.mock.calls.length !== count
270
+ ? `\n\nReceived number of calls: ${printReceived(received.mock.calls.length)}`
271
+ : '')
272
+ : () => matcherHint(matcherName, receivedName, expectedArgument, options) +
273
+ '\n\n' +
274
+ `Expected number of returns: >= ${printExpected(1)}\n` +
275
+ `Received number of returns: ${printReceived(count)}` +
276
+ (received.mock.calls.length !== count
277
+ ? `\nReceived number of calls: ${printReceived(received.mock.calls.length)}`
278
+ : '');
279
+ return { message, pass };
280
+ };
281
+ const createToBeCalledTimesMatcher = (matcherName) => function (received, expected) {
282
+ const expectedArgument = 'expected';
283
+ const options = {
284
+ isNot: this.isNot,
285
+ promise: this.promise,
286
+ };
287
+ ensureExpectedIsNonNegativeInteger(expected, matcherName, options);
288
+ ensureMockOrSpy(received, matcherName, expectedArgument, options);
289
+ const receivedIsSpy = isSpy(received);
290
+ const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
291
+ const count = receivedIsSpy
292
+ ? received.calls.count()
293
+ : received.mock.calls.length;
294
+ const pass = count === expected;
295
+ const message = pass
296
+ ? () => matcherHint(matcherName, receivedName, expectedArgument, options) +
297
+ `\n\n` +
298
+ `Expected number of calls: not ${printExpected(expected)}`
299
+ : () => matcherHint(matcherName, receivedName, expectedArgument, options) +
300
+ '\n\n' +
301
+ `Expected number of calls: ${printExpected(expected)}\n` +
302
+ `Received number of calls: ${printReceived(count)}`;
303
+ return { message, pass };
304
+ };
305
+ const createToReturnTimesMatcher = (matcherName) => function (received, expected) {
306
+ const expectedArgument = 'expected';
307
+ const options = {
308
+ isNot: this.isNot,
309
+ promise: this.promise,
310
+ };
311
+ ensureExpectedIsNonNegativeInteger(expected, matcherName, options);
312
+ ensureMock(received, matcherName, expectedArgument, options);
313
+ const receivedName = received.getMockName();
314
+ // Count return values that correspond only to calls that returned
315
+ const count = received.mock.results.reduce((n, result) => (result.type === 'return' ? n + 1 : n), 0);
316
+ const pass = count === expected;
317
+ const message = pass
318
+ ? () => matcherHint(matcherName, receivedName, expectedArgument, options) +
319
+ `\n\n` +
320
+ `Expected number of returns: not ${printExpected(expected)}` +
321
+ (received.mock.calls.length !== count
322
+ ? `\n\nReceived number of calls: ${printReceived(received.mock.calls.length)}`
323
+ : '')
324
+ : () => matcherHint(matcherName, receivedName, expectedArgument, options) +
325
+ '\n\n' +
326
+ `Expected number of returns: ${printExpected(expected)}\n` +
327
+ `Received number of returns: ${printReceived(count)}` +
328
+ (received.mock.calls.length !== count
329
+ ? `\nReceived number of calls: ${printReceived(received.mock.calls.length)}`
330
+ : '');
331
+ return { message, pass };
332
+ };
333
+ const createToBeCalledWithMatcher = (matcherName) => function (received, ...expected) {
334
+ const expectedArgument = '...expected';
335
+ const options = {
336
+ isNot: this.isNot,
337
+ promise: this.promise,
338
+ };
339
+ ensureMockOrSpy(received, matcherName, expectedArgument, options);
340
+ const receivedIsSpy = isSpy(received);
341
+ const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
342
+ const calls = receivedIsSpy
343
+ ? received.calls.all().map((x) => x.args)
344
+ : received.mock.calls;
345
+ const pass = calls.some((call) => isEqualCall(expected, call));
346
+ const message = pass
347
+ ? () => {
348
+ // Some examples of calls that are equal to expected value.
349
+ const indexedCalls = [];
350
+ let i = 0;
351
+ while (i < calls.length &&
352
+ indexedCalls.length < PRINT_LIMIT) {
353
+ if (isEqualCall(expected, calls[i])) {
354
+ indexedCalls.push([i, calls[i]]);
355
+ }
356
+ i += 1;
357
+ }
358
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
359
+ '\n\n' +
360
+ `Expected: not ${printExpectedArgs(expected)}\n` +
361
+ (calls.length === 1 &&
362
+ stringify(calls[0]) === stringify(expected)
363
+ ? ''
364
+ : printReceivedCallsNegative(expected, indexedCalls, calls.length === 1)) +
365
+ `\nNumber of calls: ${printReceived(calls.length)}`);
366
+ }
367
+ : () => {
368
+ // Some examples of calls that are not equal to expected value.
369
+ const indexedCalls = [];
370
+ let i = 0;
371
+ while (i < calls.length &&
372
+ indexedCalls.length < PRINT_LIMIT) {
373
+ indexedCalls.push([i, calls[i]]);
374
+ i += 1;
375
+ }
376
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
377
+ '\n\n' +
378
+ printExpectedReceivedCallsPositive(expected, indexedCalls, isExpand(this.expand), calls.length === 1) +
379
+ `\nNumber of calls: ${printReceived(calls.length)}`);
380
+ };
381
+ return { message, pass };
382
+ };
383
+ const createToReturnWithMatcher = (matcherName) => function (received, expected) {
384
+ const expectedArgument = 'expected';
385
+ const options = {
386
+ isNot: this.isNot,
387
+ promise: this.promise,
388
+ };
389
+ ensureMock(received, matcherName, expectedArgument, options);
390
+ const receivedName = received.getMockName();
391
+ const { calls, results } = received.mock;
392
+ const pass = results.some((result) => isEqualReturn(expected, result));
393
+ const message = pass
394
+ ? () => {
395
+ // Some examples of results that are equal to expected value.
396
+ const indexedResults = [];
397
+ let i = 0;
398
+ while (i < results.length &&
399
+ indexedResults.length < PRINT_LIMIT) {
400
+ if (isEqualReturn(expected, results[i])) {
401
+ indexedResults.push([i, results[i]]);
402
+ }
403
+ i += 1;
404
+ }
405
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
406
+ '\n\n' +
407
+ `Expected: not ${printExpected(expected)}\n` +
408
+ (results.length === 1 &&
409
+ results[0].type === 'return' &&
410
+ stringify(results[0].value) === stringify(expected)
411
+ ? ''
412
+ : printReceivedResults('Received: ', expected, indexedResults, results.length === 1)) +
413
+ printNumberOfReturns(countReturns(results), calls.length));
414
+ }
415
+ : () => {
416
+ // Some examples of results that are not equal to expected value.
417
+ const indexedResults = [];
418
+ let i = 0;
419
+ while (i < results.length &&
420
+ indexedResults.length < PRINT_LIMIT) {
421
+ indexedResults.push([i, results[i]]);
422
+ i += 1;
423
+ }
424
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
425
+ '\n\n' +
426
+ `Expected: ${printExpected(expected)}\n` +
427
+ printReceivedResults('Received: ', expected, indexedResults, results.length === 1) +
428
+ printNumberOfReturns(countReturns(results), calls.length));
429
+ };
430
+ return { message, pass };
431
+ };
432
+ const createLastCalledWithMatcher = (matcherName) => function (received, ...expected) {
433
+ const expectedArgument = '...expected';
434
+ const options = {
435
+ isNot: this.isNot,
436
+ promise: this.promise,
437
+ };
438
+ ensureMockOrSpy(received, matcherName, expectedArgument, options);
439
+ const receivedIsSpy = isSpy(received);
440
+ const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
441
+ const calls = receivedIsSpy
442
+ ? received.calls.all().map((x) => x.args)
443
+ : received.mock.calls;
444
+ const iLast = calls.length - 1;
445
+ const pass = iLast >= 0 && isEqualCall(expected, calls[iLast]);
446
+ const message = pass
447
+ ? () => {
448
+ const indexedCalls = [];
449
+ if (iLast > 0) {
450
+ // Display preceding call as context.
451
+ indexedCalls.push([iLast - 1, calls[iLast - 1]]);
452
+ }
453
+ indexedCalls.push([iLast, calls[iLast]]);
454
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
455
+ '\n\n' +
456
+ `Expected: not ${printExpectedArgs(expected)}\n` +
457
+ (calls.length === 1 &&
458
+ stringify(calls[0]) === stringify(expected)
459
+ ? ''
460
+ : printReceivedCallsNegative(expected, indexedCalls, calls.length === 1, iLast)) +
461
+ `\nNumber of calls: ${printReceived(calls.length)}`);
462
+ }
463
+ : () => {
464
+ const indexedCalls = [];
465
+ if (iLast >= 0) {
466
+ if (iLast > 0) {
467
+ let i = iLast - 1;
468
+ // Is there a preceding call that is equal to expected args?
469
+ while (i >= 0 && !isEqualCall(expected, calls[i])) {
470
+ i -= 1;
471
+ }
472
+ if (i < 0) {
473
+ i = iLast - 1; // otherwise, preceding call
474
+ }
475
+ indexedCalls.push([i, calls[i]]);
476
+ }
477
+ indexedCalls.push([iLast, calls[iLast]]);
478
+ }
479
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
480
+ '\n\n' +
481
+ printExpectedReceivedCallsPositive(expected, indexedCalls, isExpand(this.expand), calls.length === 1, iLast) +
482
+ `\nNumber of calls: ${printReceived(calls.length)}`);
483
+ };
484
+ return { message, pass };
485
+ };
486
+ const createLastReturnedMatcher = (matcherName) => function (received, expected) {
487
+ const expectedArgument = 'expected';
488
+ const options = {
489
+ isNot: this.isNot,
490
+ promise: this.promise,
491
+ };
492
+ ensureMock(received, matcherName, expectedArgument, options);
493
+ const receivedName = received.getMockName();
494
+ const { calls, results } = received.mock;
495
+ const iLast = results.length - 1;
496
+ const pass = iLast >= 0 && isEqualReturn(expected, results[iLast]);
497
+ const message = pass
498
+ ? () => {
499
+ const indexedResults = [];
500
+ if (iLast > 0) {
501
+ // Display preceding result as context.
502
+ indexedResults.push([iLast - 1, results[iLast - 1]]);
503
+ }
504
+ indexedResults.push([iLast, results[iLast]]);
505
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
506
+ '\n\n' +
507
+ `Expected: not ${printExpected(expected)}\n` +
508
+ (results.length === 1 &&
509
+ results[0].type === 'return' &&
510
+ stringify(results[0].value) === stringify(expected)
511
+ ? ''
512
+ : printReceivedResults('Received: ', expected, indexedResults, results.length === 1, iLast)) +
513
+ printNumberOfReturns(countReturns(results), calls.length));
514
+ }
515
+ : () => {
516
+ const indexedResults = [];
517
+ if (iLast >= 0) {
518
+ if (iLast > 0) {
519
+ let i = iLast - 1;
520
+ // Is there a preceding result that is equal to expected value?
521
+ while (i >= 0 &&
522
+ !isEqualReturn(expected, results[i])) {
523
+ i -= 1;
524
+ }
525
+ if (i < 0) {
526
+ i = iLast - 1; // otherwise, preceding result
527
+ }
528
+ indexedResults.push([i, results[i]]);
529
+ }
530
+ indexedResults.push([iLast, results[iLast]]);
531
+ }
532
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
533
+ '\n\n' +
534
+ `Expected: ${printExpected(expected)}\n` +
535
+ printReceivedResults('Received: ', expected, indexedResults, results.length === 1, iLast) +
536
+ printNumberOfReturns(countReturns(results), calls.length));
537
+ };
538
+ return { message, pass };
539
+ };
540
+ const createNthCalledWithMatcher = (matcherName) => function (received, nth, ...expected) {
541
+ const expectedArgument = 'n';
542
+ const options = {
543
+ expectedColor: (arg) => arg,
544
+ isNot: this.isNot,
545
+ promise: this.promise,
546
+ secondArgument: '...expected',
547
+ };
548
+ ensureMockOrSpy(received, matcherName, expectedArgument, options);
549
+ if (!Number.isSafeInteger(nth) || nth < 1) {
550
+ throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${expectedArgument} must be a positive integer`, printWithType(expectedArgument, nth, stringify)));
551
+ }
552
+ const receivedIsSpy = isSpy(received);
553
+ const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
554
+ const calls = receivedIsSpy
555
+ ? received.calls.all().map((x) => x.args)
556
+ : received.mock.calls;
557
+ const length = calls.length;
558
+ const iNth = nth - 1;
559
+ const pass = iNth < length && isEqualCall(expected, calls[iNth]);
560
+ const message = pass
561
+ ? () => {
562
+ // Display preceding and following calls,
563
+ // in case assertions fails because index is off by one.
564
+ const indexedCalls = [];
565
+ if (iNth - 1 >= 0) {
566
+ indexedCalls.push([iNth - 1, calls[iNth - 1]]);
567
+ }
568
+ indexedCalls.push([iNth, calls[iNth]]);
569
+ if (iNth + 1 < length) {
570
+ indexedCalls.push([iNth + 1, calls[iNth + 1]]);
571
+ }
572
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
573
+ '\n\n' +
574
+ `n: ${nth}\n` +
575
+ `Expected: not ${printExpectedArgs(expected)}\n` +
576
+ (calls.length === 1 &&
577
+ stringify(calls[0]) === stringify(expected)
578
+ ? ''
579
+ : printReceivedCallsNegative(expected, indexedCalls, calls.length === 1, iNth)) +
580
+ `\nNumber of calls: ${printReceived(calls.length)}`);
581
+ }
582
+ : () => {
583
+ // Display preceding and following calls:
584
+ // * nearest call that is equal to expected args
585
+ // * otherwise, adjacent call
586
+ // in case assertions fails because of index, especially off by one.
587
+ const indexedCalls = [];
588
+ if (iNth < length) {
589
+ if (iNth - 1 >= 0) {
590
+ let i = iNth - 1;
591
+ // Is there a preceding call that is equal to expected args?
592
+ while (i >= 0 && !isEqualCall(expected, calls[i])) {
593
+ i -= 1;
594
+ }
595
+ if (i < 0) {
596
+ i = iNth - 1; // otherwise, adjacent call
597
+ }
598
+ indexedCalls.push([i, calls[i]]);
599
+ }
600
+ indexedCalls.push([iNth, calls[iNth]]);
601
+ if (iNth + 1 < length) {
602
+ let i = iNth + 1;
603
+ // Is there a following call that is equal to expected args?
604
+ while (i < length &&
605
+ !isEqualCall(expected, calls[i])) {
606
+ i += 1;
607
+ }
608
+ if (i >= length) {
609
+ i = iNth + 1; // otherwise, adjacent call
610
+ }
611
+ indexedCalls.push([i, calls[i]]);
612
+ }
613
+ }
614
+ else if (length > 0) {
615
+ // The number of received calls is fewer than the expected number.
616
+ let i = length - 1;
617
+ // Is there a call that is equal to expected args?
618
+ while (i >= 0 && !isEqualCall(expected, calls[i])) {
619
+ i -= 1;
620
+ }
621
+ if (i < 0) {
622
+ i = length - 1; // otherwise, last call
623
+ }
624
+ indexedCalls.push([i, calls[i]]);
625
+ }
626
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
627
+ '\n\n' +
628
+ `n: ${nth}\n` +
629
+ printExpectedReceivedCallsPositive(expected, indexedCalls, isExpand(this.expand), calls.length === 1, iNth) +
630
+ `\nNumber of calls: ${printReceived(calls.length)}`);
631
+ };
632
+ return { message, pass };
633
+ };
634
+ const createNthReturnedWithMatcher = (matcherName) => function (received, nth, expected) {
635
+ const expectedArgument = 'n';
636
+ const options = {
637
+ expectedColor: (arg) => arg,
638
+ isNot: this.isNot,
639
+ promise: this.promise,
640
+ secondArgument: 'expected',
641
+ };
642
+ ensureMock(received, matcherName, expectedArgument, options);
643
+ if (!Number.isSafeInteger(nth) || nth < 1) {
644
+ throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${expectedArgument} must be a positive integer`, printWithType(expectedArgument, nth, stringify)));
645
+ }
646
+ const receivedName = received.getMockName();
647
+ const { calls, results } = received.mock;
648
+ const length = results.length;
649
+ const iNth = nth - 1;
650
+ const pass = iNth < length && isEqualReturn(expected, results[iNth]);
651
+ const message = pass
652
+ ? () => {
653
+ // Display preceding and following results,
654
+ // in case assertions fails because index is off by one.
655
+ const indexedResults = [];
656
+ if (iNth - 1 >= 0) {
657
+ indexedResults.push([iNth - 1, results[iNth - 1]]);
658
+ }
659
+ indexedResults.push([iNth, results[iNth]]);
660
+ if (iNth + 1 < length) {
661
+ indexedResults.push([iNth + 1, results[iNth + 1]]);
662
+ }
663
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
664
+ '\n\n' +
665
+ `n: ${nth}\n` +
666
+ `Expected: not ${printExpected(expected)}\n` +
667
+ (results.length === 1 &&
668
+ results[0].type === 'return' &&
669
+ stringify(results[0].value) === stringify(expected)
670
+ ? ''
671
+ : printReceivedResults('Received: ', expected, indexedResults, results.length === 1, iNth)) +
672
+ printNumberOfReturns(countReturns(results), calls.length));
673
+ }
674
+ : () => {
675
+ // Display preceding and following results:
676
+ // * nearest result that is equal to expected value
677
+ // * otherwise, adjacent result
678
+ // in case assertions fails because of index, especially off by one.
679
+ const indexedResults = [];
680
+ if (iNth < length) {
681
+ if (iNth - 1 >= 0) {
682
+ let i = iNth - 1;
683
+ // Is there a preceding result that is equal to expected value?
684
+ while (i >= 0 &&
685
+ !isEqualReturn(expected, results[i])) {
686
+ i -= 1;
687
+ }
688
+ if (i < 0) {
689
+ i = iNth - 1; // otherwise, adjacent result
690
+ }
691
+ indexedResults.push([i, results[i]]);
692
+ }
693
+ indexedResults.push([iNth, results[iNth]]);
694
+ if (iNth + 1 < length) {
695
+ let i = iNth + 1;
696
+ // Is there a following result that is equal to expected value?
697
+ while (i < length &&
698
+ !isEqualReturn(expected, results[i])) {
699
+ i += 1;
700
+ }
701
+ if (i >= length) {
702
+ i = iNth + 1; // otherwise, adjacent result
703
+ }
704
+ indexedResults.push([i, results[i]]);
705
+ }
706
+ }
707
+ else if (length > 0) {
708
+ // The number of received calls is fewer than the expected number.
709
+ let i = length - 1;
710
+ // Is there a result that is equal to expected value?
711
+ while (i >= 0 && !isEqualReturn(expected, results[i])) {
712
+ i -= 1;
713
+ }
714
+ if (i < 0) {
715
+ i = length - 1; // otherwise, last result
716
+ }
717
+ indexedResults.push([i, results[i]]);
718
+ }
719
+ return (matcherHint(matcherName, receivedName, expectedArgument, options) +
720
+ '\n\n' +
721
+ `n: ${nth}\n` +
722
+ `Expected: ${printExpected(expected)}\n` +
723
+ printReceivedResults('Received: ', expected, indexedResults, results.length === 1, iNth) +
724
+ printNumberOfReturns(countReturns(results), calls.length));
725
+ };
726
+ return { message, pass };
727
+ };
728
+ const spyMatchers = {
729
+ lastCalledWith: createLastCalledWithMatcher('lastCalledWith'),
730
+ lastReturnedWith: createLastReturnedMatcher('lastReturnedWith'),
731
+ nthCalledWith: createNthCalledWithMatcher('nthCalledWith'),
732
+ nthReturnedWith: createNthReturnedWithMatcher('nthReturnedWith'),
733
+ toBeCalled: createToBeCalledMatcher('toBeCalled'),
734
+ toBeCalledTimes: createToBeCalledTimesMatcher('toBeCalledTimes'),
735
+ toBeCalledWith: createToBeCalledWithMatcher('toBeCalledWith'),
736
+ toHaveBeenCalled: createToBeCalledMatcher('toHaveBeenCalled'),
737
+ toHaveBeenCalledTimes: createToBeCalledTimesMatcher('toHaveBeenCalledTimes'),
738
+ toHaveBeenCalledWith: createToBeCalledWithMatcher('toHaveBeenCalledWith'),
739
+ toHaveBeenLastCalledWith: createLastCalledWithMatcher('toHaveBeenLastCalledWith'),
740
+ toHaveBeenNthCalledWith: createNthCalledWithMatcher('toHaveBeenNthCalledWith'),
741
+ toHaveLastReturnedWith: createLastReturnedMatcher('toHaveLastReturnedWith'),
742
+ toHaveNthReturnedWith: createNthReturnedWithMatcher('toHaveNthReturnedWith'),
743
+ toHaveReturned: createToReturnMatcher('toHaveReturned'),
744
+ toHaveReturnedTimes: createToReturnTimesMatcher('toHaveReturnedTimes'),
745
+ toHaveReturnedWith: createToReturnWithMatcher('toHaveReturnedWith'),
746
+ toReturn: createToReturnMatcher('toReturn'),
747
+ toReturnTimes: createToReturnTimesMatcher('toReturnTimes'),
748
+ toReturnWith: createToReturnWithMatcher('toReturnWith'),
749
+ };
750
+ const isMock = (received) => received != null && received._isMockFunction === true;
751
+ const isSpy = (received) => received != null &&
752
+ received.calls != null &&
753
+ typeof received.calls.all === 'function' &&
754
+ typeof received.calls.count === 'function';
755
+ const ensureMockOrSpy = (received, matcherName, expectedArgument, options) => {
756
+ if (!isMock(received) && !isSpy(received)) {
757
+ throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${RECEIVED_COLOR('received')} value must be a mock or spy function`, printWithType('Received', received, printReceived)));
758
+ }
759
+ };
760
+ const ensureMock = (received, matcherName, expectedArgument, options) => {
761
+ if (!isMock(received)) {
762
+ throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${RECEIVED_COLOR('received')} value must be a mock function`, printWithType('Received', received, printReceived)));
763
+ }
764
+ };
765
+ export default spyMatchers;
766
+ //# sourceMappingURL=spyMatchers.js.map