strong-mock 8.0.1 → 9.0.0-beta.1

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 (42) hide show
  1. package/README.md +143 -51
  2. package/dist/errors/api.d.ts +13 -0
  3. package/dist/errors/diff.d.ts +4 -0
  4. package/dist/errors/unexpected-access.d.ts +5 -0
  5. package/dist/errors/unexpected-call.d.ts +14 -0
  6. package/dist/errors/verify.d.ts +8 -0
  7. package/dist/expectation/expectation.d.ts +27 -30
  8. package/dist/expectation/repository/expectation-repository.d.ts +90 -90
  9. package/dist/expectation/repository/flexible-repository.d.ts +38 -38
  10. package/dist/expectation/repository/return-value.d.ts +13 -13
  11. package/dist/expectation/strong-expectation.d.ts +30 -30
  12. package/dist/index.d.ts +14 -9
  13. package/dist/index.js +827 -511
  14. package/dist/index.js.map +1 -1
  15. package/dist/matchers/deep-equals.d.ts +16 -0
  16. package/dist/matchers/is-any.d.ts +11 -0
  17. package/dist/matchers/is-array.d.ts +22 -0
  18. package/dist/matchers/is-number.d.ts +12 -0
  19. package/dist/matchers/is-partial.d.ts +27 -0
  20. package/dist/matchers/is-plain-object.d.ts +17 -0
  21. package/dist/matchers/is-string.d.ts +15 -0
  22. package/dist/matchers/is.d.ts +9 -0
  23. package/dist/matchers/it.d.ts +10 -0
  24. package/dist/matchers/matcher.d.ts +93 -0
  25. package/dist/matchers/will-capture.d.ts +21 -0
  26. package/dist/mock/defaults.d.ts +11 -11
  27. package/dist/mock/map.d.ts +16 -16
  28. package/dist/mock/mock.d.ts +29 -29
  29. package/dist/mock/options.d.ts +99 -99
  30. package/dist/mock/stub.d.ts +5 -5
  31. package/dist/print.d.ts +10 -10
  32. package/dist/proxy.d.ts +48 -48
  33. package/dist/return/invocation-count.d.ts +44 -44
  34. package/dist/return/returns.d.ts +61 -87
  35. package/dist/verify/reset.d.ts +20 -20
  36. package/dist/verify/verify.d.ts +27 -27
  37. package/dist/when/{pending-expectation.d.ts → expectation-builder.d.ts} +26 -31
  38. package/dist/when/when.d.ts +32 -32
  39. package/package.json +21 -17
  40. package/dist/errors.d.ts +0 -28
  41. package/dist/expectation/it.d.ts +0 -29
  42. package/dist/expectation/matcher.d.ts +0 -21
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <div align="center">
3
3
  <h1>💪 strong-mock</h1>
4
4
 
5
- <p>Simple type safe mocking library</p>
5
+ <p>Type safe mocking library for TypeScript</p>
6
6
  </div>
7
7
 
8
8
  ```typescript
@@ -29,8 +29,9 @@ console.log(foo.bar(23)); // 'I am strong!'
29
29
 
30
30
  - [Features](#features)
31
31
  - [Type safety](#type-safety)
32
- - [Useful error messages](#useful-error-messages)
33
- - [Type safe argument matchers](#type-safe-argument-matchers)
32
+ - [Matchers](#matchers)
33
+ - [Awesome error messages](#awesome-error-messages)
34
+ - [Works with Promises and Errors](#works-with-promises-and-errors)
34
35
  - [Installation](#installation)
35
36
  - [Requirements](#requirements)
36
37
  - [API](#api)
@@ -43,19 +44,23 @@ console.log(foo.bar(23)); // 'I am strong!'
43
44
  - [Throwing errors](#throwing-errors)
44
45
  - [Verifying expectations](#verifying-expectations)
45
46
  - [Resetting expectations](#resetting-expectations)
46
- - [Argument matchers](#argument-matchers)
47
+ - [Matchers](#matchers-1)
48
+ - [Creating your own matcher](#creating-your-own-matcher)
47
49
  - [Mock options](#mock-options)
48
50
  - [Unexpected property return value](#unexpected-property-return-value)
49
51
  - [Exact params](#exact-params)
50
52
  - [Concrete matcher](#concrete-matcher)
51
53
  - [FAQ](#faq)
52
54
  - [Why do I have to set all expectations first?](#why-do-i-have-to-set-all-expectations-first)
53
- - [Can I partially mock an existing object/function?](#can-i-partially-mock-an-existing-objectfunction)
54
- - [How do I set expectations on setters?](#how-do-i-set-expectations-on-setters)
55
55
  - [Why do I have to set a return value even if it's `undefined`?](#why-do-i-have-to-set-a-return-value-even-if-its-undefined)
56
+ - [Why do I get a `Didn't expect mock to be called` error?](#why-do-i-get-a-didnt-expect-mock-to-be-called-error)
57
+ - [Can I partially mock a concrete implementation?](#can-i-partially-mock-a-concrete-implementation)
58
+ - [How do I set expectations on setters?](#how-do-i-set-expectations-on-setters)
56
59
  - [How do I provide a function for the mock to call?](#how-do-i-provide-a-function-for-the-mock-to-call)
57
- - [Can I spread/enumerate a mock?](#can-i-spreadenumerate-a-mock)
60
+ - [Can I spread or enumerate a mock?](#can-i-spread-or-enumerate-a-mock)
61
+ - [Why does `typeof mock()` return `function`?](#why-does-typeof-mock-return-function)
58
62
  - [How can I ignore `undefined` keys when setting expectations on objects?](#how-can-i-ignore-undefined-keys-when-setting-expectations-on-objects)
63
+ - [How can I verify order of calls?](#how-can-i-verify-order-of-calls)
59
64
 
60
65
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
61
66
 
@@ -63,31 +68,57 @@ console.log(foo.bar(23)); // 'I am strong!'
63
68
 
64
69
  ### Type safety
65
70
 
66
- The mock expectations will share the same type guarantees as your production code, and you can safely refactor in an IDE knowing that all usages will be updated.
71
+ The mocks will share the same types as your production code, and you can safely refactor in an IDE knowing that all usages will be updated.
67
72
 
68
73
  ![Renaming production code and test code](media/rename-refactor.gif)
69
74
 
70
- ### Useful error messages
75
+ ### Matchers
76
+
77
+ You can use matchers to partially match values, or create complex expectations, while still maintaining type safety.
78
+
79
+ ![Type safe matchers](media/type-safe-matchers.png)
71
80
 
72
- Error messages include the property that has been accessed, any arguments passed to it and any remaining unmet expectations.
81
+ ### Awesome error messages
82
+
83
+ Failed expectations will print a visual diff, and even integrate with the IDE.
73
84
 
74
85
  ```typescript
75
86
  import { mock, when } from 'strong-mock';
76
87
 
77
- const fn = mock<(a: number, b: number, c: number) => number>();
88
+ const fn = mock<(pos: { x: number; y: number }) => boolean>();
78
89
 
79
- when(() => fn(1, 2, 3)).thenReturn(42);
90
+ when(() =>
91
+ fn(
92
+ It.isPartial({
93
+ x: It.isNumber(),
94
+ y: It.matches<number>((y) => y > 0)
95
+ })
96
+ )
97
+ ).thenReturn(true);
80
98
 
81
- fn(4, 5, 6);
99
+ fn({ x: 1, y: -1 });
82
100
  ```
83
101
 
84
- ![Test output showing details about mock expectations](media/error-messages.png)
102
+ ![Test output from the IDE showing details about a failed mock expectation](media/error-messages.png)
103
+
104
+ ### Works with Promises and Errors
105
+
106
+ ```typescript
107
+ import { mock, when } from 'strong-mock';
85
108
 
86
- ### Type safe argument matchers
109
+ const fn = mock<(id: number) => Promise<string>>();
87
110
 
88
- You can use argument matchers to partially match values, or create complex expectations, while still maintaining type safety.
111
+ when(() => fn(42)).thenResolve('foo');
112
+ when(() => fn(-1)).thenReject('oops');
89
113
 
90
- ![Type safe matcher showing a type error](media/type-safe-matchers.png)
114
+ console.log(await fn(42)); // foo
115
+
116
+ try {
117
+ await fn(-1);
118
+ } catch (e) {
119
+ console.log(e.message); // oops
120
+ }
121
+ ```
91
122
 
92
123
  ## Installation
93
124
 
@@ -99,6 +130,10 @@ npm i -D strong-mock
99
130
  yarn add -D strong-mock
100
131
  ```
101
132
 
133
+ ```shell
134
+ pnpm add -D strong-mock
135
+ ```
136
+
102
137
  ## Requirements
103
138
 
104
139
  strong-mock requires an environment that supports the [ES6 Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). This is necessary to create dynamic mocks from types because TypeScript does not support reflection i.e. exposing the type info at runtime.
@@ -107,7 +142,7 @@ strong-mock requires an environment that supports the [ES6 Proxy object](https:/
107
142
 
108
143
  ### Setting expectations
109
144
 
110
- Expectations are set by calling the mock inside a `when` callback and finishing it by setting a return value.
145
+ Expectations are set by calling the mock inside a `when` callback and setting a return value.
111
146
 
112
147
  ```typescript
113
148
  when(() => foo.bar(23)).thenReturn('awesome');
@@ -186,7 +221,7 @@ const fn = mock<Fn>();
186
221
 
187
222
  when(() => fn(1)).thenResolve(2);
188
223
 
189
- console.log(await fn()); // 2
224
+ console.log(await fn(1)); // 2
190
225
  ```
191
226
 
192
227
  ### Throwing errors
@@ -239,10 +274,10 @@ It is recommended that you call `verify()` on your mocks at the end of every tes
239
274
  ```typescript
240
275
  afterEach(() => {
241
276
  verifyAll();
242
- })
277
+ });
243
278
  ```
244
279
 
245
- ![verify error](./media/verify.png)
280
+ ![verify error](media/verify.png)
246
281
 
247
282
  ### Resetting expectations
248
283
 
@@ -263,10 +298,10 @@ If you create common mocks that are shared by multiple tests you should reset th
263
298
  ```typescript
264
299
  beforeEach(() => {
265
300
  resetAll();
266
- })
301
+ });
267
302
  ```
268
303
 
269
- ### Argument matchers
304
+ ### Matchers
270
305
 
271
306
  Sometimes you're not interested in specifying all the arguments in an expectation. Maybe they've been covered in another test, maybe they're hard to specify e.g. callbacks, or maybe you want to match just a property from an argument.
272
307
 
@@ -277,7 +312,7 @@ const fn = mock<
277
312
 
278
313
  when(() => fn(
279
314
  It.isAny(),
280
- It.isObject({ values: [1, 2, 3] })
315
+ It.isPartial({ values: [1, 2, 3] })
281
316
  )).thenReturn('matched!');
282
317
 
283
318
  console.log(fn(
@@ -286,10 +321,10 @@ console.log(fn(
286
321
  ); // 'matched!'
287
322
  ```
288
323
 
289
- You can mix argument matchers with concrete arguments:
324
+ You can mix matchers with concrete arguments:
290
325
 
291
326
  ```typescript
292
- when(() => fn(42, It.isObject())).thenReturn('matched');
327
+ when(() => fn(42, It.isPlainObject())).thenReturn('matched');
293
328
  ```
294
329
 
295
330
  Available matchers:
@@ -299,9 +334,10 @@ Available matchers:
299
334
  - `isNumber` - matches any number,
300
335
  - `isString` - matches any string, can search for substrings and patterns,
301
336
  - `isArray` - matches any array, can search for subsets,
302
- - `isObject` - matches any object, can search for partial objects,
303
- - `matches` - build your own matcher,
304
- - `willCapture` - matches anything and stores the received value.
337
+ - `isPlainObject` - matches any plain object,
338
+ - `isPartial` - recursively matches a subset of an object,
339
+ - `willCapture` - matches anything and stores the received value,
340
+ - `matches` - [build your own matcher](#creating-your-own-matcher).
305
341
 
306
342
  The following table illustrates the differences between the equality matchers:
307
343
 
@@ -312,27 +348,16 @@ The following table illustrates the differences between the equality matchers:
312
348
  | `{ }` | `{ foo: undefined }` | not equal | not equal | equal |
313
349
  | `new (class {})()` | `new (class {})()` | not equal | not equal | equal |
314
350
 
315
- Some matchers, like `isObject` and `isArray` support nesting matchers:
351
+ Some matchers, like `isPartial` and `isArray` support nesting matchers:
316
352
 
317
353
  ```typescript
318
- It.isObject({ foo: It.isString() })
354
+ It.isPartial({ foo: It.isString() })
319
355
 
320
- It.isArray([ It.isObject({
356
+ It.isArray([ It.isPartial({
321
357
  foo: It.isString({ matching: /foo/ })
322
358
  })])
323
359
  ```
324
360
 
325
- You can create arbitrarily complex and type safe matchers with `It.matches(cb)`:
326
-
327
- ```typescript
328
- const fn = mock<(x: number, y: number[]) => string>();
329
-
330
- when(() => fn(
331
- It.matches(x => x > 0),
332
- It.matches(y => y.includes(42))
333
- )).thenReturn('matched');
334
- ```
335
-
336
361
  `It.willCapture` is a special matcher that will match any value and store it, so you can access it outside an expectation. This could be useful to capture a callback and then test it separately.
337
362
 
338
363
  ```ts
@@ -347,6 +372,57 @@ console.log(fn(23, (x) => x + 1)); // 42
347
372
  console.log(matcher.value?.(3)); // 4
348
373
  ```
349
374
 
375
+ #### Creating your own matcher
376
+
377
+ You can create arbitrarily complex and type safe matchers with `It.matches()`:
378
+
379
+ ```typescript
380
+ const fn = mock<(x: number, y: string) => string>();
381
+
382
+ when(() => fn(
383
+ It.matches(x => x > 0),
384
+ It.matches(y => y.startsWith('foo'))
385
+ )).thenReturn('matched');
386
+ ```
387
+
388
+ The types are automatically inferred, but you can also specify them explicitly through the generic parameter, which is useful if you want to create reusable matchers:
389
+
390
+ ```typescript
391
+ const startsWith = (expected: string) => It.matches<string>(
392
+ actual => actual.startsWith(expected)
393
+ );
394
+
395
+ when(() => fn(42, startsWith('foo'))).thenReturn('matched');
396
+
397
+ fn(42, 'foobar') // 'matched'
398
+ ```
399
+
400
+ You can also customize how the matcher is printed in error messages, and how the diff is printed:
401
+
402
+ ```typescript
403
+ const closeTo = (expected: number, precision = 0.01) => It.matches<number>(
404
+ actual => Math.abs(expected - actual) <= precision,
405
+ {
406
+ toString: () => `closeTo(${expected}, ${precision})`,
407
+ getDiff: (actual) => {
408
+ const diff = Math.abs(expected - actual);
409
+ const sign = diff < 0 ? '-' : '+';
410
+
411
+ return {
412
+ actual: `${actual} (${sign}${diff})`,
413
+ expected: `${expected} ±${precision}`,
414
+ };
415
+ }
416
+ }
417
+ );
418
+
419
+ when(() => fn(closeTo(1), 'foo')).thenReturn('matched');
420
+
421
+ fn(2, 'foo');
422
+ ```
423
+
424
+ ![Error message for custom matcher](media/custom-matcher.png)
425
+
350
426
  ## Mock options
351
427
 
352
428
  The following options can be set per mock, or globally with `setDefaults`.
@@ -397,7 +473,7 @@ propertiesThrow.bar(42);
397
473
 
398
474
  ### Exact params
399
475
 
400
- By default, function/method expectations will allow more arguments to be received than expected. Since the expectations are type safe, the TypeScript compiler will never allow expecting less arguments than required. Unspecified optional arguments will be considered ignored, as if they've been replaced with [argument matchers](#argument-matchers).
476
+ By default, function/method expectations will allow more arguments to be received than expected. Since the expectations are type safe, the TypeScript compiler will never allow expecting less arguments than required. Unspecified optional arguments will be considered ignored, as if they've been replaced with [matchers](#matchers-1).
401
477
 
402
478
  ```typescript
403
479
  import { mock } from 'strong-mock';
@@ -429,7 +505,7 @@ console.log(fn(1)); // throws
429
505
 
430
506
  ### Concrete matcher
431
507
 
432
- You can configure the [matcher](#argument-matchers) that will be used in expectations with concrete values e.g. `42` or `{ foo: "bar" }`. This matcher can always be overwritten inside an expectation with another matcher.
508
+ You can configure the [matcher](#matchers-1) that will be used in expectations with concrete values e.g. `42` or `{ foo: "bar" }`. This matcher can always be overwritten inside an expectation with another matcher.
433
509
 
434
510
  ```typescript
435
511
  import { mock, when, It } from 'strong-mock';
@@ -458,7 +534,19 @@ This design decision has a few reasons behind it. First, it forces you to be awa
458
534
 
459
535
  Secondly, it will highlight potential design problems such as violations of the SOLID principles. If you find yourself duplicating expectations between tests and passing dummy values to them because your test is not concerned with them, then you might want to look into splitting the code to only depend on things it really needs.
460
536
 
461
- ### Can I partially mock an existing object/function?
537
+ ### Why do I have to set a return value even if it's `undefined`?
538
+
539
+ To make side effects explicit and to prevent future refactoring headaches. If you had just `when(() => fn())`, and you later changed `fn()` to return a `number`, then your expectation would become incorrect and the compiler couldn't check that for you.
540
+
541
+ ### Why do I get a `Didn't expect mock to be called` error?
542
+
543
+ This error happens when your code under test calls a mock that didn't have a matching expectation. It could be that the arguments received didn't match the ones set in the expectation (see [matchers](#matchers-1)), or the call was made more than the allowed number of times (see [invocation count expectations](#setting-invocation-count-expectations)).
544
+
545
+ In rare cases, the code under test may try to inspect the mock by accessing special properties on it. For instance, wrapping a mock in `Promise.resolve()` will try to access a `.then` property on it. strong-mock returns stub values for most of these, but if you find another one feel free to [open an issue](https://github.com/NiGhTTraX/strong-mock/issues) with a minimal reproduction.
546
+
547
+ Unfortunately, not all of these cases can be covered with stub values, and you may have to slightly adjust your code to work around this issue.
548
+
549
+ ### Can I partially mock a concrete implementation?
462
550
 
463
551
  No, passing a concrete implementation to `mock()` will be the same as passing a type: all properties will be mocked, and you have to set expectations on the ones that will be accessed.
464
552
 
@@ -466,10 +554,6 @@ No, passing a concrete implementation to `mock()` will be the same as passing a
466
554
 
467
555
  You currently can't do that. Please use a normal method instead e.g. `setFoo()` vs `set foo()`.
468
556
 
469
- ### Why do I have to set a return value even if it's `undefined`?
470
-
471
- To make side effects explicit and to prevent future refactoring headaches. If you had just `when(() => fn())`, and you later changed `fn()` to return a `number`, then your expectation would become incorrect and the compiler couldn't check that for you.
472
-
473
557
  ### How do I provide a function for the mock to call?
474
558
 
475
559
  There is no `thenCall()` method because it can't be safely typed - the type for `thenReturn()` is inferred from the return type in `when`, meaning that the required type would be the return value for the function, not the function itself. However, we can leverage this by setting an expectation on the function property instead:
@@ -488,7 +572,7 @@ console.log(foo.bar(23)); // 'called 23'
488
572
 
489
573
  The function in `thenReturn()` will be type checked against the actual interface, so you can make sure you're passing in an implementation that makes sense. Moreover, refactoring the interface will also refactor the expectation (in a capable IDE).
490
574
 
491
- ### Can I spread/enumerate a mock?
575
+ ### Can I spread or enumerate a mock?
492
576
 
493
577
  Yes, and you will only get the properties that have expectations on them.
494
578
 
@@ -504,6 +588,10 @@ console.log(foo2.bar); // 42
504
588
  console.log(foo2.baz); // undefined
505
589
  ```
506
590
 
591
+ ### Why does `typeof mock()` return `function`?
592
+
593
+ All mocks and methods on them are functions in order to intercept function calls.
594
+
507
595
  ### How can I ignore `undefined` keys when setting expectations on objects?
508
596
 
509
597
  Use the `It.deepEquals` matcher explicitly inside `when` and pass `{ strict: false }`:
@@ -525,3 +613,7 @@ setDefaults({
525
613
  concreteMatcher: (expected) => It.deepEquals(expected, { strict: false })
526
614
  });
527
615
  ```
616
+
617
+ ### How can I verify order of calls?
618
+
619
+ `when()` expectations can be satisfied in any order. If your code under test depends on a specific order of execution, consider redesigning it to remove the coupling before the different calls.
@@ -0,0 +1,13 @@
1
+ import type { Property } from '../proxy';
2
+ export declare class UnfinishedExpectation extends Error {
3
+ constructor(property: Property, args: any[] | undefined);
4
+ }
5
+ export declare class MissingWhen extends Error {
6
+ constructor();
7
+ }
8
+ export declare class NotAMock extends Error {
9
+ constructor();
10
+ }
11
+ export declare class NestedWhen extends Error {
12
+ constructor(parentProp: Property, childProp: Property);
13
+ }
@@ -0,0 +1,4 @@
1
+ import type { Expectation } from '../expectation/expectation';
2
+ export declare const printArgsDiff: (expected: unknown[], actual: unknown[]) => string;
3
+ export declare const printExpectationDiff: (e: Expectation, args: unknown[]) => string;
4
+ export declare const printDiffForAllExpectations: (expectations: Expectation[], actual: unknown[]) => string;
@@ -0,0 +1,5 @@
1
+ import type { Expectation } from '../expectation/expectation';
2
+ import type { Property } from '../proxy';
3
+ export declare class UnexpectedAccess extends Error {
4
+ constructor(property: Property, expectations: Expectation[]);
5
+ }
@@ -0,0 +1,14 @@
1
+ import type { Expectation } from '../expectation/expectation';
2
+ import type { Property } from '../proxy';
3
+ type MatcherResult = {
4
+ expected: unknown;
5
+ actual: unknown;
6
+ };
7
+ interface MatcherError {
8
+ matcherResult?: MatcherResult;
9
+ }
10
+ export declare class UnexpectedCall extends Error implements MatcherError {
11
+ matcherResult?: MatcherResult;
12
+ constructor(property: Property, args: unknown[], expectations: Expectation[]);
13
+ }
14
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { Expectation } from '../expectation/expectation';
2
+ import type { CallMap } from '../expectation/repository/expectation-repository';
3
+ export declare class UnmetExpectations extends Error {
4
+ constructor(expectations: Expectation[]);
5
+ }
6
+ export declare class UnexpectedCalls extends Error {
7
+ constructor(unexpectedCalls: CallMap, expectations: Expectation[]);
8
+ }
@@ -1,30 +1,27 @@
1
- import type { Property } from '../proxy';
2
- import type { Matcher } from './matcher';
3
- import type { ReturnValue } from './repository/return-value';
4
- /**
5
- * Compare received arguments against matchers.
6
- */
7
- export interface Expectation {
8
- property: Property;
9
- /**
10
- * `undefined` means this is a property expectation.
11
- * `[]` means this is a function call with no arguments.
12
- */
13
- args: Matcher[] | undefined;
14
- returnValue: ReturnValue;
15
- min: number;
16
- max: number;
17
- /**
18
- * How many times should this expectation match?
19
- */
20
- setInvocationCount(min: number, max: number): void;
21
- matches(args: any[] | undefined): boolean;
22
- /**
23
- * Used by `pretty-format`.
24
- */
25
- toJSON(): string;
26
- }
27
- /**
28
- * Special symbol denoting the call of a function.
29
- */
30
- export declare const ApplyProp: unique symbol;
1
+ import type { Matcher } from '../matchers/matcher';
2
+ import type { Property } from '../proxy';
3
+ import type { ReturnValue } from './repository/return-value';
4
+ /**
5
+ * Compare received arguments against matchers.
6
+ */
7
+ export interface Expectation {
8
+ property: Property;
9
+ /**
10
+ * `undefined` means this is a property expectation.
11
+ * `[]` means this is a function call with no arguments.
12
+ */
13
+ args: Matcher[] | undefined;
14
+ returnValue: ReturnValue;
15
+ min: number;
16
+ max: number;
17
+ /**
18
+ * How many times should this expectation match?
19
+ */
20
+ setInvocationCount: (min: number, max: number) => void;
21
+ matches: (args: unknown[] | undefined) => boolean;
22
+ toString: () => string;
23
+ }
24
+ /**
25
+ * Special symbol denoting the call of a function.
26
+ */
27
+ export declare const ApplyProp: unique symbol;
@@ -1,90 +1,90 @@
1
- import type { Property } from '../../proxy';
2
- import type { Expectation } from '../expectation';
3
- export type Call = {
4
- arguments: any[] | undefined;
5
- };
6
- /**
7
- * Method calls should be recorded both as a property access and a method call.
8
- *
9
- * @example
10
- * // foo.bar(1, 2, 3) should generate
11
- * {
12
- * foo: [
13
- * { arguments: undefined },
14
- * { arguments: [1, 2, 3] }
15
- * ]
16
- * }
17
- */
18
- export type CallMap = Map<Property, Call[]>;
19
- export type CallStats = {
20
- /**
21
- * Calls that matched existing expectations.
22
- */
23
- expected: CallMap;
24
- /**
25
- * Calls that didn't match any existing expectation.
26
- */
27
- unexpected: CallMap;
28
- };
29
- export interface ExpectationRepository {
30
- add(expectation: Expectation): void;
31
- /**
32
- * Get a return value for the given property.
33
- *
34
- * The value might be a non-callable e.g. a number or a string, or it might
35
- * be a function that, upon receiving arguments, will start a new search and
36
- * return a value again.
37
- *
38
- * The list of expectations should be consulted from first to last when
39
- * getting a return value. If none of them match it is up to the
40
- * implementation to decide what to do.
41
- *
42
- * @example
43
- * add(new Expectation('getData', [1, 2], 23);
44
- * get('getData')(1, 2) === 23
45
- *
46
- * @example
47
- * add(new Expectation('hasData', undefined, true);
48
- * get('hasData') === true
49
- *
50
- * @example
51
- * add(new Expectation('getData', undefined, () => 42);
52
- * get('getData')(1, 2, '3', false, NaN) === 42
53
- */
54
- get(property: Property): unknown;
55
- /**
56
- * Get a return value for a function call.
57
- *
58
- * Note: this will only be invoked if the mocked type is a function. For
59
- * method property calls {@link get} will be called instead.
60
- *
61
- * The list of expectations should be consulted from first to last when
62
- * getting a return value. If none of them match it is up to the
63
- * implementation to decide what to do.
64
- *
65
- * @example
66
- * add(new Expectation(ApplyProp, [1, 2], 23);
67
- * apply(1, 2) === 23
68
- */
69
- apply(args: unknown[]): unknown;
70
- /**
71
- * Get all the properties that have expectations.
72
- *
73
- * @example
74
- * add(new Expectation('foo', undefined, 23));
75
- * getAllProperties() === ['foo']
76
- */
77
- getAllProperties(): Property[];
78
- /**
79
- * Remove any expectations and clear the call stats.
80
- */
81
- clear(): void;
82
- /**
83
- * Return all unmet expectations.
84
- */
85
- getUnmet(): Expectation[];
86
- /**
87
- * Return all the calls that have been made so far.
88
- */
89
- getCallStats(): CallStats;
90
- }
1
+ import type { Property } from '../../proxy';
2
+ import type { Expectation } from '../expectation';
3
+ export type Call = {
4
+ arguments: any[] | undefined;
5
+ };
6
+ /**
7
+ * Method calls should be recorded both as a property access and a method call.
8
+ *
9
+ * @example
10
+ * // foo.bar(1, 2, 3) should generate
11
+ * {
12
+ * foo: [
13
+ * { arguments: undefined },
14
+ * { arguments: [1, 2, 3] }
15
+ * ]
16
+ * }
17
+ */
18
+ export type CallMap = Map<Property, Call[]>;
19
+ export type CallStats = {
20
+ /**
21
+ * Calls that matched existing expectations.
22
+ */
23
+ expected: CallMap;
24
+ /**
25
+ * Calls that didn't match any existing expectation.
26
+ */
27
+ unexpected: CallMap;
28
+ };
29
+ export interface ExpectationRepository {
30
+ add: (expectation: Expectation) => void;
31
+ /**
32
+ * Get a return value for the given property.
33
+ *
34
+ * The value might be a non-callable e.g. a number or a string, or it might
35
+ * be a function that, upon receiving arguments, will start a new search and
36
+ * return a value again.
37
+ *
38
+ * The list of expectations should be consulted from first to last when
39
+ * getting a return value. If none of them match it is up to the
40
+ * implementation to decide what to do.
41
+ *
42
+ * @example
43
+ * add(new Expectation('getData', [1, 2], 23);
44
+ * get('getData')(1, 2) === 23
45
+ *
46
+ * @example
47
+ * add(new Expectation('hasData', undefined, true);
48
+ * get('hasData') === true
49
+ *
50
+ * @example
51
+ * add(new Expectation('getData', undefined, () => 42);
52
+ * get('getData')(1, 2, '3', false, NaN) === 42
53
+ */
54
+ get: (property: Property) => unknown;
55
+ /**
56
+ * Get a return value for a function call.
57
+ *
58
+ * Note: this will only be invoked if the mocked type is a function. For
59
+ * method property calls {@link get} will be called instead.
60
+ *
61
+ * The list of expectations should be consulted from first to last when
62
+ * getting a return value. If none of them match it is up to the
63
+ * implementation to decide what to do.
64
+ *
65
+ * @example
66
+ * add(new Expectation(ApplyProp, [1, 2], 23);
67
+ * apply(1, 2) === 23
68
+ */
69
+ apply: (args: unknown[]) => unknown;
70
+ /**
71
+ * Get all the properties that have expectations.
72
+ *
73
+ * @example
74
+ * add(new Expectation('foo', undefined, 23));
75
+ * getAllProperties() === ['foo']
76
+ */
77
+ getAllProperties: () => Property[];
78
+ /**
79
+ * Remove any expectations and clear the call stats.
80
+ */
81
+ clear: () => void;
82
+ /**
83
+ * Return all unmet expectations.
84
+ */
85
+ getUnmet: () => Expectation[];
86
+ /**
87
+ * Return all the calls that have been made so far.
88
+ */
89
+ getCallStats: () => CallStats;
90
+ }