strong-mock 9.0.0 → 9.1.0

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 (41) hide show
  1. package/README.md +25 -25
  2. package/dist/index.cjs +1175 -0
  3. package/dist/index.d.cts +572 -0
  4. package/dist/index.d.ts +572 -14
  5. package/dist/index.js +638 -836
  6. package/package.json +44 -25
  7. package/dist/errors/api.d.ts +0 -13
  8. package/dist/errors/diff.d.ts +0 -4
  9. package/dist/errors/unexpected-access.d.ts +0 -5
  10. package/dist/errors/unexpected-call.d.ts +0 -14
  11. package/dist/errors/verify.d.ts +0 -8
  12. package/dist/expectation/expectation.d.ts +0 -27
  13. package/dist/expectation/repository/expectation-repository.d.ts +0 -90
  14. package/dist/expectation/repository/flexible-repository.d.ts +0 -38
  15. package/dist/expectation/repository/return-value.d.ts +0 -13
  16. package/dist/expectation/strong-expectation.d.ts +0 -30
  17. package/dist/index.js.map +0 -1
  18. package/dist/matchers/contains-object.d.ts +0 -28
  19. package/dist/matchers/deep-equals.d.ts +0 -16
  20. package/dist/matchers/is-any.d.ts +0 -11
  21. package/dist/matchers/is-array.d.ts +0 -22
  22. package/dist/matchers/is-number.d.ts +0 -12
  23. package/dist/matchers/is-plain-object.d.ts +0 -17
  24. package/dist/matchers/is-string.d.ts +0 -15
  25. package/dist/matchers/is.d.ts +0 -9
  26. package/dist/matchers/it.d.ts +0 -10
  27. package/dist/matchers/matcher.d.ts +0 -93
  28. package/dist/matchers/will-capture.d.ts +0 -21
  29. package/dist/mock/defaults.d.ts +0 -11
  30. package/dist/mock/map.d.ts +0 -16
  31. package/dist/mock/mock.d.ts +0 -29
  32. package/dist/mock/options.d.ts +0 -99
  33. package/dist/mock/stub.d.ts +0 -5
  34. package/dist/print.d.ts +0 -10
  35. package/dist/proxy.d.ts +0 -48
  36. package/dist/return/invocation-count.d.ts +0 -44
  37. package/dist/return/returns.d.ts +0 -61
  38. package/dist/verify/reset.d.ts +0 -20
  39. package/dist/verify/verify.d.ts +0 -27
  40. package/dist/when/expectation-builder.d.ts +0 -26
  41. package/dist/when/when.d.ts +0 -32
package/dist/index.cjs ADDED
@@ -0,0 +1,1175 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all)
24
+ __defProp(target, name, { get: all[name], enumerable: true });
25
+ };
26
+ var __copyProps = (to, from, except, desc) => {
27
+ if (from && typeof from === "object" || typeof from === "function") {
28
+ for (let key of __getOwnPropNames(from))
29
+ if (!__hasOwnProp.call(to, key) && key !== except)
30
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
31
+ }
32
+ return to;
33
+ };
34
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
35
+ // If the importer is in node compatibility mode or this is not an ESM
36
+ // file that has been converted to a CommonJS file using a Babel-
37
+ // compatible transform (i.e. "__esModule" has not been set), then set
38
+ // "default" to the CommonJS "module.exports" for node compatibility.
39
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
40
+ mod
41
+ ));
42
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
+
44
+ // src/index.ts
45
+ var index_exports = {};
46
+ __export(index_exports, {
47
+ It: () => it_exports,
48
+ UnexpectedProperty: () => UnexpectedProperty,
49
+ mock: () => mock,
50
+ reset: () => reset,
51
+ resetAll: () => resetAll,
52
+ setDefaults: () => setDefaults,
53
+ verify: () => verify,
54
+ verifyAll: () => verifyAll,
55
+ when: () => when
56
+ });
57
+ module.exports = __toCommonJS(index_exports);
58
+
59
+ // src/errors/unexpected-access.ts
60
+ var import_jest_matcher_utils2 = require("jest-matcher-utils");
61
+
62
+ // src/print.ts
63
+ var import_jest_matcher_utils = require("jest-matcher-utils");
64
+ var import_cloneDeepWith = __toESM(require("lodash/cloneDeepWith.js"), 1);
65
+
66
+ // src/expectation/expectation.ts
67
+ var ApplyProp = Symbol("apply");
68
+
69
+ // src/matchers/matcher.ts
70
+ var MATCHER_SYMBOL = Symbol("matcher");
71
+ function isMatcher(f) {
72
+ return !!(f && f[MATCHER_SYMBOL]);
73
+ }
74
+ var getMatcherDiffs = (matchers, args) => {
75
+ const matcherDiffs = matchers.map((matcher, i) => matcher.getDiff(args[i]));
76
+ const actual = matcherDiffs.map((d) => d.actual);
77
+ const expected = matcherDiffs.map((d) => d.expected);
78
+ return { actual, expected };
79
+ };
80
+ var matches = (predicate, options) => {
81
+ var _a, _b;
82
+ const toString = (_a = options == null ? void 0 : options.toString) != null ? _a : () => `Matcher(${predicate.toString()})`;
83
+ const getDiff = (_b = options == null ? void 0 : options.getDiff) != null ? _b : (actual) => ({
84
+ actual,
85
+ expected: toString()
86
+ });
87
+ const matcher = {
88
+ [MATCHER_SYMBOL]: true,
89
+ matches: (actual) => predicate(actual),
90
+ toString,
91
+ getDiff: (actual) => {
92
+ if (predicate(actual)) {
93
+ return {
94
+ actual,
95
+ expected: actual
96
+ };
97
+ }
98
+ return getDiff(actual);
99
+ }
100
+ };
101
+ return matcher;
102
+ };
103
+
104
+ // src/print.ts
105
+ var printProperty = (property) => {
106
+ if (property === ApplyProp) {
107
+ return "";
108
+ }
109
+ if (typeof property === "symbol") {
110
+ return `[${property.toString()}]`;
111
+ }
112
+ return `.${property}`;
113
+ };
114
+ var printValue = (arg) => {
115
+ if (isMatcher(arg)) {
116
+ return arg.toString();
117
+ }
118
+ return (0, import_jest_matcher_utils.stringify)(arg);
119
+ };
120
+ var deepPrint = (value) => (0, import_cloneDeepWith.default)(value, (value2) => {
121
+ if (isMatcher(value2)) {
122
+ return value2.toString();
123
+ }
124
+ return void 0;
125
+ });
126
+ var printArgs = (args) => args.map((arg) => printValue(arg)).join(", ");
127
+ var printCall = (property, args) => {
128
+ const prettyProperty = printProperty(property);
129
+ if (args) {
130
+ const prettyArgs = printArgs(args);
131
+ return `mock${(0, import_jest_matcher_utils.RECEIVED_COLOR)(`${prettyProperty}(${prettyArgs})`)}`;
132
+ }
133
+ return `mock${(0, import_jest_matcher_utils.RECEIVED_COLOR)(`${prettyProperty}`)}`;
134
+ };
135
+ var printReturns = ({ isError, isPromise, value }, min, max) => {
136
+ let thenPrefix = "";
137
+ if (isPromise) {
138
+ if (isError) {
139
+ thenPrefix += "thenReject";
140
+ } else {
141
+ thenPrefix += "thenResolve";
142
+ }
143
+ } else if (isError) {
144
+ thenPrefix += "thenThrow";
145
+ } else {
146
+ thenPrefix += "thenReturn";
147
+ }
148
+ return `.${thenPrefix}(${(0, import_jest_matcher_utils.RECEIVED_COLOR)(
149
+ printValue(value)
150
+ )}).between(${min}, ${max})`;
151
+ };
152
+ var printWhen = (property, args) => {
153
+ const prettyProperty = printProperty(property);
154
+ if (args) {
155
+ return `when(() => mock${(0, import_jest_matcher_utils.EXPECTED_COLOR)(
156
+ `${prettyProperty}(${printArgs(args)})`
157
+ )})`;
158
+ }
159
+ return `when(() => mock${(0, import_jest_matcher_utils.EXPECTED_COLOR)(`${printProperty(property)}`)})`;
160
+ };
161
+ var printExpectation = (property, args, returnValue, min, max) => `${printWhen(property, args)}${printReturns(returnValue, min, max)}`;
162
+ var printRemainingExpectations = (expectations) => expectations.length ? `Remaining unmet expectations:
163
+ - ${expectations.map((e) => e.toString()).join("\n - ")}` : "There are no remaining unmet expectations.";
164
+
165
+ // src/errors/unexpected-access.ts
166
+ var UnexpectedAccess = class extends Error {
167
+ constructor(property, expectations) {
168
+ super(
169
+ (0, import_jest_matcher_utils2.DIM_COLOR)(`Didn't expect ${printCall(property)} to be accessed.
170
+
171
+ If you expect this property to be accessed then you should
172
+ set an expectation for it with when().
173
+
174
+ ${printRemainingExpectations(expectations)}`)
175
+ );
176
+ }
177
+ };
178
+
179
+ // src/errors/unexpected-call.ts
180
+ var import_jest_matcher_utils4 = require("jest-matcher-utils");
181
+
182
+ // src/errors/diff.ts
183
+ var import_jest_diff = require("jest-diff");
184
+ var import_jest_matcher_utils3 = require("jest-matcher-utils");
185
+ var noColor = (s) => s;
186
+ var printArgsDiff = (expected, actual) => {
187
+ const diff = (0, import_jest_diff.diff)(expected, actual, {
188
+ omitAnnotationLines: true,
189
+ aColor: noColor,
190
+ bColor: noColor,
191
+ changeColor: noColor,
192
+ commonColor: noColor,
193
+ patchColor: noColor
194
+ });
195
+ if (!diff) {
196
+ return "";
197
+ }
198
+ const diffLines = diff.split("\n");
199
+ let relevantDiffLines;
200
+ if (!expected.length) {
201
+ relevantDiffLines = diffLines.slice(2, -1);
202
+ } else if (!actual.length) {
203
+ relevantDiffLines = diffLines.slice(1, -2);
204
+ } else {
205
+ relevantDiffLines = diffLines.slice(1, -1);
206
+ }
207
+ const lastLine = relevantDiffLines[relevantDiffLines.length - 1].slice(0, -1);
208
+ const coloredDiffLines = [...relevantDiffLines.slice(0, -1), lastLine].map(
209
+ (line) => {
210
+ const first = line.charAt(0);
211
+ switch (first) {
212
+ case "-":
213
+ return (0, import_jest_matcher_utils3.EXPECTED_COLOR)(line);
214
+ case "+":
215
+ return (0, import_jest_matcher_utils3.RECEIVED_COLOR)(line);
216
+ default:
217
+ return line;
218
+ }
219
+ }
220
+ );
221
+ return coloredDiffLines.join("\n");
222
+ };
223
+ var printExpectationDiff = (e, args) => {
224
+ var _a;
225
+ if (!((_a = e.args) == null ? void 0 : _a.length)) {
226
+ return "";
227
+ }
228
+ const { actual, expected } = getMatcherDiffs(e.args, args);
229
+ return printArgsDiff(expected, actual);
230
+ };
231
+ var printDiffForAllExpectations = (expectations, actual) => expectations.map((e) => {
232
+ const diff = printExpectationDiff(e, actual);
233
+ if (diff) {
234
+ return `${e.toString()}
235
+ ${(0, import_jest_matcher_utils3.EXPECTED_COLOR)("- Expected")}
236
+ ${(0, import_jest_matcher_utils3.RECEIVED_COLOR)("+ Received")}
237
+
238
+ ${diff}`;
239
+ }
240
+ return void 0;
241
+ }).filter((x) => x).join("\n\n");
242
+
243
+ // src/errors/unexpected-call.ts
244
+ var UnexpectedCall = class extends Error {
245
+ constructor(property, args, expectations) {
246
+ var _a;
247
+ const header = `Didn't expect ${printCall(property, args)} to be called.`;
248
+ const propertyExpectations = expectations.filter(
249
+ (e) => e.property === property
250
+ );
251
+ if (propertyExpectations.length) {
252
+ super(
253
+ (0, import_jest_matcher_utils4.DIM_COLOR)(`${header}
254
+
255
+ Remaining expectations:
256
+ ${printDiffForAllExpectations(propertyExpectations, args)}`)
257
+ );
258
+ if (propertyExpectations.length === 1 && ((_a = propertyExpectations[0].args) == null ? void 0 : _a.length)) {
259
+ const { actual, expected } = getMatcherDiffs(
260
+ propertyExpectations[0].args,
261
+ args
262
+ );
263
+ this.actual = actual;
264
+ this.expected = expected;
265
+ this.matcherResult = {
266
+ actual,
267
+ expected
268
+ };
269
+ }
270
+ } else {
271
+ super(
272
+ (0, import_jest_matcher_utils4.DIM_COLOR)(`${header}
273
+
274
+ No remaining expectations.`)
275
+ );
276
+ }
277
+ }
278
+ };
279
+
280
+ // src/mock/options.ts
281
+ var UnexpectedProperty = /* @__PURE__ */ ((UnexpectedProperty2) => {
282
+ UnexpectedProperty2[UnexpectedProperty2["THROW"] = 0] = "THROW";
283
+ UnexpectedProperty2[UnexpectedProperty2["CALL_THROW"] = 1] = "CALL_THROW";
284
+ return UnexpectedProperty2;
285
+ })(UnexpectedProperty || {});
286
+
287
+ // src/expectation/repository/return-value.ts
288
+ var unboxReturnValue = ({
289
+ isError,
290
+ isPromise,
291
+ value
292
+ }) => {
293
+ if (isError) {
294
+ if (value instanceof Error) {
295
+ if (isPromise) {
296
+ return Promise.reject(value);
297
+ }
298
+ throw value;
299
+ }
300
+ if (isPromise) {
301
+ return Promise.reject(new Error(value));
302
+ }
303
+ throw new Error(value);
304
+ }
305
+ if (isPromise) {
306
+ return Promise.resolve(value);
307
+ }
308
+ return value;
309
+ };
310
+
311
+ // src/expectation/repository/flexible-repository.ts
312
+ var FlexibleRepository = class {
313
+ constructor(unexpectedProperty = 0 /* THROW */) {
314
+ this.unexpectedProperty = unexpectedProperty;
315
+ this.expectations = /* @__PURE__ */ new Map();
316
+ this.expectedCallStats = /* @__PURE__ */ new Map();
317
+ this.unexpectedCallStats = /* @__PURE__ */ new Map();
318
+ this.apply = (args) => this.get(ApplyProp)(...args);
319
+ this.handlePropertyWithMatchingExpectations = (property, expectations) => {
320
+ if (property !== ApplyProp) {
321
+ this.recordExpected(property, void 0);
322
+ }
323
+ const propertyExpectation = expectations.find(
324
+ (e) => e.expectation.matches(void 0)
325
+ );
326
+ if (propertyExpectation) {
327
+ this.countAndConsume(propertyExpectation);
328
+ return unboxReturnValue(propertyExpectation.expectation.returnValue);
329
+ }
330
+ return (...args) => {
331
+ const callExpectation = expectations.find(
332
+ (e) => e.expectation.matches(args)
333
+ );
334
+ if (callExpectation) {
335
+ this.recordExpected(property, args);
336
+ this.countAndConsume(callExpectation);
337
+ return unboxReturnValue(callExpectation.expectation.returnValue);
338
+ }
339
+ return this.getValueForUnexpectedCall(property, args);
340
+ };
341
+ };
342
+ this.handlePropertyWithNoExpectations = (property) => {
343
+ switch (property) {
344
+ case "toString":
345
+ return () => "mock";
346
+ case "@@toStringTag":
347
+ case Symbol.toStringTag:
348
+ case "name":
349
+ return "mock";
350
+ // Promise.resolve() tries to see if it's a "thenable".
351
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
352
+ case "then":
353
+ return void 0;
354
+ // pretty-format
355
+ case "$$typeof":
356
+ case "constructor":
357
+ case "@@__IMMUTABLE_ITERABLE__@@":
358
+ case "@@__IMMUTABLE_RECORD__@@":
359
+ return null;
360
+ case MATCHER_SYMBOL:
361
+ return false;
362
+ case ApplyProp:
363
+ return (...args) => this.getValueForUnexpectedCall(property, args);
364
+ default:
365
+ return this.getValueForUnexpectedAccess(property);
366
+ }
367
+ };
368
+ }
369
+ add(expectation) {
370
+ const { property } = expectation;
371
+ const expectations = this.expectations.get(property) || [];
372
+ this.expectations.set(property, [
373
+ ...expectations,
374
+ {
375
+ expectation,
376
+ matchCount: 0
377
+ }
378
+ ]);
379
+ }
380
+ clear() {
381
+ this.expectations.clear();
382
+ this.expectedCallStats.clear();
383
+ this.unexpectedCallStats.clear();
384
+ }
385
+ // TODO: this returns any, but the interface returns unknown
386
+ // unknown causes errors in apply tests, and any causes bugs in bootstrapped SM
387
+ get(property) {
388
+ const expectations = this.expectations.get(property);
389
+ if (expectations && expectations.length) {
390
+ return this.handlePropertyWithMatchingExpectations(
391
+ property,
392
+ expectations
393
+ );
394
+ }
395
+ return this.handlePropertyWithNoExpectations(property);
396
+ }
397
+ getAllProperties() {
398
+ return Array.from(this.expectations.keys());
399
+ }
400
+ getCallStats() {
401
+ return {
402
+ expected: this.expectedCallStats,
403
+ unexpected: this.unexpectedCallStats
404
+ };
405
+ }
406
+ getUnmet() {
407
+ return [].concat(
408
+ ...Array.from(this.expectations.values()).map(
409
+ (expectations) => expectations.filter((e) => e.expectation.min > e.matchCount).map((e) => e.expectation)
410
+ )
411
+ );
412
+ }
413
+ recordExpected(property, args) {
414
+ const calls = this.expectedCallStats.get(property) || [];
415
+ this.expectedCallStats.set(property, [...calls, { arguments: args }]);
416
+ }
417
+ recordUnexpected(property, args) {
418
+ const calls = this.unexpectedCallStats.get(property) || [];
419
+ this.unexpectedCallStats.set(property, [...calls, { arguments: args }]);
420
+ }
421
+ countAndConsume(expectation) {
422
+ expectation.matchCount++;
423
+ this.consumeExpectation(expectation);
424
+ }
425
+ consumeExpectation(expectation) {
426
+ const { property, max } = expectation.expectation;
427
+ const expectations = this.expectations.get(property);
428
+ if (expectation.matchCount === max) {
429
+ this.expectations.set(
430
+ property,
431
+ expectations.filter((e) => e !== expectation)
432
+ );
433
+ }
434
+ }
435
+ getValueForUnexpectedCall(property, args) {
436
+ this.recordUnexpected(property, args);
437
+ throw new UnexpectedCall(property, args, this.getUnmet());
438
+ }
439
+ getValueForUnexpectedAccess(property) {
440
+ if (this.unexpectedProperty === 0 /* THROW */) {
441
+ this.recordUnexpected(property, void 0);
442
+ throw new UnexpectedAccess(property, this.getUnmet());
443
+ }
444
+ return (...args) => {
445
+ this.recordUnexpected(property, args);
446
+ throw new UnexpectedCall(property, args, this.getUnmet());
447
+ };
448
+ }
449
+ };
450
+
451
+ // src/expectation/strong-expectation.ts
452
+ var StrongExpectation = class {
453
+ constructor(property, args, returnValue, exactParams = false) {
454
+ this.property = property;
455
+ this.args = args;
456
+ this.returnValue = returnValue;
457
+ this.exactParams = exactParams;
458
+ this.matched = 0;
459
+ this.min = 1;
460
+ this.max = 1;
461
+ }
462
+ setInvocationCount(min, max = 1) {
463
+ this.min = min;
464
+ this.max = max;
465
+ }
466
+ matches(args) {
467
+ if (!this.matchesArgs(args)) {
468
+ return false;
469
+ }
470
+ this.matched++;
471
+ return this.max === 0 || this.matched <= this.max;
472
+ }
473
+ isUnmet() {
474
+ return this.matched < this.min;
475
+ }
476
+ matchesArgs(received) {
477
+ if (this.args === void 0) {
478
+ return !received;
479
+ }
480
+ if (!received) {
481
+ return false;
482
+ }
483
+ if (this.exactParams) {
484
+ if (this.args.length !== received.length) {
485
+ return false;
486
+ }
487
+ }
488
+ return this.args.every((arg, i) => arg.matches(received[i]));
489
+ }
490
+ toString() {
491
+ return printExpectation(
492
+ this.property,
493
+ this.args,
494
+ this.returnValue,
495
+ this.min,
496
+ this.max
497
+ );
498
+ }
499
+ };
500
+
501
+ // src/errors/api.ts
502
+ var UnfinishedExpectation = class extends Error {
503
+ constructor(property, args) {
504
+ super(`There is an unfinished pending expectation:
505
+
506
+ ${printWhen(property, args)}
507
+
508
+ You should finish it by setting a return value with e.g. thenReturns(),
509
+ even if that value is undefined.`);
510
+ }
511
+ };
512
+ var MissingWhen = class extends Error {
513
+ constructor() {
514
+ super(`You tried setting a return value without an expectation.
515
+
516
+ Every call to set a return value must be preceded by an expectation.`);
517
+ }
518
+ };
519
+ var NotAMock = class extends Error {
520
+ constructor() {
521
+ super(`We couldn't find the mock.
522
+
523
+ Make sure you're passing in an actual mock.`);
524
+ }
525
+ };
526
+ var NestedWhen = class extends Error {
527
+ constructor(parentProp, childProp) {
528
+ const snippet = `
529
+ const parentMock = mock<T1>();
530
+ const childMock = mock<T2>();
531
+
532
+ when(() => childMock${printProperty(childProp)}).thenReturn(...);
533
+ when(() => parentMock${printProperty(parentProp)}).thenReturn(childMock)
534
+ `;
535
+ super(
536
+ `Setting an expectation on a nested property is not supported.
537
+
538
+ You can return an object directly when the first property is accessed,
539
+ or you can even return a separate mock:
540
+ ${snippet}`
541
+ );
542
+ }
543
+ };
544
+
545
+ // src/when/expectation-builder.ts
546
+ var ExpectationBuilderWithFactory = class {
547
+ constructor(createExpectation, concreteMatcher, exactParams) {
548
+ this.createExpectation = createExpectation;
549
+ this.concreteMatcher = concreteMatcher;
550
+ this.exactParams = exactParams;
551
+ }
552
+ setProperty(value) {
553
+ if (this.property) {
554
+ throw new UnfinishedExpectation(this.property, this.args);
555
+ }
556
+ this.property = value;
557
+ }
558
+ setArgs(value) {
559
+ this.args = value;
560
+ }
561
+ finish(returnValue) {
562
+ if (!this.property) {
563
+ throw new MissingWhen();
564
+ }
565
+ const expectation = this.createExpectation(
566
+ this.property,
567
+ this.args,
568
+ returnValue,
569
+ this.concreteMatcher,
570
+ this.exactParams
571
+ );
572
+ this.property = void 0;
573
+ this.args = void 0;
574
+ return expectation;
575
+ }
576
+ };
577
+
578
+ // src/matchers/deep-equals.ts
579
+ var import_cloneDeep = __toESM(require("lodash/cloneDeep.js"), 1);
580
+ var import_cloneDeepWith2 = __toESM(require("lodash/cloneDeepWith.js"), 1);
581
+ var import_isEqualWith = __toESM(require("lodash/isEqualWith.js"), 1);
582
+ var import_isMap = __toESM(require("lodash/isMap.js"), 1);
583
+ var import_isObjectLike = __toESM(require("lodash/isObjectLike.js"), 1);
584
+ var import_omitBy = __toESM(require("lodash/omitBy.js"), 1);
585
+ var removeUndefined = (object) => {
586
+ if (Array.isArray(object)) {
587
+ return object.map((x) => removeUndefined(x));
588
+ }
589
+ if (!(0, import_isObjectLike.default)(object)) {
590
+ return object;
591
+ }
592
+ return (0, import_omitBy.default)(object, (value) => value === void 0);
593
+ };
594
+ var getKey = (key, object) => {
595
+ if (key === void 0) {
596
+ return object;
597
+ }
598
+ return (0, import_isMap.default)(object) ? object.get(key) : object[key];
599
+ };
600
+ var deepEquals = (expected, {
601
+ strict = true
602
+ } = {}) => matches(
603
+ (actual) => (0, import_isEqualWith.default)(
604
+ strict ? actual : removeUndefined(actual),
605
+ strict ? expected : removeUndefined(expected),
606
+ (actualValue, expectedValue) => {
607
+ if (isMatcher(expectedValue)) {
608
+ return expectedValue.matches(actualValue);
609
+ }
610
+ return void 0;
611
+ }
612
+ ),
613
+ {
614
+ toString: () => printValue(deepPrint(expected)),
615
+ getDiff: (actual) => {
616
+ let actualResult = (0, import_cloneDeep.default)(actual);
617
+ const expectedResult = (0, import_cloneDeepWith2.default)(expected, (expectedValue, key) => {
618
+ const actualValue = getKey(key, actualResult);
619
+ if (isMatcher(expectedValue)) {
620
+ if (expectedValue.matches(actualValue)) {
621
+ return actualValue;
622
+ }
623
+ const result = expectedValue.getDiff(actualValue);
624
+ if (key !== void 0) {
625
+ if ((0, import_isMap.default)(actualResult)) {
626
+ actualResult.set(key, result.actual);
627
+ } else {
628
+ actualResult[key] = result.actual;
629
+ }
630
+ } else {
631
+ actualResult = result.actual;
632
+ }
633
+ return result.expected;
634
+ }
635
+ return void 0;
636
+ });
637
+ return {
638
+ actual: actualResult,
639
+ expected: expectedResult
640
+ };
641
+ }
642
+ }
643
+ );
644
+
645
+ // src/mock/defaults.ts
646
+ var defaults = {
647
+ concreteMatcher: deepEquals,
648
+ unexpectedProperty: 1 /* CALL_THROW */,
649
+ exactParams: false
650
+ };
651
+ var currentDefaults = defaults;
652
+ var setDefaults = (newDefaults) => {
653
+ currentDefaults = __spreadValues(__spreadValues({}, defaults), newDefaults);
654
+ };
655
+
656
+ // src/mock/map.ts
657
+ var activeMock;
658
+ var setActiveMock = (mock2) => {
659
+ activeMock = mock2;
660
+ };
661
+ var getActiveMock = () => activeMock;
662
+ var mockMap = /* @__PURE__ */ new Map();
663
+ var getMockState = (mock2) => {
664
+ if (mockMap.has(mock2)) {
665
+ return mockMap.get(mock2);
666
+ }
667
+ throw new NotAMock();
668
+ };
669
+ var setMockState = (mock2, state) => {
670
+ mockMap.set(mock2, state);
671
+ };
672
+ var getAllMocks = () => Array.from(mockMap.entries());
673
+
674
+ // src/mock/mode.ts
675
+ var currentMode = 1 /* CALL */;
676
+ var setMode = (mode) => {
677
+ currentMode = mode;
678
+ };
679
+ var getMode = () => currentMode;
680
+
681
+ // src/proxy.ts
682
+ var createProxy = (traps) => (
683
+ // The Proxy target MUST be a function, otherwise we can't use the `apply` trap:
684
+ // https://262.ecma-international.org/6.0/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
685
+ new Proxy(
686
+ /* c8 ignore next */
687
+ () => {
688
+ },
689
+ {
690
+ get: (target, prop) => {
691
+ if (prop === "bind") {
692
+ return (thisArg, ...args) => (...moreArgs) => traps.apply([...args, ...moreArgs]);
693
+ }
694
+ if (prop === "apply") {
695
+ return (thisArg, args) => traps.apply(args || []);
696
+ }
697
+ if (prop === "call") {
698
+ return (thisArg, ...args) => traps.apply(args);
699
+ }
700
+ return traps.property(prop);
701
+ },
702
+ apply: (target, thisArg, args) => traps.apply(args),
703
+ ownKeys: () => traps.ownKeys(),
704
+ getOwnPropertyDescriptor(target, prop) {
705
+ const keys = traps.ownKeys();
706
+ if (keys.includes(prop)) {
707
+ return {
708
+ configurable: true,
709
+ enumerable: true
710
+ };
711
+ }
712
+ return void 0;
713
+ }
714
+ }
715
+ )
716
+ );
717
+
718
+ // src/mock/stub.ts
719
+ var createStub = (repo, builder, getCurrentMode) => {
720
+ const stub = createProxy({
721
+ property: (property) => {
722
+ if (getCurrentMode() === 1 /* CALL */) {
723
+ return repo.get(property);
724
+ }
725
+ setActiveMock(stub);
726
+ builder.setProperty(property);
727
+ return createProxy({
728
+ property: (childProp) => {
729
+ throw new NestedWhen(property, childProp);
730
+ },
731
+ apply: (args) => {
732
+ builder.setArgs(args);
733
+ },
734
+ ownKeys: () => {
735
+ throw new Error("Spreading during an expectation is not supported.");
736
+ }
737
+ });
738
+ },
739
+ apply: (args) => {
740
+ if (getCurrentMode() === 1 /* CALL */) {
741
+ return repo.apply(args);
742
+ }
743
+ setActiveMock(stub);
744
+ builder.setProperty(ApplyProp);
745
+ builder.setArgs(args);
746
+ return void 0;
747
+ },
748
+ ownKeys: () => {
749
+ if (getCurrentMode() === 1 /* CALL */) {
750
+ return repo.getAllProperties();
751
+ }
752
+ throw new Error("Spreading during an expectation is not supported.");
753
+ }
754
+ });
755
+ return stub;
756
+ };
757
+
758
+ // src/mock/mock.ts
759
+ var strongExpectationFactory = (property, args, returnValue, concreteMatcher, exactParams) => new StrongExpectation(
760
+ property,
761
+ // Wrap every non-matcher in the default matcher.
762
+ args == null ? void 0 : args.map((arg) => isMatcher(arg) ? arg : concreteMatcher(arg)),
763
+ returnValue,
764
+ exactParams
765
+ );
766
+ var mock = ({
767
+ unexpectedProperty,
768
+ concreteMatcher,
769
+ exactParams
770
+ } = {}) => {
771
+ const options = {
772
+ unexpectedProperty: unexpectedProperty != null ? unexpectedProperty : currentDefaults.unexpectedProperty,
773
+ concreteMatcher: concreteMatcher != null ? concreteMatcher : currentDefaults.concreteMatcher,
774
+ exactParams: exactParams != null ? exactParams : currentDefaults.exactParams
775
+ };
776
+ const repository = new FlexibleRepository(options.unexpectedProperty);
777
+ const builder = new ExpectationBuilderWithFactory(
778
+ strongExpectationFactory,
779
+ options.concreteMatcher,
780
+ options.exactParams
781
+ );
782
+ const stub = createStub(repository, builder, getMode);
783
+ setMockState(stub, {
784
+ repository,
785
+ builder,
786
+ options
787
+ });
788
+ return stub;
789
+ };
790
+
791
+ // src/return/invocation-count.ts
792
+ var createInvocationCount = (expectation) => ({
793
+ between(min, max) {
794
+ expectation.setInvocationCount(min, max);
795
+ },
796
+ /* c8 ignore next 3 */
797
+ times(exact) {
798
+ expectation.setInvocationCount(exact, exact);
799
+ },
800
+ /* c8 ignore next 3 */
801
+ anyTimes() {
802
+ expectation.setInvocationCount(0, 0);
803
+ },
804
+ /* c8 ignore next 3 */
805
+ atLeast(min) {
806
+ expectation.setInvocationCount(min, Infinity);
807
+ },
808
+ /* c8 ignore next 3 */
809
+ atMost(max) {
810
+ expectation.setInvocationCount(0, max);
811
+ },
812
+ /* c8 ignore next 3 */
813
+ once() {
814
+ expectation.setInvocationCount(1, 1);
815
+ },
816
+ /* c8 ignore next 3 */
817
+ twice() {
818
+ expectation.setInvocationCount(2, 2);
819
+ }
820
+ });
821
+
822
+ // src/return/returns.ts
823
+ var finishExpectation = (returnValue, builder, repo) => {
824
+ const finishedExpectation = builder.finish(returnValue);
825
+ repo.add(finishedExpectation);
826
+ return createInvocationCount(finishedExpectation);
827
+ };
828
+ var getError = (errorOrMessage) => {
829
+ if (typeof errorOrMessage === "string") {
830
+ return new Error(errorOrMessage);
831
+ }
832
+ if (errorOrMessage instanceof Error) {
833
+ return errorOrMessage;
834
+ }
835
+ return new Error();
836
+ };
837
+ var createReturns = (builder, repository) => ({
838
+ thenReturn: (returnValue) => finishExpectation(
839
+ // This will handle both thenReturn(23) and thenReturn(Promise.resolve(3)).
840
+ { value: returnValue, isError: false, isPromise: false },
841
+ builder,
842
+ repository
843
+ ),
844
+ thenThrow: (errorOrMessage) => finishExpectation(
845
+ { value: getError(errorOrMessage), isError: true, isPromise: false },
846
+ builder,
847
+ repository
848
+ ),
849
+ thenResolve: (promiseValue) => finishExpectation(
850
+ {
851
+ value: promiseValue,
852
+ isError: false,
853
+ isPromise: true
854
+ },
855
+ builder,
856
+ repository
857
+ ),
858
+ thenReject: (errorOrMessage) => finishExpectation(
859
+ {
860
+ value: getError(errorOrMessage),
861
+ isError: true,
862
+ isPromise: true
863
+ },
864
+ builder,
865
+ repository
866
+ )
867
+ });
868
+
869
+ // src/when/when.ts
870
+ var when = (expectation) => {
871
+ setMode(0 /* EXPECT */);
872
+ expectation();
873
+ setMode(1 /* CALL */);
874
+ const { builder, repository } = getMockState(getActiveMock());
875
+ return createReturns(builder, repository);
876
+ };
877
+
878
+ // src/verify/reset.ts
879
+ var reset = (mock2) => {
880
+ getMockState(mock2).repository.clear();
881
+ };
882
+ var resetAll = () => {
883
+ getAllMocks().forEach(([mock2]) => {
884
+ reset(mock2);
885
+ });
886
+ };
887
+
888
+ // src/errors/verify.ts
889
+ var import_jest_matcher_utils5 = require("jest-matcher-utils");
890
+ var UnmetExpectations = class extends Error {
891
+ constructor(expectations) {
892
+ super(
893
+ (0, import_jest_matcher_utils5.DIM_COLOR)(`There are unmet expectations:
894
+
895
+ - ${expectations.map((e) => e.toString()).join("\n - ")}`)
896
+ );
897
+ }
898
+ };
899
+ var mergeCalls = (callMap) => new Map(
900
+ Array.from(callMap.entries()).map(([property, calls]) => {
901
+ const hasMethodCalls = calls.some((call) => call.arguments);
902
+ const hasPropertyAccesses = calls.some((call) => !call.arguments);
903
+ if (hasMethodCalls && hasPropertyAccesses) {
904
+ return [property, calls.filter((call) => call.arguments)];
905
+ }
906
+ return [property, calls];
907
+ })
908
+ );
909
+ var UnexpectedCalls = class extends Error {
910
+ constructor(unexpectedCalls, expectations) {
911
+ const printedCalls = Array.from(mergeCalls(unexpectedCalls).entries()).map(
912
+ ([property, calls]) => calls.map((call) => printCall(property, call.arguments)).join("\n - ")
913
+ ).join("\n - ");
914
+ super(
915
+ (0, import_jest_matcher_utils5.DIM_COLOR)(`The following calls were unexpected:
916
+
917
+ - ${printedCalls}
918
+
919
+ ${printRemainingExpectations(expectations)}`)
920
+ );
921
+ }
922
+ };
923
+
924
+ // src/verify/verify.ts
925
+ var verifyRepo = (repository) => {
926
+ const unmetExpectations = repository.getUnmet();
927
+ if (unmetExpectations.length) {
928
+ throw new UnmetExpectations(unmetExpectations);
929
+ }
930
+ const callStats = repository.getCallStats();
931
+ if (callStats.unexpected.size) {
932
+ throw new UnexpectedCalls(callStats.unexpected, unmetExpectations);
933
+ }
934
+ };
935
+ var verify = (mock2) => {
936
+ const { repository } = getMockState(mock2);
937
+ verifyRepo(repository);
938
+ };
939
+ var verifyAll = () => {
940
+ getAllMocks().forEach(([mock2]) => {
941
+ verify(mock2);
942
+ });
943
+ };
944
+
945
+ // src/matchers/it.ts
946
+ var it_exports = {};
947
+ __export(it_exports, {
948
+ containsObject: () => containsObject,
949
+ deepEquals: () => deepEquals,
950
+ is: () => is,
951
+ isAny: () => isAny,
952
+ isArray: () => isArray,
953
+ isNumber: () => isNumber,
954
+ isPlainObject: () => isPlainObject,
955
+ isString: () => isString,
956
+ matches: () => matches,
957
+ willCapture: () => willCapture
958
+ });
959
+
960
+ // src/matchers/is.ts
961
+ var is = (expected) => matches((actual) => Object.is(actual, expected), {
962
+ toString: () => `${printValue(expected)}`,
963
+ getDiff: (actual) => ({ actual, expected })
964
+ });
965
+
966
+ // src/matchers/is-any.ts
967
+ var isAny = () => matches(() => true, {
968
+ toString: () => "Matcher<any>"
969
+ });
970
+
971
+ // src/matchers/is-array.ts
972
+ var isArray = (containing) => matches(
973
+ (actual) => {
974
+ if (!Array.isArray(actual)) {
975
+ return false;
976
+ }
977
+ if (!containing) {
978
+ return true;
979
+ }
980
+ return containing.every(
981
+ (x) => actual.find((y) => {
982
+ if (isMatcher(x)) {
983
+ return x.matches(y);
984
+ }
985
+ return deepEquals(x).matches(y);
986
+ }) !== void 0
987
+ );
988
+ },
989
+ {
990
+ toString: () => containing ? `array([${containing.map((v) => printValue(v)).join(", ")}])` : "array",
991
+ getDiff: (actual) => {
992
+ if (containing) {
993
+ return {
994
+ actual,
995
+ expected: `Matcher<array>([${containing.map((value) => {
996
+ if (isMatcher(value)) {
997
+ return value.toString();
998
+ }
999
+ return value;
1000
+ }).join(", ")}])`
1001
+ };
1002
+ }
1003
+ return {
1004
+ actual: `${printValue(actual)} (${typeof actual})`,
1005
+ expected: "Matcher<array>"
1006
+ };
1007
+ }
1008
+ }
1009
+ );
1010
+
1011
+ // src/matchers/is-number.ts
1012
+ var isNumber = () => matches((actual) => typeof actual === "number" && !Number.isNaN(actual), {
1013
+ toString: () => "Matcher<number>",
1014
+ getDiff: (actual) => ({
1015
+ actual: `${printValue(actual)} (${typeof actual})`,
1016
+ expected: "Matcher<number>"
1017
+ })
1018
+ });
1019
+
1020
+ // src/matchers/is-plain-object.ts
1021
+ var import_isObjectLike2 = __toESM(require("lodash/isObjectLike.js"), 1);
1022
+ var import_isPlainObject = __toESM(require("lodash/isPlainObject.js"), 1);
1023
+ var isPlainObject = () => matches((actual) => (0, import_isPlainObject.default)(actual), {
1024
+ toString: () => "Matcher<object>",
1025
+ getDiff: (actual) => {
1026
+ const type = (0, import_isObjectLike2.default)(actual) ? "object-like" : typeof actual;
1027
+ return {
1028
+ actual: `${printValue(actual)} (${type})`,
1029
+ expected: "Matcher<object>"
1030
+ };
1031
+ }
1032
+ });
1033
+
1034
+ // src/matchers/contains-object.ts
1035
+ var import_isPlainObject2 = __toESM(require("lodash/isPlainObject.js"), 1);
1036
+ var looksLikeObject = (value) => (0, import_isPlainObject2.default)(value);
1037
+ var getExpectedObjectDiff = (actual, expected) => Object.fromEntries(
1038
+ getKeys(expected).map((key) => {
1039
+ const expectedValue = getKey2(expected, key);
1040
+ const actualValue = getKey2(actual, key);
1041
+ if (isMatcher(expectedValue)) {
1042
+ return [key, expectedValue.getDiff(actualValue).expected];
1043
+ }
1044
+ if (looksLikeObject(expectedValue)) {
1045
+ return [key, getExpectedObjectDiff(actualValue, expectedValue)];
1046
+ }
1047
+ return [key, expectedValue];
1048
+ })
1049
+ );
1050
+ var getActualObjectDiff = (actual, expected) => {
1051
+ const actualKeys = getKeys(actual);
1052
+ const expectedKeys = new Set(getKeys(expected));
1053
+ const commonKeys = actualKeys.filter((key) => expectedKeys.has(key));
1054
+ if (!commonKeys.length) {
1055
+ return actual;
1056
+ }
1057
+ return Object.fromEntries(
1058
+ commonKeys.map((key) => {
1059
+ const expectedValue = getKey2(expected, key);
1060
+ const actualValue = getKey2(actual, key);
1061
+ if (isMatcher(expectedValue)) {
1062
+ return [key, expectedValue.getDiff(actualValue).actual];
1063
+ }
1064
+ if (looksLikeObject(expectedValue)) {
1065
+ return [key, getActualObjectDiff(actualValue, expectedValue)];
1066
+ }
1067
+ return [key, actualValue];
1068
+ })
1069
+ );
1070
+ };
1071
+ var getKeys = (value) => {
1072
+ if (typeof value === "object" && value !== null) {
1073
+ return Reflect.ownKeys(value);
1074
+ }
1075
+ return [];
1076
+ };
1077
+ var getKey2 = (value, key) => (
1078
+ // @ts-expect-error because we're fine with a runtime undefined value
1079
+ value == null ? void 0 : value[key]
1080
+ );
1081
+ var isMatch = (actual, expected) => {
1082
+ const actualKeys = getKeys(actual);
1083
+ const expectedKeys = getKeys(expected);
1084
+ if (!isArray(expectedKeys).matches(actualKeys)) {
1085
+ return false;
1086
+ }
1087
+ return expectedKeys.every((key) => {
1088
+ const expectedValue = getKey2(expected, key);
1089
+ const actualValue = getKey2(actual, key);
1090
+ if (isMatcher(expectedValue)) {
1091
+ return expectedValue.matches(actualValue);
1092
+ }
1093
+ if (looksLikeObject(expectedValue)) {
1094
+ return isMatch(actualValue, expectedValue);
1095
+ }
1096
+ return deepEquals(expectedValue).matches(actualValue);
1097
+ });
1098
+ };
1099
+ var containsObject = (partial) => matches((actual) => isMatch(actual, partial), {
1100
+ toString: () => `Matcher<object>(${printValue(deepPrint(partial))})`,
1101
+ getDiff: (actual) => ({
1102
+ actual: getActualObjectDiff(actual, partial),
1103
+ expected: getExpectedObjectDiff(actual, partial)
1104
+ })
1105
+ });
1106
+
1107
+ // src/matchers/is-string.ts
1108
+ var isString = (matching) => matches(
1109
+ (actual) => {
1110
+ if (typeof actual !== "string") {
1111
+ return false;
1112
+ }
1113
+ if (!matching) {
1114
+ return true;
1115
+ }
1116
+ if (typeof matching === "string") {
1117
+ return actual.indexOf(matching) !== -1;
1118
+ }
1119
+ return matching.test(actual);
1120
+ },
1121
+ {
1122
+ toString: () => {
1123
+ if (matching) {
1124
+ return `Matcher<string>(${matching})`;
1125
+ }
1126
+ return "Matcher<string>";
1127
+ },
1128
+ getDiff: (actual) => {
1129
+ if (matching) {
1130
+ return {
1131
+ expected: `Matcher<string>(${matching})`,
1132
+ actual
1133
+ };
1134
+ }
1135
+ return {
1136
+ expected: "Matcher<string>",
1137
+ actual: `${actual} (${typeof actual})`
1138
+ };
1139
+ }
1140
+ }
1141
+ );
1142
+
1143
+ // src/matchers/will-capture.ts
1144
+ var willCapture = (name) => {
1145
+ let capturedValue;
1146
+ const matcher = {
1147
+ [MATCHER_SYMBOL]: true,
1148
+ matches: (actual) => {
1149
+ capturedValue = actual;
1150
+ return true;
1151
+ },
1152
+ toString: () => name ? `Capture(${name})` : "Capture",
1153
+ getDiff: (actual) => ({
1154
+ actual,
1155
+ expected: actual
1156
+ }),
1157
+ get value() {
1158
+ return capturedValue;
1159
+ }
1160
+ };
1161
+ return matcher;
1162
+ };
1163
+ // Annotate the CommonJS export names for ESM import in node:
1164
+ 0 && (module.exports = {
1165
+ It,
1166
+ UnexpectedProperty,
1167
+ mock,
1168
+ reset,
1169
+ resetAll,
1170
+ setDefaults,
1171
+ verify,
1172
+ verifyAll,
1173
+ when
1174
+ });
1175
+ /* c8 ignore next 3 this is not expected in practice -- @preserve */