strong-mock 9.0.1 → 9.2.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 +41 -25
- package/dist/index.cjs +1191 -0
- package/dist/index.d.cts +584 -0
- package/dist/index.d.ts +584 -14
- package/dist/index.js +658 -842
- package/package.json +35 -21
- 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 -24
- package/dist/mock/mode.d.ts +0 -6
- 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.js
CHANGED
|
@@ -1,64 +1,57 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
4
21
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
const ApplyProp = Symbol('apply');
|
|
22
|
+
// src/errors/unexpected-access.ts
|
|
23
|
+
import { DIM_COLOR } from "jest-matcher-utils";
|
|
9
24
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
// src/print.ts
|
|
26
|
+
import { EXPECTED_COLOR, RECEIVED_COLOR, stringify } from "jest-matcher-utils";
|
|
27
|
+
import cloneDeepWith from "lodash/cloneDeepWith.js";
|
|
28
|
+
|
|
29
|
+
// src/expectation/expectation.ts
|
|
30
|
+
var ApplyProp = Symbol("apply");
|
|
31
|
+
|
|
32
|
+
// src/matchers/matcher.ts
|
|
33
|
+
var MATCHER_SYMBOL = Symbol("matcher");
|
|
14
34
|
function isMatcher(f) {
|
|
15
35
|
return !!(f && f[MATCHER_SYMBOL]);
|
|
16
36
|
}
|
|
17
|
-
|
|
37
|
+
var getMatcherDiffs = (matchers, args) => {
|
|
18
38
|
const matcherDiffs = matchers.map((matcher, i) => matcher.getDiff(args[i]));
|
|
19
|
-
const actual = matcherDiffs.map(d => d.actual);
|
|
20
|
-
const expected = matcherDiffs.map(d => d.expected);
|
|
21
|
-
return {
|
|
22
|
-
actual,
|
|
23
|
-
expected
|
|
24
|
-
};
|
|
39
|
+
const actual = matcherDiffs.map((d) => d.actual);
|
|
40
|
+
const expected = matcherDiffs.map((d) => d.expected);
|
|
41
|
+
return { actual, expected };
|
|
25
42
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
* @param options
|
|
31
|
-
* @param options.toString An optional function that should return a string that will be
|
|
32
|
-
* used when the matcher needs to be printed in an error message. By default,
|
|
33
|
-
* it stringifies `predicate`.
|
|
34
|
-
* @param options.getDiff An optional function that will be called when printing the
|
|
35
|
-
* diff for a failed expectation. It will only be called if there's a mismatch
|
|
36
|
-
* between the expected and received values i.e. `predicate(actual)` fails.
|
|
37
|
-
* By default, the `toString` method will be used to format the expected value,
|
|
38
|
-
* while the received value will be returned as-is.
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* // Create a matcher for positive numbers.
|
|
42
|
-
* const fn = mock<(x: number) => number>();
|
|
43
|
-
* when(() => fn(It.matches(x => x >= 0))).thenReturn(42);
|
|
44
|
-
*
|
|
45
|
-
* fn(2) === 42
|
|
46
|
-
* fn(-1) // throws
|
|
47
|
-
*/
|
|
48
|
-
const matches = (predicate, options) => {
|
|
49
|
-
var _options$toString, _options$getDiff;
|
|
50
|
-
// We can't use destructuring with default values because `options` is optional,
|
|
51
|
-
// so it needs a default value of `{}`, which will come with a native `toString`.
|
|
52
|
-
const toString = (_options$toString = options == null ? void 0 : options.toString) != null ? _options$toString : () => `Matcher(${predicate.toString()})`;
|
|
53
|
-
const getDiff = (_options$getDiff = options == null ? void 0 : options.getDiff) != null ? _options$getDiff : actual => ({
|
|
43
|
+
var matches = (predicate, options) => {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
const toString = (_a = options == null ? void 0 : options.toString) != null ? _a : () => `Matcher(${predicate.toString()})`;
|
|
46
|
+
const getDiff = (_b = options == null ? void 0 : options.getDiff) != null ? _b : (actual) => ({
|
|
54
47
|
actual,
|
|
55
48
|
expected: toString()
|
|
56
49
|
});
|
|
57
50
|
const matcher = {
|
|
58
51
|
[MATCHER_SYMBOL]: true,
|
|
59
|
-
matches: actual => predicate(actual),
|
|
52
|
+
matches: (actual) => predicate(actual),
|
|
60
53
|
toString,
|
|
61
|
-
getDiff: actual => {
|
|
54
|
+
getDiff: (actual) => {
|
|
62
55
|
if (predicate(actual)) {
|
|
63
56
|
return {
|
|
64
57
|
actual,
|
|
@@ -71,75 +64,90 @@ const matches = (predicate, options) => {
|
|
|
71
64
|
return matcher;
|
|
72
65
|
};
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
// src/print.ts
|
|
68
|
+
var printProperty = (property) => {
|
|
75
69
|
if (property === ApplyProp) {
|
|
76
|
-
return
|
|
70
|
+
return "";
|
|
77
71
|
}
|
|
78
|
-
if (typeof property ===
|
|
72
|
+
if (typeof property === "symbol") {
|
|
79
73
|
return `[${property.toString()}]`;
|
|
80
74
|
}
|
|
81
75
|
return `.${property}`;
|
|
82
76
|
};
|
|
83
|
-
|
|
84
|
-
// Call toString on matchers directly to avoid wrapping strings returned by them in quotes.
|
|
77
|
+
var printValue = (arg) => {
|
|
85
78
|
if (isMatcher(arg)) {
|
|
86
79
|
return arg.toString();
|
|
87
80
|
}
|
|
88
|
-
return
|
|
81
|
+
return stringify(arg);
|
|
89
82
|
};
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
var deepPrint = (value) => cloneDeepWith(value, (value2) => {
|
|
84
|
+
if (isMatcher(value2)) {
|
|
85
|
+
return value2.toString();
|
|
86
|
+
}
|
|
87
|
+
return void 0;
|
|
88
|
+
});
|
|
89
|
+
var printArgs = (args) => args.map((arg) => printValue(arg)).join(", ");
|
|
90
|
+
var printCall = (mockName, property, args) => {
|
|
92
91
|
const prettyProperty = printProperty(property);
|
|
93
92
|
if (args) {
|
|
94
93
|
const prettyArgs = printArgs(args);
|
|
95
|
-
return
|
|
94
|
+
return `${mockName}${RECEIVED_COLOR(`${prettyProperty}(${prettyArgs})`)}`;
|
|
96
95
|
}
|
|
97
|
-
return
|
|
96
|
+
return `${mockName}${RECEIVED_COLOR(`${prettyProperty}`)}`;
|
|
98
97
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
isPromise,
|
|
102
|
-
value
|
|
103
|
-
}, min, max) => {
|
|
104
|
-
let thenPrefix = '';
|
|
98
|
+
var printReturns = ({ isError, isPromise, value }, min, max) => {
|
|
99
|
+
let thenPrefix = "";
|
|
105
100
|
if (isPromise) {
|
|
106
101
|
if (isError) {
|
|
107
|
-
thenPrefix +=
|
|
102
|
+
thenPrefix += "thenReject";
|
|
108
103
|
} else {
|
|
109
|
-
thenPrefix +=
|
|
104
|
+
thenPrefix += "thenResolve";
|
|
110
105
|
}
|
|
111
106
|
} else if (isError) {
|
|
112
|
-
thenPrefix +=
|
|
107
|
+
thenPrefix += "thenThrow";
|
|
113
108
|
} else {
|
|
114
|
-
thenPrefix +=
|
|
109
|
+
thenPrefix += "thenReturn";
|
|
115
110
|
}
|
|
116
|
-
return `.${thenPrefix}(${
|
|
111
|
+
return `.${thenPrefix}(${RECEIVED_COLOR(
|
|
112
|
+
printValue(value)
|
|
113
|
+
)}).between(${min}, ${max})`;
|
|
117
114
|
};
|
|
118
|
-
|
|
115
|
+
var printWhen = (mockName, property, args) => {
|
|
119
116
|
const prettyProperty = printProperty(property);
|
|
120
117
|
if (args) {
|
|
121
|
-
return `when(() =>
|
|
118
|
+
return `when(() => ${mockName}${EXPECTED_COLOR(
|
|
119
|
+
`${prettyProperty}(${printArgs(args)})`
|
|
120
|
+
)})`;
|
|
122
121
|
}
|
|
123
|
-
return `when(() =>
|
|
122
|
+
return `when(() => ${mockName}${EXPECTED_COLOR(`${printProperty(property)}`)})`;
|
|
124
123
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- ${expectations.map(e => e.toString()).join(
|
|
124
|
+
var printExpectation = (mockName, property, args, returnValue, min, max) => `${printWhen(mockName, property, args)}${printReturns(returnValue, min, max)}`;
|
|
125
|
+
var printRemainingExpectations = (expectations) => expectations.length ? `Remaining unmet expectations:
|
|
126
|
+
- ${expectations.map((e) => e.toString()).join("\n - ")}` : "There are no remaining unmet expectations.";
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
// src/errors/unexpected-access.ts
|
|
129
|
+
var UnexpectedAccess = class extends Error {
|
|
130
|
+
constructor(mockName, property, expectations) {
|
|
131
|
+
super(
|
|
132
|
+
DIM_COLOR(`Didn't expect ${printCall(mockName, property)} to be accessed.
|
|
132
133
|
|
|
133
|
-
If you expect this property to be accessed then
|
|
134
|
-
set an expectation for it.
|
|
134
|
+
If you expect this property to be accessed then you should
|
|
135
|
+
set an expectation for it with when().
|
|
135
136
|
|
|
136
|
-
${printRemainingExpectations(expectations)}`)
|
|
137
|
+
${printRemainingExpectations(expectations)}`)
|
|
138
|
+
);
|
|
137
139
|
}
|
|
138
|
-
}
|
|
140
|
+
};
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
// src/errors/unexpected-call.ts
|
|
143
|
+
import { DIM_COLOR as DIM_COLOR2 } from "jest-matcher-utils";
|
|
144
|
+
|
|
145
|
+
// src/errors/diff.ts
|
|
146
|
+
import { diff as printDiff } from "jest-diff";
|
|
147
|
+
import { EXPECTED_COLOR as EXPECTED_COLOR2, RECEIVED_COLOR as RECEIVED_COLOR2 } from "jest-matcher-utils";
|
|
148
|
+
var noColor = (s) => s;
|
|
149
|
+
var printArgsDiff = (expected, actual) => {
|
|
150
|
+
const diff = printDiff(expected, actual, {
|
|
143
151
|
omitAnnotationLines: true,
|
|
144
152
|
aColor: noColor,
|
|
145
153
|
bColor: noColor,
|
|
@@ -147,147 +155,100 @@ const printArgsDiff = (expected, actual) => {
|
|
|
147
155
|
commonColor: noColor,
|
|
148
156
|
patchColor: noColor
|
|
149
157
|
});
|
|
150
|
-
/* istanbul ignore next this is not expected in practice */
|
|
151
158
|
if (!diff) {
|
|
152
|
-
return
|
|
159
|
+
return "";
|
|
153
160
|
}
|
|
154
|
-
const diffLines = diff.split(
|
|
161
|
+
const diffLines = diff.split("\n");
|
|
155
162
|
let relevantDiffLines;
|
|
156
|
-
// Strip Array [ ... ] surroundings.
|
|
157
163
|
if (!expected.length) {
|
|
158
|
-
// - Array []
|
|
159
|
-
// + Array [
|
|
160
|
-
// ...
|
|
161
|
-
// ]
|
|
162
164
|
relevantDiffLines = diffLines.slice(2, -1);
|
|
163
165
|
} else if (!actual.length) {
|
|
164
|
-
// - Array [
|
|
165
|
-
// ...
|
|
166
|
-
// ]
|
|
167
|
-
// + Array []
|
|
168
166
|
relevantDiffLines = diffLines.slice(1, -2);
|
|
169
167
|
} else {
|
|
170
|
-
// Array [
|
|
171
|
-
// ...
|
|
172
|
-
// ]
|
|
173
168
|
relevantDiffLines = diffLines.slice(1, -1);
|
|
174
169
|
}
|
|
175
|
-
// Strip the trailing comma.
|
|
176
170
|
const lastLine = relevantDiffLines[relevantDiffLines.length - 1].slice(0, -1);
|
|
177
|
-
const coloredDiffLines = [...relevantDiffLines.slice(0, -1), lastLine].map(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
171
|
+
const coloredDiffLines = [...relevantDiffLines.slice(0, -1), lastLine].map(
|
|
172
|
+
(line) => {
|
|
173
|
+
const first = line.charAt(0);
|
|
174
|
+
switch (first) {
|
|
175
|
+
case "-":
|
|
176
|
+
return EXPECTED_COLOR2(line);
|
|
177
|
+
case "+":
|
|
178
|
+
return RECEIVED_COLOR2(line);
|
|
179
|
+
default:
|
|
180
|
+
return line;
|
|
181
|
+
}
|
|
186
182
|
}
|
|
187
|
-
|
|
188
|
-
return coloredDiffLines.join(
|
|
183
|
+
);
|
|
184
|
+
return coloredDiffLines.join("\n");
|
|
189
185
|
};
|
|
190
|
-
|
|
191
|
-
var
|
|
192
|
-
if (!((
|
|
193
|
-
return
|
|
186
|
+
var printExpectationDiff = (e, args) => {
|
|
187
|
+
var _a;
|
|
188
|
+
if (!((_a = e.args) == null ? void 0 : _a.length)) {
|
|
189
|
+
return "";
|
|
194
190
|
}
|
|
195
|
-
const {
|
|
196
|
-
actual,
|
|
197
|
-
expected
|
|
198
|
-
} = getMatcherDiffs(e.args, args);
|
|
191
|
+
const { actual, expected } = getMatcherDiffs(e.args, args);
|
|
199
192
|
return printArgsDiff(expected, actual);
|
|
200
193
|
};
|
|
201
|
-
|
|
194
|
+
var printDiffForAllExpectations = (expectations, actual) => expectations.map((e) => {
|
|
202
195
|
const diff = printExpectationDiff(e, actual);
|
|
203
196
|
if (diff) {
|
|
204
197
|
return `${e.toString()}
|
|
205
|
-
${
|
|
206
|
-
${
|
|
198
|
+
${EXPECTED_COLOR2("- Expected")}
|
|
199
|
+
${RECEIVED_COLOR2("+ Received")}
|
|
207
200
|
|
|
208
201
|
${diff}`;
|
|
209
202
|
}
|
|
210
|
-
return
|
|
211
|
-
}).filter(x => x).join(
|
|
203
|
+
return void 0;
|
|
204
|
+
}).filter((x) => x).join("\n\n");
|
|
212
205
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
206
|
+
// src/errors/unexpected-call.ts
|
|
207
|
+
var UnexpectedCall = class extends Error {
|
|
208
|
+
constructor(mockName, property, args, expectations) {
|
|
209
|
+
var _a;
|
|
210
|
+
const header = `Didn't expect ${printCall(mockName, property, args)} to be called.`;
|
|
211
|
+
const propertyExpectations = expectations.filter(
|
|
212
|
+
(e) => e.property === property
|
|
213
|
+
);
|
|
217
214
|
if (propertyExpectations.length) {
|
|
218
|
-
|
|
219
|
-
|
|
215
|
+
super(
|
|
216
|
+
DIM_COLOR2(`${header}
|
|
220
217
|
|
|
221
218
|
Remaining expectations:
|
|
222
|
-
${printDiffForAllExpectations(propertyExpectations, args)}`)
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
219
|
+
${printDiffForAllExpectations(propertyExpectations, args)}`)
|
|
220
|
+
);
|
|
221
|
+
if (propertyExpectations.length === 1 && ((_a = propertyExpectations[0].args) == null ? void 0 : _a.length)) {
|
|
222
|
+
const { actual, expected } = getMatcherDiffs(
|
|
223
|
+
propertyExpectations[0].args,
|
|
224
|
+
args
|
|
225
|
+
);
|
|
226
|
+
this.actual = actual;
|
|
227
|
+
this.expected = expected;
|
|
231
228
|
this.matcherResult = {
|
|
232
229
|
actual,
|
|
233
230
|
expected
|
|
234
231
|
};
|
|
235
232
|
}
|
|
236
233
|
} else {
|
|
237
|
-
super(
|
|
234
|
+
super(
|
|
235
|
+
DIM_COLOR2(`${header}
|
|
238
236
|
|
|
239
|
-
No remaining expectations.`)
|
|
240
|
-
|
|
237
|
+
No remaining expectations.`)
|
|
238
|
+
);
|
|
241
239
|
}
|
|
242
240
|
}
|
|
243
|
-
}
|
|
241
|
+
};
|
|
244
242
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
* // Will throw "Didn't expect foo to be accessed".
|
|
252
|
-
* const { foo } = service;
|
|
253
|
-
*
|
|
254
|
-
* // Will throw "Didn't expect foo to be accessed",
|
|
255
|
-
* // without printing the arguments.
|
|
256
|
-
* foo(42);
|
|
257
|
-
*/
|
|
258
|
-
UnexpectedProperty[UnexpectedProperty["THROW"] = 0] = "THROW";
|
|
259
|
-
/**
|
|
260
|
-
* Return a function that will throw if called. This can be useful if your
|
|
261
|
-
* code destructures a function but never calls it.
|
|
262
|
-
*
|
|
263
|
-
* It will also improve error messages for unexpected calls because arguments
|
|
264
|
-
* will be captured instead of throwing immediately on the property access.
|
|
265
|
-
*
|
|
266
|
-
* The function will be returned even if the property is not supposed to be a
|
|
267
|
-
* function. This could cause weird behavior at runtime, when your code expects
|
|
268
|
-
* e.g. a number and gets a function instead.
|
|
269
|
-
*
|
|
270
|
-
* @example
|
|
271
|
-
* // This will NOT throw.
|
|
272
|
-
* const { foo } = service;
|
|
273
|
-
*
|
|
274
|
-
* // This will NOT throw, and might produce unexpected results.
|
|
275
|
-
* foo > 0
|
|
276
|
-
*
|
|
277
|
-
* // Will throw "Didn't expect foo(42) to be called".
|
|
278
|
-
* foo(42);
|
|
279
|
-
*/
|
|
280
|
-
UnexpectedProperty[UnexpectedProperty["CALL_THROW"] = 1] = "CALL_THROW";
|
|
281
|
-
})(exports.UnexpectedProperty || (exports.UnexpectedProperty = {}));
|
|
243
|
+
// src/mock/options.ts
|
|
244
|
+
var UnexpectedProperty = /* @__PURE__ */ ((UnexpectedProperty2) => {
|
|
245
|
+
UnexpectedProperty2[UnexpectedProperty2["THROW"] = 0] = "THROW";
|
|
246
|
+
UnexpectedProperty2[UnexpectedProperty2["CALL_THROW"] = 1] = "CALL_THROW";
|
|
247
|
+
return UnexpectedProperty2;
|
|
248
|
+
})(UnexpectedProperty || {});
|
|
282
249
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
*
|
|
286
|
-
* If the value is an error then throw it.
|
|
287
|
-
*
|
|
288
|
-
* If the value is a promise then resolve/reject it.
|
|
289
|
-
*/
|
|
290
|
-
const unboxReturnValue = ({
|
|
250
|
+
// src/expectation/repository/return-value.ts
|
|
251
|
+
var unboxReturnValue = ({
|
|
291
252
|
isError,
|
|
292
253
|
isPromise,
|
|
293
254
|
value
|
|
@@ -310,32 +271,30 @@ const unboxReturnValue = ({
|
|
|
310
271
|
return value;
|
|
311
272
|
};
|
|
312
273
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
this.
|
|
320
|
-
this.
|
|
321
|
-
this.
|
|
322
|
-
this.unexpectedCallStats = new Map();
|
|
323
|
-
this.apply = args => this.get(ApplyProp)(...args);
|
|
274
|
+
// src/expectation/repository/flexible-repository.ts
|
|
275
|
+
var FlexibleRepository = class {
|
|
276
|
+
constructor(mockName, unexpectedProperty = 0 /* THROW */) {
|
|
277
|
+
this.mockName = mockName;
|
|
278
|
+
this.unexpectedProperty = unexpectedProperty;
|
|
279
|
+
this.expectations = /* @__PURE__ */ new Map();
|
|
280
|
+
this.expectedCallStats = /* @__PURE__ */ new Map();
|
|
281
|
+
this.unexpectedCallStats = /* @__PURE__ */ new Map();
|
|
282
|
+
this.apply = (args) => this.get(ApplyProp)(...args);
|
|
324
283
|
this.handlePropertyWithMatchingExpectations = (property, expectations) => {
|
|
325
|
-
// Avoid recording call stats for function calls, since the property is an
|
|
326
|
-
// internal detail.
|
|
327
284
|
if (property !== ApplyProp) {
|
|
328
|
-
|
|
329
|
-
// function that will not match the given args.
|
|
330
|
-
this.recordExpected(property, undefined);
|
|
285
|
+
this.recordExpected(property, void 0);
|
|
331
286
|
}
|
|
332
|
-
const propertyExpectation = expectations.find(
|
|
287
|
+
const propertyExpectation = expectations.find(
|
|
288
|
+
(e) => e.expectation.matches(void 0)
|
|
289
|
+
);
|
|
333
290
|
if (propertyExpectation) {
|
|
334
291
|
this.countAndConsume(propertyExpectation);
|
|
335
292
|
return unboxReturnValue(propertyExpectation.expectation.returnValue);
|
|
336
293
|
}
|
|
337
294
|
return (...args) => {
|
|
338
|
-
const callExpectation = expectations.find(
|
|
295
|
+
const callExpectation = expectations.find(
|
|
296
|
+
(e) => e.expectation.matches(args)
|
|
297
|
+
);
|
|
339
298
|
if (callExpectation) {
|
|
340
299
|
this.recordExpected(property, args);
|
|
341
300
|
this.countAndConsume(callExpectation);
|
|
@@ -344,23 +303,23 @@ class FlexibleRepository {
|
|
|
344
303
|
return this.getValueForUnexpectedCall(property, args);
|
|
345
304
|
};
|
|
346
305
|
};
|
|
347
|
-
this.handlePropertyWithNoExpectations = property => {
|
|
306
|
+
this.handlePropertyWithNoExpectations = (property) => {
|
|
348
307
|
switch (property) {
|
|
349
|
-
case
|
|
350
|
-
return () =>
|
|
351
|
-
case
|
|
308
|
+
case "toString":
|
|
309
|
+
return () => this.mockName;
|
|
310
|
+
case "@@toStringTag":
|
|
352
311
|
case Symbol.toStringTag:
|
|
353
|
-
case
|
|
354
|
-
return
|
|
312
|
+
case "name":
|
|
313
|
+
return this.mockName;
|
|
355
314
|
// Promise.resolve() tries to see if it's a "thenable".
|
|
356
315
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
|
|
357
|
-
case
|
|
358
|
-
return
|
|
316
|
+
case "then":
|
|
317
|
+
return void 0;
|
|
359
318
|
// pretty-format
|
|
360
|
-
case
|
|
361
|
-
case
|
|
362
|
-
case
|
|
363
|
-
case
|
|
319
|
+
case "$$typeof":
|
|
320
|
+
case "constructor":
|
|
321
|
+
case "@@__IMMUTABLE_ITERABLE__@@":
|
|
322
|
+
case "@@__IMMUTABLE_RECORD__@@":
|
|
364
323
|
return null;
|
|
365
324
|
case MATCHER_SYMBOL:
|
|
366
325
|
return false;
|
|
@@ -370,17 +329,17 @@ class FlexibleRepository {
|
|
|
370
329
|
return this.getValueForUnexpectedAccess(property);
|
|
371
330
|
}
|
|
372
331
|
};
|
|
373
|
-
this.unexpectedProperty = unexpectedProperty;
|
|
374
332
|
}
|
|
375
333
|
add(expectation) {
|
|
376
|
-
const {
|
|
377
|
-
property
|
|
378
|
-
} = expectation;
|
|
334
|
+
const { property } = expectation;
|
|
379
335
|
const expectations = this.expectations.get(property) || [];
|
|
380
|
-
this.expectations.set(property, [
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
336
|
+
this.expectations.set(property, [
|
|
337
|
+
...expectations,
|
|
338
|
+
{
|
|
339
|
+
expectation,
|
|
340
|
+
matchCount: 0
|
|
341
|
+
}
|
|
342
|
+
]);
|
|
384
343
|
}
|
|
385
344
|
clear() {
|
|
386
345
|
this.expectations.clear();
|
|
@@ -392,7 +351,10 @@ class FlexibleRepository {
|
|
|
392
351
|
get(property) {
|
|
393
352
|
const expectations = this.expectations.get(property);
|
|
394
353
|
if (expectations && expectations.length) {
|
|
395
|
-
return this.handlePropertyWithMatchingExpectations(
|
|
354
|
+
return this.handlePropertyWithMatchingExpectations(
|
|
355
|
+
property,
|
|
356
|
+
expectations
|
|
357
|
+
);
|
|
396
358
|
}
|
|
397
359
|
return this.handlePropertyWithNoExpectations(property);
|
|
398
360
|
}
|
|
@@ -406,75 +368,61 @@ class FlexibleRepository {
|
|
|
406
368
|
};
|
|
407
369
|
}
|
|
408
370
|
getUnmet() {
|
|
409
|
-
return [].concat(
|
|
371
|
+
return [].concat(
|
|
372
|
+
...Array.from(this.expectations.values()).map(
|
|
373
|
+
(expectations) => expectations.filter((e) => e.expectation.min > e.matchCount).map((e) => e.expectation)
|
|
374
|
+
)
|
|
375
|
+
);
|
|
410
376
|
}
|
|
411
377
|
recordExpected(property, args) {
|
|
412
378
|
const calls = this.expectedCallStats.get(property) || [];
|
|
413
|
-
this.expectedCallStats.set(property, [...calls, {
|
|
414
|
-
arguments: args
|
|
415
|
-
}]);
|
|
379
|
+
this.expectedCallStats.set(property, [...calls, { arguments: args }]);
|
|
416
380
|
}
|
|
417
381
|
recordUnexpected(property, args) {
|
|
418
382
|
const calls = this.unexpectedCallStats.get(property) || [];
|
|
419
|
-
this.unexpectedCallStats.set(property, [...calls, {
|
|
420
|
-
arguments: args
|
|
421
|
-
}]);
|
|
383
|
+
this.unexpectedCallStats.set(property, [...calls, { arguments: args }]);
|
|
422
384
|
}
|
|
423
385
|
countAndConsume(expectation) {
|
|
424
|
-
// eslint-disable-next-line no-param-reassign
|
|
425
386
|
expectation.matchCount++;
|
|
426
387
|
this.consumeExpectation(expectation);
|
|
427
388
|
}
|
|
428
389
|
consumeExpectation(expectation) {
|
|
429
|
-
const {
|
|
430
|
-
property,
|
|
431
|
-
max
|
|
432
|
-
} = expectation.expectation;
|
|
390
|
+
const { property, max } = expectation.expectation;
|
|
433
391
|
const expectations = this.expectations.get(property);
|
|
434
392
|
if (expectation.matchCount === max) {
|
|
435
|
-
this.expectations.set(
|
|
393
|
+
this.expectations.set(
|
|
394
|
+
property,
|
|
395
|
+
expectations.filter((e) => e !== expectation)
|
|
396
|
+
);
|
|
436
397
|
}
|
|
437
398
|
}
|
|
438
399
|
getValueForUnexpectedCall(property, args) {
|
|
439
400
|
this.recordUnexpected(property, args);
|
|
440
|
-
throw new UnexpectedCall(property, args, this.getUnmet());
|
|
401
|
+
throw new UnexpectedCall(this.mockName, property, args, this.getUnmet());
|
|
441
402
|
}
|
|
442
403
|
getValueForUnexpectedAccess(property) {
|
|
443
|
-
if (this.unexpectedProperty ===
|
|
444
|
-
this.recordUnexpected(property,
|
|
445
|
-
throw new UnexpectedAccess(property, this.getUnmet());
|
|
404
|
+
if (this.unexpectedProperty === 0 /* THROW */) {
|
|
405
|
+
this.recordUnexpected(property, void 0);
|
|
406
|
+
throw new UnexpectedAccess(this.mockName, property, this.getUnmet());
|
|
446
407
|
}
|
|
447
408
|
return (...args) => {
|
|
448
409
|
this.recordUnexpected(property, args);
|
|
449
|
-
throw new UnexpectedCall(property, args, this.getUnmet());
|
|
410
|
+
throw new UnexpectedCall(this.mockName, property, args, this.getUnmet());
|
|
450
411
|
};
|
|
451
412
|
}
|
|
452
|
-
}
|
|
413
|
+
};
|
|
453
414
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
* @example
|
|
459
|
-
* new StrongExpectation(
|
|
460
|
-
* 'bar',
|
|
461
|
-
* deepEquals([1, 2, 3]),
|
|
462
|
-
* 23
|
|
463
|
-
* ).matches('bar', [1, 2, 3]) === true;
|
|
464
|
-
*/
|
|
465
|
-
class StrongExpectation {
|
|
466
|
-
constructor(property, args, returnValue, exactParams = false) {
|
|
467
|
-
this.property = void 0;
|
|
468
|
-
this.args = void 0;
|
|
469
|
-
this.returnValue = void 0;
|
|
470
|
-
this.exactParams = void 0;
|
|
471
|
-
this.matched = 0;
|
|
472
|
-
this.min = 1;
|
|
473
|
-
this.max = 1;
|
|
415
|
+
// src/expectation/strong-expectation.ts
|
|
416
|
+
var StrongExpectation = class {
|
|
417
|
+
constructor(mockName, property, args, returnValue, exactParams = false) {
|
|
418
|
+
this.mockName = mockName;
|
|
474
419
|
this.property = property;
|
|
475
420
|
this.args = args;
|
|
476
421
|
this.returnValue = returnValue;
|
|
477
422
|
this.exactParams = exactParams;
|
|
423
|
+
this.matched = 0;
|
|
424
|
+
this.min = 1;
|
|
425
|
+
this.max = 1;
|
|
478
426
|
}
|
|
479
427
|
setInvocationCount(min, max = 1) {
|
|
480
428
|
this.min = min;
|
|
@@ -491,7 +439,7 @@ class StrongExpectation {
|
|
|
491
439
|
return this.matched < this.min;
|
|
492
440
|
}
|
|
493
441
|
matchesArgs(received) {
|
|
494
|
-
if (this.args ===
|
|
442
|
+
if (this.args === void 0) {
|
|
495
443
|
return !received;
|
|
496
444
|
}
|
|
497
445
|
if (!received) {
|
|
@@ -505,35 +453,43 @@ class StrongExpectation {
|
|
|
505
453
|
return this.args.every((arg, i) => arg.matches(received[i]));
|
|
506
454
|
}
|
|
507
455
|
toString() {
|
|
508
|
-
return printExpectation(
|
|
456
|
+
return printExpectation(
|
|
457
|
+
this.mockName,
|
|
458
|
+
this.property,
|
|
459
|
+
this.args,
|
|
460
|
+
this.returnValue,
|
|
461
|
+
this.min,
|
|
462
|
+
this.max
|
|
463
|
+
);
|
|
509
464
|
}
|
|
510
|
-
}
|
|
465
|
+
};
|
|
511
466
|
|
|
512
|
-
|
|
513
|
-
|
|
467
|
+
// src/errors/api.ts
|
|
468
|
+
var UnfinishedExpectation = class extends Error {
|
|
469
|
+
constructor(mockName, property, args) {
|
|
514
470
|
super(`There is an unfinished pending expectation:
|
|
515
471
|
|
|
516
|
-
${printWhen(property, args)}
|
|
472
|
+
${printWhen(mockName, property, args)}
|
|
517
473
|
|
|
518
|
-
|
|
519
|
-
is undefined.`);
|
|
474
|
+
You should finish it by setting a return value with e.g. thenReturns(),
|
|
475
|
+
even if that value is undefined.`);
|
|
520
476
|
}
|
|
521
|
-
}
|
|
522
|
-
|
|
477
|
+
};
|
|
478
|
+
var MissingWhen = class extends Error {
|
|
523
479
|
constructor() {
|
|
524
480
|
super(`You tried setting a return value without an expectation.
|
|
525
481
|
|
|
526
482
|
Every call to set a return value must be preceded by an expectation.`);
|
|
527
483
|
}
|
|
528
|
-
}
|
|
529
|
-
|
|
484
|
+
};
|
|
485
|
+
var NotAMock = class extends Error {
|
|
530
486
|
constructor() {
|
|
531
487
|
super(`We couldn't find the mock.
|
|
532
488
|
|
|
533
489
|
Make sure you're passing in an actual mock.`);
|
|
534
490
|
}
|
|
535
|
-
}
|
|
536
|
-
|
|
491
|
+
};
|
|
492
|
+
var NestedWhen = class extends Error {
|
|
537
493
|
constructor(parentProp, childProp) {
|
|
538
494
|
const snippet = `
|
|
539
495
|
const parentMock = mock<T1>();
|
|
@@ -542,28 +498,27 @@ const childMock = mock<T2>();
|
|
|
542
498
|
when(() => childMock${printProperty(childProp)}).thenReturn(...);
|
|
543
499
|
when(() => parentMock${printProperty(parentProp)}).thenReturn(childMock)
|
|
544
500
|
`;
|
|
545
|
-
super(
|
|
501
|
+
super(
|
|
502
|
+
`Setting an expectation on a nested property is not supported.
|
|
546
503
|
|
|
547
504
|
You can return an object directly when the first property is accessed,
|
|
548
505
|
or you can even return a separate mock:
|
|
549
|
-
${snippet}`
|
|
506
|
+
${snippet}`
|
|
507
|
+
);
|
|
550
508
|
}
|
|
551
|
-
}
|
|
509
|
+
};
|
|
552
510
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
this.concreteMatcher = void 0;
|
|
557
|
-
this.exactParams = void 0;
|
|
558
|
-
this.args = void 0;
|
|
559
|
-
this.property = void 0;
|
|
511
|
+
// src/when/expectation-builder.ts
|
|
512
|
+
var ExpectationBuilderWithFactory = class {
|
|
513
|
+
constructor(createExpectation, concreteMatcher, mockName, exactParams) {
|
|
560
514
|
this.createExpectation = createExpectation;
|
|
561
515
|
this.concreteMatcher = concreteMatcher;
|
|
516
|
+
this.mockName = mockName;
|
|
562
517
|
this.exactParams = exactParams;
|
|
563
518
|
}
|
|
564
519
|
setProperty(value) {
|
|
565
520
|
if (this.property) {
|
|
566
|
-
throw new UnfinishedExpectation(this.property, this.args);
|
|
521
|
+
throw new UnfinishedExpectation(this.mockName, this.property, this.args);
|
|
567
522
|
}
|
|
568
523
|
this.property = value;
|
|
569
524
|
}
|
|
@@ -574,223 +529,231 @@ class ExpectationBuilderWithFactory {
|
|
|
574
529
|
if (!this.property) {
|
|
575
530
|
throw new MissingWhen();
|
|
576
531
|
}
|
|
577
|
-
const expectation = this.createExpectation(
|
|
578
|
-
|
|
579
|
-
|
|
532
|
+
const expectation = this.createExpectation(
|
|
533
|
+
this.mockName,
|
|
534
|
+
this.property,
|
|
535
|
+
this.args,
|
|
536
|
+
returnValue,
|
|
537
|
+
this.concreteMatcher,
|
|
538
|
+
this.exactParams
|
|
539
|
+
);
|
|
540
|
+
this.property = void 0;
|
|
541
|
+
this.args = void 0;
|
|
580
542
|
return expectation;
|
|
581
543
|
}
|
|
582
|
-
}
|
|
544
|
+
};
|
|
583
545
|
|
|
584
|
-
|
|
546
|
+
// src/matchers/deep-equals.ts
|
|
547
|
+
import cloneDeep from "lodash/cloneDeep.js";
|
|
548
|
+
import cloneDeepWith2 from "lodash/cloneDeepWith.js";
|
|
549
|
+
import isEqualWith from "lodash/isEqualWith.js";
|
|
550
|
+
import isMap from "lodash/isMap.js";
|
|
551
|
+
import isObjectLike from "lodash/isObjectLike.js";
|
|
552
|
+
import omitBy from "lodash/omitBy.js";
|
|
553
|
+
var removeUndefined = (object) => {
|
|
585
554
|
if (Array.isArray(object)) {
|
|
586
|
-
return object.map(x => removeUndefined(x));
|
|
555
|
+
return object.map((x) => removeUndefined(x));
|
|
587
556
|
}
|
|
588
|
-
if (!
|
|
557
|
+
if (!isObjectLike(object)) {
|
|
589
558
|
return object;
|
|
590
559
|
}
|
|
591
|
-
return
|
|
560
|
+
return omitBy(object, (value) => value === void 0);
|
|
592
561
|
};
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
* this to `false` will consider the objects in both cases as equal.
|
|
601
|
-
*
|
|
602
|
-
* @see {@link It.containsObject} or {@link It.isArray} if you want to nest matchers.
|
|
603
|
-
* @see {@link It.is} if you want to use strict equality.
|
|
604
|
-
*/
|
|
605
|
-
const deepEquals = (expected, {
|
|
562
|
+
var getKey = (key, object) => {
|
|
563
|
+
if (key === void 0) {
|
|
564
|
+
return object;
|
|
565
|
+
}
|
|
566
|
+
return isMap(object) ? object.get(key) : object[key];
|
|
567
|
+
};
|
|
568
|
+
var deepEquals = (expected, {
|
|
606
569
|
strict = true
|
|
607
|
-
} = {}) => matches(
|
|
608
|
-
|
|
609
|
-
|
|
570
|
+
} = {}) => matches(
|
|
571
|
+
(actual) => isEqualWith(
|
|
572
|
+
strict ? actual : removeUndefined(actual),
|
|
573
|
+
strict ? expected : removeUndefined(expected),
|
|
574
|
+
(actualValue, expectedValue) => {
|
|
575
|
+
if (isMatcher(expectedValue)) {
|
|
576
|
+
return expectedValue.matches(actualValue);
|
|
577
|
+
}
|
|
578
|
+
return void 0;
|
|
579
|
+
}
|
|
580
|
+
),
|
|
581
|
+
{
|
|
582
|
+
toString: () => printValue(deepPrint(expected)),
|
|
583
|
+
getDiff: (actual) => {
|
|
584
|
+
let actualResult = cloneDeep(actual);
|
|
585
|
+
const expectedResult = cloneDeepWith2(expected, (expectedValue, key) => {
|
|
586
|
+
const actualValue = getKey(key, actualResult);
|
|
587
|
+
if (isMatcher(expectedValue)) {
|
|
588
|
+
if (expectedValue.matches(actualValue)) {
|
|
589
|
+
return actualValue;
|
|
590
|
+
}
|
|
591
|
+
const result = expectedValue.getDiff(actualValue);
|
|
592
|
+
if (key !== void 0) {
|
|
593
|
+
if (isMap(actualResult)) {
|
|
594
|
+
actualResult.set(key, result.actual);
|
|
595
|
+
} else {
|
|
596
|
+
actualResult[key] = result.actual;
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
actualResult = result.actual;
|
|
600
|
+
}
|
|
601
|
+
return result.expected;
|
|
602
|
+
}
|
|
603
|
+
return void 0;
|
|
604
|
+
});
|
|
605
|
+
return {
|
|
606
|
+
actual: actualResult,
|
|
607
|
+
expected: expectedResult
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
610
|
}
|
|
611
|
-
|
|
612
|
-
}, {
|
|
613
|
-
toString: () => printValue(expected),
|
|
614
|
-
getDiff: actual => ({
|
|
615
|
-
actual,
|
|
616
|
-
expected
|
|
617
|
-
})
|
|
618
|
-
});
|
|
611
|
+
);
|
|
619
612
|
|
|
620
|
-
|
|
613
|
+
// src/mock/defaults.ts
|
|
614
|
+
var defaults = {
|
|
615
|
+
name: "mock",
|
|
621
616
|
concreteMatcher: deepEquals,
|
|
622
|
-
unexpectedProperty:
|
|
617
|
+
unexpectedProperty: 1 /* CALL_THROW */,
|
|
623
618
|
exactParams: false
|
|
624
619
|
};
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
*
|
|
629
|
-
* @param newDefaults These will be applied to the library defaults. Multiple
|
|
630
|
-
* calls don't stack e.g. calling this with `{}` will clear any previously
|
|
631
|
-
* applied defaults.
|
|
632
|
-
*/
|
|
633
|
-
const setDefaults = newDefaults => {
|
|
634
|
-
currentDefaults = {
|
|
635
|
-
...defaults,
|
|
636
|
-
...newDefaults
|
|
637
|
-
};
|
|
620
|
+
var currentDefaults = defaults;
|
|
621
|
+
var setDefaults = (newDefaults) => {
|
|
622
|
+
currentDefaults = __spreadValues(__spreadValues({}, defaults), newDefaults);
|
|
638
623
|
};
|
|
639
624
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
*
|
|
645
|
-
* We also want to throw in the following case:
|
|
646
|
-
*
|
|
647
|
-
* ```
|
|
648
|
-
* when(() => mock()) // forgot returns here
|
|
649
|
-
* when(() => mock()) // should throw
|
|
650
|
-
* ```
|
|
651
|
-
*
|
|
652
|
-
* For that reason we can't just store the currently active mock, but also
|
|
653
|
-
* whether we finished the expectation or not.
|
|
654
|
-
*/
|
|
655
|
-
let activeMock;
|
|
656
|
-
const setActiveMock = mock => {
|
|
657
|
-
activeMock = mock;
|
|
625
|
+
// src/mock/map.ts
|
|
626
|
+
var activeMock;
|
|
627
|
+
var setActiveMock = (mock2) => {
|
|
628
|
+
activeMock = mock2;
|
|
658
629
|
};
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
* and `thenReturn`.
|
|
665
|
-
*/
|
|
666
|
-
const mockMap = new Map();
|
|
667
|
-
const getMockState = mock => {
|
|
668
|
-
if (mockMap.has(mock)) {
|
|
669
|
-
return mockMap.get(mock);
|
|
630
|
+
var getActiveMock = () => activeMock;
|
|
631
|
+
var mockMap = /* @__PURE__ */ new Map();
|
|
632
|
+
var getMockState = (mock2) => {
|
|
633
|
+
if (mockMap.has(mock2)) {
|
|
634
|
+
return mockMap.get(mock2);
|
|
670
635
|
}
|
|
671
636
|
throw new NotAMock();
|
|
672
637
|
};
|
|
673
|
-
|
|
674
|
-
mockMap.set(
|
|
638
|
+
var setMockState = (mock2, state) => {
|
|
639
|
+
mockMap.set(mock2, state);
|
|
675
640
|
};
|
|
676
|
-
|
|
641
|
+
var getAllMocks = () => Array.from(mockMap.entries());
|
|
677
642
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
Mode[Mode["CALL"] = 1] = "CALL";
|
|
682
|
-
})(Mode || (Mode = {}));
|
|
683
|
-
let currentMode = Mode.CALL;
|
|
684
|
-
const setMode = mode => {
|
|
643
|
+
// src/mock/mode.ts
|
|
644
|
+
var currentMode = 1 /* CALL */;
|
|
645
|
+
var setMode = (mode) => {
|
|
685
646
|
currentMode = mode;
|
|
686
647
|
};
|
|
687
|
-
|
|
648
|
+
var getMode = () => currentMode;
|
|
688
649
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
//
|
|
692
|
-
//
|
|
693
|
-
new Proxy(
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
650
|
+
// src/proxy.ts
|
|
651
|
+
var createProxy = (traps) => (
|
|
652
|
+
// The Proxy target MUST be a function, otherwise we can't use the `apply` trap:
|
|
653
|
+
// https://262.ecma-international.org/6.0/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
|
|
654
|
+
new Proxy(
|
|
655
|
+
/* c8 ignore next */
|
|
656
|
+
() => {
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
get: (target, prop) => {
|
|
660
|
+
if (prop === "bind") {
|
|
661
|
+
return (thisArg, ...args) => (...moreArgs) => traps.apply([...args, ...moreArgs]);
|
|
662
|
+
}
|
|
663
|
+
if (prop === "apply") {
|
|
664
|
+
return (thisArg, args) => traps.apply(args || []);
|
|
665
|
+
}
|
|
666
|
+
if (prop === "call") {
|
|
667
|
+
return (thisArg, ...args) => traps.apply(args);
|
|
668
|
+
}
|
|
669
|
+
return traps.property(prop);
|
|
670
|
+
},
|
|
671
|
+
apply: (target, thisArg, args) => traps.apply(args),
|
|
672
|
+
ownKeys: () => traps.ownKeys(),
|
|
673
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
674
|
+
const keys = traps.ownKeys();
|
|
675
|
+
if (keys.includes(prop)) {
|
|
676
|
+
return {
|
|
677
|
+
configurable: true,
|
|
678
|
+
enumerable: true
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
return void 0;
|
|
682
|
+
}
|
|
715
683
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
});
|
|
684
|
+
)
|
|
685
|
+
);
|
|
719
686
|
|
|
720
|
-
|
|
687
|
+
// src/mock/stub.ts
|
|
688
|
+
var createStub = (repo, builder, getCurrentMode) => {
|
|
721
689
|
const stub = createProxy({
|
|
722
|
-
property: property => {
|
|
723
|
-
if (getCurrentMode() ===
|
|
690
|
+
property: (property) => {
|
|
691
|
+
if (getCurrentMode() === 1 /* CALL */) {
|
|
724
692
|
return repo.get(property);
|
|
725
693
|
}
|
|
726
694
|
setActiveMock(stub);
|
|
727
695
|
builder.setProperty(property);
|
|
728
696
|
return createProxy({
|
|
729
|
-
property: childProp => {
|
|
697
|
+
property: (childProp) => {
|
|
730
698
|
throw new NestedWhen(property, childProp);
|
|
731
699
|
},
|
|
732
|
-
apply: args => {
|
|
700
|
+
apply: (args) => {
|
|
733
701
|
builder.setArgs(args);
|
|
734
702
|
},
|
|
735
703
|
ownKeys: () => {
|
|
736
|
-
throw new Error(
|
|
704
|
+
throw new Error("Spreading during an expectation is not supported.");
|
|
737
705
|
}
|
|
738
706
|
});
|
|
739
707
|
},
|
|
740
|
-
apply: args => {
|
|
741
|
-
if (getCurrentMode() ===
|
|
708
|
+
apply: (args) => {
|
|
709
|
+
if (getCurrentMode() === 1 /* CALL */) {
|
|
742
710
|
return repo.apply(args);
|
|
743
711
|
}
|
|
744
712
|
setActiveMock(stub);
|
|
745
713
|
builder.setProperty(ApplyProp);
|
|
746
714
|
builder.setArgs(args);
|
|
747
|
-
return
|
|
715
|
+
return void 0;
|
|
748
716
|
},
|
|
749
717
|
ownKeys: () => {
|
|
750
|
-
if (getCurrentMode() ===
|
|
718
|
+
if (getCurrentMode() === 1 /* CALL */) {
|
|
751
719
|
return repo.getAllProperties();
|
|
752
720
|
}
|
|
753
|
-
throw new Error(
|
|
721
|
+
throw new Error("Spreading during an expectation is not supported.");
|
|
754
722
|
}
|
|
755
723
|
});
|
|
756
724
|
return stub;
|
|
757
725
|
};
|
|
758
726
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
* property is accessed.
|
|
770
|
-
* @param options.concreteMatcher The matcher that will be used when one isn't
|
|
771
|
-
* specified explicitly.
|
|
772
|
-
* @param options.exactParams Controls whether the number of received arguments
|
|
773
|
-
* has to match the expectation.
|
|
774
|
-
*
|
|
775
|
-
* @example
|
|
776
|
-
* const fn = mock<() => number>();
|
|
777
|
-
*
|
|
778
|
-
* when(() => fn()).thenReturn(23);
|
|
779
|
-
*
|
|
780
|
-
* fn() === 23;
|
|
781
|
-
*/
|
|
782
|
-
const mock = ({
|
|
727
|
+
// src/mock/mock.ts
|
|
728
|
+
var strongExpectationFactory = (name, property, args, returnValue, concreteMatcher, exactParams) => new StrongExpectation(
|
|
729
|
+
name,
|
|
730
|
+
property,
|
|
731
|
+
args == null ? void 0 : args.map((arg) => isMatcher(arg) ? arg : concreteMatcher(arg)),
|
|
732
|
+
returnValue,
|
|
733
|
+
exactParams
|
|
734
|
+
);
|
|
735
|
+
var mock = ({
|
|
736
|
+
name,
|
|
783
737
|
unexpectedProperty,
|
|
784
738
|
concreteMatcher,
|
|
785
739
|
exactParams
|
|
786
740
|
} = {}) => {
|
|
787
741
|
const options = {
|
|
742
|
+
name: name != null ? name : currentDefaults.name,
|
|
788
743
|
unexpectedProperty: unexpectedProperty != null ? unexpectedProperty : currentDefaults.unexpectedProperty,
|
|
789
744
|
concreteMatcher: concreteMatcher != null ? concreteMatcher : currentDefaults.concreteMatcher,
|
|
790
745
|
exactParams: exactParams != null ? exactParams : currentDefaults.exactParams
|
|
791
746
|
};
|
|
792
|
-
const repository = new FlexibleRepository(
|
|
793
|
-
|
|
747
|
+
const repository = new FlexibleRepository(
|
|
748
|
+
options.name,
|
|
749
|
+
options.unexpectedProperty
|
|
750
|
+
);
|
|
751
|
+
const builder = new ExpectationBuilderWithFactory(
|
|
752
|
+
strongExpectationFactory,
|
|
753
|
+
options.concreteMatcher,
|
|
754
|
+
options.name,
|
|
755
|
+
options.exactParams
|
|
756
|
+
);
|
|
794
757
|
const stub = createStub(repository, builder, getMode);
|
|
795
758
|
setMockState(stub, {
|
|
796
759
|
repository,
|
|
@@ -800,44 +763,45 @@ const mock = ({
|
|
|
800
763
|
return stub;
|
|
801
764
|
};
|
|
802
765
|
|
|
803
|
-
|
|
766
|
+
// src/return/invocation-count.ts
|
|
767
|
+
var createInvocationCount = (expectation) => ({
|
|
804
768
|
between(min, max) {
|
|
805
769
|
expectation.setInvocationCount(min, max);
|
|
806
770
|
},
|
|
807
|
-
/*
|
|
771
|
+
/* c8 ignore next 3 */
|
|
808
772
|
times(exact) {
|
|
809
773
|
expectation.setInvocationCount(exact, exact);
|
|
810
774
|
},
|
|
811
|
-
/*
|
|
775
|
+
/* c8 ignore next 3 */
|
|
812
776
|
anyTimes() {
|
|
813
777
|
expectation.setInvocationCount(0, 0);
|
|
814
778
|
},
|
|
815
|
-
/*
|
|
779
|
+
/* c8 ignore next 3 */
|
|
816
780
|
atLeast(min) {
|
|
817
781
|
expectation.setInvocationCount(min, Infinity);
|
|
818
782
|
},
|
|
819
|
-
/*
|
|
783
|
+
/* c8 ignore next 3 */
|
|
820
784
|
atMost(max) {
|
|
821
785
|
expectation.setInvocationCount(0, max);
|
|
822
786
|
},
|
|
823
|
-
/*
|
|
787
|
+
/* c8 ignore next 3 */
|
|
824
788
|
once() {
|
|
825
789
|
expectation.setInvocationCount(1, 1);
|
|
826
790
|
},
|
|
827
|
-
/*
|
|
791
|
+
/* c8 ignore next 3 */
|
|
828
792
|
twice() {
|
|
829
793
|
expectation.setInvocationCount(2, 2);
|
|
830
794
|
}
|
|
831
|
-
/* eslint-enable no-param-reassign, no-multi-assign */
|
|
832
795
|
});
|
|
833
796
|
|
|
834
|
-
|
|
797
|
+
// src/return/returns.ts
|
|
798
|
+
var finishExpectation = (returnValue, builder, repo) => {
|
|
835
799
|
const finishedExpectation = builder.finish(returnValue);
|
|
836
800
|
repo.add(finishedExpectation);
|
|
837
801
|
return createInvocationCount(finishedExpectation);
|
|
838
802
|
};
|
|
839
|
-
|
|
840
|
-
if (typeof errorOrMessage ===
|
|
803
|
+
var getError = (errorOrMessage) => {
|
|
804
|
+
if (typeof errorOrMessage === "string") {
|
|
841
805
|
return new Error(errorOrMessage);
|
|
842
806
|
}
|
|
843
807
|
if (errorOrMessage instanceof Error) {
|
|
@@ -845,344 +809,263 @@ const getError = errorOrMessage => {
|
|
|
845
809
|
}
|
|
846
810
|
return new Error();
|
|
847
811
|
};
|
|
848
|
-
|
|
849
|
-
thenReturn: returnValue => finishExpectation(
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
812
|
+
var createReturns = (builder, repository) => ({
|
|
813
|
+
thenReturn: (returnValue) => finishExpectation(
|
|
814
|
+
// This will handle both thenReturn(23) and thenReturn(Promise.resolve(3)).
|
|
815
|
+
{ value: returnValue, isError: false, isPromise: false },
|
|
816
|
+
builder,
|
|
817
|
+
repository
|
|
818
|
+
),
|
|
819
|
+
thenThrow: (errorOrMessage) => finishExpectation(
|
|
820
|
+
{ value: getError(errorOrMessage), isError: true, isPromise: false },
|
|
821
|
+
builder,
|
|
822
|
+
repository
|
|
823
|
+
),
|
|
824
|
+
thenResolve: (promiseValue) => finishExpectation(
|
|
825
|
+
{
|
|
826
|
+
value: promiseValue,
|
|
827
|
+
isError: false,
|
|
828
|
+
isPromise: true
|
|
829
|
+
},
|
|
830
|
+
builder,
|
|
831
|
+
repository
|
|
832
|
+
),
|
|
833
|
+
thenReject: (errorOrMessage) => finishExpectation(
|
|
834
|
+
{
|
|
835
|
+
value: getError(errorOrMessage),
|
|
836
|
+
isError: true,
|
|
837
|
+
isPromise: true
|
|
838
|
+
},
|
|
839
|
+
builder,
|
|
840
|
+
repository
|
|
841
|
+
)
|
|
871
842
|
});
|
|
872
843
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
* The expectation must be finished by setting a return value, even if the value
|
|
877
|
-
* is `undefined`.
|
|
878
|
-
*
|
|
879
|
-
* If a call happens that was not expected then the mock will throw an error.
|
|
880
|
-
* By default, the call is expected to only be made once. Use the invocation
|
|
881
|
-
* count helpers to expect a call multiple times.
|
|
882
|
-
*
|
|
883
|
-
* @param expectation A callback to set the expectation on your mock. The
|
|
884
|
-
* callback must return the value from the mock to properly infer types.
|
|
885
|
-
*
|
|
886
|
-
* @example
|
|
887
|
-
* const fn = mock<() => void>();
|
|
888
|
-
* when(() => fn()).thenReturn(undefined);
|
|
889
|
-
*
|
|
890
|
-
* @example
|
|
891
|
-
* const fn = mock<() => number>();
|
|
892
|
-
* when(() => fn()).thenReturn(42).atMost(3);
|
|
893
|
-
*
|
|
894
|
-
* @example
|
|
895
|
-
* const fn = mock<(x: number) => Promise<number>();
|
|
896
|
-
* when(() => fn(23)).thenResolve(42);
|
|
897
|
-
*/
|
|
898
|
-
const when = expectation => {
|
|
899
|
-
setMode(Mode.EXPECT);
|
|
844
|
+
// src/when/when.ts
|
|
845
|
+
var when = (expectation) => {
|
|
846
|
+
setMode(0 /* EXPECT */);
|
|
900
847
|
expectation();
|
|
901
|
-
setMode(
|
|
902
|
-
const {
|
|
903
|
-
builder,
|
|
904
|
-
repository
|
|
905
|
-
} = getMockState(getActiveMock());
|
|
848
|
+
setMode(1 /* CALL */);
|
|
849
|
+
const { builder, repository } = getMockState(getActiveMock());
|
|
906
850
|
return createReturns(builder, repository);
|
|
907
851
|
};
|
|
908
852
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
* @example
|
|
913
|
-
* const fn = mock<() => number>();
|
|
914
|
-
*
|
|
915
|
-
* when(() => fn()).thenReturn(23);
|
|
916
|
-
*
|
|
917
|
-
* reset(fn);
|
|
918
|
-
*
|
|
919
|
-
* fn(); // throws
|
|
920
|
-
*/
|
|
921
|
-
const reset = mock => {
|
|
922
|
-
getMockState(mock).repository.clear();
|
|
853
|
+
// src/verify/reset.ts
|
|
854
|
+
var reset = (mock2) => {
|
|
855
|
+
getMockState(mock2).repository.clear();
|
|
923
856
|
};
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
* @see reset
|
|
928
|
-
*/
|
|
929
|
-
const resetAll = () => {
|
|
930
|
-
getAllMocks().forEach(([mock]) => {
|
|
931
|
-
reset(mock);
|
|
857
|
+
var resetAll = () => {
|
|
858
|
+
getAllMocks().forEach(([mock2]) => {
|
|
859
|
+
reset(mock2);
|
|
932
860
|
});
|
|
933
861
|
};
|
|
934
862
|
|
|
935
|
-
|
|
863
|
+
// src/errors/verify.ts
|
|
864
|
+
import { DIM_COLOR as DIM_COLOR3 } from "jest-matcher-utils";
|
|
865
|
+
var UnmetExpectations = class extends Error {
|
|
936
866
|
constructor(expectations) {
|
|
937
|
-
super(
|
|
867
|
+
super(
|
|
868
|
+
DIM_COLOR3(`There are unmet expectations:
|
|
938
869
|
|
|
939
|
-
- ${expectations.map(e => e.toString()).join(
|
|
940
|
-
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Merge property accesses and method calls for the same property
|
|
944
|
-
* into a single call.
|
|
945
|
-
*
|
|
946
|
-
* @example
|
|
947
|
-
* mergeCalls({ getData: [{ arguments: undefined }, { arguments: [1, 2, 3] }] }
|
|
948
|
-
* // returns { getData: [{ arguments: [1, 2, 3] } }
|
|
949
|
-
*/
|
|
950
|
-
const mergeCalls = callMap => new Map(Array.from(callMap.entries()).map(([property, calls]) => {
|
|
951
|
-
const hasMethodCalls = calls.some(call => call.arguments);
|
|
952
|
-
const hasPropertyAccesses = calls.some(call => !call.arguments);
|
|
953
|
-
if (hasMethodCalls && hasPropertyAccesses) {
|
|
954
|
-
return [property, calls.filter(call => call.arguments)];
|
|
870
|
+
- ${expectations.map((e) => e.toString()).join("\n - ")}`)
|
|
871
|
+
);
|
|
955
872
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
const
|
|
961
|
-
|
|
873
|
+
};
|
|
874
|
+
var mergeCalls = (callMap) => new Map(
|
|
875
|
+
Array.from(callMap.entries()).map(([property, calls]) => {
|
|
876
|
+
const hasMethodCalls = calls.some((call) => call.arguments);
|
|
877
|
+
const hasPropertyAccesses = calls.some((call) => !call.arguments);
|
|
878
|
+
if (hasMethodCalls && hasPropertyAccesses) {
|
|
879
|
+
return [property, calls.filter((call) => call.arguments)];
|
|
880
|
+
}
|
|
881
|
+
return [property, calls];
|
|
882
|
+
})
|
|
883
|
+
);
|
|
884
|
+
var UnexpectedCalls = class extends Error {
|
|
885
|
+
constructor(mockName, unexpectedCalls, expectations) {
|
|
886
|
+
const printedCalls = Array.from(mergeCalls(unexpectedCalls).entries()).map(
|
|
887
|
+
([property, calls]) => calls.map((call) => printCall(mockName, property, call.arguments)).join("\n - ")
|
|
888
|
+
).join("\n - ");
|
|
889
|
+
super(
|
|
890
|
+
DIM_COLOR3(`The following calls were unexpected:
|
|
962
891
|
|
|
963
892
|
- ${printedCalls}
|
|
964
893
|
|
|
965
|
-
${printRemainingExpectations(expectations)}`)
|
|
894
|
+
${printRemainingExpectations(expectations)}`)
|
|
895
|
+
);
|
|
966
896
|
}
|
|
967
|
-
}
|
|
897
|
+
};
|
|
968
898
|
|
|
969
|
-
|
|
899
|
+
// src/verify/verify.ts
|
|
900
|
+
var verifyRepo = (repository) => {
|
|
970
901
|
const unmetExpectations = repository.getUnmet();
|
|
971
902
|
if (unmetExpectations.length) {
|
|
972
903
|
throw new UnmetExpectations(unmetExpectations);
|
|
973
904
|
}
|
|
974
905
|
const callStats = repository.getCallStats();
|
|
975
906
|
if (callStats.unexpected.size) {
|
|
976
|
-
throw new UnexpectedCalls(
|
|
907
|
+
throw new UnexpectedCalls(
|
|
908
|
+
repository.mockName,
|
|
909
|
+
callStats.unexpected,
|
|
910
|
+
unmetExpectations
|
|
911
|
+
);
|
|
977
912
|
}
|
|
978
913
|
};
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
*
|
|
982
|
-
* @throws Will throw if there are remaining expectations that were set
|
|
983
|
-
* using `when` and that weren't met.
|
|
984
|
-
*
|
|
985
|
-
* @throws Will throw if any unexpected calls happened. Normally those
|
|
986
|
-
* calls throw on their own, but the error might be caught by the code
|
|
987
|
-
* being tested.
|
|
988
|
-
*
|
|
989
|
-
* @example
|
|
990
|
-
* const fn = mock<() => number>();
|
|
991
|
-
*
|
|
992
|
-
* when(() => fn()).thenReturn(23);
|
|
993
|
-
*
|
|
994
|
-
* verify(fn); // throws
|
|
995
|
-
*/
|
|
996
|
-
const verify = mock => {
|
|
997
|
-
const {
|
|
998
|
-
repository
|
|
999
|
-
} = getMockState(mock);
|
|
914
|
+
var verify = (mock2) => {
|
|
915
|
+
const { repository } = getMockState(mock2);
|
|
1000
916
|
verifyRepo(repository);
|
|
1001
917
|
};
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
* @see verify
|
|
1006
|
-
*/
|
|
1007
|
-
const verifyAll = () => {
|
|
1008
|
-
getAllMocks().forEach(([mock]) => {
|
|
1009
|
-
verify(mock);
|
|
918
|
+
var verifyAll = () => {
|
|
919
|
+
getAllMocks().forEach(([mock2]) => {
|
|
920
|
+
verify(mock2);
|
|
1010
921
|
});
|
|
1011
922
|
};
|
|
1012
923
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
924
|
+
// src/matchers/it.ts
|
|
925
|
+
var it_exports = {};
|
|
926
|
+
__export(it_exports, {
|
|
927
|
+
containsObject: () => containsObject,
|
|
928
|
+
deepEquals: () => deepEquals,
|
|
929
|
+
is: () => is,
|
|
930
|
+
isAny: () => isAny,
|
|
931
|
+
isArray: () => isArray,
|
|
932
|
+
isNumber: () => isNumber,
|
|
933
|
+
isPlainObject: () => isPlainObject,
|
|
934
|
+
isString: () => isString,
|
|
935
|
+
matches: () => matches,
|
|
936
|
+
willCapture: () => willCapture
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
// src/matchers/is.ts
|
|
940
|
+
var is = (expected) => matches((actual) => Object.is(actual, expected), {
|
|
1021
941
|
toString: () => `${printValue(expected)}`,
|
|
1022
|
-
getDiff: actual => ({
|
|
1023
|
-
actual,
|
|
1024
|
-
expected
|
|
1025
|
-
})
|
|
942
|
+
getDiff: (actual) => ({ actual, expected })
|
|
1026
943
|
});
|
|
1027
944
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
* @example
|
|
1032
|
-
* const fn = mock<(x: number, y: string) => number>();
|
|
1033
|
-
* when(() => fn(It.isAny(), It.isAny())).thenReturn(1);
|
|
1034
|
-
*
|
|
1035
|
-
* fn(23, 'foobar') === 1
|
|
1036
|
-
*/
|
|
1037
|
-
const isAny = () => matches(() => true, {
|
|
1038
|
-
toString: () => 'Matcher<any>'
|
|
945
|
+
// src/matchers/is-any.ts
|
|
946
|
+
var isAny = () => matches(() => true, {
|
|
947
|
+
toString: () => "Matcher<any>"
|
|
1039
948
|
});
|
|
1040
949
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
* @param containing If given, the matched array has to contain ALL of these
|
|
1047
|
-
* elements in ANY order.
|
|
1048
|
-
*
|
|
1049
|
-
* @example
|
|
1050
|
-
* const fn = mock<(arr: number[]) => number>();
|
|
1051
|
-
* when(() => fn(It.isArray())).thenReturn(1);
|
|
1052
|
-
* when(() => fn(It.isArray([2, 3]))).thenReturn(2);
|
|
1053
|
-
*
|
|
1054
|
-
* fn({ length: 1, 0: 42 }) // throws
|
|
1055
|
-
* fn([]) === 1
|
|
1056
|
-
* fn([3, 2, 1]) === 2
|
|
1057
|
-
*
|
|
1058
|
-
* @example
|
|
1059
|
-
* It.isArray([It.isString({ containing: 'foobar' })])
|
|
1060
|
-
*/
|
|
1061
|
-
const isArray = containing => matches(actual => {
|
|
1062
|
-
if (!Array.isArray(actual)) {
|
|
1063
|
-
return false;
|
|
1064
|
-
}
|
|
1065
|
-
if (!containing) {
|
|
1066
|
-
return true;
|
|
1067
|
-
}
|
|
1068
|
-
return containing.every(x => actual.find(y => {
|
|
1069
|
-
if (isMatcher(x)) {
|
|
1070
|
-
return x.matches(y);
|
|
950
|
+
// src/matchers/is-array.ts
|
|
951
|
+
var isArray = (containing) => matches(
|
|
952
|
+
(actual) => {
|
|
953
|
+
if (!Array.isArray(actual)) {
|
|
954
|
+
return false;
|
|
1071
955
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
956
|
+
if (!containing) {
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
return containing.every(
|
|
960
|
+
(x) => actual.find((y) => {
|
|
961
|
+
if (isMatcher(x)) {
|
|
962
|
+
return x.matches(y);
|
|
963
|
+
}
|
|
964
|
+
return deepEquals(x).matches(y);
|
|
965
|
+
}) !== void 0
|
|
966
|
+
);
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
toString: () => containing ? `array([${containing.map((v) => printValue(v)).join(", ")}])` : "array",
|
|
970
|
+
getDiff: (actual) => {
|
|
971
|
+
if (containing) {
|
|
972
|
+
return {
|
|
973
|
+
actual,
|
|
974
|
+
expected: `Matcher<array>([${containing.map((value) => {
|
|
975
|
+
if (isMatcher(value)) {
|
|
976
|
+
return value.toString();
|
|
977
|
+
}
|
|
978
|
+
return value;
|
|
979
|
+
}).join(", ")}])`
|
|
980
|
+
};
|
|
981
|
+
}
|
|
1078
982
|
return {
|
|
1079
|
-
actual
|
|
1080
|
-
expected:
|
|
1081
|
-
if (isMatcher(value)) {
|
|
1082
|
-
return value.toString();
|
|
1083
|
-
}
|
|
1084
|
-
return value;
|
|
1085
|
-
}).join(', ')}])`
|
|
983
|
+
actual: `${printValue(actual)} (${typeof actual})`,
|
|
984
|
+
expected: "Matcher<array>"
|
|
1086
985
|
};
|
|
1087
986
|
}
|
|
1088
|
-
return {
|
|
1089
|
-
actual: `${printValue(actual)} (${typeof actual})`,
|
|
1090
|
-
expected: 'Matcher<array>'
|
|
1091
|
-
};
|
|
1092
987
|
}
|
|
1093
|
-
|
|
988
|
+
);
|
|
1094
989
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
* const fn = mock<(x: number) => number>();
|
|
1100
|
-
* when(() => fn(It.isNumber())).returns(42);
|
|
1101
|
-
*
|
|
1102
|
-
* fn(20.5) === 42
|
|
1103
|
-
* fn(NaN) // throws
|
|
1104
|
-
*/
|
|
1105
|
-
const isNumber = () => matches(actual => typeof actual === 'number' && !Number.isNaN(actual), {
|
|
1106
|
-
toString: () => 'Matcher<number>',
|
|
1107
|
-
getDiff: actual => ({
|
|
990
|
+
// src/matchers/is-number.ts
|
|
991
|
+
var isNumber = () => matches((actual) => typeof actual === "number" && !Number.isNaN(actual), {
|
|
992
|
+
toString: () => "Matcher<number>",
|
|
993
|
+
getDiff: (actual) => ({
|
|
1108
994
|
actual: `${printValue(actual)} (${typeof actual})`,
|
|
1109
|
-
expected:
|
|
995
|
+
expected: "Matcher<number>"
|
|
1110
996
|
})
|
|
1111
997
|
});
|
|
1112
998
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
* const fn = mock<({ foo: string }) => number>();
|
|
1121
|
-
* when(() => fn(It.isPlainObject())).thenReturn(42);
|
|
1122
|
-
*
|
|
1123
|
-
* fn({ foo: 'bar' }) // returns 42
|
|
1124
|
-
*/
|
|
1125
|
-
const isPlainObject = () => matches(actual => lodash.isPlainObject(actual), {
|
|
1126
|
-
toString: () => 'Matcher<object>',
|
|
1127
|
-
getDiff: actual => {
|
|
1128
|
-
const type = lodash.isObjectLike(actual) ? 'object-like' : typeof actual;
|
|
999
|
+
// src/matchers/is-plain-object.ts
|
|
1000
|
+
import isObjectLike2 from "lodash/isObjectLike.js";
|
|
1001
|
+
import isPlainObjectLodash from "lodash/isPlainObject.js";
|
|
1002
|
+
var isPlainObject = () => matches((actual) => isPlainObjectLodash(actual), {
|
|
1003
|
+
toString: () => "Matcher<object>",
|
|
1004
|
+
getDiff: (actual) => {
|
|
1005
|
+
const type = isObjectLike2(actual) ? "object-like" : typeof actual;
|
|
1129
1006
|
return {
|
|
1130
1007
|
actual: `${printValue(actual)} (${type})`,
|
|
1131
|
-
expected:
|
|
1008
|
+
expected: "Matcher<object>"
|
|
1132
1009
|
};
|
|
1133
1010
|
}
|
|
1134
1011
|
});
|
|
1135
1012
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1013
|
+
// src/matchers/contains-object.ts
|
|
1014
|
+
import isPlainObject2 from "lodash/isPlainObject.js";
|
|
1015
|
+
var looksLikeObject = (value) => isPlainObject2(value);
|
|
1016
|
+
var getExpectedObjectDiff = (actual, expected) => Object.fromEntries(
|
|
1017
|
+
getKeys(expected).map((key) => {
|
|
1018
|
+
const expectedValue = getKey2(expected, key);
|
|
1019
|
+
const actualValue = getKey2(actual, key);
|
|
1020
|
+
if (isMatcher(expectedValue)) {
|
|
1021
|
+
return [key, expectedValue.getDiff(actualValue).expected];
|
|
1022
|
+
}
|
|
1023
|
+
if (looksLikeObject(expectedValue)) {
|
|
1024
|
+
return [key, getExpectedObjectDiff(actualValue, expectedValue)];
|
|
1025
|
+
}
|
|
1026
|
+
return [key, expectedValue];
|
|
1027
|
+
})
|
|
1028
|
+
);
|
|
1029
|
+
var getActualObjectDiff = (actual, expected) => {
|
|
1149
1030
|
const actualKeys = getKeys(actual);
|
|
1150
1031
|
const expectedKeys = new Set(getKeys(expected));
|
|
1151
|
-
const commonKeys = actualKeys.filter(key => expectedKeys.has(key));
|
|
1032
|
+
const commonKeys = actualKeys.filter((key) => expectedKeys.has(key));
|
|
1152
1033
|
if (!commonKeys.length) {
|
|
1153
|
-
// When we don't have any common keys we return the whole object
|
|
1154
|
-
// so the user can inspect what's in there.
|
|
1155
1034
|
return actual;
|
|
1156
1035
|
}
|
|
1157
|
-
return Object.fromEntries(
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1036
|
+
return Object.fromEntries(
|
|
1037
|
+
commonKeys.map((key) => {
|
|
1038
|
+
const expectedValue = getKey2(expected, key);
|
|
1039
|
+
const actualValue = getKey2(actual, key);
|
|
1040
|
+
if (isMatcher(expectedValue)) {
|
|
1041
|
+
return [key, expectedValue.getDiff(actualValue).actual];
|
|
1042
|
+
}
|
|
1043
|
+
if (looksLikeObject(expectedValue)) {
|
|
1044
|
+
return [key, getActualObjectDiff(actualValue, expectedValue)];
|
|
1045
|
+
}
|
|
1046
|
+
return [key, actualValue];
|
|
1047
|
+
})
|
|
1048
|
+
);
|
|
1168
1049
|
};
|
|
1169
|
-
|
|
1170
|
-
if (typeof value ===
|
|
1050
|
+
var getKeys = (value) => {
|
|
1051
|
+
if (typeof value === "object" && value !== null) {
|
|
1171
1052
|
return Reflect.ownKeys(value);
|
|
1172
1053
|
}
|
|
1173
1054
|
return [];
|
|
1174
1055
|
};
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1056
|
+
var getKey2 = (value, key) => (
|
|
1057
|
+
// @ts-expect-error because we're fine with a runtime undefined value
|
|
1058
|
+
value == null ? void 0 : value[key]
|
|
1059
|
+
);
|
|
1060
|
+
var isMatch = (actual, expected) => {
|
|
1178
1061
|
const actualKeys = getKeys(actual);
|
|
1179
1062
|
const expectedKeys = getKeys(expected);
|
|
1180
1063
|
if (!isArray(expectedKeys).matches(actualKeys)) {
|
|
1181
1064
|
return false;
|
|
1182
1065
|
}
|
|
1183
|
-
return expectedKeys.every(key => {
|
|
1184
|
-
const expectedValue =
|
|
1185
|
-
const actualValue =
|
|
1066
|
+
return expectedKeys.every((key) => {
|
|
1067
|
+
const expectedValue = getKey2(expected, key);
|
|
1068
|
+
const actualValue = getKey2(actual, key);
|
|
1186
1069
|
if (isMatcher(expectedValue)) {
|
|
1187
1070
|
return expectedValue.matches(actualValue);
|
|
1188
1071
|
}
|
|
@@ -1192,114 +1075,61 @@ const isMatch = (actual, expected) => {
|
|
|
1192
1075
|
return deepEquals(expectedValue).matches(actualValue);
|
|
1193
1076
|
});
|
|
1194
1077
|
};
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
}
|
|
1199
|
-
return undefined;
|
|
1200
|
-
});
|
|
1201
|
-
/**
|
|
1202
|
-
* Check if an object recursively contains the expected properties,
|
|
1203
|
-
* i.e. the expected object is a subset of the received object.
|
|
1204
|
-
*
|
|
1205
|
-
* @param partial A subset of the expected object that will be recursively matched.
|
|
1206
|
-
* Supports nested matchers.
|
|
1207
|
-
* Concrete values will be compared with {@link deepEquals}.
|
|
1208
|
-
*
|
|
1209
|
-
* @see {@link isPlainObject} if you want to match any plain object.
|
|
1210
|
-
*
|
|
1211
|
-
* @example
|
|
1212
|
-
* const fn = mock<(pos: { x: number, y: number }) => number>();
|
|
1213
|
-
* when(() => fn(It.containsObject({ x: 23 }))).returns(42);
|
|
1214
|
-
*
|
|
1215
|
-
* fn({ x: 23, y: 200 }) // returns 42
|
|
1216
|
-
*
|
|
1217
|
-
* @example
|
|
1218
|
-
* It.containsObject({ foo: It.isString() })
|
|
1219
|
-
*/
|
|
1220
|
-
// T is not constrained to ObjectType because of
|
|
1221
|
-
// https://github.com/microsoft/TypeScript/issues/57810,
|
|
1222
|
-
// but K is to avoid inferring non-object partials
|
|
1223
|
-
const containsObject = partial => matches(actual => isMatch(actual, partial), {
|
|
1224
|
-
toString: () => `Matcher<object>(${printValue(deepPrintObject(partial))})`,
|
|
1225
|
-
getDiff: actual => ({
|
|
1078
|
+
var containsObject = (partial) => matches((actual) => isMatch(actual, partial), {
|
|
1079
|
+
toString: () => `Matcher<object>(${printValue(deepPrint(partial))})`,
|
|
1080
|
+
getDiff: (actual) => ({
|
|
1226
1081
|
actual: getActualObjectDiff(actual, partial),
|
|
1227
1082
|
expected: getExpectedObjectDiff(actual, partial)
|
|
1228
1083
|
})
|
|
1229
1084
|
});
|
|
1230
1085
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
*
|
|
1237
|
-
* @example
|
|
1238
|
-
* const fn = mock<(x: string, y: string) => number>();
|
|
1239
|
-
* when(() => fn(It.isString(), It.isString('bar'))).returns(42);
|
|
1240
|
-
*
|
|
1241
|
-
* fn('foo', 'baz') // throws
|
|
1242
|
-
* fn('foo', 'bar') === 42
|
|
1243
|
-
*/
|
|
1244
|
-
const isString = matching => matches(actual => {
|
|
1245
|
-
if (typeof actual !== 'string') {
|
|
1246
|
-
return false;
|
|
1247
|
-
}
|
|
1248
|
-
if (!matching) {
|
|
1249
|
-
return true;
|
|
1250
|
-
}
|
|
1251
|
-
if (typeof matching === 'string') {
|
|
1252
|
-
return actual.indexOf(matching) !== -1;
|
|
1253
|
-
}
|
|
1254
|
-
return matching.test(actual);
|
|
1255
|
-
}, {
|
|
1256
|
-
toString: () => {
|
|
1257
|
-
if (matching) {
|
|
1258
|
-
return `Matcher<string>(${matching})`;
|
|
1086
|
+
// src/matchers/is-string.ts
|
|
1087
|
+
var isString = (matching) => matches(
|
|
1088
|
+
(actual) => {
|
|
1089
|
+
if (typeof actual !== "string") {
|
|
1090
|
+
return false;
|
|
1259
1091
|
}
|
|
1260
|
-
|
|
1092
|
+
if (!matching) {
|
|
1093
|
+
return true;
|
|
1094
|
+
}
|
|
1095
|
+
if (typeof matching === "string") {
|
|
1096
|
+
return actual.indexOf(matching) !== -1;
|
|
1097
|
+
}
|
|
1098
|
+
return matching.test(actual);
|
|
1261
1099
|
},
|
|
1262
|
-
|
|
1263
|
-
|
|
1100
|
+
{
|
|
1101
|
+
toString: () => {
|
|
1102
|
+
if (matching) {
|
|
1103
|
+
return `Matcher<string>(${matching})`;
|
|
1104
|
+
}
|
|
1105
|
+
return "Matcher<string>";
|
|
1106
|
+
},
|
|
1107
|
+
getDiff: (actual) => {
|
|
1108
|
+
if (matching) {
|
|
1109
|
+
return {
|
|
1110
|
+
expected: `Matcher<string>(${matching})`,
|
|
1111
|
+
actual
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1264
1114
|
return {
|
|
1265
|
-
expected:
|
|
1266
|
-
actual
|
|
1115
|
+
expected: "Matcher<string>",
|
|
1116
|
+
actual: `${actual} (${typeof actual})`
|
|
1267
1117
|
};
|
|
1268
1118
|
}
|
|
1269
|
-
return {
|
|
1270
|
-
expected: 'Matcher<string>',
|
|
1271
|
-
actual: `${actual} (${typeof actual})`
|
|
1272
|
-
};
|
|
1273
1119
|
}
|
|
1274
|
-
|
|
1120
|
+
);
|
|
1275
1121
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
*
|
|
1279
|
-
* This should not be needed for most cases, but can be useful if you need
|
|
1280
|
-
* access to a complex argument outside the expectation e.g. to test a
|
|
1281
|
-
* callback.
|
|
1282
|
-
*
|
|
1283
|
-
* @param name If given, this name will be printed in error messages.
|
|
1284
|
-
*
|
|
1285
|
-
* @example
|
|
1286
|
-
* const fn = mock<(cb: (value: number) => number) => void>();
|
|
1287
|
-
* const matcher = It.willCapture();
|
|
1288
|
-
* when(() => fn(matcher)).thenReturn();
|
|
1289
|
-
*
|
|
1290
|
-
* fn(x => x + 1);
|
|
1291
|
-
* matcher.value?.(3) === 4
|
|
1292
|
-
*/
|
|
1293
|
-
const willCapture = name => {
|
|
1122
|
+
// src/matchers/will-capture.ts
|
|
1123
|
+
var willCapture = (name) => {
|
|
1294
1124
|
let capturedValue;
|
|
1295
1125
|
const matcher = {
|
|
1296
1126
|
[MATCHER_SYMBOL]: true,
|
|
1297
|
-
matches: actual => {
|
|
1127
|
+
matches: (actual) => {
|
|
1298
1128
|
capturedValue = actual;
|
|
1299
1129
|
return true;
|
|
1300
1130
|
},
|
|
1301
|
-
toString: () => name ? `Capture(${name})` :
|
|
1302
|
-
getDiff: actual => ({
|
|
1131
|
+
toString: () => name ? `Capture(${name})` : "Capture",
|
|
1132
|
+
getDiff: (actual) => ({
|
|
1303
1133
|
actual,
|
|
1304
1134
|
expected: actual
|
|
1305
1135
|
}),
|
|
@@ -1309,29 +1139,15 @@ const willCapture = name => {
|
|
|
1309
1139
|
};
|
|
1310
1140
|
return matcher;
|
|
1311
1141
|
};
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
isPlainObject: isPlainObject,
|
|
1323
|
-
containsObject: containsObject,
|
|
1324
|
-
isString: isString,
|
|
1325
|
-
matches: matches,
|
|
1326
|
-
willCapture: willCapture
|
|
1142
|
+
export {
|
|
1143
|
+
it_exports as It,
|
|
1144
|
+
UnexpectedProperty,
|
|
1145
|
+
mock,
|
|
1146
|
+
reset,
|
|
1147
|
+
resetAll,
|
|
1148
|
+
setDefaults,
|
|
1149
|
+
verify,
|
|
1150
|
+
verifyAll,
|
|
1151
|
+
when
|
|
1327
1152
|
};
|
|
1328
|
-
|
|
1329
|
-
exports.It = it;
|
|
1330
|
-
exports.mock = mock;
|
|
1331
|
-
exports.reset = reset;
|
|
1332
|
-
exports.resetAll = resetAll;
|
|
1333
|
-
exports.setDefaults = setDefaults;
|
|
1334
|
-
exports.verify = verify;
|
|
1335
|
-
exports.verifyAll = verifyAll;
|
|
1336
|
-
exports.when = when;
|
|
1337
|
-
//# sourceMappingURL=index.js.map
|
|
1153
|
+
/* c8 ignore next 3 this is not expected in practice -- @preserve */
|