strong-mock 9.0.0-beta.1 → 9.0.0-beta.3

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.
package/dist/index.js CHANGED
@@ -16,7 +16,6 @@ const MATCHER_SYMBOL = Symbol('matcher');
16
16
  /**
17
17
  * Used to test if an expectation is an argument is a custom matcher.
18
18
  */
19
-
20
19
  function isMatcher(f) {
21
20
  return !!(f && f[MATCHER_SYMBOL]);
22
21
  }
@@ -51,10 +50,8 @@ const getMatcherDiffs = (matchers, args) => {
51
50
  * fn(2) === 42
52
51
  * fn(-1) // throws
53
52
  */
54
-
55
53
  const matches = (predicate, options) => {
56
54
  var _options$toString, _options$getDiff;
57
-
58
55
  // We can't use destructuring with default values because `options` is optional,
59
56
  // so it needs a default value of `{}`, which will come with a native `toString`.
60
57
  const toString = (_options$toString = options == null ? void 0 : options.toString) != null ? _options$toString : () => `Matcher(${predicate.toString()})`;
@@ -73,7 +70,6 @@ const matches = (predicate, options) => {
73
70
  expected: actual
74
71
  };
75
72
  }
76
-
77
73
  return getDiff(actual);
78
74
  }
79
75
  };
@@ -84,11 +80,9 @@ const printProperty = property => {
84
80
  if (property === ApplyProp) {
85
81
  return '';
86
82
  }
87
-
88
83
  if (typeof property === 'symbol') {
89
84
  return `[${property.toString()}]`;
90
85
  }
91
-
92
86
  return `.${property}`;
93
87
  };
94
88
  const printValue = arg => {
@@ -96,20 +90,15 @@ const printValue = arg => {
96
90
  if (isMatcher(arg)) {
97
91
  return arg.toString();
98
92
  }
99
-
100
93
  return jestMatcherUtils.stringify(arg);
101
94
  };
102
-
103
95
  const printArgs = args => args.map(arg => printValue(arg)).join(', ');
104
-
105
96
  const printCall = (property, args) => {
106
97
  const prettyProperty = printProperty(property);
107
-
108
98
  if (args) {
109
99
  const prettyArgs = printArgs(args);
110
100
  return `mock${jestMatcherUtils.RECEIVED_COLOR(`${prettyProperty}(${prettyArgs})`)}`;
111
101
  }
112
-
113
102
  return `mock${jestMatcherUtils.RECEIVED_COLOR(`${prettyProperty}`)}`;
114
103
  };
115
104
  const printReturns = ({
@@ -118,7 +107,6 @@ const printReturns = ({
118
107
  value
119
108
  }, min, max) => {
120
109
  let thenPrefix = '';
121
-
122
110
  if (isPromise) {
123
111
  if (isError) {
124
112
  thenPrefix += 'thenReject';
@@ -130,16 +118,13 @@ const printReturns = ({
130
118
  } else {
131
119
  thenPrefix += 'thenReturn';
132
120
  }
133
-
134
121
  return `.${thenPrefix}(${jestMatcherUtils.RECEIVED_COLOR(printValue(value))}).between(${min}, ${max})`;
135
122
  };
136
123
  const printWhen = (property, args) => {
137
124
  const prettyProperty = printProperty(property);
138
-
139
125
  if (args) {
140
126
  return `when(() => mock${jestMatcherUtils.EXPECTED_COLOR(`${prettyProperty}(${printArgs(args)})`)})`;
141
127
  }
142
-
143
128
  return `when(() => mock${jestMatcherUtils.EXPECTED_COLOR(`${printProperty(property)}`)})`;
144
129
  };
145
130
  const printExpectation = (property, args, returnValue, min, max) => `${printWhen(property, args)}${printReturns(returnValue, min, max)}`;
@@ -155,7 +140,6 @@ set an expectation for it.
155
140
 
156
141
  ${printRemainingExpectations(expectations)}`));
157
142
  }
158
-
159
143
  }
160
144
 
161
145
  const printArgsDiff = (expected, actual) => {
@@ -163,14 +147,12 @@ const printArgsDiff = (expected, actual) => {
163
147
  omitAnnotationLines: true
164
148
  });
165
149
  /* istanbul ignore next this is not expected in practice */
166
-
167
150
  if (!diff) {
168
151
  return '';
169
152
  }
170
-
171
153
  const ansilessDiffLines = stripAnsi__default["default"](diff).split('\n');
172
- let relevantDiffLines; // Strip Array [ ... ] surroundings.
173
-
154
+ let relevantDiffLines;
155
+ // Strip Array [ ... ] surroundings.
174
156
  if (!expected.length) {
175
157
  // - Array []
176
158
  // + Array [
@@ -188,20 +170,16 @@ const printArgsDiff = (expected, actual) => {
188
170
  // ...
189
171
  // ]
190
172
  relevantDiffLines = ansilessDiffLines.slice(1, -1);
191
- } // Strip the trailing comma.
192
-
193
-
173
+ }
174
+ // Strip the trailing comma.
194
175
  const lastLine = relevantDiffLines[relevantDiffLines.length - 1].slice(0, -1);
195
176
  const coloredDiffLines = [...relevantDiffLines.slice(0, -1), lastLine].map(line => {
196
177
  const first = line.charAt(0);
197
-
198
178
  switch (first) {
199
179
  case '-':
200
180
  return jestMatcherUtils.EXPECTED_COLOR(line);
201
-
202
181
  case '+':
203
182
  return jestMatcherUtils.RECEIVED_COLOR(line);
204
-
205
183
  default:
206
184
  return line;
207
185
  }
@@ -210,11 +188,9 @@ const printArgsDiff = (expected, actual) => {
210
188
  };
211
189
  const printExpectationDiff = (e, args) => {
212
190
  var _e$args;
213
-
214
191
  if (!((_e$args = e.args) != null && _e$args.length)) {
215
192
  return '';
216
193
  }
217
-
218
194
  const {
219
195
  actual,
220
196
  expected
@@ -223,7 +199,6 @@ const printExpectationDiff = (e, args) => {
223
199
  };
224
200
  const printDiffForAllExpectations = (expectations, actual) => expectations.map(e => {
225
201
  const diff = printExpectationDiff(e, actual);
226
-
227
202
  if (diff) {
228
203
  return `${e.toString()}
229
204
  ${jestMatcherUtils.EXPECTED_COLOR('- Expected')}
@@ -231,7 +206,6 @@ ${jestMatcherUtils.RECEIVED_COLOR('+ Received')}
231
206
 
232
207
  ${diff}`;
233
208
  }
234
-
235
209
  return undefined;
236
210
  }).filter(x => x).join('\n\n');
237
211
 
@@ -239,18 +213,15 @@ class UnexpectedCall extends Error {
239
213
  constructor(property, args, expectations) {
240
214
  const header = `Didn't expect ${printCall(property, args)} to be called.`;
241
215
  const propertyExpectations = expectations.filter(e => e.property === property);
242
-
243
216
  if (propertyExpectations.length) {
244
217
  var _propertyExpectations;
245
-
246
218
  super(jestMatcherUtils.DIM_COLOR(`${header}
247
219
 
248
220
  Remaining expectations:
249
- ${printDiffForAllExpectations(propertyExpectations, args)}`)); // If we have a single expectation we can attach the actual/expected args
221
+ ${printDiffForAllExpectations(propertyExpectations, args)}`));
222
+ // If we have a single expectation we can attach the actual/expected args
250
223
  // to the error instance, so that an IDE may show its own diff for them.
251
-
252
224
  this.matcherResult = void 0;
253
-
254
225
  if (propertyExpectations.length === 1 && (_propertyExpectations = propertyExpectations[0].args) != null && _propertyExpectations.length) {
255
226
  const {
256
227
  actual,
@@ -268,11 +239,9 @@ No remaining expectations.`));
268
239
  this.matcherResult = void 0;
269
240
  }
270
241
  }
271
-
272
242
  }
273
243
 
274
244
  exports.UnexpectedProperty = void 0;
275
-
276
245
  (function (UnexpectedProperty) {
277
246
  /**
278
247
  * Throw an error immediately.
@@ -307,7 +276,6 @@ exports.UnexpectedProperty = void 0;
307
276
  * // Will throw "Didn't expect foo(42) to be called".
308
277
  * foo(42);
309
278
  */
310
-
311
279
  UnexpectedProperty[UnexpectedProperty["CALL_THROW"] = 1] = "CALL_THROW";
312
280
  })(exports.UnexpectedProperty || (exports.UnexpectedProperty = {}));
313
281
 
@@ -328,21 +296,16 @@ const unboxReturnValue = ({
328
296
  if (isPromise) {
329
297
  return Promise.reject(value);
330
298
  }
331
-
332
299
  throw value;
333
300
  }
334
-
335
301
  if (isPromise) {
336
302
  return Promise.reject(new Error(value));
337
303
  }
338
-
339
304
  throw new Error(value);
340
305
  }
341
-
342
306
  if (isPromise) {
343
307
  return Promise.resolve(value);
344
308
  }
345
-
346
309
  return value;
347
310
  };
348
311
 
@@ -350,16 +313,13 @@ const unboxReturnValue = ({
350
313
  * An expectation repository with a configurable behavior for
351
314
  * unexpected property access.
352
315
  */
353
-
354
316
  class FlexibleRepository {
355
317
  constructor(unexpectedProperty = exports.UnexpectedProperty.THROW) {
356
318
  this.unexpectedProperty = void 0;
357
319
  this.expectations = new Map();
358
320
  this.expectedCallStats = new Map();
359
321
  this.unexpectedCallStats = new Map();
360
-
361
322
  this.apply = args => this.get(ApplyProp)(...args);
362
-
363
323
  this.handlePropertyWithMatchingExpectations = (property, expectations) => {
364
324
  // Avoid recording call stats for function calls, since the property is an
365
325
  // internal detail.
@@ -368,63 +328,49 @@ class FlexibleRepository {
368
328
  // function that will not match the given args.
369
329
  this.recordExpected(property, undefined);
370
330
  }
371
-
372
331
  const propertyExpectation = expectations.find(e => e.expectation.matches(undefined));
373
-
374
332
  if (propertyExpectation) {
375
333
  this.countAndConsume(propertyExpectation);
376
334
  return unboxReturnValue(propertyExpectation.expectation.returnValue);
377
335
  }
378
-
379
336
  return (...args) => {
380
337
  const callExpectation = expectations.find(e => e.expectation.matches(args));
381
-
382
338
  if (callExpectation) {
383
339
  this.recordExpected(property, args);
384
340
  this.countAndConsume(callExpectation);
385
341
  return unboxReturnValue(callExpectation.expectation.returnValue);
386
342
  }
387
-
388
343
  return this.getValueForUnexpectedCall(property, args);
389
344
  };
390
345
  };
391
-
392
346
  this.handlePropertyWithNoExpectations = property => {
393
347
  switch (property) {
394
348
  case 'toString':
395
349
  return () => 'mock';
396
-
397
350
  case '@@toStringTag':
398
351
  case Symbol.toStringTag:
399
352
  case 'name':
400
353
  return 'mock';
401
354
  // Promise.resolve() tries to see if it's a "thenable".
402
355
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
403
-
404
356
  case 'then':
405
357
  return undefined;
406
358
  // pretty-format
407
-
408
359
  case '$$typeof':
409
360
  case 'constructor':
410
361
  case '@@__IMMUTABLE_ITERABLE__@@':
411
362
  case '@@__IMMUTABLE_RECORD__@@':
412
363
  return null;
413
-
414
364
  case MATCHER_SYMBOL:
415
365
  return false;
416
-
417
366
  case ApplyProp:
418
367
  return (...args) => this.getValueForUnexpectedCall(property, args);
419
-
420
368
  default:
421
369
  return this.getValueForUnexpectedAccess(property);
422
370
  }
423
371
  };
424
-
425
372
  this.unexpectedProperty = unexpectedProperty;
426
373
  }
427
-
428
374
  add(expectation) {
429
375
  const {
430
376
  property
@@ -435,89 +381,73 @@ class FlexibleRepository {
435
381
  matchCount: 0
436
382
  }]);
437
383
  }
438
-
439
384
  clear() {
440
385
  this.expectations.clear();
441
386
  this.expectedCallStats.clear();
442
387
  this.unexpectedCallStats.clear();
443
388
  }
444
-
445
389
  // TODO: this returns any, but the interface returns unknown
446
390
  // unknown causes errors in apply tests, and any causes bugs in bootstrapped SM
447
391
  get(property) {
448
392
  const expectations = this.expectations.get(property);
449
-
450
393
  if (expectations && expectations.length) {
451
394
  return this.handlePropertyWithMatchingExpectations(property, expectations);
452
395
  }
453
-
454
396
  return this.handlePropertyWithNoExpectations(property);
455
397
  }
456
-
457
398
  getAllProperties() {
458
399
  return Array.from(this.expectations.keys());
459
400
  }
460
-
461
401
  getCallStats() {
462
402
  return {
463
403
  expected: this.expectedCallStats,
464
404
  unexpected: this.unexpectedCallStats
465
405
  };
466
406
  }
467
-
468
407
  getUnmet() {
469
408
  return [].concat(...Array.from(this.expectations.values()).map(expectations => expectations.filter(e => e.expectation.min > e.matchCount).map(e => e.expectation)));
470
409
  }
471
-
472
410
  recordExpected(property, args) {
473
411
  const calls = this.expectedCallStats.get(property) || [];
474
412
  this.expectedCallStats.set(property, [...calls, {
475
413
  arguments: args
476
414
  }]);
477
415
  }
478
-
479
416
  recordUnexpected(property, args) {
480
417
  const calls = this.unexpectedCallStats.get(property) || [];
481
418
  this.unexpectedCallStats.set(property, [...calls, {
482
419
  arguments: args
483
420
  }]);
484
421
  }
485
-
486
422
  countAndConsume(expectation) {
487
423
  // eslint-disable-next-line no-param-reassign
488
424
  expectation.matchCount++;
489
425
  this.consumeExpectation(expectation);
490
426
  }
491
-
492
427
  consumeExpectation(expectation) {
493
428
  const {
494
429
  property,
495
430
  max
496
431
  } = expectation.expectation;
497
432
  const expectations = this.expectations.get(property);
498
-
499
433
  if (expectation.matchCount === max) {
500
434
  this.expectations.set(property, expectations.filter(e => e !== expectation));
501
435
  }
502
436
  }
503
-
504
437
  getValueForUnexpectedCall(property, args) {
505
438
  this.recordUnexpected(property, args);
506
439
  throw new UnexpectedCall(property, args, this.getUnmet());
507
440
  }
508
-
509
441
  getValueForUnexpectedAccess(property) {
510
442
  if (this.unexpectedProperty === exports.UnexpectedProperty.THROW) {
511
443
  this.recordUnexpected(property, undefined);
512
444
  throw new UnexpectedAccess(property, this.getUnmet());
513
445
  }
514
-
515
446
  return (...args) => {
516
447
  this.recordUnexpected(property, args);
517
448
  throw new UnexpectedCall(property, args, this.getUnmet());
518
449
  };
519
450
  }
520
-
521
451
  }
522
452
 
523
453
  /**
@@ -531,7 +461,6 @@ class FlexibleRepository {
531
461
  * 23
532
462
  * ).matches('bar', [1, 2, 3]) === true;
533
463
  */
534
-
535
464
  class StrongExpectation {
536
465
  constructor(property, args, returnValue, exactParams = false) {
537
466
  this.property = void 0;
@@ -546,47 +475,37 @@ class StrongExpectation {
546
475
  this.returnValue = returnValue;
547
476
  this.exactParams = exactParams;
548
477
  }
549
-
550
478
  setInvocationCount(min, max = 1) {
551
479
  this.min = min;
552
480
  this.max = max;
553
481
  }
554
-
555
482
  matches(args) {
556
483
  if (!this.matchesArgs(args)) {
557
484
  return false;
558
485
  }
559
-
560
486
  this.matched++;
561
487
  return this.max === 0 || this.matched <= this.max;
562
488
  }
563
-
564
489
  isUnmet() {
565
490
  return this.matched < this.min;
566
491
  }
567
-
568
492
  matchesArgs(received) {
569
493
  if (this.args === undefined) {
570
494
  return !received;
571
495
  }
572
-
573
496
  if (!received) {
574
497
  return false;
575
498
  }
576
-
577
499
  if (this.exactParams) {
578
500
  if (this.args.length !== received.length) {
579
501
  return false;
580
502
  }
581
503
  }
582
-
583
504
  return this.args.every((arg, i) => arg.matches(received[i]));
584
505
  }
585
-
586
506
  toString() {
587
507
  return printExpectation(this.property, this.args, this.returnValue, this.min, this.max);
588
508
  }
589
-
590
509
  }
591
510
 
592
511
  class UnfinishedExpectation extends Error {
@@ -598,7 +517,6 @@ ${printWhen(property, args)}
598
517
  Please finish it by setting a return value even if the value
599
518
  is undefined.`);
600
519
  }
601
-
602
520
  }
603
521
  class MissingWhen extends Error {
604
522
  constructor() {
@@ -606,7 +524,6 @@ class MissingWhen extends Error {
606
524
 
607
525
  Every call to set a return value must be preceded by an expectation.`);
608
526
  }
609
-
610
527
  }
611
528
  class NotAMock extends Error {
612
529
  constructor() {
@@ -614,7 +531,6 @@ class NotAMock extends Error {
614
531
 
615
532
  Make sure you're passing in an actual mock.`);
616
533
  }
617
-
618
534
  }
619
535
  class NestedWhen extends Error {
620
536
  constructor(parentProp, childProp) {
@@ -631,7 +547,6 @@ You can return an object directly when the first property is accessed,
631
547
  or you can even return a separate mock:
632
548
  ${snippet}`);
633
549
  }
634
-
635
550
  }
636
551
 
637
552
  class ExpectationBuilderWithFactory {
@@ -645,59 +560,33 @@ class ExpectationBuilderWithFactory {
645
560
  this.concreteMatcher = concreteMatcher;
646
561
  this.exactParams = exactParams;
647
562
  }
648
-
649
563
  setProperty(value) {
650
564
  if (this.property) {
651
565
  throw new UnfinishedExpectation(this.property, this.args);
652
566
  }
653
-
654
567
  this.property = value;
655
568
  }
656
-
657
569
  setArgs(value) {
658
570
  this.args = value;
659
571
  }
660
-
661
572
  finish(returnValue) {
662
573
  if (!this.property) {
663
574
  throw new MissingWhen();
664
575
  }
665
-
666
576
  const expectation = this.createExpectation(this.property, this.args, returnValue, this.concreteMatcher, this.exactParams);
667
577
  this.property = undefined;
668
578
  this.args = undefined;
669
579
  return expectation;
670
580
  }
671
-
672
- }
673
-
674
- function _extends() {
675
- _extends = Object.assign || function (target) {
676
- for (var i = 1; i < arguments.length; i++) {
677
- var source = arguments[i];
678
-
679
- for (var key in source) {
680
- if (Object.prototype.hasOwnProperty.call(source, key)) {
681
- target[key] = source[key];
682
- }
683
- }
684
- }
685
-
686
- return target;
687
- };
688
-
689
- return _extends.apply(this, arguments);
690
581
  }
691
582
 
692
583
  const removeUndefined = object => {
693
584
  if (Array.isArray(object)) {
694
585
  return object.map(x => removeUndefined(x));
695
586
  }
696
-
697
587
  if (!lodash.isObjectLike(object)) {
698
588
  return object;
699
589
  }
700
-
701
590
  return lodash.omitBy(object, lodash.isUndefined);
702
591
  };
703
592
  /**
@@ -709,18 +598,15 @@ const removeUndefined = object => {
709
598
  * non `Object` instances with different constructors as not equal. Setting
710
599
  * this to `false` will consider the objects in both cases as equal.
711
600
  *
712
- * @see {@link It.isPartial} or {@link It.isArray} if you want to nest matchers.
601
+ * @see {@link It.containsObject} or {@link It.isArray} if you want to nest matchers.
713
602
  * @see {@link It.is} if you want to use strict equality.
714
603
  */
715
-
716
-
717
604
  const deepEquals = (expected, {
718
605
  strict = true
719
606
  } = {}) => matches(actual => {
720
607
  if (strict) {
721
608
  return lodash.isEqual(actual, expected);
722
609
  }
723
-
724
610
  return lodash.isEqual(removeUndefined(actual), removeUndefined(expected));
725
611
  }, {
726
612
  toString: () => printValue(expected),
@@ -743,9 +629,11 @@ let currentDefaults = defaults;
743
629
  * calls don't stack e.g. calling this with `{}` will clear any previously
744
630
  * applied defaults.
745
631
  */
746
-
747
632
  const setDefaults = newDefaults => {
748
- currentDefaults = _extends({}, defaults, newDefaults);
633
+ currentDefaults = {
634
+ ...defaults,
635
+ ...newDefaults
636
+ };
749
637
  };
750
638
 
751
639
  /**
@@ -763,7 +651,6 @@ const setDefaults = newDefaults => {
763
651
  * For that reason we can't just store the currently active mock, but also
764
652
  * whether we finished the expectation or not.
765
653
  */
766
-
767
654
  let activeMock;
768
655
  const setActiveMock = mock => {
769
656
  activeMock = mock;
@@ -775,13 +662,11 @@ const getActiveMock = () => activeMock;
775
662
  * This is needed because we can't reliably pass the state between `when`
776
663
  * and `thenReturn`.
777
664
  */
778
-
779
665
  const mockMap = new Map();
780
666
  const getMockState = mock => {
781
667
  if (mockMap.has(mock)) {
782
668
  return mockMap.get(mock);
783
669
  }
784
-
785
670
  throw new NotAMock();
786
671
  };
787
672
  const setMockState = (mock, state) => {
@@ -789,43 +674,35 @@ const setMockState = (mock, state) => {
789
674
  };
790
675
  const getAllMocks = () => Array.from(mockMap.entries());
791
676
 
792
- const createProxy = traps => // The Proxy target MUST be a function, otherwise we can't use the `apply` trap:
677
+ const createProxy = traps =>
678
+ // The Proxy target MUST be a function, otherwise we can't use the `apply` trap:
793
679
  // https://262.ecma-international.org/6.0/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
794
680
  // eslint-disable-next-line no-empty-function,@typescript-eslint/no-empty-function
795
- new Proxy(
796
- /* istanbul ignore next */
797
- () => {}, {
681
+ new Proxy( /* istanbul ignore next */() => {}, {
798
682
  get: (target, prop) => {
799
683
  if (prop === 'bind') {
800
684
  return (thisArg, ...args) => (...moreArgs) => traps.apply([...args, ...moreArgs]);
801
685
  }
802
-
803
686
  if (prop === 'apply') {
804
687
  return (thisArg, args) => traps.apply(args || []);
805
688
  }
806
-
807
689
  if (prop === 'call') {
808
690
  return (thisArg, ...args) => traps.apply(args);
809
691
  }
810
-
811
692
  return traps.property(prop);
812
693
  },
813
694
  apply: (target, thisArg, args) => traps.apply(args),
814
695
  ownKeys: () => traps.ownKeys(),
815
-
816
696
  getOwnPropertyDescriptor(target, prop) {
817
697
  const keys = traps.ownKeys();
818
-
819
698
  if (keys.includes(prop)) {
820
699
  return {
821
700
  configurable: true,
822
701
  enumerable: true
823
702
  };
824
703
  }
825
-
826
704
  return undefined;
827
705
  }
828
-
829
706
  });
830
707
 
831
708
  const createStub = (repo, builder, getCurrentMode) => {
@@ -834,7 +711,6 @@ const createStub = (repo, builder, getCurrentMode) => {
834
711
  if (getCurrentMode() === Mode.CALL) {
835
712
  return repo.get(property);
836
713
  }
837
-
838
714
  setActiveMock(stub);
839
715
  builder.setProperty(property);
840
716
  return createProxy({
@@ -853,7 +729,6 @@ const createStub = (repo, builder, getCurrentMode) => {
853
729
  if (getCurrentMode() === Mode.CALL) {
854
730
  return repo.apply(args);
855
731
  }
856
-
857
732
  setActiveMock(stub);
858
733
  builder.setProperty(ApplyProp);
859
734
  builder.setArgs(args);
@@ -863,7 +738,6 @@ const createStub = (repo, builder, getCurrentMode) => {
863
738
  if (getCurrentMode() === Mode.CALL) {
864
739
  return repo.getAllProperties();
865
740
  }
866
-
867
741
  throw new Error('Spreading during an expectation is not supported.');
868
742
  }
869
743
  });
@@ -872,19 +746,15 @@ const createStub = (repo, builder, getCurrentMode) => {
872
746
 
873
747
  const strongExpectationFactory = (property, args, returnValue, concreteMatcher, exactParams) => new StrongExpectation(property, // Wrap every non-matcher in the default matcher.
874
748
  args == null ? void 0 : args.map(arg => isMatcher(arg) ? arg : concreteMatcher(arg)), returnValue, exactParams);
875
-
876
749
  var Mode;
877
-
878
750
  (function (Mode) {
879
751
  Mode[Mode["EXPECT"] = 0] = "EXPECT";
880
752
  Mode[Mode["CALL"] = 1] = "CALL";
881
753
  })(Mode || (Mode = {}));
882
-
883
754
  let currentMode = Mode.CALL;
884
755
  const setMode = mode => {
885
756
  currentMode = mode;
886
757
  };
887
-
888
758
  const getMode = () => currentMode;
889
759
  /**
890
760
  * Create a type safe mock.
@@ -907,8 +777,6 @@ const getMode = () => currentMode;
907
777
  *
908
778
  * fn() === 23;
909
779
  */
910
-
911
-
912
780
  const mock = ({
913
781
  unexpectedProperty,
914
782
  concreteMatcher,
@@ -934,39 +802,31 @@ const createInvocationCount = expectation => ({
934
802
  between(min, max) {
935
803
  expectation.setInvocationCount(min, max);
936
804
  },
937
-
938
805
  /* istanbul ignore next */
939
806
  times(exact) {
940
807
  expectation.setInvocationCount(exact, exact);
941
808
  },
942
-
943
809
  /* istanbul ignore next */
944
810
  anyTimes() {
945
811
  expectation.setInvocationCount(0, 0);
946
812
  },
947
-
948
813
  /* istanbul ignore next */
949
814
  atLeast(min) {
950
815
  expectation.setInvocationCount(min, Infinity);
951
816
  },
952
-
953
817
  /* istanbul ignore next */
954
818
  atMost(max) {
955
819
  expectation.setInvocationCount(0, max);
956
820
  },
957
-
958
821
  /* istanbul ignore next */
959
822
  once() {
960
823
  expectation.setInvocationCount(1, 1);
961
824
  },
962
-
963
825
  /* istanbul ignore next */
964
826
  twice() {
965
827
  expectation.setInvocationCount(2, 2);
966
828
  }
967
829
  /* eslint-enable no-param-reassign, no-multi-assign */
968
-
969
-
970
830
  });
971
831
 
972
832
  const finishExpectation = (returnValue, builder, repo) => {
@@ -974,21 +834,18 @@ const finishExpectation = (returnValue, builder, repo) => {
974
834
  repo.add(finishedExpectation);
975
835
  return createInvocationCount(finishedExpectation);
976
836
  };
977
-
978
837
  const getError = errorOrMessage => {
979
838
  if (typeof errorOrMessage === 'string') {
980
839
  return new Error(errorOrMessage);
981
840
  }
982
-
983
841
  if (errorOrMessage instanceof Error) {
984
842
  return errorOrMessage;
985
843
  }
986
-
987
844
  return new Error();
988
845
  };
989
-
990
846
  const createReturns = (builder, repository) => ({
991
- thenReturn: returnValue => finishExpectation( // This will handle both thenReturn(23) and thenReturn(Promise.resolve(3)).
847
+ thenReturn: returnValue => finishExpectation(
848
+ // This will handle both thenReturn(23) and thenReturn(Promise.resolve(3)).
992
849
  {
993
850
  value: returnValue,
994
851
  isError: false,
@@ -1036,7 +893,6 @@ const createReturns = (builder, repository) => ({
1036
893
  * const fn = mock<(x: number) => Promise<number>();
1037
894
  * when(() => fn(23)).thenResolve(42);
1038
895
  */
1039
-
1040
896
  const when = expectation => {
1041
897
  setMode(Mode.EXPECT);
1042
898
  expectation();
@@ -1060,7 +916,6 @@ const when = expectation => {
1060
916
  *
1061
917
  * fn(); // throws
1062
918
  */
1063
-
1064
919
  const reset = mock => {
1065
920
  getMockState(mock).repository.clear();
1066
921
  };
@@ -1069,7 +924,6 @@ const reset = mock => {
1069
924
  *
1070
925
  * @see reset
1071
926
  */
1072
-
1073
927
  const resetAll = () => {
1074
928
  getAllMocks().forEach(([mock]) => {
1075
929
  reset(mock);
@@ -1082,7 +936,6 @@ class UnmetExpectations extends Error {
1082
936
 
1083
937
  - ${expectations.map(e => e.toString()).join('\n - ')}`));
1084
938
  }
1085
-
1086
939
  }
1087
940
  /**
1088
941
  * Merge property accesses and method calls for the same property
@@ -1092,18 +945,14 @@ class UnmetExpectations extends Error {
1092
945
  * mergeCalls({ getData: [{ arguments: undefined }, { arguments: [1, 2, 3] }] }
1093
946
  * // returns { getData: [{ arguments: [1, 2, 3] } }
1094
947
  */
1095
-
1096
948
  const mergeCalls = callMap => new Map(Array.from(callMap.entries()).map(([property, calls]) => {
1097
949
  const hasMethodCalls = calls.some(call => call.arguments);
1098
950
  const hasPropertyAccesses = calls.some(call => !call.arguments);
1099
-
1100
951
  if (hasMethodCalls && hasPropertyAccesses) {
1101
952
  return [property, calls.filter(call => call.arguments)];
1102
953
  }
1103
-
1104
954
  return [property, calls];
1105
955
  }));
1106
-
1107
956
  class UnexpectedCalls extends Error {
1108
957
  constructor(unexpectedCalls, expectations) {
1109
958
  const printedCalls = Array.from(mergeCalls(unexpectedCalls).entries()).map(([property, calls]) => calls.map(call => printCall(property, call.arguments)).join('\n - ')).join('\n - ');
@@ -1113,18 +962,14 @@ class UnexpectedCalls extends Error {
1113
962
 
1114
963
  ${printRemainingExpectations(expectations)}`));
1115
964
  }
1116
-
1117
965
  }
1118
966
 
1119
967
  const verifyRepo = repository => {
1120
968
  const unmetExpectations = repository.getUnmet();
1121
-
1122
969
  if (unmetExpectations.length) {
1123
970
  throw new UnmetExpectations(unmetExpectations);
1124
971
  }
1125
-
1126
972
  const callStats = repository.getCallStats();
1127
-
1128
973
  if (callStats.unexpected.size) {
1129
974
  throw new UnexpectedCalls(callStats.unexpected, unmetExpectations);
1130
975
  }
@@ -1146,7 +991,6 @@ const verifyRepo = repository => {
1146
991
  *
1147
992
  * verify(fn); // throws
1148
993
  */
1149
-
1150
994
  const verify = mock => {
1151
995
  const {
1152
996
  repository
@@ -1158,7 +1002,6 @@ const verify = mock => {
1158
1002
  *
1159
1003
  * @see verify
1160
1004
  */
1161
-
1162
1005
  const verifyAll = () => {
1163
1006
  getAllMocks().forEach(([mock]) => {
1164
1007
  verify(mock);
@@ -1172,7 +1015,6 @@ const verifyAll = () => {
1172
1015
  *
1173
1016
  * @see It.deepEquals A matcher that uses deep equality.
1174
1017
  */
1175
-
1176
1018
  const is = expected => matches(actual => Object.is(actual, expected), {
1177
1019
  toString: () => `${printValue(expected)}`,
1178
1020
  getDiff: actual => ({
@@ -1190,7 +1032,6 @@ const is = expected => matches(actual => Object.is(actual, expected), {
1190
1032
  *
1191
1033
  * fn(23, 'foobar') === 1
1192
1034
  */
1193
-
1194
1035
  const isAny = () => matches(() => true, {
1195
1036
  toString: () => 'Matcher<any>'
1196
1037
  });
@@ -1215,21 +1056,17 @@ const isAny = () => matches(() => true, {
1215
1056
  * @example
1216
1057
  * It.isArray([It.isString({ containing: 'foobar' })])
1217
1058
  */
1218
-
1219
1059
  const isArray = containing => matches(actual => {
1220
1060
  if (!Array.isArray(actual)) {
1221
1061
  return false;
1222
1062
  }
1223
-
1224
1063
  if (!containing) {
1225
1064
  return true;
1226
1065
  }
1227
-
1228
1066
  return containing.every(x => actual.find(y => {
1229
1067
  if (isMatcher(x)) {
1230
1068
  return x.matches(y);
1231
1069
  }
1232
-
1233
1070
  return deepEquals(x).matches(y);
1234
1071
  }) !== undefined);
1235
1072
  }, {
@@ -1242,12 +1079,10 @@ const isArray = containing => matches(actual => {
1242
1079
  if (isMatcher(value)) {
1243
1080
  return value.toString();
1244
1081
  }
1245
-
1246
1082
  return value;
1247
1083
  }).join(', ')}])`
1248
1084
  };
1249
1085
  }
1250
-
1251
1086
  return {
1252
1087
  actual: `${printValue(actual)} (${typeof actual})`,
1253
1088
  expected: 'Matcher<array>'
@@ -1265,7 +1100,6 @@ const isArray = containing => matches(actual => {
1265
1100
  * fn(20.5) === 42
1266
1101
  * fn(NaN) // throws
1267
1102
  */
1268
-
1269
1103
  const isNumber = () => matches(actual => typeof actual === 'number' && !Number.isNaN(actual), {
1270
1104
  toString: () => 'Matcher<number>',
1271
1105
  getDiff: actual => ({
@@ -1278,7 +1112,7 @@ const isNumber = () => matches(actual => typeof actual === 'number' && !Number.i
1278
1112
  * Matches any plain object e.g. object literals or objects created with `Object.create()`.
1279
1113
  *
1280
1114
  * Classes, arrays, maps, sets etc. are not considered plain objects.
1281
- * You can use {@link isPartial} or {@link matches} to match those.
1115
+ * You can use {@link containsObject} or {@link matches} to match those.
1282
1116
  *
1283
1117
  * @example
1284
1118
  * const fn = mock<({ foo: string }) => number>();
@@ -1286,7 +1120,6 @@ const isNumber = () => matches(actual => typeof actual === 'number' && !Number.i
1286
1120
  *
1287
1121
  * fn({ foo: 'bar' }) // returns 42
1288
1122
  */
1289
-
1290
1123
  const isPlainObject = () => matches(actual => lodash.isPlainObject(actual), {
1291
1124
  toString: () => 'Matcher<object>',
1292
1125
  getDiff: actual => {
@@ -1299,89 +1132,68 @@ const isPlainObject = () => matches(actual => lodash.isPlainObject(actual), {
1299
1132
  });
1300
1133
 
1301
1134
  const looksLikeObject = value => lodash.isPlainObject(value);
1302
-
1303
1135
  const getExpectedObjectDiff = (actual, expected) => Object.fromEntries(getKeys(expected).map(key => {
1304
1136
  const expectedValue = getKey(expected, key);
1305
1137
  const actualValue = getKey(actual, key);
1306
-
1307
1138
  if (isMatcher(expectedValue)) {
1308
1139
  return [key, expectedValue.getDiff(actualValue).expected];
1309
1140
  }
1310
-
1311
1141
  if (looksLikeObject(expectedValue)) {
1312
1142
  return [key, getExpectedObjectDiff(actualValue, expectedValue)];
1313
1143
  }
1314
-
1315
1144
  return [key, expectedValue];
1316
1145
  }));
1317
-
1318
1146
  const getActualObjectDiff = (actual, expected) => {
1319
1147
  const actualKeys = getKeys(actual);
1320
1148
  const expectedKeys = new Set(getKeys(expected));
1321
1149
  const commonKeys = actualKeys.filter(key => expectedKeys.has(key));
1322
-
1323
1150
  if (!commonKeys.length) {
1324
1151
  // When we don't have any common keys we return the whole object
1325
1152
  // so the user can inspect what's in there.
1326
1153
  return actual;
1327
1154
  }
1328
-
1329
1155
  return Object.fromEntries(commonKeys.map(key => {
1330
1156
  const expectedValue = getKey(expected, key);
1331
1157
  const actualValue = getKey(actual, key);
1332
-
1333
1158
  if (isMatcher(expectedValue)) {
1334
1159
  return [key, expectedValue.getDiff(actualValue).actual];
1335
1160
  }
1336
-
1337
1161
  if (looksLikeObject(expectedValue)) {
1338
1162
  return [key, getActualObjectDiff(actualValue, expectedValue)];
1339
1163
  }
1340
-
1341
1164
  return [key, actualValue];
1342
1165
  }));
1343
1166
  };
1344
-
1345
1167
  const getKeys = value => {
1346
1168
  if (typeof value === 'object' && value !== null) {
1347
1169
  return Reflect.ownKeys(value);
1348
1170
  }
1349
-
1350
1171
  return [];
1351
1172
  };
1352
-
1353
1173
  const getKey = (value, key) => // @ts-expect-error because we're fine with a runtime undefined value
1354
1174
  value == null ? void 0 : value[key];
1355
-
1356
1175
  const isMatch = (actual, expected) => {
1357
1176
  const actualKeys = getKeys(actual);
1358
1177
  const expectedKeys = getKeys(expected);
1359
-
1360
1178
  if (!isArray(expectedKeys).matches(actualKeys)) {
1361
1179
  return false;
1362
1180
  }
1363
-
1364
1181
  return expectedKeys.every(key => {
1365
1182
  const expectedValue = getKey(expected, key);
1366
1183
  const actualValue = getKey(actual, key);
1367
-
1368
1184
  if (isMatcher(expectedValue)) {
1369
1185
  return expectedValue.matches(actualValue);
1370
1186
  }
1371
-
1372
1187
  if (looksLikeObject(expectedValue)) {
1373
1188
  return isMatch(actualValue, expectedValue);
1374
1189
  }
1375
-
1376
1190
  return deepEquals(expectedValue).matches(actualValue);
1377
1191
  });
1378
1192
  };
1379
-
1380
1193
  const deepPrintObject = value => lodash.cloneDeepWith(value, value => {
1381
1194
  if (isMatcher(value)) {
1382
1195
  return value.toString();
1383
1196
  }
1384
-
1385
1197
  return undefined;
1386
1198
  });
1387
1199
  /**
@@ -1391,21 +1203,22 @@ const deepPrintObject = value => lodash.cloneDeepWith(value, value => {
1391
1203
  * @param partial A subset of the expected object that will be recursively matched.
1392
1204
  * Supports nested matchers.
1393
1205
  * Concrete values will be compared with {@link deepEquals}.
1394
- * Note that a `{}` partial will match ANY value including non-objects.
1395
- * Use {@link isPlainObject} if you want to match any plain object.
1206
+ *
1207
+ * @see {@link isPlainObject} if you want to match any plain object.
1396
1208
  *
1397
1209
  * @example
1398
1210
  * const fn = mock<(pos: { x: number, y: number }) => number>();
1399
- * when(() => fn(It.isPartial({ x: 23 }))).returns(42);
1211
+ * when(() => fn(It.containsObject({ x: 23 }))).returns(42);
1400
1212
  *
1401
1213
  * fn({ x: 23, y: 200 }) // returns 42
1402
1214
  *
1403
1215
  * @example
1404
- * It.isPartial({ foo: It.isString() })
1216
+ * It.containsObject({ foo: It.isString() })
1405
1217
  */
1406
-
1407
-
1408
- const isPartial = partial => matches(actual => isMatch(actual, partial), {
1218
+ // T is not constrained to ObjectType because of
1219
+ // https://github.com/microsoft/TypeScript/issues/57810,
1220
+ // but K is to avoid inferring non-object partials
1221
+ const containsObject = partial => matches(actual => isMatch(actual, partial), {
1409
1222
  toString: () => `Matcher<object>(${printValue(deepPrintObject(partial))})`,
1410
1223
  getDiff: actual => ({
1411
1224
  actual: getActualObjectDiff(actual, partial),
@@ -1426,27 +1239,22 @@ const isPartial = partial => matches(actual => isMatch(actual, partial), {
1426
1239
  * fn('foo', 'baz') // throws
1427
1240
  * fn('foo', 'bar') === 42
1428
1241
  */
1429
-
1430
1242
  const isString = matching => matches(actual => {
1431
1243
  if (typeof actual !== 'string') {
1432
1244
  return false;
1433
1245
  }
1434
-
1435
1246
  if (!matching) {
1436
1247
  return true;
1437
1248
  }
1438
-
1439
1249
  if (typeof matching === 'string') {
1440
1250
  return actual.indexOf(matching) !== -1;
1441
1251
  }
1442
-
1443
1252
  return matching.test(actual);
1444
1253
  }, {
1445
1254
  toString: () => {
1446
1255
  if (matching) {
1447
1256
  return `Matcher<string>(${matching})`;
1448
1257
  }
1449
-
1450
1258
  return 'Matcher<string>';
1451
1259
  },
1452
1260
  getDiff: actual => {
@@ -1456,7 +1264,6 @@ const isString = matching => matches(actual => {
1456
1264
  actual
1457
1265
  };
1458
1266
  }
1459
-
1460
1267
  return {
1461
1268
  expected: 'Matcher<string>',
1462
1269
  actual: `${actual} (${typeof actual})`
@@ -1481,7 +1288,6 @@ const isString = matching => matches(actual => {
1481
1288
  * fn(x => x + 1);
1482
1289
  * matcher.value?.(3) === 4
1483
1290
  */
1484
-
1485
1291
  const willCapture = name => {
1486
1292
  let capturedValue;
1487
1293
  const matcher = {
@@ -1495,11 +1301,9 @@ const willCapture = name => {
1495
1301
  actual,
1496
1302
  expected: actual
1497
1303
  }),
1498
-
1499
1304
  get value() {
1500
1305
  return capturedValue;
1501
1306
  }
1502
-
1503
1307
  };
1504
1308
  return matcher;
1505
1309
  };
@@ -1514,7 +1318,7 @@ var it = {
1514
1318
  isArray: isArray,
1515
1319
  isNumber: isNumber,
1516
1320
  isPlainObject: isPlainObject,
1517
- isPartial: isPartial,
1321
+ containsObject: containsObject,
1518
1322
  isString: isString,
1519
1323
  matches: matches,
1520
1324
  willCapture: willCapture