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