strong-mock 7.2.1 → 8.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.
- package/README.md +180 -118
- 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/expectation-repository.d.ts +17 -2
- package/dist/expectation/repository/flexible-repository.d.ts +37 -0
- package/dist/expectation/{matcher-expectation.d.ts → strong-expectation.d.ts} +4 -6
- package/dist/index.d.ts +9 -7
- package/dist/index.js +1095 -953
- package/dist/index.js.map +1 -0
- package/dist/mock/defaults.d.ts +11 -0
- package/dist/mock/map.d.ts +3 -1
- package/dist/mock/mock.d.ts +16 -17
- package/dist/mock/options.d.ts +72 -0
- package/dist/mock/stub.d.ts +12 -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/pending-expectation.d.ts +5 -3
- package/dist/when/when.d.ts +6 -5
- package/package.json +23 -25
- package/CHANGELOG.md +0 -135
- package/dist/expectation/repository/base-repository.d.ts +0 -41
- package/dist/expectation/repository/strong-repository.d.ts +0 -10
- package/dist/expectation/repository/weak-repository.d.ts +0 -17
- package/dist/instance/instance.d.ts +0 -14
package/dist/index.js
CHANGED
|
@@ -1,144 +1,777 @@
|
|
|
1
|
-
|
|
1
|
+
var jestMatcherUtils = require('jest-matcher-utils');
|
|
2
|
+
var lodash = require('lodash');
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const MATCHER_SYMBOL = Symbol('matcher');
|
|
5
|
+
/**
|
|
6
|
+
* Used to test if an expectation on an argument is a custom matcher.
|
|
7
|
+
*/
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var isMatchWith = require('lodash/isMatchWith');
|
|
8
|
-
|
|
9
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
10
|
-
|
|
11
|
-
var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
|
|
12
|
-
var isMatchWith__default = /*#__PURE__*/_interopDefaultLegacy(isMatchWith);
|
|
13
|
-
|
|
14
|
-
/*! *****************************************************************************
|
|
15
|
-
Copyright (c) Microsoft Corporation.
|
|
16
|
-
|
|
17
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
18
|
-
purpose with or without fee is hereby granted.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
21
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
22
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
23
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
24
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
25
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
26
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
27
|
-
***************************************************************************** */
|
|
28
|
-
/* global Reflect, Promise */
|
|
29
|
-
|
|
30
|
-
var extendStatics = function(d, b) {
|
|
31
|
-
extendStatics = Object.setPrototypeOf ||
|
|
32
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
33
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
34
|
-
return extendStatics(d, b);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
function __extends(d, b) {
|
|
38
|
-
if (typeof b !== "function" && b !== null)
|
|
39
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
40
|
-
extendStatics(d, b);
|
|
41
|
-
function __() { this.constructor = d; }
|
|
42
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
var __assign = function() {
|
|
46
|
-
__assign = Object.assign || function __assign(t) {
|
|
47
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
48
|
-
s = arguments[i];
|
|
49
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
50
|
-
}
|
|
51
|
-
return t;
|
|
52
|
-
};
|
|
53
|
-
return __assign.apply(this, arguments);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
function __read(o, n) {
|
|
57
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
58
|
-
if (!m) return o;
|
|
59
|
-
var i = m.call(o), r, ar = [], e;
|
|
60
|
-
try {
|
|
61
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
62
|
-
}
|
|
63
|
-
catch (error) { e = { error: error }; }
|
|
64
|
-
finally {
|
|
65
|
-
try {
|
|
66
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
67
|
-
}
|
|
68
|
-
finally { if (e) throw e.error; }
|
|
69
|
-
}
|
|
70
|
-
return ar;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function __spreadArray(to, from) {
|
|
74
|
-
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
|
75
|
-
to[j] = from[i];
|
|
76
|
-
return to;
|
|
9
|
+
function isMatcher(f) {
|
|
10
|
+
return !!(f && f[MATCHER_SYMBOL]);
|
|
77
11
|
}
|
|
78
12
|
|
|
79
13
|
/**
|
|
80
14
|
* Special symbol denoting the call of a function.
|
|
81
|
-
*/
|
|
82
|
-
|
|
15
|
+
*/
|
|
16
|
+
const ApplyProp = Symbol('apply');
|
|
17
|
+
|
|
18
|
+
const printProperty = property => {
|
|
19
|
+
if (property === ApplyProp) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof property === 'symbol') {
|
|
24
|
+
return `[${property.toString()}]`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return `.${property}`;
|
|
28
|
+
};
|
|
29
|
+
const printArg = arg => // Call toJSON on matchers directly to avoid wrapping them in quotes.
|
|
30
|
+
isMatcher(arg) ? arg.toJSON() : jestMatcherUtils.printExpected(arg);
|
|
31
|
+
const printCall = (property, args) => {
|
|
32
|
+
const prettyArgs = args.map(arg => printArg(arg)).join(', ');
|
|
33
|
+
const prettyProperty = printProperty(property);
|
|
34
|
+
return `${prettyProperty}(${prettyArgs})`;
|
|
35
|
+
};
|
|
36
|
+
const printReturns = ({
|
|
37
|
+
isError,
|
|
38
|
+
isPromise,
|
|
39
|
+
value
|
|
40
|
+
}, min, max) => {
|
|
41
|
+
let thenPrefix = '';
|
|
42
|
+
|
|
43
|
+
if (isPromise) {
|
|
44
|
+
if (isError) {
|
|
45
|
+
thenPrefix += 'thenReject';
|
|
46
|
+
} else {
|
|
47
|
+
thenPrefix += 'thenResolve';
|
|
48
|
+
}
|
|
49
|
+
} else if (isError) {
|
|
50
|
+
thenPrefix += 'thenThrow';
|
|
51
|
+
} else {
|
|
52
|
+
thenPrefix += 'thenReturn';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return `.${thenPrefix}(${jestMatcherUtils.printExpected(value)}).between(${min}, ${max})`;
|
|
56
|
+
};
|
|
57
|
+
const printWhen = (property, args) => {
|
|
58
|
+
if (args) {
|
|
59
|
+
return `when(() => ${jestMatcherUtils.EXPECTED_COLOR(`mock${printCall(property, args)}`)})`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return `when(() => ${jestMatcherUtils.EXPECTED_COLOR(`mock${printProperty(property)}`)})`;
|
|
63
|
+
};
|
|
64
|
+
const printExpectation = (property, args, returnValue, min, max) => `${printWhen(property, args)}${printReturns(returnValue, min, max)}`;
|
|
65
|
+
const printRemainingExpectations = expectations => expectations.length ? `Remaining unmet expectations:
|
|
66
|
+
- ${expectations.map(e => e.toJSON()).join('\n - ')}` : 'There are no remaining unmet expectations.';
|
|
67
|
+
|
|
68
|
+
class UnfinishedExpectation extends Error {
|
|
69
|
+
constructor(pendingExpectation) {
|
|
70
|
+
super(`There is an unfinished pending expectation:
|
|
71
|
+
|
|
72
|
+
${pendingExpectation.toJSON()}
|
|
73
|
+
|
|
74
|
+
Please finish it by setting a return value even if the value
|
|
75
|
+
is undefined.`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
class MissingWhen extends Error {
|
|
80
|
+
constructor() {
|
|
81
|
+
super(`You tried setting a return value without an expectation.
|
|
82
|
+
|
|
83
|
+
Every call to set a return value must be preceded by an expectation.`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
class UnexpectedAccess extends Error {
|
|
88
|
+
constructor(property, expectations) {
|
|
89
|
+
super(`Didn't expect ${jestMatcherUtils.EXPECTED_COLOR(`mock${printProperty(property)}`)} to be accessed.
|
|
90
|
+
|
|
91
|
+
If you expect this property to be accessed then please
|
|
92
|
+
set an expectation for it.
|
|
93
|
+
|
|
94
|
+
${printRemainingExpectations(expectations)}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
class UnexpectedCall extends Error {
|
|
99
|
+
constructor(property, args, expectations) {
|
|
100
|
+
super(`Didn't expect ${jestMatcherUtils.EXPECTED_COLOR(`mock${printCall(property, args)}`)} to be called.
|
|
101
|
+
|
|
102
|
+
${printRemainingExpectations(expectations)}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
class NotAMock extends Error {
|
|
107
|
+
constructor() {
|
|
108
|
+
super(`We couldn't find the mock.
|
|
109
|
+
|
|
110
|
+
Make sure you're passing in an actual mock.`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
class UnmetExpectations extends Error {
|
|
115
|
+
constructor(expectations) {
|
|
116
|
+
super(`There are unmet expectations:
|
|
117
|
+
|
|
118
|
+
- ${expectations.map(e => e.toJSON()).join('\n - ')}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Merge property accesses and method calls for the same property
|
|
124
|
+
* into a single call.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* mergeCalls({ foo: [{ arguments: undefined }, { arguments: [1, 2, 3] }] }
|
|
128
|
+
* // returns { foo: [{ arguments: [1, 2, 3] } }
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
const mergeCalls = callMap => new Map(Array.from(callMap.entries()).map(([property, calls]) => {
|
|
132
|
+
const hasMethodCalls = calls.some(call => call.arguments);
|
|
133
|
+
const hasPropertyAccesses = calls.some(call => !call.arguments);
|
|
134
|
+
|
|
135
|
+
if (hasMethodCalls && hasPropertyAccesses) {
|
|
136
|
+
return [property, calls.filter(call => call.arguments)];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return [property, calls];
|
|
140
|
+
}));
|
|
141
|
+
|
|
142
|
+
class UnexpectedCalls extends Error {
|
|
143
|
+
constructor(unexpectedCalls, expectations) {
|
|
144
|
+
const printedCalls = Array.from(mergeCalls(unexpectedCalls).entries()).map(([property, calls]) => calls.map(call => call.arguments ? jestMatcherUtils.EXPECTED_COLOR(`mock${printCall(property, call.arguments)}`) : jestMatcherUtils.EXPECTED_COLOR(`mock${printProperty(property)}`)).join('\n - ')).join('\n - ');
|
|
145
|
+
super(`The following calls were unexpected:
|
|
146
|
+
|
|
147
|
+
- ${printedCalls}
|
|
148
|
+
|
|
149
|
+
${printRemainingExpectations(expectations)}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
class NestedWhen extends Error {
|
|
154
|
+
constructor(parentProp, childProp) {
|
|
155
|
+
const snippet = `
|
|
156
|
+
const parentMock = mock<T1>();
|
|
157
|
+
const childMock = mock<T2>();
|
|
158
|
+
|
|
159
|
+
when(() => childMock${printProperty(childProp)}).thenReturn(...);
|
|
160
|
+
when(() => parentMock${printProperty(parentProp)}).thenReturn(childMock)
|
|
161
|
+
`;
|
|
162
|
+
super(`Setting an expectation on a nested property is not supported.
|
|
163
|
+
|
|
164
|
+
You can return an object directly when the first property is accessed,
|
|
165
|
+
or you can even return a separate mock:
|
|
166
|
+
${snippet}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
}
|
|
83
170
|
|
|
84
171
|
/**
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
172
|
+
* Controls what happens when a property is accessed, or a call is made,
|
|
173
|
+
* and there are no expectations set for it.
|
|
174
|
+
*/
|
|
175
|
+
exports.Strictness = void 0;
|
|
176
|
+
|
|
177
|
+
(function (Strictness) {
|
|
178
|
+
/**
|
|
179
|
+
* Any property that's accessed, or any call that's made, without a matching
|
|
180
|
+
* expectation, will throw immediately.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* type Service = { foo: (x: number) => number };
|
|
184
|
+
* const service = mock<Service>();
|
|
185
|
+
*
|
|
186
|
+
* // This will throw.
|
|
187
|
+
* const { foo } = service;
|
|
188
|
+
*
|
|
189
|
+
* // Will throw "Didn't expect foo to be accessed",
|
|
190
|
+
* // without printing the arguments.
|
|
191
|
+
* foo(42);
|
|
192
|
+
*/
|
|
193
|
+
Strictness[Strictness["SUPER_STRICT"] = 0] = "SUPER_STRICT";
|
|
194
|
+
/**
|
|
195
|
+
* Properties with unmatched expectations will return functions that will
|
|
196
|
+
* throw if called. This can be useful if your code destructures a function
|
|
197
|
+
* but never calls it.
|
|
198
|
+
*
|
|
199
|
+
* It will also improve error messages for unexpected calls because arguments
|
|
200
|
+
* will be captured instead of throwing immediately on the property access.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* type Service = { foo: (x: number) => number };
|
|
204
|
+
* const service = mock<Service>();
|
|
205
|
+
*
|
|
206
|
+
* // This will not throw.
|
|
207
|
+
* const { foo } = service;
|
|
208
|
+
*
|
|
209
|
+
* // Will throw "Didn't expect foo(42) to be called".
|
|
210
|
+
* foo(42);
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
Strictness[Strictness["STRICT"] = 1] = "STRICT";
|
|
214
|
+
})(exports.Strictness || (exports.Strictness = {}));
|
|
215
|
+
|
|
216
|
+
const createProxy = traps => // eslint-disable-next-line no-empty-function
|
|
217
|
+
new Proxy(
|
|
218
|
+
/* istanbul ignore next */
|
|
219
|
+
() => {}, {
|
|
220
|
+
get: (target, prop) => {
|
|
221
|
+
if (prop === 'bind') {
|
|
222
|
+
return (thisArg, ...args) => (...moreArgs) => traps.apply([...args, ...moreArgs]);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (prop === 'apply') {
|
|
226
|
+
return (thisArg, args) => traps.apply(args || []);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (prop === 'call') {
|
|
230
|
+
return (thisArg, ...args) => traps.apply(args);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return traps.property(prop);
|
|
234
|
+
},
|
|
235
|
+
apply: (target, thisArg, args) => traps.apply(args),
|
|
236
|
+
ownKeys: () => traps.ownKeys(),
|
|
237
|
+
|
|
238
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
239
|
+
const keys = traps.ownKeys();
|
|
240
|
+
|
|
241
|
+
if (keys.includes(prop)) {
|
|
242
|
+
return {
|
|
243
|
+
configurable: true,
|
|
244
|
+
enumerable: true
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
});
|
|
252
|
+
|
|
90
253
|
/**
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
254
|
+
* Since `when` doesn't receive the mock subject (because we can't make it
|
|
255
|
+
* consistently return it from `mock()`, `mock.foo` and `mock.bar()`) we need
|
|
256
|
+
* to store a global state for the currently active mock.
|
|
257
|
+
*
|
|
258
|
+
* We also want to throw in the following case:
|
|
259
|
+
*
|
|
260
|
+
* ```
|
|
261
|
+
* when(() => mock()) // forgot returns here
|
|
262
|
+
* when(() => mock()) // should throw
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* For that reason we can't just store the currently active mock, but also
|
|
266
|
+
* whether we finished the expectation or not.
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
let activeMock;
|
|
270
|
+
const setActiveMock = mock => {
|
|
271
|
+
activeMock = mock;
|
|
272
|
+
};
|
|
273
|
+
const getActiveMock = () => activeMock;
|
|
102
274
|
/**
|
|
103
|
-
*
|
|
275
|
+
* Store a global map of all mocks created and their state.
|
|
104
276
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
|
|
277
|
+
* This is needed because we can't reliably pass the state between `when`
|
|
278
|
+
* and `thenReturn`.
|
|
279
|
+
*/
|
|
280
|
+
|
|
281
|
+
const mockMap = new Map();
|
|
282
|
+
const getMockState = mock => {
|
|
283
|
+
if (mockMap.has(mock)) {
|
|
284
|
+
return mockMap.get(mock);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
throw new NotAMock();
|
|
288
|
+
};
|
|
289
|
+
const setMockState = (mock, state) => {
|
|
290
|
+
mockMap.set(mock, state);
|
|
291
|
+
};
|
|
292
|
+
const getAllMocks = () => Array.from(mockMap.entries());
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Return the expectation's return value.
|
|
296
|
+
*
|
|
297
|
+
* If the value is an error then throw it.
|
|
298
|
+
*
|
|
299
|
+
* If the value is a promise then resolve/reject it.
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
const returnOrThrow = ({
|
|
303
|
+
isError,
|
|
304
|
+
isPromise,
|
|
305
|
+
value
|
|
306
|
+
}) => {
|
|
307
|
+
if (isError) {
|
|
308
|
+
if (isPromise) {
|
|
309
|
+
return Promise.reject(value);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (value instanceof Error) {
|
|
313
|
+
throw value;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
throw new Error(value);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (isPromise) {
|
|
320
|
+
return Promise.resolve(value);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return value;
|
|
324
|
+
};
|
|
325
|
+
const createStub = (repo, pendingExpectation, getCurrentMode, concreteMatcher) => {
|
|
326
|
+
const stub = createProxy({
|
|
327
|
+
property: property => {
|
|
328
|
+
if (getCurrentMode() === Mode.CALL) {
|
|
329
|
+
return returnOrThrow(repo.get(property));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
setActiveMock(stub);
|
|
333
|
+
pendingExpectation.start(repo, concreteMatcher); // eslint-disable-next-line no-param-reassign
|
|
334
|
+
|
|
335
|
+
pendingExpectation.property = property;
|
|
336
|
+
return createProxy({
|
|
337
|
+
property: childProp => {
|
|
338
|
+
pendingExpectation.clear();
|
|
339
|
+
throw new NestedWhen(property, childProp);
|
|
340
|
+
},
|
|
341
|
+
apply: args => {
|
|
342
|
+
// eslint-disable-next-line no-param-reassign
|
|
343
|
+
pendingExpectation.args = args;
|
|
344
|
+
},
|
|
345
|
+
ownKeys: () => {
|
|
346
|
+
throw new Error('Spreading during an expectation is not supported.');
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
},
|
|
350
|
+
apply: args => {
|
|
351
|
+
if (getCurrentMode() === Mode.CALL) {
|
|
352
|
+
return repo.apply(args);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
setActiveMock(stub);
|
|
356
|
+
pendingExpectation.start(repo, concreteMatcher); // eslint-disable-next-line no-param-reassign
|
|
357
|
+
|
|
358
|
+
pendingExpectation.property = ApplyProp; // eslint-disable-next-line no-param-reassign
|
|
359
|
+
|
|
360
|
+
pendingExpectation.args = args;
|
|
361
|
+
return undefined;
|
|
362
|
+
},
|
|
363
|
+
ownKeys: () => {
|
|
364
|
+
if (getCurrentMode() === Mode.CALL) {
|
|
365
|
+
return repo.getAllProperties();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
throw new Error('Spreading during an expectation is not supported.');
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
return stub;
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* An expectation repository for configurable levels of strictness.
|
|
376
|
+
*/
|
|
377
|
+
|
|
378
|
+
class FlexibleRepository {
|
|
379
|
+
constructor(strictness = exports.Strictness.SUPER_STRICT) {
|
|
380
|
+
this.strictness = void 0;
|
|
381
|
+
this.expectations = new Map();
|
|
382
|
+
this.expectedCallStats = new Map();
|
|
383
|
+
this.unexpectedCallStats = new Map();
|
|
384
|
+
|
|
385
|
+
this.apply = args => this.get(ApplyProp).value(...args);
|
|
386
|
+
|
|
387
|
+
this.handlePropertyWithMatchingExpectations = (property, expectations) => {
|
|
388
|
+
// Avoid recording call stats for function calls, since the property is an
|
|
389
|
+
// internal detail.
|
|
390
|
+
if (property !== ApplyProp) {
|
|
391
|
+
// An unexpected call could still happen later, if the property returns a
|
|
392
|
+
// function that will not match the given args.
|
|
393
|
+
this.recordExpected(property, undefined);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const propertyExpectation = expectations.find(e => e.expectation.matches(undefined));
|
|
397
|
+
|
|
398
|
+
if (propertyExpectation) {
|
|
399
|
+
this.countAndConsume(propertyExpectation);
|
|
400
|
+
return propertyExpectation.expectation.returnValue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
value: (...args) => {
|
|
405
|
+
const callExpectation = expectations.find(e => e.expectation.matches(args));
|
|
406
|
+
|
|
407
|
+
if (callExpectation) {
|
|
408
|
+
this.recordExpected(property, args);
|
|
409
|
+
this.countAndConsume(callExpectation); // TODO: this is duplicated in stub
|
|
410
|
+
|
|
411
|
+
return returnOrThrow(callExpectation.expectation.returnValue);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return this.getValueForUnexpectedCall(property, args);
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
this.handlePropertyWithNoExpectations = property => {
|
|
420
|
+
switch (property) {
|
|
421
|
+
case 'toString':
|
|
422
|
+
return {
|
|
423
|
+
value: () => 'mock'
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
case '@@toStringTag':
|
|
427
|
+
case Symbol.toStringTag:
|
|
428
|
+
case 'name':
|
|
429
|
+
return {
|
|
430
|
+
value: 'mock'
|
|
431
|
+
};
|
|
432
|
+
// pretty-format
|
|
433
|
+
|
|
434
|
+
case '$$typeof':
|
|
435
|
+
case 'constructor':
|
|
436
|
+
case '@@__IMMUTABLE_ITERABLE__@@':
|
|
437
|
+
case '@@__IMMUTABLE_RECORD__@@':
|
|
438
|
+
return {
|
|
439
|
+
value: null
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
case MATCHER_SYMBOL:
|
|
443
|
+
return {
|
|
444
|
+
value: false
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
case ApplyProp:
|
|
448
|
+
return {
|
|
449
|
+
value: (...args) => this.getValueForUnexpectedCall(property, args)
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
default:
|
|
453
|
+
return this.getValueForUnexpectedAccess(property);
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
this.strictness = strictness;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
add(expectation) {
|
|
461
|
+
const {
|
|
462
|
+
property
|
|
463
|
+
} = expectation;
|
|
464
|
+
const expectations = this.expectations.get(property) || [];
|
|
465
|
+
this.expectations.set(property, [...expectations, {
|
|
466
|
+
expectation,
|
|
467
|
+
matchCount: 0
|
|
468
|
+
}]);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
clear() {
|
|
472
|
+
this.expectations.clear();
|
|
473
|
+
this.expectedCallStats.clear();
|
|
474
|
+
this.unexpectedCallStats.clear();
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
get(property) {
|
|
478
|
+
const expectations = this.expectations.get(property);
|
|
479
|
+
|
|
480
|
+
if (expectations && expectations.length) {
|
|
481
|
+
return this.handlePropertyWithMatchingExpectations(property, expectations);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return this.handlePropertyWithNoExpectations(property);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
getAllProperties() {
|
|
488
|
+
return Array.from(this.expectations.keys());
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
getCallStats() {
|
|
492
|
+
return {
|
|
493
|
+
expected: this.expectedCallStats,
|
|
494
|
+
unexpected: this.unexpectedCallStats
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
getUnmet() {
|
|
499
|
+
return [].concat(...Array.from(this.expectations.values()).map(expectations => expectations.filter(e => e.expectation.min > e.matchCount).map(e => e.expectation)));
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
recordExpected(property, args) {
|
|
503
|
+
const calls = this.expectedCallStats.get(property) || [];
|
|
504
|
+
this.expectedCallStats.set(property, [...calls, {
|
|
505
|
+
arguments: args
|
|
506
|
+
}]);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
recordUnexpected(property, args) {
|
|
510
|
+
const calls = this.unexpectedCallStats.get(property) || [];
|
|
511
|
+
this.unexpectedCallStats.set(property, [...calls, {
|
|
512
|
+
arguments: args
|
|
513
|
+
}]);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
countAndConsume(expectation) {
|
|
517
|
+
// eslint-disable-next-line no-param-reassign
|
|
518
|
+
expectation.matchCount++;
|
|
519
|
+
this.consumeExpectation(expectation);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
consumeExpectation(expectation) {
|
|
523
|
+
const {
|
|
524
|
+
property,
|
|
525
|
+
max
|
|
526
|
+
} = expectation.expectation;
|
|
527
|
+
const expectations = this.expectations.get(property);
|
|
528
|
+
|
|
529
|
+
if (expectation.matchCount === max) {
|
|
530
|
+
this.expectations.set(property, expectations.filter(e => e !== expectation));
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
getValueForUnexpectedCall(property, args) {
|
|
535
|
+
this.recordUnexpected(property, args);
|
|
536
|
+
throw new UnexpectedCall(property, args, this.getUnmet());
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
getValueForUnexpectedAccess(property) {
|
|
540
|
+
if (this.strictness === exports.Strictness.SUPER_STRICT) {
|
|
541
|
+
this.recordUnexpected(property, undefined);
|
|
542
|
+
throw new UnexpectedAccess(property, this.getUnmet());
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
value: (...args) => {
|
|
547
|
+
this.recordUnexpected(property, args);
|
|
548
|
+
throw new UnexpectedCall(property, args, this.getUnmet());
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Matches a call with more parameters than expected because it is assumed the
|
|
557
|
+
* compiler will check that those parameters are optional.
|
|
108
558
|
*
|
|
109
|
-
*
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
559
|
+
* @example
|
|
560
|
+
* new StrongExpectation(
|
|
561
|
+
* 'bar',
|
|
562
|
+
* deepEquals([1, 2, 3]),
|
|
563
|
+
* 23
|
|
564
|
+
* ).matches('bar', [1, 2, 3]) === true;
|
|
565
|
+
*/
|
|
566
|
+
|
|
567
|
+
class StrongExpectation {
|
|
568
|
+
constructor(property, args, returnValue) {
|
|
569
|
+
this.property = void 0;
|
|
570
|
+
this.args = void 0;
|
|
571
|
+
this.returnValue = void 0;
|
|
572
|
+
this.matched = 0;
|
|
573
|
+
this.min = 1;
|
|
574
|
+
this.max = 1;
|
|
575
|
+
this.property = property;
|
|
576
|
+
this.args = args;
|
|
577
|
+
this.returnValue = returnValue;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
setInvocationCount(min, max = 1) {
|
|
581
|
+
this.min = min;
|
|
582
|
+
this.max = max;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
matches(args) {
|
|
586
|
+
if (!this.matchesArgs(args)) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
this.matched++;
|
|
591
|
+
return this.max === 0 || this.matched <= this.max;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
isUnmet() {
|
|
595
|
+
return this.matched < this.min;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
matchesArgs(received) {
|
|
599
|
+
if (this.args === undefined) {
|
|
600
|
+
return !received;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (!received) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return this.args.every((arg, i) => arg.matches(received[i]));
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
toJSON() {
|
|
611
|
+
return printExpectation(this.property, this.args, this.returnValue, this.min, this.max);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
class RepoSideEffectPendingExpectation {
|
|
617
|
+
constructor(createExpectation) {
|
|
618
|
+
this.createExpectation = void 0;
|
|
619
|
+
this._repo = void 0;
|
|
620
|
+
this._concreteMatcher = void 0;
|
|
621
|
+
this._args = void 0;
|
|
622
|
+
this._property = '';
|
|
623
|
+
this.createExpectation = createExpectation;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
start(repo, concreteMatcher) {
|
|
627
|
+
if (this._repo) {
|
|
628
|
+
throw new UnfinishedExpectation(this);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
this.clear();
|
|
632
|
+
this._repo = repo;
|
|
633
|
+
this._concreteMatcher = concreteMatcher;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
set property(value) {
|
|
637
|
+
this._property = value;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
set args(value) {
|
|
641
|
+
this._args = value;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
finish(returnValue) {
|
|
645
|
+
if (!this._repo || !this._concreteMatcher) {
|
|
646
|
+
throw new MissingWhen();
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const expectation = this.createExpectation(this._property, this._args, returnValue, this._concreteMatcher);
|
|
650
|
+
|
|
651
|
+
this._repo.add(expectation);
|
|
652
|
+
|
|
653
|
+
this.clear();
|
|
654
|
+
return expectation;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
clear() {
|
|
658
|
+
this._repo = undefined;
|
|
659
|
+
this._args = undefined;
|
|
660
|
+
this._property = '';
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
toJSON() {
|
|
664
|
+
return printWhen(this._property, this._args);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function _extends() {
|
|
670
|
+
_extends = Object.assign || function (target) {
|
|
671
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
672
|
+
var source = arguments[i];
|
|
673
|
+
|
|
674
|
+
for (var key in source) {
|
|
675
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
676
|
+
target[key] = source[key];
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
return target;
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
return _extends.apply(this, arguments);
|
|
685
|
+
}
|
|
686
|
+
|
|
121
687
|
/**
|
|
122
688
|
* Match a custom predicate.
|
|
123
689
|
*
|
|
124
690
|
* @param cb Will receive the value and returns whether it matches.
|
|
691
|
+
* @param toJSON An optional function that should return a string that will be
|
|
692
|
+
* used when the matcher needs to be printed in an error message. By default,
|
|
693
|
+
* it stringifies `cb`.
|
|
125
694
|
*
|
|
126
695
|
* @example
|
|
127
696
|
* const fn = mock<(x: number) => number>();
|
|
128
|
-
* when(fn(It.matches(x => x >= 0)).returns(42);
|
|
697
|
+
* when(() => fn(It.matches(x => x >= 0))).returns(42);
|
|
698
|
+
*
|
|
699
|
+
* fn(2) === 42
|
|
700
|
+
* fn(-1) // throws
|
|
701
|
+
*/
|
|
702
|
+
|
|
703
|
+
const matches = (cb, {
|
|
704
|
+
toJSON = () => `matches(${cb.toString()})`
|
|
705
|
+
} = {}) => {
|
|
706
|
+
const matcher = {
|
|
707
|
+
[MATCHER_SYMBOL]: true,
|
|
708
|
+
matches: arg => cb(arg),
|
|
709
|
+
toJSON
|
|
710
|
+
};
|
|
711
|
+
return matcher;
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
const removeUndefined = object => {
|
|
715
|
+
if (Array.isArray(object)) {
|
|
716
|
+
return object.map(x => removeUndefined(x));
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (!lodash.isObjectLike(object)) {
|
|
720
|
+
return object;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
return lodash.omitBy(object, lodash.isUndefined);
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* Compare values using deep equality.
|
|
727
|
+
*
|
|
728
|
+
* @param expected
|
|
729
|
+
* @param strict By default, this matcher will treat a missing key in an object
|
|
730
|
+
* and a key with the value `undefined` as not equal. It will also consider
|
|
731
|
+
* non `Object` instances with different constructors as not equal. Setting
|
|
732
|
+
* this to `false` will consider the objects in both cases as equal.
|
|
733
|
+
*
|
|
734
|
+
* @see It.is A matcher that uses strict equality.
|
|
735
|
+
*/
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
const deepEquals = (expected, {
|
|
739
|
+
strict = true
|
|
740
|
+
} = {}) => matches(actual => {
|
|
741
|
+
if (strict) {
|
|
742
|
+
return lodash.isEqual(actual, expected);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return lodash.isEqual(removeUndefined(actual), removeUndefined(expected));
|
|
746
|
+
}, {
|
|
747
|
+
toJSON: () => printArg(expected)
|
|
748
|
+
});
|
|
749
|
+
/**
|
|
750
|
+
* Compare values using `Object.is`.
|
|
751
|
+
*
|
|
752
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
|
129
753
|
*
|
|
130
|
-
*
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
754
|
+
* @see It.deepEquals A matcher that uses deep equality.
|
|
755
|
+
*/
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
const is = expected => matches(actual => Object.is(actual, expected), {
|
|
759
|
+
toJSON: () => `${jestMatcherUtils.printExpected(expected)}`
|
|
760
|
+
});
|
|
761
|
+
/**
|
|
762
|
+
* Match any value, including `undefined` and `null`.
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* const fn = mock<(x: number, y: string) => number>();
|
|
766
|
+
* when(() => fn(It.isAny(), It.isAny())).thenReturn(1);
|
|
767
|
+
*
|
|
768
|
+
* fn(23, 'foobar') === 1
|
|
769
|
+
*/
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
const isAny = () => matches(() => true, {
|
|
773
|
+
toJSON: () => 'anything'
|
|
774
|
+
});
|
|
142
775
|
/**
|
|
143
776
|
* Recursively match an object.
|
|
144
777
|
*
|
|
@@ -148,48 +781,41 @@ var matches = function (cb) {
|
|
|
148
781
|
*
|
|
149
782
|
* @example
|
|
150
783
|
* const fn = mock<(foo: { x: number, y: number }) => number>();
|
|
151
|
-
* when(fn(It.isObject({ x: 23 }).returns(42);
|
|
784
|
+
* when(() => fn(It.isObject({ x: 23 }))).returns(42);
|
|
152
785
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
786
|
+
* fn({ x: 100, y: 200 }) // throws
|
|
787
|
+
* fn({ x: 23, y: 200 }) // returns 42
|
|
155
788
|
*
|
|
156
789
|
* @example
|
|
157
790
|
* It.isObject({ foo: It.isString() })
|
|
158
|
-
*/
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
toJSON: function () {
|
|
172
|
-
return partial ? "object(" + jestMatcherUtils.printExpected(partial) + ")" : 'object';
|
|
173
|
-
},
|
|
174
|
-
});
|
|
175
|
-
};
|
|
791
|
+
*/
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
const isObject = partial => matches(actual => lodash.isMatchWith(actual, partial || {}, (argValue, partialValue) => {
|
|
795
|
+
if (isMatcher(partialValue)) {
|
|
796
|
+
return partialValue.matches(argValue);
|
|
797
|
+
} // Let lodash handle it otherwise.
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
return undefined;
|
|
801
|
+
}), {
|
|
802
|
+
toJSON: () => partial ? `object(${jestMatcherUtils.printExpected(partial)})` : 'object'
|
|
803
|
+
});
|
|
176
804
|
/**
|
|
177
805
|
* Match any number.
|
|
178
806
|
*
|
|
179
807
|
* @example
|
|
180
808
|
* const fn = mock<(x: number) => number>();
|
|
181
|
-
* when(fn(It.isNumber()).returns(42);
|
|
809
|
+
* when(() => fn(It.isNumber())).returns(42);
|
|
182
810
|
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
192
|
-
};
|
|
811
|
+
* fn(20.5) === 42
|
|
812
|
+
* fn(NaN) // throws
|
|
813
|
+
*/
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
const isNumber = () => matches(actual => typeof actual === 'number' && !Number.isNaN(actual), {
|
|
817
|
+
toJSON: () => 'number'
|
|
818
|
+
});
|
|
193
819
|
/**
|
|
194
820
|
* Match a string, potentially by a pattern.
|
|
195
821
|
*
|
|
@@ -198,35 +824,37 @@ var isNumber = function () {
|
|
|
198
824
|
*
|
|
199
825
|
* @example
|
|
200
826
|
* const fn = mock<(x: string, y: string) => number>();
|
|
201
|
-
* when(fn(It.isString(), It.isString({ containing: 'bar' }).returns(42);
|
|
827
|
+
* when(() => fn(It.isString(), It.isString({ containing: 'bar' }))).returns(42);
|
|
202
828
|
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*/
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
829
|
+
* fn('foo', 'baz') // throws
|
|
830
|
+
* fn('foo', 'bar') === 42
|
|
831
|
+
*/
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
const isString = ({
|
|
835
|
+
matching,
|
|
836
|
+
containing
|
|
837
|
+
} = {}) => {
|
|
838
|
+
if (matching && containing) {
|
|
839
|
+
throw new Error('You can only pass `matching` or `containing`, not both.');
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return matches(actual => {
|
|
843
|
+
var _matching$test;
|
|
844
|
+
|
|
845
|
+
if (typeof actual !== 'string') {
|
|
846
|
+
return false;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (containing) {
|
|
850
|
+
return actual.indexOf(containing) !== -1;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return (_matching$test = matching == null ? void 0 : matching.test(actual)) != null ? _matching$test : true;
|
|
854
|
+
}, {
|
|
855
|
+
toJSON: () => containing || matching ? `string(${jestMatcherUtils.printExpected(containing || matching)})` : 'string'
|
|
856
|
+
});
|
|
857
|
+
};
|
|
230
858
|
/**
|
|
231
859
|
* Match an array.
|
|
232
860
|
*
|
|
@@ -237,45 +865,42 @@ var isString = function (_a) {
|
|
|
237
865
|
*
|
|
238
866
|
* @example
|
|
239
867
|
* const fn = mock<(arr: number[]) => number>();
|
|
240
|
-
* when(fn(It.isArray())).thenReturn(1);
|
|
241
|
-
* when(fn(It.isArray([2, 3))).thenReturn(2);
|
|
868
|
+
* when(() => fn(It.isArray())).thenReturn(1);
|
|
869
|
+
* when(() => fn(It.isArray([2, 3]))).thenReturn(2);
|
|
242
870
|
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
871
|
+
* fn({ length: 1, 0: 42 }) // throws
|
|
872
|
+
* fn([]) === 1
|
|
873
|
+
* fn([3, 2, 1]) === 2
|
|
246
874
|
*
|
|
247
875
|
* @example
|
|
248
|
-
* It.isArray([It.isString({ containing: 'foobar' }))
|
|
249
|
-
*/
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
};
|
|
876
|
+
* It.isArray([It.isString({ containing: 'foobar' })])
|
|
877
|
+
*/
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
const isArray = containing => matches(actual => {
|
|
881
|
+
if (!Array.isArray(actual)) {
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (!containing) {
|
|
886
|
+
return true;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return containing.every(x => actual.find(y => {
|
|
890
|
+
if (isMatcher(x)) {
|
|
891
|
+
return x.matches(y);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
return deepEquals(x).matches(y);
|
|
895
|
+
}) !== undefined);
|
|
896
|
+
}, {
|
|
897
|
+
toJSON: () => containing ? `array(${jestMatcherUtils.printExpected(containing)})` : 'array'
|
|
898
|
+
});
|
|
274
899
|
/**
|
|
275
900
|
* Matches anything and stores the received value.
|
|
276
901
|
*
|
|
277
902
|
* This should not be needed for most cases, but can be useful if you need
|
|
278
|
-
* access to a complex argument outside
|
|
903
|
+
* access to a complex argument outside the expectation e.g. to test a
|
|
279
904
|
* callback.
|
|
280
905
|
*
|
|
281
906
|
* @param name If given, this name will be printed in error messages.
|
|
@@ -283,629 +908,253 @@ var isArray = function (containing) {
|
|
|
283
908
|
* @example
|
|
284
909
|
* const fn = mock<(cb: (value: number) => number) => void>();
|
|
285
910
|
* const matcher = It.willCapture();
|
|
286
|
-
* when(fn(matcher)).thenReturn();
|
|
911
|
+
* when(() => fn(matcher)).thenReturn();
|
|
287
912
|
*
|
|
288
|
-
*
|
|
913
|
+
* fn(x => x + 1);
|
|
289
914
|
* matcher.value?.(3) === 4
|
|
290
|
-
*/
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
|
|
915
|
+
*/
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
const willCapture = name => {
|
|
919
|
+
let capturedValue;
|
|
920
|
+
const matcher = {
|
|
921
|
+
[MATCHER_SYMBOL]: true,
|
|
922
|
+
matches: actual => {
|
|
923
|
+
capturedValue = actual;
|
|
924
|
+
return true;
|
|
925
|
+
},
|
|
926
|
+
toJSON: () => name != null ? name : 'captures',
|
|
927
|
+
|
|
928
|
+
get value() {
|
|
929
|
+
return capturedValue;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
};
|
|
933
|
+
return matcher;
|
|
934
|
+
};
|
|
307
935
|
/**
|
|
308
936
|
* Contains argument matchers that can be used to ignore arguments in an
|
|
309
937
|
* expectation or to match complex arguments.
|
|
310
|
-
*/
|
|
311
|
-
|
|
312
|
-
isAny: isAny,
|
|
313
|
-
matches: matches,
|
|
314
|
-
isObject: isObject,
|
|
315
|
-
isNumber: isNumber,
|
|
316
|
-
isString: isString,
|
|
317
|
-
isArray: isArray,
|
|
318
|
-
willCapture: willCapture,
|
|
319
|
-
};
|
|
938
|
+
*/
|
|
939
|
+
|
|
320
940
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
// Call toJSON on matchers directly to avoid wrapping them in quotes.
|
|
332
|
-
return isMatcher(arg) ? arg.toJSON() : jestMatcherUtils.printExpected(arg);
|
|
333
|
-
};
|
|
334
|
-
var printCall = function (property, args) {
|
|
335
|
-
// TODO: don't leak the matcher concept here
|
|
336
|
-
var prettyArgs = args.map(function (arg) { return printArg(arg); }).join(', ');
|
|
337
|
-
var prettyProperty = printProperty(property);
|
|
338
|
-
return prettyProperty + "(" + prettyArgs + ")";
|
|
339
|
-
};
|
|
340
|
-
var printReturns = function (_a, min, max) {
|
|
341
|
-
var isError = _a.isError, isPromise = _a.isPromise, value = _a.value;
|
|
342
|
-
var thenPrefix = '';
|
|
343
|
-
if (isPromise) {
|
|
344
|
-
if (isError) {
|
|
345
|
-
thenPrefix += 'thenReject';
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
thenPrefix += 'thenResolve';
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
else if (isError) {
|
|
352
|
-
thenPrefix += 'thenThrow';
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
thenPrefix += 'thenReturn';
|
|
356
|
-
}
|
|
357
|
-
return "." + thenPrefix + "(" + jestMatcherUtils.printExpected(value) + ").between(" + min + ", " + max + ")";
|
|
358
|
-
};
|
|
359
|
-
var printWhen = function (property, args) {
|
|
360
|
-
if (args) {
|
|
361
|
-
return "when(" + jestMatcherUtils.EXPECTED_COLOR("mock" + printCall(property, args)) + ")";
|
|
362
|
-
}
|
|
363
|
-
return "when(" + jestMatcherUtils.EXPECTED_COLOR("mock" + printProperty(property)) + ")";
|
|
364
|
-
};
|
|
365
|
-
var printExpectation = function (property, args, returnValue, min, max) { return "" + printWhen(property, args) + printReturns(returnValue, min, max); };
|
|
366
|
-
var printRemainingExpectations = function (expectations) {
|
|
367
|
-
return expectations.length
|
|
368
|
-
? "Remaining unmet expectations:\n - " + expectations.map(function (e) { return e.toJSON(); }).join('\n - ')
|
|
369
|
-
: 'There are no remaining unmet expectations.';
|
|
941
|
+
const It = {
|
|
942
|
+
matches,
|
|
943
|
+
deepEquals,
|
|
944
|
+
is,
|
|
945
|
+
isAny,
|
|
946
|
+
isObject,
|
|
947
|
+
isNumber,
|
|
948
|
+
isString,
|
|
949
|
+
isArray,
|
|
950
|
+
willCapture
|
|
370
951
|
};
|
|
371
952
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return UnfinishedExpectation;
|
|
378
|
-
}(Error));
|
|
379
|
-
var MissingWhen = /** @class */ (function (_super) {
|
|
380
|
-
__extends(MissingWhen, _super);
|
|
381
|
-
function MissingWhen() {
|
|
382
|
-
return _super.call(this, "You tried setting a return value without an expectation.\n\nEvery call to set a return value must be preceded by an expectation.") || this;
|
|
383
|
-
}
|
|
384
|
-
return MissingWhen;
|
|
385
|
-
}(Error));
|
|
386
|
-
var UnexpectedAccess = /** @class */ (function (_super) {
|
|
387
|
-
__extends(UnexpectedAccess, _super);
|
|
388
|
-
function UnexpectedAccess(property, expectations) {
|
|
389
|
-
return _super.call(this, "Didn't expect " + jestMatcherUtils.EXPECTED_COLOR("mock" + printProperty(property)) + " to be accessed.\n\nIf you expect this property to be accessed then please\nset an expectation for it.\n\n" + printRemainingExpectations(expectations)) || this;
|
|
390
|
-
}
|
|
391
|
-
return UnexpectedAccess;
|
|
392
|
-
}(Error));
|
|
393
|
-
var UnexpectedCall = /** @class */ (function (_super) {
|
|
394
|
-
__extends(UnexpectedCall, _super);
|
|
395
|
-
function UnexpectedCall(property, args, expectations) {
|
|
396
|
-
return _super.call(this, "Didn't expect " + jestMatcherUtils.EXPECTED_COLOR("mock" + printCall(property, args)) + " to be called.\n\n" + printRemainingExpectations(expectations)) || this;
|
|
397
|
-
}
|
|
398
|
-
return UnexpectedCall;
|
|
399
|
-
}(Error));
|
|
400
|
-
var NotAMock = /** @class */ (function (_super) {
|
|
401
|
-
__extends(NotAMock, _super);
|
|
402
|
-
function NotAMock() {
|
|
403
|
-
return _super.call(this, "We couldn't find the mock.\n\nMake sure you're passing in an actual mock.") || this;
|
|
404
|
-
}
|
|
405
|
-
return NotAMock;
|
|
406
|
-
}(Error));
|
|
407
|
-
var UnmetExpectations = /** @class */ (function (_super) {
|
|
408
|
-
__extends(UnmetExpectations, _super);
|
|
409
|
-
function UnmetExpectations(expectations) {
|
|
410
|
-
return _super.call(this, "There are unmet expectations:\n\n - " + expectations.map(function (e) { return e.toJSON(); }).join('\n - ')) || this;
|
|
411
|
-
}
|
|
412
|
-
return UnmetExpectations;
|
|
413
|
-
}(Error));
|
|
953
|
+
const defaults = {
|
|
954
|
+
concreteMatcher: It.deepEquals,
|
|
955
|
+
strictness: exports.Strictness.STRICT
|
|
956
|
+
};
|
|
957
|
+
let currentDefaults = defaults;
|
|
414
958
|
/**
|
|
415
|
-
*
|
|
416
|
-
* into a single call.
|
|
959
|
+
* Override strong-mock's defaults.
|
|
417
960
|
*
|
|
418
|
-
* @
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*/
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
var hasPropertyAccesses = calls.some(function (call) { return !call.arguments; });
|
|
427
|
-
if (hasMethodCalls && hasPropertyAccesses) {
|
|
428
|
-
return [property, calls.filter(function (call) { return call.arguments; })];
|
|
429
|
-
}
|
|
430
|
-
return [property, calls];
|
|
431
|
-
}));
|
|
432
|
-
};
|
|
433
|
-
var UnexpectedCalls = /** @class */ (function (_super) {
|
|
434
|
-
__extends(UnexpectedCalls, _super);
|
|
435
|
-
function UnexpectedCalls(unexpectedCalls, expectations) {
|
|
436
|
-
var _this = this;
|
|
437
|
-
var printedCalls = Array.from(mergeCalls(unexpectedCalls).entries())
|
|
438
|
-
.map(function (_a) {
|
|
439
|
-
var _b = __read(_a, 2), property = _b[0], calls = _b[1];
|
|
440
|
-
return calls
|
|
441
|
-
.map(function (call) {
|
|
442
|
-
return call.arguments
|
|
443
|
-
? jestMatcherUtils.EXPECTED_COLOR("mock" + printCall(property, call.arguments))
|
|
444
|
-
: jestMatcherUtils.EXPECTED_COLOR("mock" + printProperty(property));
|
|
445
|
-
})
|
|
446
|
-
.join('\n - ');
|
|
447
|
-
})
|
|
448
|
-
.join('\n - ');
|
|
449
|
-
_this = _super.call(this, "The following calls were unexpected:\n\n - " + printedCalls + "\n\n" + printRemainingExpectations(expectations)) || this;
|
|
450
|
-
return _this;
|
|
451
|
-
}
|
|
452
|
-
return UnexpectedCalls;
|
|
453
|
-
}(Error));
|
|
454
|
-
var NestedWhen = /** @class */ (function (_super) {
|
|
455
|
-
__extends(NestedWhen, _super);
|
|
456
|
-
function NestedWhen(parentProp, childProp) {
|
|
457
|
-
var _this = this;
|
|
458
|
-
var snippet = "\nconst parentMock = mock<T1>();\nconst childMock = mock<T2>();\n\nwhen(childMock" + printProperty(childProp) + ").thenReturn(...);\nwhen(parentMock" + printProperty(parentProp) + ").thenReturn(instance(childMock))\n";
|
|
459
|
-
_this = _super.call(this, "Setting an expectation on a nested property is not supported.\n\nYou can return an object directly when the first property is accessed,\nor you can even return a separate mock:\n" + snippet) || this;
|
|
460
|
-
return _this;
|
|
461
|
-
}
|
|
462
|
-
return NestedWhen;
|
|
463
|
-
}(Error));
|
|
961
|
+
* @param newDefaults These will be applied to the library defaults. Multiple
|
|
962
|
+
* calls don't stack e.g. calling this with `{}` will clear any previously
|
|
963
|
+
* applied defaults.
|
|
964
|
+
*/
|
|
965
|
+
|
|
966
|
+
const setDefaults = newDefaults => {
|
|
967
|
+
currentDefaults = _extends({}, defaults, newDefaults);
|
|
968
|
+
};
|
|
464
969
|
|
|
970
|
+
const strongExpectationFactory = (property, args, returnValue, concreteMatcher) => new StrongExpectation(property, // Wrap every non-matcher in the default matcher.
|
|
971
|
+
args == null ? void 0 : args.map(arg => isMatcher(arg) ? arg : concreteMatcher(arg)), returnValue);
|
|
972
|
+
|
|
973
|
+
var Mode;
|
|
974
|
+
|
|
975
|
+
(function (Mode) {
|
|
976
|
+
Mode[Mode["EXPECT"] = 0] = "EXPECT";
|
|
977
|
+
Mode[Mode["CALL"] = 1] = "CALL";
|
|
978
|
+
})(Mode || (Mode = {}));
|
|
979
|
+
|
|
980
|
+
let currentMode = Mode.CALL;
|
|
981
|
+
const setMode = mode => {
|
|
982
|
+
currentMode = mode;
|
|
983
|
+
};
|
|
465
984
|
/**
|
|
466
|
-
*
|
|
467
|
-
* consistently return it from `mock()`, `mock.foo` and `mock.bar()`) we need
|
|
468
|
-
* to store a global state for the currently active mock.
|
|
985
|
+
* Create a type safe mock.
|
|
469
986
|
*
|
|
470
|
-
*
|
|
987
|
+
* @see {@link when} Set expectations on the mock using `when`.
|
|
471
988
|
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
* when
|
|
475
|
-
*
|
|
989
|
+
* @param options Configure the options for this specific mock, overriding any
|
|
990
|
+
* defaults that were set with {@link setDefaults}.
|
|
991
|
+
* @param options.strictness Controls what happens when a property is accessed,
|
|
992
|
+
* or a call is made, and there are no expectations set for it.
|
|
993
|
+
* @param options.concreteMatcher The matcher that will be used when one isn't specified explicitly.
|
|
476
994
|
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*/
|
|
480
|
-
var activeMock;
|
|
481
|
-
var setActiveMock = function (mock) {
|
|
482
|
-
activeMock = mock;
|
|
483
|
-
};
|
|
484
|
-
var getActiveMock = function () { return activeMock; };
|
|
485
|
-
/**
|
|
486
|
-
* Store a global map of all mocks created and their state.
|
|
995
|
+
* @example
|
|
996
|
+
* const fn = mock<() => number>();
|
|
487
997
|
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
var getMockState = function (mock) {
|
|
493
|
-
if (mockMap.has(mock)) {
|
|
494
|
-
return mockMap.get(mock);
|
|
495
|
-
}
|
|
496
|
-
throw new NotAMock();
|
|
497
|
-
};
|
|
498
|
-
var setMockState = function (mock, state) {
|
|
499
|
-
mockMap.set(mock, state);
|
|
500
|
-
};
|
|
501
|
-
var getAllMocks = function () {
|
|
502
|
-
return Array.from(mockMap.entries());
|
|
503
|
-
};
|
|
998
|
+
* when(() => fn()).thenReturn(23);
|
|
999
|
+
*
|
|
1000
|
+
* fn() === 23;
|
|
1001
|
+
*/
|
|
504
1002
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
if (prop === 'apply') {
|
|
525
|
-
return function (thisArg, args) {
|
|
526
|
-
return traps.apply(args || []);
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
if (prop === 'call') {
|
|
530
|
-
return function (thisArg) {
|
|
531
|
-
var args = [];
|
|
532
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
533
|
-
args[_i - 1] = arguments[_i];
|
|
534
|
-
}
|
|
535
|
-
return traps.apply(args);
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
return traps.property(prop);
|
|
539
|
-
},
|
|
540
|
-
apply: function (target, thisArg, args) { return traps.apply(args); },
|
|
541
|
-
ownKeys: function () { return traps.ownKeys(); },
|
|
542
|
-
getOwnPropertyDescriptor: function (target, prop) {
|
|
543
|
-
var keys = traps.ownKeys();
|
|
544
|
-
if (keys.includes(prop)) {
|
|
545
|
-
return {
|
|
546
|
-
configurable: true,
|
|
547
|
-
enumerable: true,
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
return undefined;
|
|
551
|
-
},
|
|
552
|
-
});
|
|
1003
|
+
const mock = ({
|
|
1004
|
+
strictness,
|
|
1005
|
+
concreteMatcher
|
|
1006
|
+
} = {}) => {
|
|
1007
|
+
const pendingExpectation = new RepoSideEffectPendingExpectation(strongExpectationFactory);
|
|
1008
|
+
const options = {
|
|
1009
|
+
strictness: strictness != null ? strictness : currentDefaults.strictness,
|
|
1010
|
+
concreteMatcher: concreteMatcher != null ? concreteMatcher : currentDefaults.concreteMatcher
|
|
1011
|
+
};
|
|
1012
|
+
const repository = new FlexibleRepository(options.strictness);
|
|
1013
|
+
const stub = createStub(repository, pendingExpectation, () => currentMode, options.concreteMatcher);
|
|
1014
|
+
setMockState(stub, {
|
|
1015
|
+
repository,
|
|
1016
|
+
pendingExpectation,
|
|
1017
|
+
options
|
|
1018
|
+
});
|
|
1019
|
+
return stub;
|
|
553
1020
|
};
|
|
554
1021
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
1022
|
+
const createInvocationCount = expectation => ({
|
|
1023
|
+
between(min, max) {
|
|
1024
|
+
expectation.setInvocationCount(min, max);
|
|
1025
|
+
},
|
|
1026
|
+
|
|
1027
|
+
/* istanbul ignore next */
|
|
1028
|
+
times(exact) {
|
|
1029
|
+
expectation.setInvocationCount(exact, exact);
|
|
1030
|
+
},
|
|
1031
|
+
|
|
1032
|
+
/* istanbul ignore next */
|
|
1033
|
+
anyTimes() {
|
|
1034
|
+
expectation.setInvocationCount(0, 0);
|
|
1035
|
+
},
|
|
1036
|
+
|
|
1037
|
+
/* istanbul ignore next */
|
|
1038
|
+
atLeast(min) {
|
|
1039
|
+
expectation.setInvocationCount(min, Infinity);
|
|
1040
|
+
},
|
|
1041
|
+
|
|
1042
|
+
/* istanbul ignore next */
|
|
1043
|
+
atMost(max) {
|
|
1044
|
+
expectation.setInvocationCount(0, max);
|
|
1045
|
+
},
|
|
1046
|
+
|
|
1047
|
+
/* istanbul ignore next */
|
|
1048
|
+
once() {
|
|
1049
|
+
expectation.setInvocationCount(1, 1);
|
|
1050
|
+
},
|
|
1051
|
+
|
|
1052
|
+
/* istanbul ignore next */
|
|
1053
|
+
twice() {
|
|
1054
|
+
expectation.setInvocationCount(2, 2);
|
|
1055
|
+
}
|
|
1056
|
+
/* eslint-enable no-param-reassign, no-multi-assign */
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
});
|
|
1060
|
+
|
|
581
1061
|
/**
|
|
582
|
-
*
|
|
583
|
-
*/
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
var proxy = createProxy({
|
|
590
|
-
property: function (property) { return returnOrThrow(repository.get(property)); },
|
|
591
|
-
apply: function (args) {
|
|
592
|
-
var fn = repository.get(ApplyProp);
|
|
593
|
-
// This is not using `returnOrThrow` because the repo will use it.
|
|
594
|
-
return fn.value.apply(fn, __spreadArray([], __read(args)));
|
|
595
|
-
},
|
|
596
|
-
ownKeys: function () { return repository.getAllProperties(); },
|
|
597
|
-
});
|
|
598
|
-
cache.set(mock, proxy);
|
|
599
|
-
return proxy;
|
|
1062
|
+
* Set a return value for the currently pending expectation.
|
|
1063
|
+
*/
|
|
1064
|
+
|
|
1065
|
+
const finishPendingExpectation = (returnValue, pendingExpectation) => {
|
|
1066
|
+
const finishedExpectation = pendingExpectation.finish(returnValue);
|
|
1067
|
+
pendingExpectation.clear();
|
|
1068
|
+
return createInvocationCount(finishedExpectation);
|
|
600
1069
|
};
|
|
601
1070
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
RepoSideEffectPendingExpectation.prototype.start = function (repo) {
|
|
608
|
-
if (this._repo) {
|
|
609
|
-
throw new UnfinishedExpectation(this);
|
|
610
|
-
}
|
|
611
|
-
this.clear();
|
|
612
|
-
this._repo = repo;
|
|
613
|
-
};
|
|
614
|
-
Object.defineProperty(RepoSideEffectPendingExpectation.prototype, "property", {
|
|
615
|
-
set: function (value) {
|
|
616
|
-
this._property = value;
|
|
617
|
-
},
|
|
618
|
-
enumerable: false,
|
|
619
|
-
configurable: true
|
|
620
|
-
});
|
|
621
|
-
Object.defineProperty(RepoSideEffectPendingExpectation.prototype, "args", {
|
|
622
|
-
set: function (value) {
|
|
623
|
-
this._args = value;
|
|
624
|
-
},
|
|
625
|
-
enumerable: false,
|
|
626
|
-
configurable: true
|
|
627
|
-
});
|
|
628
|
-
RepoSideEffectPendingExpectation.prototype.finish = function (returnValue) {
|
|
629
|
-
if (!this._repo) {
|
|
630
|
-
throw new MissingWhen();
|
|
631
|
-
}
|
|
632
|
-
var expectation = this.createExpectation(this._property, this._args, returnValue);
|
|
633
|
-
this._repo.add(expectation);
|
|
634
|
-
this.clear();
|
|
635
|
-
return expectation;
|
|
636
|
-
};
|
|
637
|
-
RepoSideEffectPendingExpectation.prototype.clear = function () {
|
|
638
|
-
this._repo = undefined;
|
|
639
|
-
this._args = undefined;
|
|
640
|
-
this._property = '';
|
|
641
|
-
};
|
|
642
|
-
RepoSideEffectPendingExpectation.prototype.toJSON = function () {
|
|
643
|
-
return printWhen(this._property, this._args);
|
|
644
|
-
};
|
|
645
|
-
return RepoSideEffectPendingExpectation;
|
|
646
|
-
}());
|
|
1071
|
+
const getError = errorOrMessage => {
|
|
1072
|
+
if (typeof errorOrMessage === 'string') {
|
|
1073
|
+
return new Error(errorOrMessage);
|
|
1074
|
+
}
|
|
647
1075
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
* Matches a call with more parameters than expected because it is assumed the
|
|
652
|
-
* compiler will check that those parameters are optional.
|
|
653
|
-
*
|
|
654
|
-
* @example
|
|
655
|
-
* new MatcherExpectation(
|
|
656
|
-
* 'bar',
|
|
657
|
-
* deepEquals([1, 2, 3]),
|
|
658
|
-
* 23
|
|
659
|
-
* ).matches('bar', [1, 2, 3]) === true;
|
|
660
|
-
*/
|
|
661
|
-
var MatcherExpectation = /** @class */ (function () {
|
|
662
|
-
function MatcherExpectation(property, args, returnValue) {
|
|
663
|
-
this.property = property;
|
|
664
|
-
this.args = args;
|
|
665
|
-
this.returnValue = returnValue;
|
|
666
|
-
this.matched = 0;
|
|
667
|
-
this.min = 1;
|
|
668
|
-
this.max = 1;
|
|
669
|
-
}
|
|
670
|
-
MatcherExpectation.prototype.setInvocationCount = function (min, max) {
|
|
671
|
-
if (max === void 0) { max = 1; }
|
|
672
|
-
this.min = min;
|
|
673
|
-
this.max = max;
|
|
674
|
-
};
|
|
675
|
-
MatcherExpectation.prototype.matches = function (args) {
|
|
676
|
-
if (!this.matchesArgs(args)) {
|
|
677
|
-
return false;
|
|
678
|
-
}
|
|
679
|
-
this.matched++;
|
|
680
|
-
return this.max === 0 || this.matched <= this.max;
|
|
681
|
-
};
|
|
682
|
-
MatcherExpectation.prototype.isUnmet = function () {
|
|
683
|
-
return this.matched < this.min;
|
|
684
|
-
};
|
|
685
|
-
MatcherExpectation.prototype.matchesArgs = function (received) {
|
|
686
|
-
if (this.args === undefined) {
|
|
687
|
-
return !received;
|
|
688
|
-
}
|
|
689
|
-
if (!received) {
|
|
690
|
-
return false;
|
|
691
|
-
}
|
|
692
|
-
return this.args.every(function (arg, i) { return arg.matches(received[i]); });
|
|
693
|
-
};
|
|
694
|
-
MatcherExpectation.prototype.toJSON = function () {
|
|
695
|
-
return printExpectation(this.property, this.args, this.returnValue, this.min, this.max);
|
|
696
|
-
};
|
|
697
|
-
return MatcherExpectation;
|
|
698
|
-
}());
|
|
699
|
-
|
|
700
|
-
var BaseRepository = /** @class */ (function () {
|
|
701
|
-
function BaseRepository() {
|
|
702
|
-
this.expectations = new Map();
|
|
703
|
-
this.expectedCallStats = new Map();
|
|
704
|
-
this.unexpectedCallStats = new Map();
|
|
705
|
-
}
|
|
706
|
-
BaseRepository.prototype.add = function (expectation) {
|
|
707
|
-
var property = expectation.property;
|
|
708
|
-
var expectations = this.expectations.get(property) || [];
|
|
709
|
-
this.expectations.set(property, __spreadArray(__spreadArray([], __read(expectations), false), [
|
|
710
|
-
{
|
|
711
|
-
expectation: expectation,
|
|
712
|
-
matchCount: 0,
|
|
713
|
-
},
|
|
714
|
-
]));
|
|
715
|
-
};
|
|
716
|
-
BaseRepository.prototype.clear = function () {
|
|
717
|
-
this.expectations.clear();
|
|
718
|
-
this.expectedCallStats.clear();
|
|
719
|
-
this.unexpectedCallStats.clear();
|
|
720
|
-
};
|
|
721
|
-
BaseRepository.prototype.get = function (property) {
|
|
722
|
-
var _this = this;
|
|
723
|
-
var expectations = this.expectations.get(property);
|
|
724
|
-
if (expectations && expectations.length) {
|
|
725
|
-
// We record that an expected property access has happened, but an
|
|
726
|
-
// unexpected call could still happen later.
|
|
727
|
-
this.recordExpected(property, undefined);
|
|
728
|
-
var propertyExpectation = expectations.find(function (e) {
|
|
729
|
-
return e.expectation.matches(undefined);
|
|
730
|
-
});
|
|
731
|
-
if (propertyExpectation) {
|
|
732
|
-
this.countAndConsume(propertyExpectation);
|
|
733
|
-
return propertyExpectation.expectation.returnValue;
|
|
734
|
-
}
|
|
735
|
-
return {
|
|
736
|
-
value: function () {
|
|
737
|
-
var args = [];
|
|
738
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
739
|
-
args[_i] = arguments[_i];
|
|
740
|
-
}
|
|
741
|
-
var callExpectation = expectations.find(function (e) {
|
|
742
|
-
return e.expectation.matches(args);
|
|
743
|
-
});
|
|
744
|
-
if (callExpectation) {
|
|
745
|
-
_this.recordExpected(property, args);
|
|
746
|
-
_this.countAndConsume(callExpectation);
|
|
747
|
-
// TODO: this is duplicated in instance
|
|
748
|
-
return returnOrThrow(callExpectation.expectation.returnValue);
|
|
749
|
-
}
|
|
750
|
-
_this.recordUnexpected(property, args);
|
|
751
|
-
return _this.getValueForUnexpectedCall(property, args);
|
|
752
|
-
},
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
switch (property) {
|
|
756
|
-
case 'toString':
|
|
757
|
-
return { value: function () { return 'mock'; } };
|
|
758
|
-
case '@@toStringTag':
|
|
759
|
-
case Symbol.toStringTag:
|
|
760
|
-
case 'name':
|
|
761
|
-
return { value: 'mock' };
|
|
762
|
-
// pretty-format
|
|
763
|
-
case '$$typeof':
|
|
764
|
-
case 'constructor':
|
|
765
|
-
case '@@__IMMUTABLE_ITERABLE__@@':
|
|
766
|
-
case '@@__IMMUTABLE_RECORD__@@':
|
|
767
|
-
return { value: null };
|
|
768
|
-
case '__isMatcher':
|
|
769
|
-
return { value: false };
|
|
770
|
-
case ApplyProp:
|
|
771
|
-
return {
|
|
772
|
-
value: function () {
|
|
773
|
-
var args = [];
|
|
774
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
775
|
-
args[_i] = arguments[_i];
|
|
776
|
-
}
|
|
777
|
-
_this.recordUnexpected(property, args);
|
|
778
|
-
return _this.getValueForUnexpectedCall(property, args);
|
|
779
|
-
},
|
|
780
|
-
};
|
|
781
|
-
default:
|
|
782
|
-
this.recordUnexpected(property, undefined);
|
|
783
|
-
return this.getValueForUnexpectedAccess(property);
|
|
784
|
-
}
|
|
785
|
-
};
|
|
786
|
-
BaseRepository.prototype.getAllProperties = function () {
|
|
787
|
-
return Array.from(this.expectations.keys());
|
|
788
|
-
};
|
|
789
|
-
BaseRepository.prototype.getCallStats = function () {
|
|
790
|
-
return {
|
|
791
|
-
expected: this.expectedCallStats,
|
|
792
|
-
unexpected: this.unexpectedCallStats,
|
|
793
|
-
};
|
|
794
|
-
};
|
|
795
|
-
BaseRepository.prototype.getUnmet = function () {
|
|
796
|
-
var _a;
|
|
797
|
-
return (_a = []).concat.apply(_a, __spreadArray([], __read(Array.from(this.expectations.values()).map(function (expectations) {
|
|
798
|
-
return expectations
|
|
799
|
-
.filter(function (e) { return e.expectation.min > e.matchCount; })
|
|
800
|
-
.map(function (e) { return e.expectation; });
|
|
801
|
-
}))));
|
|
802
|
-
};
|
|
803
|
-
/**
|
|
804
|
-
* Record an expected property access/method call.
|
|
805
|
-
*/
|
|
806
|
-
BaseRepository.prototype.recordExpected = function (property, args) {
|
|
807
|
-
var calls = this.expectedCallStats.get(property) || [];
|
|
808
|
-
this.expectedCallStats.set(property, __spreadArray(__spreadArray([], __read(calls), false), [{ arguments: args }]));
|
|
809
|
-
};
|
|
810
|
-
/**
|
|
811
|
-
* Record an unexpected property access/method call.
|
|
812
|
-
*/
|
|
813
|
-
BaseRepository.prototype.recordUnexpected = function (property, args) {
|
|
814
|
-
var calls = this.unexpectedCallStats.get(property) || [];
|
|
815
|
-
this.unexpectedCallStats.set(property, __spreadArray(__spreadArray([], __read(calls), false), [{ arguments: args }]));
|
|
816
|
-
};
|
|
817
|
-
BaseRepository.prototype.countAndConsume = function (expectation) {
|
|
818
|
-
// eslint-disable-next-line no-param-reassign
|
|
819
|
-
expectation.matchCount++;
|
|
820
|
-
this.consumeExpectation(expectation);
|
|
821
|
-
};
|
|
822
|
-
return BaseRepository;
|
|
823
|
-
}());
|
|
1076
|
+
if (errorOrMessage instanceof Error) {
|
|
1077
|
+
return errorOrMessage;
|
|
1078
|
+
}
|
|
824
1079
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
throw new Error('Spreading during an expectation is not supported.');
|
|
867
|
-
},
|
|
868
|
-
});
|
|
869
|
-
},
|
|
870
|
-
apply: function (args) {
|
|
871
|
-
setActiveMock(stub);
|
|
872
|
-
pendingExpectation.start(repo);
|
|
873
|
-
// eslint-disable-next-line no-param-reassign
|
|
874
|
-
pendingExpectation.property = ApplyProp;
|
|
875
|
-
// eslint-disable-next-line no-param-reassign
|
|
876
|
-
pendingExpectation.args = args;
|
|
877
|
-
},
|
|
878
|
-
ownKeys: function () {
|
|
879
|
-
throw new Error('Spreading during an expectation is not supported.');
|
|
880
|
-
},
|
|
881
|
-
});
|
|
882
|
-
return stub;
|
|
1080
|
+
return new Error();
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
const createReturns = pendingExpectation => {
|
|
1084
|
+
const nonPromiseStub = {
|
|
1085
|
+
// TODO: merge this with the promise version
|
|
1086
|
+
thenReturn:
|
|
1087
|
+
/* istanbul ignore next: because this is overwritten by the promise version */
|
|
1088
|
+
returnValue => finishPendingExpectation({
|
|
1089
|
+
value: returnValue,
|
|
1090
|
+
isError: false,
|
|
1091
|
+
isPromise: false
|
|
1092
|
+
}, pendingExpectation),
|
|
1093
|
+
thenThrow: errorOrMessage => finishPendingExpectation({
|
|
1094
|
+
value: getError(errorOrMessage),
|
|
1095
|
+
isError: true,
|
|
1096
|
+
isPromise: false
|
|
1097
|
+
}, pendingExpectation)
|
|
1098
|
+
};
|
|
1099
|
+
const promiseStub = {
|
|
1100
|
+
thenReturn: promise => finishPendingExpectation({
|
|
1101
|
+
value: promise,
|
|
1102
|
+
isError: false,
|
|
1103
|
+
// We're setting this to false because we can't distinguish between a
|
|
1104
|
+
// promise thenReturn and a normal thenReturn.
|
|
1105
|
+
isPromise: false
|
|
1106
|
+
}, pendingExpectation),
|
|
1107
|
+
thenResolve: promiseValue => finishPendingExpectation({
|
|
1108
|
+
value: promiseValue,
|
|
1109
|
+
isError: false,
|
|
1110
|
+
isPromise: true
|
|
1111
|
+
}, pendingExpectation),
|
|
1112
|
+
thenReject: errorOrMessage => finishPendingExpectation({
|
|
1113
|
+
value: getError(errorOrMessage),
|
|
1114
|
+
isError: true,
|
|
1115
|
+
isPromise: true
|
|
1116
|
+
}, pendingExpectation)
|
|
1117
|
+
}; // @ts-expect-error because the return type is a conditional, and we're merging
|
|
1118
|
+
// both branches here
|
|
1119
|
+
|
|
1120
|
+
return _extends({}, nonPromiseStub, promiseStub);
|
|
883
1121
|
};
|
|
884
1122
|
|
|
885
|
-
var strongExpectationFactory = function (property, args, returnValue) {
|
|
886
|
-
return new MatcherExpectation(property,
|
|
887
|
-
// Wrap every non-matcher in the default matcher.
|
|
888
|
-
args === null || args === void 0 ? void 0 : args.map(function (arg) { return (isMatcher(arg) ? arg : deepEquals(arg)); }), returnValue);
|
|
889
|
-
};
|
|
890
1123
|
/**
|
|
891
|
-
*
|
|
1124
|
+
* Set an expectation on a mock.
|
|
1125
|
+
*
|
|
1126
|
+
* The expectation must be finished by setting a return value, even if the value
|
|
1127
|
+
* is `undefined`.
|
|
1128
|
+
*
|
|
1129
|
+
* If a call happens that was not expected then the mock will throw an error.
|
|
1130
|
+
* By default, the call is expected to only be made once. Use the invocation
|
|
1131
|
+
* count helpers to expect a call multiple times.
|
|
892
1132
|
*
|
|
893
|
-
*
|
|
894
|
-
*
|
|
1133
|
+
* @param expectation A callback to set the expectation on your mock. The
|
|
1134
|
+
* callback must return the value from the mock to properly infer types.
|
|
895
1135
|
*
|
|
896
1136
|
* @example
|
|
897
|
-
* const fn = mock<() =>
|
|
1137
|
+
* const fn = mock<() => void>();
|
|
1138
|
+
* when(() => fn()).thenReturn(undefined);
|
|
898
1139
|
*
|
|
899
|
-
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* const fn = mock<() => number>();
|
|
1142
|
+
* when(() => fn()).thenReturn(42).atMost(3);
|
|
900
1143
|
*
|
|
901
|
-
*
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1144
|
+
* @example
|
|
1145
|
+
* const fn = mock<(x: number) => Promise<number>();
|
|
1146
|
+
* when(() => fn(23)).thenResolve(42);
|
|
1147
|
+
*/
|
|
1148
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
|
|
1149
|
+
|
|
1150
|
+
const when = expectation => {
|
|
1151
|
+
setMode(Mode.EXPECT);
|
|
1152
|
+
expectation();
|
|
1153
|
+
setMode(Mode.CALL);
|
|
1154
|
+
const {
|
|
1155
|
+
pendingExpectation
|
|
1156
|
+
} = getMockState(getActiveMock());
|
|
1157
|
+
return createReturns(pendingExpectation);
|
|
909
1158
|
};
|
|
910
1159
|
|
|
911
1160
|
/**
|
|
@@ -914,37 +1163,41 @@ var mock = function (_a) {
|
|
|
914
1163
|
* @example
|
|
915
1164
|
* const fn = mock<() => number>();
|
|
916
1165
|
*
|
|
917
|
-
* when(fn()).thenReturn(23);
|
|
1166
|
+
* when(() => fn()).thenReturn(23);
|
|
918
1167
|
*
|
|
919
1168
|
* reset(fn);
|
|
920
1169
|
*
|
|
921
|
-
*
|
|
922
|
-
*/
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1170
|
+
* fn(); // throws
|
|
1171
|
+
*/
|
|
1172
|
+
|
|
1173
|
+
const reset = mock => {
|
|
1174
|
+
getMockState(mock).repository.clear();
|
|
1175
|
+
};
|
|
926
1176
|
/**
|
|
927
1177
|
* Reset all existing mocks.
|
|
928
1178
|
*
|
|
929
1179
|
* @see reset
|
|
930
|
-
*/
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1180
|
+
*/
|
|
1181
|
+
|
|
1182
|
+
const resetAll = () => {
|
|
1183
|
+
getAllMocks().forEach(([mock]) => {
|
|
1184
|
+
reset(mock);
|
|
1185
|
+
});
|
|
936
1186
|
};
|
|
937
1187
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1188
|
+
const verifyRepo = repository => {
|
|
1189
|
+
const unmetExpectations = repository.getUnmet();
|
|
1190
|
+
|
|
1191
|
+
if (unmetExpectations.length) {
|
|
1192
|
+
throw new UnmetExpectations(unmetExpectations);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
const callStats = repository.getCallStats();
|
|
1196
|
+
|
|
1197
|
+
if (callStats.unexpected.size) {
|
|
1198
|
+
throw new UnexpectedCalls(callStats.unexpected, unmetExpectations);
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
948
1201
|
/**
|
|
949
1202
|
* Verify that all expectations on the given mock have been met.
|
|
950
1203
|
*
|
|
@@ -958,146 +1211,35 @@ var verifyRepo = function (repository) {
|
|
|
958
1211
|
* @example
|
|
959
1212
|
* const fn = mock<() => number>();
|
|
960
1213
|
*
|
|
961
|
-
* when(fn()).thenReturn(23);
|
|
1214
|
+
* when(() => fn()).thenReturn(23);
|
|
962
1215
|
*
|
|
963
1216
|
* verify(fn); // throws
|
|
964
|
-
*/
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1217
|
+
*/
|
|
1218
|
+
|
|
1219
|
+
const verify = mock => {
|
|
1220
|
+
const {
|
|
1221
|
+
repository
|
|
1222
|
+
} = getMockState(mock);
|
|
1223
|
+
verifyRepo(repository);
|
|
1224
|
+
};
|
|
969
1225
|
/**
|
|
970
1226
|
* Verify all existing mocks.
|
|
971
1227
|
*
|
|
972
1228
|
* @see verify
|
|
973
|
-
*/
|
|
974
|
-
var verifyAll = function () {
|
|
975
|
-
getAllMocks().forEach(function (_a) {
|
|
976
|
-
var _b = __read(_a, 1), mock = _b[0];
|
|
977
|
-
verify(mock);
|
|
978
|
-
});
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
var createInvocationCount = function (expectation) { return ({
|
|
982
|
-
between: function (min, max) {
|
|
983
|
-
expectation.setInvocationCount(min, max);
|
|
984
|
-
},
|
|
985
|
-
/* istanbul ignore next */
|
|
986
|
-
times: function (exact) {
|
|
987
|
-
expectation.setInvocationCount(exact, exact);
|
|
988
|
-
},
|
|
989
|
-
/* istanbul ignore next */
|
|
990
|
-
anyTimes: function () {
|
|
991
|
-
expectation.setInvocationCount(0, 0);
|
|
992
|
-
},
|
|
993
|
-
/* istanbul ignore next */
|
|
994
|
-
atLeast: function (min) {
|
|
995
|
-
expectation.setInvocationCount(min, Infinity);
|
|
996
|
-
},
|
|
997
|
-
/* istanbul ignore next */
|
|
998
|
-
atMost: function (max) {
|
|
999
|
-
expectation.setInvocationCount(0, max);
|
|
1000
|
-
},
|
|
1001
|
-
/* istanbul ignore next */
|
|
1002
|
-
once: function () {
|
|
1003
|
-
expectation.setInvocationCount(1, 1);
|
|
1004
|
-
},
|
|
1005
|
-
/* istanbul ignore next */
|
|
1006
|
-
twice: function () {
|
|
1007
|
-
expectation.setInvocationCount(2, 2);
|
|
1008
|
-
},
|
|
1009
|
-
/* eslint-enable no-param-reassign, no-multi-assign */
|
|
1010
|
-
}); };
|
|
1011
|
-
|
|
1012
|
-
/**
|
|
1013
|
-
* Set a return value for the currently pending expectation.
|
|
1014
|
-
*/
|
|
1015
|
-
var finishPendingExpectation = function (returnValue, pendingExpectation) {
|
|
1016
|
-
var finishedExpectation = pendingExpectation.finish(returnValue);
|
|
1017
|
-
pendingExpectation.clear();
|
|
1018
|
-
return createInvocationCount(finishedExpectation);
|
|
1019
|
-
};
|
|
1020
|
-
var getError = function (errorOrMessage) {
|
|
1021
|
-
if (typeof errorOrMessage === 'string') {
|
|
1022
|
-
return new Error(errorOrMessage);
|
|
1023
|
-
}
|
|
1024
|
-
if (errorOrMessage instanceof Error) {
|
|
1025
|
-
return errorOrMessage;
|
|
1026
|
-
}
|
|
1027
|
-
return new Error();
|
|
1028
|
-
};
|
|
1029
|
-
var createReturns = function (pendingExpectation) {
|
|
1030
|
-
var nonPromiseStub = {
|
|
1031
|
-
// TODO: merge this with the promise version
|
|
1032
|
-
thenReturn: /* istanbul ignore next: because this is overwritten by the promise version */ function (returnValue) {
|
|
1033
|
-
return finishPendingExpectation({ value: returnValue, isError: false, isPromise: false }, pendingExpectation);
|
|
1034
|
-
},
|
|
1035
|
-
thenThrow: function (errorOrMessage) {
|
|
1036
|
-
return finishPendingExpectation({ value: getError(errorOrMessage), isError: true, isPromise: false }, pendingExpectation);
|
|
1037
|
-
},
|
|
1038
|
-
};
|
|
1039
|
-
var promiseStub = {
|
|
1040
|
-
thenReturn: function (promise) {
|
|
1041
|
-
return finishPendingExpectation({
|
|
1042
|
-
value: promise,
|
|
1043
|
-
isError: false,
|
|
1044
|
-
// We're setting this to false because we can't distinguish between a
|
|
1045
|
-
// promise thenReturn and a normal thenReturn.
|
|
1046
|
-
isPromise: false,
|
|
1047
|
-
}, pendingExpectation);
|
|
1048
|
-
},
|
|
1049
|
-
thenResolve: function (promiseValue) {
|
|
1050
|
-
return finishPendingExpectation({
|
|
1051
|
-
value: promiseValue,
|
|
1052
|
-
isError: false,
|
|
1053
|
-
isPromise: true,
|
|
1054
|
-
}, pendingExpectation);
|
|
1055
|
-
},
|
|
1056
|
-
thenReject: function (errorOrMessage) {
|
|
1057
|
-
return finishPendingExpectation({
|
|
1058
|
-
value: getError(errorOrMessage),
|
|
1059
|
-
isError: true,
|
|
1060
|
-
isPromise: true,
|
|
1061
|
-
}, pendingExpectation);
|
|
1062
|
-
},
|
|
1063
|
-
};
|
|
1064
|
-
return __assign(__assign({}, nonPromiseStub), promiseStub);
|
|
1065
|
-
};
|
|
1229
|
+
*/
|
|
1066
1230
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
* is `undefined`.
|
|
1072
|
-
*
|
|
1073
|
-
* If a call happens that was not expected then the mock will throw an error.
|
|
1074
|
-
* By default, the call is expected to only be made once. Use the invocation
|
|
1075
|
-
* count helpers to expect a call multiple times.
|
|
1076
|
-
*
|
|
1077
|
-
* @param expectedCall Make a "real" call using the value returned by `mock()`.
|
|
1078
|
-
*
|
|
1079
|
-
* @example
|
|
1080
|
-
* const fn = mock<() => void>();
|
|
1081
|
-
* when(fn()).thenReturn(undefined);
|
|
1082
|
-
*
|
|
1083
|
-
* @example
|
|
1084
|
-
* const fn = mock<() => number>();
|
|
1085
|
-
* when(fn()).thenReturn(42).atMost(3);
|
|
1086
|
-
*
|
|
1087
|
-
* @example
|
|
1088
|
-
* const fn = mock<(x: number) => Promise<number>();
|
|
1089
|
-
* when(fn(23)).thenResolve(42);
|
|
1090
|
-
*/
|
|
1091
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
|
|
1092
|
-
var when = function (expectedCall) {
|
|
1093
|
-
return createReturns(getMockState(getActiveMock()).pendingExpectation);
|
|
1231
|
+
const verifyAll = () => {
|
|
1232
|
+
getAllMocks().forEach(([mock]) => {
|
|
1233
|
+
verify(mock);
|
|
1234
|
+
});
|
|
1094
1235
|
};
|
|
1095
1236
|
|
|
1096
1237
|
exports.It = It;
|
|
1097
|
-
exports.instance = instance;
|
|
1098
1238
|
exports.mock = mock;
|
|
1099
1239
|
exports.reset = reset;
|
|
1100
1240
|
exports.resetAll = resetAll;
|
|
1241
|
+
exports.setDefaults = setDefaults;
|
|
1101
1242
|
exports.verify = verify;
|
|
1102
1243
|
exports.verifyAll = verifyAll;
|
|
1103
1244
|
exports.when = when;
|
|
1245
|
+
//# sourceMappingURL=index.js.map
|