strong-mock 7.2.0 → 8.0.0-beta.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.
- package/README.md +120 -72
- package/dist/errors.d.ts +1 -1
- package/dist/expectation/expectation.d.ts +5 -1
- package/dist/expectation/it.d.ts +29 -0
- package/dist/expectation/matcher.d.ts +9 -45
- package/dist/expectation/repository/base-repository.d.ts +1 -1
- package/dist/expectation/strong-expectation.d.ts +9 -10
- package/dist/index.d.ts +8 -7
- package/dist/index.js +1014 -944
- package/dist/index.js.map +1 -0
- package/dist/mock/defaults.d.ts +27 -0
- package/dist/mock/map.d.ts +1 -1
- package/dist/mock/mock.d.ts +5 -4
- package/dist/mock/stub.d.ts +11 -2
- package/dist/return/returns.d.ts +6 -6
- package/dist/verify/reset.d.ts +2 -2
- package/dist/verify/verify.d.ts +1 -1
- package/dist/when/when.d.ts +6 -5
- package/package.json +22 -24
- package/CHANGELOG.md +0 -128
- package/dist/instance/instance.d.ts +0 -14
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
```typescript
|
|
9
|
-
import { mock, when
|
|
9
|
+
import { mock, when } from 'strong-mock';
|
|
10
10
|
|
|
11
11
|
interface Foo {
|
|
12
12
|
bar: (x: number) => string;
|
|
@@ -14,9 +14,9 @@ interface Foo {
|
|
|
14
14
|
|
|
15
15
|
const foo = mock<Foo>();
|
|
16
16
|
|
|
17
|
-
when(foo.bar(23)).thenReturn('I am strong!');
|
|
17
|
+
when(() => foo.bar(23)).thenReturn('I am strong!');
|
|
18
18
|
|
|
19
|
-
console.log(
|
|
19
|
+
console.log(foo.bar(23)); // 'I am strong!'
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
----
|
|
@@ -27,12 +27,12 @@ console.log(instance(foo).bar(23)); // 'I am strong!'
|
|
|
27
27
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
|
28
28
|
**Table of Contents**
|
|
29
29
|
|
|
30
|
-
- [Installation](#installation)
|
|
31
|
-
- [Requirements](#requirements)
|
|
32
30
|
- [Features](#features)
|
|
33
31
|
- [Type safety](#type-safety)
|
|
34
32
|
- [Useful error messages](#useful-error-messages)
|
|
35
33
|
- [Type safe argument matchers](#type-safe-argument-matchers)
|
|
34
|
+
- [Installation](#installation)
|
|
35
|
+
- [Requirements](#requirements)
|
|
36
36
|
- [API](#api)
|
|
37
37
|
- [Setting expectations](#setting-expectations)
|
|
38
38
|
- [Setting multiple expectations](#setting-multiple-expectations)
|
|
@@ -44,6 +44,7 @@ console.log(instance(foo).bar(23)); // 'I am strong!'
|
|
|
44
44
|
- [Verifying expectations](#verifying-expectations)
|
|
45
45
|
- [Resetting expectations](#resetting-expectations)
|
|
46
46
|
- [Argument matchers](#argument-matchers)
|
|
47
|
+
- [Overriding default matcher](#overriding-default-matcher)
|
|
47
48
|
- [FAQ](#faq)
|
|
48
49
|
- [Why do I have to set all expectations first?](#why-do-i-have-to-set-all-expectations-first)
|
|
49
50
|
- [Can I mock an existing object/function?](#can-i-mock-an-existing-objectfunction)
|
|
@@ -51,24 +52,11 @@ console.log(instance(foo).bar(23)); // 'I am strong!'
|
|
|
51
52
|
- [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)
|
|
52
53
|
- [How do I provide a function for the mock to call?](#how-do-i-provide-a-function-for-the-mock-to-call)
|
|
53
54
|
- [Why does accessing an unused method throw?](#why-does-accessing-an-unused-method-throw)
|
|
54
|
-
- [Can I spread/enumerate a mock
|
|
55
|
+
- [Can I spread/enumerate a mock?](#can-i-spreadenumerate-a-mock)
|
|
56
|
+
- [How can I ignore `undefined` keys when setting expectations on objects?](#how-can-i-ignore-undefined-keys-when-setting-expectations-on-objects)
|
|
55
57
|
|
|
56
58
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
57
59
|
|
|
58
|
-
## Installation
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
npm i -D strong-mock
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
yarn add -D strong-mock
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Requirements
|
|
69
|
-
|
|
70
|
-
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.
|
|
71
|
-
|
|
72
60
|
## Features
|
|
73
61
|
|
|
74
62
|
### Type safety
|
|
@@ -85,34 +73,44 @@ Error messages include the property that has been accessed, any arguments passed
|
|
|
85
73
|
|
|
86
74
|
### Type safe argument matchers
|
|
87
75
|
|
|
88
|
-
|
|
76
|
+
Optional argument matchers allow you to create complex expectations, while still maintaining type safety.
|
|
89
77
|
|
|
90
|
-
|
|
78
|
+

|
|
91
79
|
|
|
92
|
-
|
|
80
|
+
## Installation
|
|
93
81
|
|
|
94
|
-
|
|
82
|
+
```
|
|
83
|
+
npm i -D strong-mock
|
|
84
|
+
```
|
|
95
85
|
|
|
96
|
-
```
|
|
97
|
-
|
|
86
|
+
```
|
|
87
|
+
yarn add -D strong-mock
|
|
98
88
|
```
|
|
99
89
|
|
|
100
|
-
|
|
90
|
+
## Requirements
|
|
91
|
+
|
|
92
|
+
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.
|
|
93
|
+
|
|
94
|
+
## API
|
|
95
|
+
|
|
96
|
+
### Setting expectations
|
|
97
|
+
|
|
98
|
+
Expectations are set by calling the mock inside a `when` callback and finishing it by setting a return value.
|
|
101
99
|
|
|
102
100
|
```typescript
|
|
103
|
-
|
|
101
|
+
when(() => foo.bar(23)).thenReturn('awesome');
|
|
104
102
|
```
|
|
105
103
|
|
|
106
104
|
### Setting multiple expectations
|
|
107
105
|
|
|
108
|
-
You can set as many expectations as you want by calling `when
|
|
106
|
+
You can set as many expectations as you want by calling `when` multiple times. If you have multiple expectations with the same arguments they will be consumed in the order they were created.
|
|
109
107
|
|
|
110
108
|
```typescript
|
|
111
|
-
when(foo.bar(23)).thenReturn('awesome');
|
|
112
|
-
when(foo.bar(23)).thenReturn('even more awesome');
|
|
109
|
+
when(() => foo.bar(23)).thenReturn('awesome');
|
|
110
|
+
when(() => foo.bar(23)).thenReturn('even more awesome');
|
|
113
111
|
|
|
114
|
-
console.log(
|
|
115
|
-
console.log(
|
|
112
|
+
console.log(foo.bar(23)); // awesome
|
|
113
|
+
console.log(foo.bar(23)); // even more awesome
|
|
116
114
|
```
|
|
117
115
|
|
|
118
116
|
By default, each call is expected to be called only once. You can expect a call to be made multiple times using the [invocation count](#setting-invocation-count-expectations) helpers.
|
|
@@ -124,12 +122,12 @@ You can expect a call to be made multiple times by using the invocation count he
|
|
|
124
122
|
```typescript
|
|
125
123
|
const fn = mock<(x: number) => number>();
|
|
126
124
|
|
|
127
|
-
when(fn(1)).thenReturn(1).between(2, 3);
|
|
125
|
+
when(() => fn(1)).thenReturn(1).between(2, 3);
|
|
128
126
|
|
|
129
|
-
console.log(
|
|
130
|
-
console.log(
|
|
131
|
-
console.log(
|
|
132
|
-
console.log(
|
|
127
|
+
console.log(fn(1)); // 1
|
|
128
|
+
console.log(fn(1)); // 1
|
|
129
|
+
console.log(fn(1)); // 1
|
|
130
|
+
console.log(fn(1)); // throws because the expectation is finished
|
|
133
131
|
```
|
|
134
132
|
|
|
135
133
|
### Mocking interfaces
|
|
@@ -144,11 +142,11 @@ interface Foo {
|
|
|
144
142
|
|
|
145
143
|
const foo = mock<Foo>();
|
|
146
144
|
|
|
147
|
-
when(foo.bar(23)).thenReturn('awesome');
|
|
148
|
-
when(foo.baz).thenReturn(100);
|
|
145
|
+
when(() => foo.bar(23)).thenReturn('awesome');
|
|
146
|
+
when(() => foo.baz).thenReturn(100);
|
|
149
147
|
|
|
150
|
-
console.log(
|
|
151
|
-
console.log(
|
|
148
|
+
console.log(foo.bar(23)); // 'awesome'
|
|
149
|
+
console.log(foo.baz); // 100
|
|
152
150
|
```
|
|
153
151
|
|
|
154
152
|
Since the mock is type safe the compiler will guarantee that you're only mocking things that actually exist on the interface.
|
|
@@ -162,9 +160,9 @@ type Fn = (x: number) => number;
|
|
|
162
160
|
|
|
163
161
|
const fn = mock<Fn>();
|
|
164
162
|
|
|
165
|
-
when(fn(1)).thenReturn(2);
|
|
163
|
+
when(() => fn(1)).thenReturn(2);
|
|
166
164
|
|
|
167
|
-
console.log(
|
|
165
|
+
console.log(fn(1)); // 2
|
|
168
166
|
```
|
|
169
167
|
|
|
170
168
|
### Mocking promises
|
|
@@ -176,9 +174,9 @@ type Fn = (x: number) => Promise<number>;
|
|
|
176
174
|
|
|
177
175
|
const fn = mock<Fn>();
|
|
178
176
|
|
|
179
|
-
when(fn(1)).thenResolve(2);
|
|
177
|
+
when(() => fn(1)).thenResolve(2);
|
|
180
178
|
|
|
181
|
-
console.log(await
|
|
179
|
+
console.log(await fn()); // 2
|
|
182
180
|
```
|
|
183
181
|
|
|
184
182
|
### Throwing errors
|
|
@@ -190,8 +188,8 @@ type FnWithPromise = (x: number) => Promise<void>;
|
|
|
190
188
|
const fn = mock<Fn>();
|
|
191
189
|
const fnWithPromise = mock<FnWithPromise>();
|
|
192
190
|
|
|
193
|
-
when(fn(1)).thenThrow();
|
|
194
|
-
when(fnWithPromise(1)).thenReject();
|
|
191
|
+
when(() => fn(1)).thenThrow();
|
|
192
|
+
when(() => fnWithPromise(1)).thenReject();
|
|
195
193
|
```
|
|
196
194
|
|
|
197
195
|
You'll notice there is no `never()` helper - if you expect a call to not be made simply don't set an expectation on it and the mock will throw if the call happens.
|
|
@@ -203,7 +201,7 @@ Calling `verify(mock)` will make sure that all expectations set on `mock` have b
|
|
|
203
201
|
```typescript
|
|
204
202
|
const fn = mock<(x: number) => number>();
|
|
205
203
|
|
|
206
|
-
when(fn(1)).thenReturn(1).between(2, 10);
|
|
204
|
+
when(() => fn(1)).thenReturn(1).between(2, 10);
|
|
207
205
|
|
|
208
206
|
verify(fn); // throws
|
|
209
207
|
```
|
|
@@ -214,7 +212,7 @@ It will also throw if any unexpected calls happened that were maybe caught in th
|
|
|
214
212
|
const fn = mock<() => void>();
|
|
215
213
|
|
|
216
214
|
try {
|
|
217
|
-
|
|
215
|
+
fn(); // throws because the call is unexpected
|
|
218
216
|
} catch(e) {
|
|
219
217
|
// your code might transition to an error state here
|
|
220
218
|
}
|
|
@@ -222,7 +220,7 @@ try {
|
|
|
222
220
|
verify(fn); // throws
|
|
223
221
|
```
|
|
224
222
|
|
|
225
|
-
It is recommended that
|
|
223
|
+
It is recommended that you call `verify()` on your mocks at the end of every test. This will make sure you don't have any unused expectations in your tests and that your code did not silently catch any of the errors that are thrown when an unexpected call happens. You can use `verifyAll()` to check all existing mocks e.g. in an `afterEach` hook.
|
|
226
224
|
|
|
227
225
|

|
|
228
226
|
|
|
@@ -233,11 +231,11 @@ You can remove all expectations from a mock by using the `reset()` method:
|
|
|
233
231
|
```typescript
|
|
234
232
|
const fn = mock<(x: number) => number>();
|
|
235
233
|
|
|
236
|
-
when(fn(1)).thenReturn(1);
|
|
234
|
+
when(() => fn(1)).thenReturn(1);
|
|
237
235
|
|
|
238
236
|
reset(fn);
|
|
239
237
|
|
|
240
|
-
|
|
238
|
+
fn(1); // throws
|
|
241
239
|
```
|
|
242
240
|
|
|
243
241
|
If you create common mocks that are shared by multiple tests you should reset them before using them e.g. in a `beforeEach` hook. You can use `resetAll()` to reset all existing mocks.
|
|
@@ -251,18 +249,20 @@ const fn = mock<
|
|
|
251
249
|
(x: number, data: { values: number[]; labels: string[] }) => string
|
|
252
250
|
>();
|
|
253
251
|
|
|
254
|
-
when(fn(
|
|
252
|
+
when(() => fn(
|
|
255
253
|
It.isAny(),
|
|
256
254
|
It.isObject({ values: [1, 2, 3] })
|
|
257
255
|
)).thenReturn('matched!');
|
|
258
256
|
|
|
259
|
-
console.log(
|
|
257
|
+
console.log(fn(
|
|
260
258
|
123,
|
|
261
259
|
{ values: [1, 2, 3], labels: ['a', 'b', 'c'] })
|
|
262
260
|
); // 'matched!'
|
|
263
261
|
```
|
|
264
262
|
|
|
265
263
|
Available matchers:
|
|
264
|
+
- `deepEquals` - the default, uses deep equality,
|
|
265
|
+
- `is` - uses `Object.is` for comparison,
|
|
266
266
|
- `isAny` - matches anything,
|
|
267
267
|
- `isNumber` - matches any number,
|
|
268
268
|
- `isString` - matches any string, can search for substrings and patterns,
|
|
@@ -271,6 +271,15 @@ Available matchers:
|
|
|
271
271
|
- `matches` - build your own matcher,
|
|
272
272
|
- `willCapture` - matches anything and stores the received value.
|
|
273
273
|
|
|
274
|
+
The following table illustrates the differences between the equality matchers:
|
|
275
|
+
|
|
276
|
+
| expected | actual | `It.is` | `It.deepEquals` | `It.deepEquals({ strict: false })` |
|
|
277
|
+
|--------------------|----------------------|-----------|-----------------|------------------------------------|
|
|
278
|
+
| `"foo"` | `"bar"` | equal | equal | equal |
|
|
279
|
+
| `{ foo: "bar" }` | `{ foo: "bar" }` | not equal | equal | equal |
|
|
280
|
+
| `{ }` | `{ foo: undefined }` | not equal | not equal | equal |
|
|
281
|
+
| `new (class {})()` | `new (class {})()` | not equal | not equal | equal |
|
|
282
|
+
|
|
274
283
|
Some matchers, like `isObject` and `isArray` support nesting matchers:
|
|
275
284
|
|
|
276
285
|
```typescript
|
|
@@ -286,9 +295,9 @@ You can create arbitrarily complex and type safe matchers with `It.matches(cb)`:
|
|
|
286
295
|
```typescript
|
|
287
296
|
const fn = mock<(x: number, y: number[]) => string>();
|
|
288
297
|
|
|
289
|
-
when(fn(
|
|
298
|
+
when(() => fn(
|
|
290
299
|
It.matches(x => x > 0),
|
|
291
|
-
It.matches(y => y.
|
|
300
|
+
It.matches(y => y.includes(42))
|
|
292
301
|
)).thenReturn('matched');
|
|
293
302
|
```
|
|
294
303
|
|
|
@@ -300,19 +309,37 @@ type Cb = (value: number) => number;
|
|
|
300
309
|
const fn = mock<(cb: Cb) => number>();
|
|
301
310
|
|
|
302
311
|
const matcher = It.willCapture<Cb>();
|
|
303
|
-
when(fn(matcher)).thenReturn(42);
|
|
312
|
+
when(() => fn(matcher)).thenReturn(42);
|
|
304
313
|
|
|
305
|
-
console.log(
|
|
314
|
+
console.log(fn(23, (x) => x + 1)); // 42
|
|
306
315
|
console.log(matcher.value?.(3)); // 4
|
|
307
316
|
```
|
|
308
317
|
|
|
318
|
+
### Overriding default matcher
|
|
319
|
+
|
|
320
|
+
You can override the default matcher that will be used when setting expectations with non-matcher values e.g. `42` or `{ foo: "bar" }`.
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { mock, when, It, setDefaults } from 'strong-mock';
|
|
324
|
+
|
|
325
|
+
// Use strict equality instead of deep equality.
|
|
326
|
+
setDefaults({
|
|
327
|
+
matcher: It.is
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
const fn = mock<(x: number[]) => boolean>();
|
|
331
|
+
when(() => fn([1, 2, 3])).thenReturn(true);
|
|
332
|
+
|
|
333
|
+
fn([1, 2, 3]); // throws because different arrays
|
|
334
|
+
```
|
|
335
|
+
|
|
309
336
|
## FAQ
|
|
310
337
|
|
|
311
338
|
### Why do I have to set all expectations first?
|
|
312
339
|
|
|
313
340
|
This library is different from other mocking/spying libraries you might have used before such as [sinon](https://sinonjs.org) or [jest](https://jestjs.io/docs/en/mock-functions). Whereas those libraries are focused on recording calls to the mocks and always returning something, strong-mock requires you to set your expectations upfront. If a call happens that is not expected the mock will throw an error.
|
|
314
341
|
|
|
315
|
-
This design decision has a few reasons behind it. First
|
|
342
|
+
This design decision has a few reasons behind it. First, it forces you to be aware of what your code needs from its dependencies. Spying libraries encourage checking those needs at the end of the test after the code has already called the mocks. This can lead to tests missing dependency calls that just happen to not throw any error at runtime with the dummy values that the spies return.
|
|
316
343
|
|
|
317
344
|
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.
|
|
318
345
|
|
|
@@ -326,11 +353,11 @@ You currently can't do that. Please use a normal method instead e.g. `setFoo()`
|
|
|
326
353
|
|
|
327
354
|
### Why do I have to set a return value even if it's `undefined`?
|
|
328
355
|
|
|
329
|
-
To make side effects explicit and to prevent future refactoring headaches. If you
|
|
356
|
+
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.
|
|
330
357
|
|
|
331
358
|
### How do I provide a function for the mock to call?
|
|
332
359
|
|
|
333
|
-
There is no `thenCall()` method because it can't be safely typed - the type for `thenReturn()` is inferred from the return type in `when
|
|
360
|
+
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:
|
|
334
361
|
|
|
335
362
|
```typescript
|
|
336
363
|
interface Foo {
|
|
@@ -339,12 +366,12 @@ interface Foo {
|
|
|
339
366
|
|
|
340
367
|
const foo = mock<Foo>();
|
|
341
368
|
|
|
342
|
-
when(foo.bar).thenReturn(x => `called ${x}`);
|
|
369
|
+
when(() => foo.bar).thenReturn(x => `called ${x}`);
|
|
343
370
|
|
|
344
|
-
console.log(
|
|
371
|
+
console.log(foo.bar(23)); // 'called 23'
|
|
345
372
|
```
|
|
346
373
|
|
|
347
|
-
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).
|
|
374
|
+
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).
|
|
348
375
|
|
|
349
376
|

|
|
350
377
|
|
|
@@ -370,10 +397,10 @@ function doFoo(foo: Foo, { callBaz }: { callBaz: boolean }) {
|
|
|
370
397
|
}
|
|
371
398
|
|
|
372
399
|
const foo = mock<Foo>();
|
|
373
|
-
when(foo.bar()).thenReturn(42);
|
|
400
|
+
when(() => foo.bar()).thenReturn(42);
|
|
374
401
|
|
|
375
402
|
// Throws with unexpected access on `baz`.
|
|
376
|
-
doFoo(
|
|
403
|
+
doFoo(foo, { callBaz: false });
|
|
377
404
|
```
|
|
378
405
|
|
|
379
406
|
To work around this, either change your code to avoid destructuring
|
|
@@ -391,21 +418,42 @@ function doFoo(foo: Foo, callBaz: boolean) {
|
|
|
391
418
|
or set a dummy expectation on the methods you're not interested in during the test.
|
|
392
419
|
|
|
393
420
|
```typescript
|
|
394
|
-
when(foo.baz()).thenThrow('should not be called').anyTimes();
|
|
421
|
+
when(() => foo.baz()).thenThrow('should not be called').anyTimes();
|
|
395
422
|
```
|
|
396
423
|
|
|
397
|
-
### Can I spread/enumerate a mock
|
|
424
|
+
### Can I spread/enumerate a mock?
|
|
398
425
|
|
|
399
426
|
Yes, and you will only get the properties that have expectations on them.
|
|
400
427
|
|
|
401
428
|
```typescript
|
|
402
429
|
const foo = mock<{ bar: number; baz: number }>();
|
|
403
|
-
when(foo.bar).thenReturn(42);
|
|
430
|
+
when(() => foo.bar).thenReturn(42);
|
|
404
431
|
|
|
405
|
-
console.log(Object.keys(
|
|
432
|
+
console.log(Object.keys(foo)); // ['bar']
|
|
406
433
|
|
|
407
|
-
const foo2 = { ...
|
|
434
|
+
const foo2 = { ...foo };
|
|
408
435
|
|
|
409
436
|
console.log(foo2.bar); // 42
|
|
410
437
|
console.log(foo2.baz); // undefined
|
|
411
438
|
```
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
### How can I ignore `undefined` keys when setting expectations on objects?
|
|
442
|
+
|
|
443
|
+
Use the `It.deepEquals` matcher explicitly inside `when` and pass `{ strict: false }`:
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
const fn = mock<(x: { foo: string }) => boolean>();
|
|
447
|
+
|
|
448
|
+
when(() => fn(It.deepEquals({ foo: "bar" }, { strict: false }))).thenReturn(true);
|
|
449
|
+
|
|
450
|
+
fn({ foo: "bar", baz: undefined }) === true
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
You can also set this behavior to be the default by using [`setDefaults`](#overriding-default-matcher):
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
setDefaults({
|
|
457
|
+
matcher: (expected) => It.deepEquals(expected, { strict: false })
|
|
458
|
+
});
|
|
459
|
+
```
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Expectation } from './expectation/expectation';
|
|
2
2
|
import { CallMap } from './expectation/repository/expectation-repository';
|
|
3
|
-
import { PendingExpectation } from './when/pending-expectation';
|
|
4
3
|
import { Property } from './proxy';
|
|
4
|
+
import { PendingExpectation } from './when/pending-expectation';
|
|
5
5
|
export declare class UnfinishedExpectation extends Error {
|
|
6
6
|
constructor(pendingExpectation: PendingExpectation);
|
|
7
7
|
}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { Property } from '../proxy';
|
|
2
|
+
import { Matcher } from './matcher';
|
|
2
3
|
export declare type ReturnValue = {
|
|
3
4
|
value: any;
|
|
4
5
|
isPromise?: boolean;
|
|
5
6
|
isError?: boolean;
|
|
6
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* Compare received arguments against matchers.
|
|
10
|
+
*/
|
|
7
11
|
export interface Expectation {
|
|
8
12
|
property: Property;
|
|
9
13
|
/**
|
|
10
14
|
* `undefined` means this is a property expectation.
|
|
11
15
|
* `[]` means this is a function call with no arguments.
|
|
12
16
|
*/
|
|
13
|
-
args:
|
|
17
|
+
args: Matcher[] | undefined;
|
|
14
18
|
returnValue: ReturnValue;
|
|
15
19
|
min: number;
|
|
16
20
|
max: number;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Matcher, TypeMatcher } from './matcher';
|
|
2
|
+
declare type DeepPartial<T> = T extends object ? {
|
|
3
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
4
|
+
} : T;
|
|
5
|
+
/**
|
|
6
|
+
* Contains argument matchers that can be used to ignore arguments in an
|
|
7
|
+
* expectation or to match complex arguments.
|
|
8
|
+
*/
|
|
9
|
+
export declare const It: {
|
|
10
|
+
matches: <T>(cb: (actual: T) => boolean, { toJSON }?: {
|
|
11
|
+
toJSON?: (() => string) | undefined;
|
|
12
|
+
}) => TypeMatcher<T>;
|
|
13
|
+
deepEquals: <T_1>(expected: T_1, { strict }?: {
|
|
14
|
+
strict?: boolean | undefined;
|
|
15
|
+
}) => TypeMatcher<T_1>;
|
|
16
|
+
is: <T_2 = unknown>(expected: T_2) => TypeMatcher<T_2>;
|
|
17
|
+
isAny: () => TypeMatcher<any>;
|
|
18
|
+
isObject: <T_3 extends object, K extends DeepPartial<T_3>>(partial?: K | undefined) => TypeMatcher<T_3>;
|
|
19
|
+
isNumber: () => TypeMatcher<number>;
|
|
20
|
+
isString: ({ matching, containing, }?: {
|
|
21
|
+
matching?: RegExp | undefined;
|
|
22
|
+
containing?: string | undefined;
|
|
23
|
+
}) => TypeMatcher<string>;
|
|
24
|
+
isArray: <T_4 extends any[]>(containing?: T_4 | undefined) => TypeMatcher<T_4>;
|
|
25
|
+
willCapture: <T_5 = unknown>(name?: string) => T_5 & Matcher & {
|
|
26
|
+
value: T_5 | undefined;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export {};
|
|
@@ -1,57 +1,21 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const MATCHER_SYMBOL: unique symbol;
|
|
2
|
+
export declare type Matcher = {
|
|
2
3
|
/**
|
|
3
4
|
* Will be called with a value to match against.
|
|
4
5
|
*/
|
|
5
|
-
matches: (arg:
|
|
6
|
-
|
|
7
|
-
* TODO: turn into a symbol
|
|
8
|
-
*/
|
|
9
|
-
__isMatcher: boolean;
|
|
6
|
+
matches: (arg: any) => boolean;
|
|
7
|
+
[MATCHER_SYMBOL]: boolean;
|
|
10
8
|
/**
|
|
11
9
|
* Used by `pretty-format`.
|
|
12
10
|
*/
|
|
13
11
|
toJSON(): string;
|
|
14
12
|
};
|
|
15
13
|
/**
|
|
16
|
-
*
|
|
14
|
+
* This takes the shape of T to satisfy call sites, but strong-mock will only
|
|
15
|
+
* care about the matcher type.
|
|
17
16
|
*/
|
|
18
|
-
export declare
|
|
17
|
+
export declare type TypeMatcher<T> = T & Matcher;
|
|
19
18
|
/**
|
|
20
|
-
*
|
|
19
|
+
* Used to test if an expectation on an argument is a custom matcher.
|
|
21
20
|
*/
|
|
22
|
-
export declare
|
|
23
|
-
declare type DeepPartial<T> = T extends object ? {
|
|
24
|
-
[K in keyof T]?: DeepPartial<T[K]>;
|
|
25
|
-
} : T;
|
|
26
|
-
/**
|
|
27
|
-
* Contains argument matchers that can be used to ignore arguments in an
|
|
28
|
-
* expectation or to match complex arguments.
|
|
29
|
-
*/
|
|
30
|
-
export declare const It: {
|
|
31
|
-
isAny: () => Matcher<any>;
|
|
32
|
-
matches: <T>(cb: (arg: T) => boolean) => Matcher<T>;
|
|
33
|
-
isObject: <T_1 extends object, K extends DeepPartial<T_1>>(partial?: K | undefined) => Matcher<T_1>;
|
|
34
|
-
isNumber: () => Matcher<number>;
|
|
35
|
-
isString: ({ matching, containing, }?: {
|
|
36
|
-
matching?: RegExp | undefined;
|
|
37
|
-
containing?: string | undefined;
|
|
38
|
-
}) => Matcher<string>;
|
|
39
|
-
isArray: <T_2 extends any[]>(containing?: T_2 | undefined) => Matcher<T_2>;
|
|
40
|
-
willCapture: <T_3 = unknown>(name?: string | undefined) => T_3 & {
|
|
41
|
-
/**
|
|
42
|
-
* Will be called with a value to match against.
|
|
43
|
-
*/
|
|
44
|
-
matches: (arg: unknown) => boolean;
|
|
45
|
-
/**
|
|
46
|
-
* TODO: turn into a symbol
|
|
47
|
-
*/
|
|
48
|
-
__isMatcher: boolean;
|
|
49
|
-
/**
|
|
50
|
-
* Used by `pretty-format`.
|
|
51
|
-
*/
|
|
52
|
-
toJSON(): string;
|
|
53
|
-
} & {
|
|
54
|
-
value: T_3 | undefined;
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
export {};
|
|
21
|
+
export declare function isMatcher(f: unknown): f is Matcher;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { Property } from '../../proxy';
|
|
1
2
|
import { Expectation, ReturnValue } from '../expectation';
|
|
2
3
|
import { CallMap, ExpectationRepository } from './expectation-repository';
|
|
3
|
-
import { Property } from '../../proxy';
|
|
4
4
|
export declare type CountableExpectation = {
|
|
5
5
|
expectation: Expectation;
|
|
6
6
|
matchCount: number;
|
|
@@ -2,25 +2,24 @@ import { Property } from '../proxy';
|
|
|
2
2
|
import { Expectation, ReturnValue } from './expectation';
|
|
3
3
|
import { Matcher } from './matcher';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Supports argument matchers. Matches a call with more parameters
|
|
8
|
-
* than expected because it is assumed the compiler will check that those
|
|
9
|
-
* parameters are optional.
|
|
5
|
+
* Matches a call with more parameters than expected because it is assumed the
|
|
6
|
+
* compiler will check that those parameters are optional.
|
|
10
7
|
*
|
|
11
8
|
* @example
|
|
12
|
-
* new
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* new StrongExpectation(
|
|
10
|
+
* 'bar',
|
|
11
|
+
* deepEquals([1, 2, 3]),
|
|
12
|
+
* 23
|
|
13
|
+
* ).matches('bar', [1, 2, 3]) === true;
|
|
15
14
|
*/
|
|
16
15
|
export declare class StrongExpectation implements Expectation {
|
|
17
16
|
property: Property;
|
|
18
|
-
args: Matcher
|
|
17
|
+
args: Matcher[] | undefined;
|
|
19
18
|
returnValue: ReturnValue;
|
|
20
19
|
private matched;
|
|
21
20
|
min: number;
|
|
22
21
|
max: number;
|
|
23
|
-
constructor(property: Property, args: Matcher
|
|
22
|
+
constructor(property: Property, args: Matcher[] | undefined, returnValue: ReturnValue);
|
|
24
23
|
setInvocationCount(min: number, max?: number): void;
|
|
25
24
|
matches(args: any[] | undefined): boolean;
|
|
26
25
|
isUnmet(): boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export {
|
|
1
|
+
export { mock } from './mock/mock';
|
|
2
|
+
export { when } from './when/when';
|
|
3
|
+
export { reset, resetAll } from './verify/reset';
|
|
4
|
+
export { verify, verifyAll } from './verify/verify';
|
|
5
|
+
export { It } from './expectation/it';
|
|
6
|
+
export { setDefaults } from './mock/defaults';
|
|
7
|
+
export type { Matcher } from './expectation/matcher';
|
|
8
|
+
export type { StrongMockDefaults } from './mock/defaults';
|