strong-mock 9.0.1 → 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 +628 -828
- 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 = (property, args) => {
|
|
92
91
|
const prettyProperty = printProperty(property);
|
|
93
92
|
if (args) {
|
|
94
93
|
const prettyArgs = printArgs(args);
|
|
95
|
-
return `mock${
|
|
94
|
+
return `mock${RECEIVED_COLOR(`${prettyProperty}(${prettyArgs})`)}`;
|
|
96
95
|
}
|
|
97
|
-
return `mock${
|
|
96
|
+
return `mock${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 = (property, args) => {
|
|
119
116
|
const prettyProperty = printProperty(property);
|
|
120
117
|
if (args) {
|
|
121
|
-
return `when(() => mock${
|
|
118
|
+
return `when(() => mock${EXPECTED_COLOR(
|
|
119
|
+
`${prettyProperty}(${printArgs(args)})`
|
|
120
|
+
)})`;
|
|
122
121
|
}
|
|
123
|
-
return `when(() => mock${
|
|
122
|
+
return `when(() => mock${EXPECTED_COLOR(`${printProperty(property)}`)})`;
|
|
124
123
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- ${expectations.map(e => e.toString()).join(
|
|
124
|
+
var printExpectation = (property, args, returnValue, min, max) => `${printWhen(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
|
-
|
|
128
|
+
// src/errors/unexpected-access.ts
|
|
129
|
+
var UnexpectedAccess = class extends Error {
|
|
130
130
|
constructor(property, expectations) {
|
|
131
|
-
super(
|
|
131
|
+
super(
|
|
132
|
+
DIM_COLOR(`Didn't expect ${printCall(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
|
-
|
|
206
|
+
// src/errors/unexpected-call.ts
|
|
207
|
+
var UnexpectedCall = class extends Error {
|
|
214
208
|
constructor(property, args, expectations) {
|
|
209
|
+
var _a;
|
|
215
210
|
const header = `Didn't expect ${printCall(property, args)} to be called.`;
|
|
216
|
-
const propertyExpectations = expectations.filter(
|
|
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,29 @@ const unboxReturnValue = ({
|
|
|
310
271
|
return value;
|
|
311
272
|
};
|
|
312
273
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
this.
|
|
320
|
-
this.
|
|
321
|
-
this.expectedCallStats = new Map();
|
|
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(unexpectedProperty = 0 /* THROW */) {
|
|
277
|
+
this.unexpectedProperty = unexpectedProperty;
|
|
278
|
+
this.expectations = /* @__PURE__ */ new Map();
|
|
279
|
+
this.expectedCallStats = /* @__PURE__ */ new Map();
|
|
280
|
+
this.unexpectedCallStats = /* @__PURE__ */ new Map();
|
|
281
|
+
this.apply = (args) => this.get(ApplyProp)(...args);
|
|
324
282
|
this.handlePropertyWithMatchingExpectations = (property, expectations) => {
|
|
325
|
-
// Avoid recording call stats for function calls, since the property is an
|
|
326
|
-
// internal detail.
|
|
327
283
|
if (property !== ApplyProp) {
|
|
328
|
-
|
|
329
|
-
// function that will not match the given args.
|
|
330
|
-
this.recordExpected(property, undefined);
|
|
284
|
+
this.recordExpected(property, void 0);
|
|
331
285
|
}
|
|
332
|
-
const propertyExpectation = expectations.find(
|
|
286
|
+
const propertyExpectation = expectations.find(
|
|
287
|
+
(e) => e.expectation.matches(void 0)
|
|
288
|
+
);
|
|
333
289
|
if (propertyExpectation) {
|
|
334
290
|
this.countAndConsume(propertyExpectation);
|
|
335
291
|
return unboxReturnValue(propertyExpectation.expectation.returnValue);
|
|
336
292
|
}
|
|
337
293
|
return (...args) => {
|
|
338
|
-
const callExpectation = expectations.find(
|
|
294
|
+
const callExpectation = expectations.find(
|
|
295
|
+
(e) => e.expectation.matches(args)
|
|
296
|
+
);
|
|
339
297
|
if (callExpectation) {
|
|
340
298
|
this.recordExpected(property, args);
|
|
341
299
|
this.countAndConsume(callExpectation);
|
|
@@ -344,23 +302,23 @@ class FlexibleRepository {
|
|
|
344
302
|
return this.getValueForUnexpectedCall(property, args);
|
|
345
303
|
};
|
|
346
304
|
};
|
|
347
|
-
this.handlePropertyWithNoExpectations = property => {
|
|
305
|
+
this.handlePropertyWithNoExpectations = (property) => {
|
|
348
306
|
switch (property) {
|
|
349
|
-
case
|
|
350
|
-
return () =>
|
|
351
|
-
case
|
|
307
|
+
case "toString":
|
|
308
|
+
return () => "mock";
|
|
309
|
+
case "@@toStringTag":
|
|
352
310
|
case Symbol.toStringTag:
|
|
353
|
-
case
|
|
354
|
-
return
|
|
311
|
+
case "name":
|
|
312
|
+
return "mock";
|
|
355
313
|
// Promise.resolve() tries to see if it's a "thenable".
|
|
356
314
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
|
|
357
|
-
case
|
|
358
|
-
return
|
|
315
|
+
case "then":
|
|
316
|
+
return void 0;
|
|
359
317
|
// pretty-format
|
|
360
|
-
case
|
|
361
|
-
case
|
|
362
|
-
case
|
|
363
|
-
case
|
|
318
|
+
case "$$typeof":
|
|
319
|
+
case "constructor":
|
|
320
|
+
case "@@__IMMUTABLE_ITERABLE__@@":
|
|
321
|
+
case "@@__IMMUTABLE_RECORD__@@":
|
|
364
322
|
return null;
|
|
365
323
|
case MATCHER_SYMBOL:
|
|
366
324
|
return false;
|
|
@@ -370,17 +328,17 @@ class FlexibleRepository {
|
|
|
370
328
|
return this.getValueForUnexpectedAccess(property);
|
|
371
329
|
}
|
|
372
330
|
};
|
|
373
|
-
this.unexpectedProperty = unexpectedProperty;
|
|
374
331
|
}
|
|
375
332
|
add(expectation) {
|
|
376
|
-
const {
|
|
377
|
-
property
|
|
378
|
-
} = expectation;
|
|
333
|
+
const { property } = expectation;
|
|
379
334
|
const expectations = this.expectations.get(property) || [];
|
|
380
|
-
this.expectations.set(property, [
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
335
|
+
this.expectations.set(property, [
|
|
336
|
+
...expectations,
|
|
337
|
+
{
|
|
338
|
+
expectation,
|
|
339
|
+
matchCount: 0
|
|
340
|
+
}
|
|
341
|
+
]);
|
|
384
342
|
}
|
|
385
343
|
clear() {
|
|
386
344
|
this.expectations.clear();
|
|
@@ -392,7 +350,10 @@ class FlexibleRepository {
|
|
|
392
350
|
get(property) {
|
|
393
351
|
const expectations = this.expectations.get(property);
|
|
394
352
|
if (expectations && expectations.length) {
|
|
395
|
-
return this.handlePropertyWithMatchingExpectations(
|
|
353
|
+
return this.handlePropertyWithMatchingExpectations(
|
|
354
|
+
property,
|
|
355
|
+
expectations
|
|
356
|
+
);
|
|
396
357
|
}
|
|
397
358
|
return this.handlePropertyWithNoExpectations(property);
|
|
398
359
|
}
|
|
@@ -406,33 +367,32 @@ class FlexibleRepository {
|
|
|
406
367
|
};
|
|
407
368
|
}
|
|
408
369
|
getUnmet() {
|
|
409
|
-
return [].concat(
|
|
370
|
+
return [].concat(
|
|
371
|
+
...Array.from(this.expectations.values()).map(
|
|
372
|
+
(expectations) => expectations.filter((e) => e.expectation.min > e.matchCount).map((e) => e.expectation)
|
|
373
|
+
)
|
|
374
|
+
);
|
|
410
375
|
}
|
|
411
376
|
recordExpected(property, args) {
|
|
412
377
|
const calls = this.expectedCallStats.get(property) || [];
|
|
413
|
-
this.expectedCallStats.set(property, [...calls, {
|
|
414
|
-
arguments: args
|
|
415
|
-
}]);
|
|
378
|
+
this.expectedCallStats.set(property, [...calls, { arguments: args }]);
|
|
416
379
|
}
|
|
417
380
|
recordUnexpected(property, args) {
|
|
418
381
|
const calls = this.unexpectedCallStats.get(property) || [];
|
|
419
|
-
this.unexpectedCallStats.set(property, [...calls, {
|
|
420
|
-
arguments: args
|
|
421
|
-
}]);
|
|
382
|
+
this.unexpectedCallStats.set(property, [...calls, { arguments: args }]);
|
|
422
383
|
}
|
|
423
384
|
countAndConsume(expectation) {
|
|
424
|
-
// eslint-disable-next-line no-param-reassign
|
|
425
385
|
expectation.matchCount++;
|
|
426
386
|
this.consumeExpectation(expectation);
|
|
427
387
|
}
|
|
428
388
|
consumeExpectation(expectation) {
|
|
429
|
-
const {
|
|
430
|
-
property,
|
|
431
|
-
max
|
|
432
|
-
} = expectation.expectation;
|
|
389
|
+
const { property, max } = expectation.expectation;
|
|
433
390
|
const expectations = this.expectations.get(property);
|
|
434
391
|
if (expectation.matchCount === max) {
|
|
435
|
-
this.expectations.set(
|
|
392
|
+
this.expectations.set(
|
|
393
|
+
property,
|
|
394
|
+
expectations.filter((e) => e !== expectation)
|
|
395
|
+
);
|
|
436
396
|
}
|
|
437
397
|
}
|
|
438
398
|
getValueForUnexpectedCall(property, args) {
|
|
@@ -440,8 +400,8 @@ class FlexibleRepository {
|
|
|
440
400
|
throw new UnexpectedCall(property, args, this.getUnmet());
|
|
441
401
|
}
|
|
442
402
|
getValueForUnexpectedAccess(property) {
|
|
443
|
-
if (this.unexpectedProperty ===
|
|
444
|
-
this.recordUnexpected(property,
|
|
403
|
+
if (this.unexpectedProperty === 0 /* THROW */) {
|
|
404
|
+
this.recordUnexpected(property, void 0);
|
|
445
405
|
throw new UnexpectedAccess(property, this.getUnmet());
|
|
446
406
|
}
|
|
447
407
|
return (...args) => {
|
|
@@ -449,32 +409,18 @@ class FlexibleRepository {
|
|
|
449
409
|
throw new UnexpectedCall(property, args, this.getUnmet());
|
|
450
410
|
};
|
|
451
411
|
}
|
|
452
|
-
}
|
|
412
|
+
};
|
|
453
413
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
* compiler will check that those parameters are optional.
|
|
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 {
|
|
414
|
+
// src/expectation/strong-expectation.ts
|
|
415
|
+
var StrongExpectation = class {
|
|
466
416
|
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;
|
|
474
417
|
this.property = property;
|
|
475
418
|
this.args = args;
|
|
476
419
|
this.returnValue = returnValue;
|
|
477
420
|
this.exactParams = exactParams;
|
|
421
|
+
this.matched = 0;
|
|
422
|
+
this.min = 1;
|
|
423
|
+
this.max = 1;
|
|
478
424
|
}
|
|
479
425
|
setInvocationCount(min, max = 1) {
|
|
480
426
|
this.min = min;
|
|
@@ -491,7 +437,7 @@ class StrongExpectation {
|
|
|
491
437
|
return this.matched < this.min;
|
|
492
438
|
}
|
|
493
439
|
matchesArgs(received) {
|
|
494
|
-
if (this.args ===
|
|
440
|
+
if (this.args === void 0) {
|
|
495
441
|
return !received;
|
|
496
442
|
}
|
|
497
443
|
if (!received) {
|
|
@@ -505,35 +451,42 @@ class StrongExpectation {
|
|
|
505
451
|
return this.args.every((arg, i) => arg.matches(received[i]));
|
|
506
452
|
}
|
|
507
453
|
toString() {
|
|
508
|
-
return printExpectation(
|
|
454
|
+
return printExpectation(
|
|
455
|
+
this.property,
|
|
456
|
+
this.args,
|
|
457
|
+
this.returnValue,
|
|
458
|
+
this.min,
|
|
459
|
+
this.max
|
|
460
|
+
);
|
|
509
461
|
}
|
|
510
|
-
}
|
|
462
|
+
};
|
|
511
463
|
|
|
512
|
-
|
|
464
|
+
// src/errors/api.ts
|
|
465
|
+
var UnfinishedExpectation = class extends Error {
|
|
513
466
|
constructor(property, args) {
|
|
514
467
|
super(`There is an unfinished pending expectation:
|
|
515
468
|
|
|
516
469
|
${printWhen(property, args)}
|
|
517
470
|
|
|
518
|
-
|
|
519
|
-
is undefined.`);
|
|
471
|
+
You should finish it by setting a return value with e.g. thenReturns(),
|
|
472
|
+
even if that value is undefined.`);
|
|
520
473
|
}
|
|
521
|
-
}
|
|
522
|
-
|
|
474
|
+
};
|
|
475
|
+
var MissingWhen = class extends Error {
|
|
523
476
|
constructor() {
|
|
524
477
|
super(`You tried setting a return value without an expectation.
|
|
525
478
|
|
|
526
479
|
Every call to set a return value must be preceded by an expectation.`);
|
|
527
480
|
}
|
|
528
|
-
}
|
|
529
|
-
|
|
481
|
+
};
|
|
482
|
+
var NotAMock = class extends Error {
|
|
530
483
|
constructor() {
|
|
531
484
|
super(`We couldn't find the mock.
|
|
532
485
|
|
|
533
486
|
Make sure you're passing in an actual mock.`);
|
|
534
487
|
}
|
|
535
|
-
}
|
|
536
|
-
|
|
488
|
+
};
|
|
489
|
+
var NestedWhen = class extends Error {
|
|
537
490
|
constructor(parentProp, childProp) {
|
|
538
491
|
const snippet = `
|
|
539
492
|
const parentMock = mock<T1>();
|
|
@@ -542,21 +495,19 @@ const childMock = mock<T2>();
|
|
|
542
495
|
when(() => childMock${printProperty(childProp)}).thenReturn(...);
|
|
543
496
|
when(() => parentMock${printProperty(parentProp)}).thenReturn(childMock)
|
|
544
497
|
`;
|
|
545
|
-
super(
|
|
498
|
+
super(
|
|
499
|
+
`Setting an expectation on a nested property is not supported.
|
|
546
500
|
|
|
547
501
|
You can return an object directly when the first property is accessed,
|
|
548
502
|
or you can even return a separate mock:
|
|
549
|
-
${snippet}`
|
|
503
|
+
${snippet}`
|
|
504
|
+
);
|
|
550
505
|
}
|
|
551
|
-
}
|
|
506
|
+
};
|
|
552
507
|
|
|
553
|
-
|
|
508
|
+
// src/when/expectation-builder.ts
|
|
509
|
+
var ExpectationBuilderWithFactory = class {
|
|
554
510
|
constructor(createExpectation, concreteMatcher, exactParams) {
|
|
555
|
-
this.createExpectation = void 0;
|
|
556
|
-
this.concreteMatcher = void 0;
|
|
557
|
-
this.exactParams = void 0;
|
|
558
|
-
this.args = void 0;
|
|
559
|
-
this.property = void 0;
|
|
560
511
|
this.createExpectation = createExpectation;
|
|
561
512
|
this.concreteMatcher = concreteMatcher;
|
|
562
513
|
this.exactParams = exactParams;
|
|
@@ -574,212 +525,208 @@ class ExpectationBuilderWithFactory {
|
|
|
574
525
|
if (!this.property) {
|
|
575
526
|
throw new MissingWhen();
|
|
576
527
|
}
|
|
577
|
-
const expectation = this.createExpectation(
|
|
578
|
-
|
|
579
|
-
|
|
528
|
+
const expectation = this.createExpectation(
|
|
529
|
+
this.property,
|
|
530
|
+
this.args,
|
|
531
|
+
returnValue,
|
|
532
|
+
this.concreteMatcher,
|
|
533
|
+
this.exactParams
|
|
534
|
+
);
|
|
535
|
+
this.property = void 0;
|
|
536
|
+
this.args = void 0;
|
|
580
537
|
return expectation;
|
|
581
538
|
}
|
|
582
|
-
}
|
|
539
|
+
};
|
|
583
540
|
|
|
584
|
-
|
|
541
|
+
// src/matchers/deep-equals.ts
|
|
542
|
+
import cloneDeep from "lodash/cloneDeep.js";
|
|
543
|
+
import cloneDeepWith2 from "lodash/cloneDeepWith.js";
|
|
544
|
+
import isEqualWith from "lodash/isEqualWith.js";
|
|
545
|
+
import isMap from "lodash/isMap.js";
|
|
546
|
+
import isObjectLike from "lodash/isObjectLike.js";
|
|
547
|
+
import omitBy from "lodash/omitBy.js";
|
|
548
|
+
var removeUndefined = (object) => {
|
|
585
549
|
if (Array.isArray(object)) {
|
|
586
|
-
return object.map(x => removeUndefined(x));
|
|
550
|
+
return object.map((x) => removeUndefined(x));
|
|
587
551
|
}
|
|
588
|
-
if (!
|
|
552
|
+
if (!isObjectLike(object)) {
|
|
589
553
|
return object;
|
|
590
554
|
}
|
|
591
|
-
return
|
|
555
|
+
return omitBy(object, (value) => value === void 0);
|
|
592
556
|
};
|
|
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, {
|
|
557
|
+
var getKey = (key, object) => {
|
|
558
|
+
if (key === void 0) {
|
|
559
|
+
return object;
|
|
560
|
+
}
|
|
561
|
+
return isMap(object) ? object.get(key) : object[key];
|
|
562
|
+
};
|
|
563
|
+
var deepEquals = (expected, {
|
|
606
564
|
strict = true
|
|
607
|
-
} = {}) => matches(
|
|
608
|
-
|
|
609
|
-
|
|
565
|
+
} = {}) => matches(
|
|
566
|
+
(actual) => isEqualWith(
|
|
567
|
+
strict ? actual : removeUndefined(actual),
|
|
568
|
+
strict ? expected : removeUndefined(expected),
|
|
569
|
+
(actualValue, expectedValue) => {
|
|
570
|
+
if (isMatcher(expectedValue)) {
|
|
571
|
+
return expectedValue.matches(actualValue);
|
|
572
|
+
}
|
|
573
|
+
return void 0;
|
|
574
|
+
}
|
|
575
|
+
),
|
|
576
|
+
{
|
|
577
|
+
toString: () => printValue(deepPrint(expected)),
|
|
578
|
+
getDiff: (actual) => {
|
|
579
|
+
let actualResult = cloneDeep(actual);
|
|
580
|
+
const expectedResult = cloneDeepWith2(expected, (expectedValue, key) => {
|
|
581
|
+
const actualValue = getKey(key, actualResult);
|
|
582
|
+
if (isMatcher(expectedValue)) {
|
|
583
|
+
if (expectedValue.matches(actualValue)) {
|
|
584
|
+
return actualValue;
|
|
585
|
+
}
|
|
586
|
+
const result = expectedValue.getDiff(actualValue);
|
|
587
|
+
if (key !== void 0) {
|
|
588
|
+
if (isMap(actualResult)) {
|
|
589
|
+
actualResult.set(key, result.actual);
|
|
590
|
+
} else {
|
|
591
|
+
actualResult[key] = result.actual;
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
actualResult = result.actual;
|
|
595
|
+
}
|
|
596
|
+
return result.expected;
|
|
597
|
+
}
|
|
598
|
+
return void 0;
|
|
599
|
+
});
|
|
600
|
+
return {
|
|
601
|
+
actual: actualResult,
|
|
602
|
+
expected: expectedResult
|
|
603
|
+
};
|
|
604
|
+
}
|
|
610
605
|
}
|
|
611
|
-
|
|
612
|
-
}, {
|
|
613
|
-
toString: () => printValue(expected),
|
|
614
|
-
getDiff: actual => ({
|
|
615
|
-
actual,
|
|
616
|
-
expected
|
|
617
|
-
})
|
|
618
|
-
});
|
|
606
|
+
);
|
|
619
607
|
|
|
620
|
-
|
|
608
|
+
// src/mock/defaults.ts
|
|
609
|
+
var defaults = {
|
|
621
610
|
concreteMatcher: deepEquals,
|
|
622
|
-
unexpectedProperty:
|
|
611
|
+
unexpectedProperty: 1 /* CALL_THROW */,
|
|
623
612
|
exactParams: false
|
|
624
613
|
};
|
|
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
|
-
};
|
|
614
|
+
var currentDefaults = defaults;
|
|
615
|
+
var setDefaults = (newDefaults) => {
|
|
616
|
+
currentDefaults = __spreadValues(__spreadValues({}, defaults), newDefaults);
|
|
638
617
|
};
|
|
639
618
|
|
|
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;
|
|
619
|
+
// src/mock/map.ts
|
|
620
|
+
var activeMock;
|
|
621
|
+
var setActiveMock = (mock2) => {
|
|
622
|
+
activeMock = mock2;
|
|
658
623
|
};
|
|
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);
|
|
624
|
+
var getActiveMock = () => activeMock;
|
|
625
|
+
var mockMap = /* @__PURE__ */ new Map();
|
|
626
|
+
var getMockState = (mock2) => {
|
|
627
|
+
if (mockMap.has(mock2)) {
|
|
628
|
+
return mockMap.get(mock2);
|
|
670
629
|
}
|
|
671
630
|
throw new NotAMock();
|
|
672
631
|
};
|
|
673
|
-
|
|
674
|
-
mockMap.set(
|
|
632
|
+
var setMockState = (mock2, state) => {
|
|
633
|
+
mockMap.set(mock2, state);
|
|
675
634
|
};
|
|
676
|
-
|
|
635
|
+
var getAllMocks = () => Array.from(mockMap.entries());
|
|
677
636
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
Mode[Mode["CALL"] = 1] = "CALL";
|
|
682
|
-
})(Mode || (Mode = {}));
|
|
683
|
-
let currentMode = Mode.CALL;
|
|
684
|
-
const setMode = mode => {
|
|
637
|
+
// src/mock/mode.ts
|
|
638
|
+
var currentMode = 1 /* CALL */;
|
|
639
|
+
var setMode = (mode) => {
|
|
685
640
|
currentMode = mode;
|
|
686
641
|
};
|
|
687
|
-
|
|
642
|
+
var getMode = () => currentMode;
|
|
688
643
|
|
|
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
|
-
|
|
644
|
+
// src/proxy.ts
|
|
645
|
+
var createProxy = (traps) => (
|
|
646
|
+
// The Proxy target MUST be a function, otherwise we can't use the `apply` trap:
|
|
647
|
+
// https://262.ecma-international.org/6.0/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
|
|
648
|
+
new Proxy(
|
|
649
|
+
/* c8 ignore next */
|
|
650
|
+
() => {
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
get: (target, prop) => {
|
|
654
|
+
if (prop === "bind") {
|
|
655
|
+
return (thisArg, ...args) => (...moreArgs) => traps.apply([...args, ...moreArgs]);
|
|
656
|
+
}
|
|
657
|
+
if (prop === "apply") {
|
|
658
|
+
return (thisArg, args) => traps.apply(args || []);
|
|
659
|
+
}
|
|
660
|
+
if (prop === "call") {
|
|
661
|
+
return (thisArg, ...args) => traps.apply(args);
|
|
662
|
+
}
|
|
663
|
+
return traps.property(prop);
|
|
664
|
+
},
|
|
665
|
+
apply: (target, thisArg, args) => traps.apply(args),
|
|
666
|
+
ownKeys: () => traps.ownKeys(),
|
|
667
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
668
|
+
const keys = traps.ownKeys();
|
|
669
|
+
if (keys.includes(prop)) {
|
|
670
|
+
return {
|
|
671
|
+
configurable: true,
|
|
672
|
+
enumerable: true
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
return void 0;
|
|
676
|
+
}
|
|
715
677
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
});
|
|
678
|
+
)
|
|
679
|
+
);
|
|
719
680
|
|
|
720
|
-
|
|
681
|
+
// src/mock/stub.ts
|
|
682
|
+
var createStub = (repo, builder, getCurrentMode) => {
|
|
721
683
|
const stub = createProxy({
|
|
722
|
-
property: property => {
|
|
723
|
-
if (getCurrentMode() ===
|
|
684
|
+
property: (property) => {
|
|
685
|
+
if (getCurrentMode() === 1 /* CALL */) {
|
|
724
686
|
return repo.get(property);
|
|
725
687
|
}
|
|
726
688
|
setActiveMock(stub);
|
|
727
689
|
builder.setProperty(property);
|
|
728
690
|
return createProxy({
|
|
729
|
-
property: childProp => {
|
|
691
|
+
property: (childProp) => {
|
|
730
692
|
throw new NestedWhen(property, childProp);
|
|
731
693
|
},
|
|
732
|
-
apply: args => {
|
|
694
|
+
apply: (args) => {
|
|
733
695
|
builder.setArgs(args);
|
|
734
696
|
},
|
|
735
697
|
ownKeys: () => {
|
|
736
|
-
throw new Error(
|
|
698
|
+
throw new Error("Spreading during an expectation is not supported.");
|
|
737
699
|
}
|
|
738
700
|
});
|
|
739
701
|
},
|
|
740
|
-
apply: args => {
|
|
741
|
-
if (getCurrentMode() ===
|
|
702
|
+
apply: (args) => {
|
|
703
|
+
if (getCurrentMode() === 1 /* CALL */) {
|
|
742
704
|
return repo.apply(args);
|
|
743
705
|
}
|
|
744
706
|
setActiveMock(stub);
|
|
745
707
|
builder.setProperty(ApplyProp);
|
|
746
708
|
builder.setArgs(args);
|
|
747
|
-
return
|
|
709
|
+
return void 0;
|
|
748
710
|
},
|
|
749
711
|
ownKeys: () => {
|
|
750
|
-
if (getCurrentMode() ===
|
|
712
|
+
if (getCurrentMode() === 1 /* CALL */) {
|
|
751
713
|
return repo.getAllProperties();
|
|
752
714
|
}
|
|
753
|
-
throw new Error(
|
|
715
|
+
throw new Error("Spreading during an expectation is not supported.");
|
|
754
716
|
}
|
|
755
717
|
});
|
|
756
718
|
return stub;
|
|
757
719
|
};
|
|
758
720
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
* @param options.unexpectedProperty Controls what happens when an unexpected
|
|
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 = ({
|
|
721
|
+
// src/mock/mock.ts
|
|
722
|
+
var strongExpectationFactory = (property, args, returnValue, concreteMatcher, exactParams) => new StrongExpectation(
|
|
723
|
+
property,
|
|
724
|
+
// Wrap every non-matcher in the default matcher.
|
|
725
|
+
args == null ? void 0 : args.map((arg) => isMatcher(arg) ? arg : concreteMatcher(arg)),
|
|
726
|
+
returnValue,
|
|
727
|
+
exactParams
|
|
728
|
+
);
|
|
729
|
+
var mock = ({
|
|
783
730
|
unexpectedProperty,
|
|
784
731
|
concreteMatcher,
|
|
785
732
|
exactParams
|
|
@@ -790,7 +737,11 @@ const mock = ({
|
|
|
790
737
|
exactParams: exactParams != null ? exactParams : currentDefaults.exactParams
|
|
791
738
|
};
|
|
792
739
|
const repository = new FlexibleRepository(options.unexpectedProperty);
|
|
793
|
-
const builder = new ExpectationBuilderWithFactory(
|
|
740
|
+
const builder = new ExpectationBuilderWithFactory(
|
|
741
|
+
strongExpectationFactory,
|
|
742
|
+
options.concreteMatcher,
|
|
743
|
+
options.exactParams
|
|
744
|
+
);
|
|
794
745
|
const stub = createStub(repository, builder, getMode);
|
|
795
746
|
setMockState(stub, {
|
|
796
747
|
repository,
|
|
@@ -800,44 +751,45 @@ const mock = ({
|
|
|
800
751
|
return stub;
|
|
801
752
|
};
|
|
802
753
|
|
|
803
|
-
|
|
754
|
+
// src/return/invocation-count.ts
|
|
755
|
+
var createInvocationCount = (expectation) => ({
|
|
804
756
|
between(min, max) {
|
|
805
757
|
expectation.setInvocationCount(min, max);
|
|
806
758
|
},
|
|
807
|
-
/*
|
|
759
|
+
/* c8 ignore next 3 */
|
|
808
760
|
times(exact) {
|
|
809
761
|
expectation.setInvocationCount(exact, exact);
|
|
810
762
|
},
|
|
811
|
-
/*
|
|
763
|
+
/* c8 ignore next 3 */
|
|
812
764
|
anyTimes() {
|
|
813
765
|
expectation.setInvocationCount(0, 0);
|
|
814
766
|
},
|
|
815
|
-
/*
|
|
767
|
+
/* c8 ignore next 3 */
|
|
816
768
|
atLeast(min) {
|
|
817
769
|
expectation.setInvocationCount(min, Infinity);
|
|
818
770
|
},
|
|
819
|
-
/*
|
|
771
|
+
/* c8 ignore next 3 */
|
|
820
772
|
atMost(max) {
|
|
821
773
|
expectation.setInvocationCount(0, max);
|
|
822
774
|
},
|
|
823
|
-
/*
|
|
775
|
+
/* c8 ignore next 3 */
|
|
824
776
|
once() {
|
|
825
777
|
expectation.setInvocationCount(1, 1);
|
|
826
778
|
},
|
|
827
|
-
/*
|
|
779
|
+
/* c8 ignore next 3 */
|
|
828
780
|
twice() {
|
|
829
781
|
expectation.setInvocationCount(2, 2);
|
|
830
782
|
}
|
|
831
|
-
/* eslint-enable no-param-reassign, no-multi-assign */
|
|
832
783
|
});
|
|
833
784
|
|
|
834
|
-
|
|
785
|
+
// src/return/returns.ts
|
|
786
|
+
var finishExpectation = (returnValue, builder, repo) => {
|
|
835
787
|
const finishedExpectation = builder.finish(returnValue);
|
|
836
788
|
repo.add(finishedExpectation);
|
|
837
789
|
return createInvocationCount(finishedExpectation);
|
|
838
790
|
};
|
|
839
|
-
|
|
840
|
-
if (typeof errorOrMessage ===
|
|
791
|
+
var getError = (errorOrMessage) => {
|
|
792
|
+
if (typeof errorOrMessage === "string") {
|
|
841
793
|
return new Error(errorOrMessage);
|
|
842
794
|
}
|
|
843
795
|
if (errorOrMessage instanceof Error) {
|
|
@@ -845,128 +797,95 @@ const getError = errorOrMessage => {
|
|
|
845
797
|
}
|
|
846
798
|
return new Error();
|
|
847
799
|
};
|
|
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
|
-
|
|
800
|
+
var createReturns = (builder, repository) => ({
|
|
801
|
+
thenReturn: (returnValue) => finishExpectation(
|
|
802
|
+
// This will handle both thenReturn(23) and thenReturn(Promise.resolve(3)).
|
|
803
|
+
{ value: returnValue, isError: false, isPromise: false },
|
|
804
|
+
builder,
|
|
805
|
+
repository
|
|
806
|
+
),
|
|
807
|
+
thenThrow: (errorOrMessage) => finishExpectation(
|
|
808
|
+
{ value: getError(errorOrMessage), isError: true, isPromise: false },
|
|
809
|
+
builder,
|
|
810
|
+
repository
|
|
811
|
+
),
|
|
812
|
+
thenResolve: (promiseValue) => finishExpectation(
|
|
813
|
+
{
|
|
814
|
+
value: promiseValue,
|
|
815
|
+
isError: false,
|
|
816
|
+
isPromise: true
|
|
817
|
+
},
|
|
818
|
+
builder,
|
|
819
|
+
repository
|
|
820
|
+
),
|
|
821
|
+
thenReject: (errorOrMessage) => finishExpectation(
|
|
822
|
+
{
|
|
823
|
+
value: getError(errorOrMessage),
|
|
824
|
+
isError: true,
|
|
825
|
+
isPromise: true
|
|
826
|
+
},
|
|
827
|
+
builder,
|
|
828
|
+
repository
|
|
829
|
+
)
|
|
871
830
|
});
|
|
872
831
|
|
|
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);
|
|
832
|
+
// src/when/when.ts
|
|
833
|
+
var when = (expectation) => {
|
|
834
|
+
setMode(0 /* EXPECT */);
|
|
900
835
|
expectation();
|
|
901
|
-
setMode(
|
|
902
|
-
const {
|
|
903
|
-
builder,
|
|
904
|
-
repository
|
|
905
|
-
} = getMockState(getActiveMock());
|
|
836
|
+
setMode(1 /* CALL */);
|
|
837
|
+
const { builder, repository } = getMockState(getActiveMock());
|
|
906
838
|
return createReturns(builder, repository);
|
|
907
839
|
};
|
|
908
840
|
|
|
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();
|
|
841
|
+
// src/verify/reset.ts
|
|
842
|
+
var reset = (mock2) => {
|
|
843
|
+
getMockState(mock2).repository.clear();
|
|
923
844
|
};
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
* @see reset
|
|
928
|
-
*/
|
|
929
|
-
const resetAll = () => {
|
|
930
|
-
getAllMocks().forEach(([mock]) => {
|
|
931
|
-
reset(mock);
|
|
845
|
+
var resetAll = () => {
|
|
846
|
+
getAllMocks().forEach(([mock2]) => {
|
|
847
|
+
reset(mock2);
|
|
932
848
|
});
|
|
933
849
|
};
|
|
934
850
|
|
|
935
|
-
|
|
851
|
+
// src/errors/verify.ts
|
|
852
|
+
import { DIM_COLOR as DIM_COLOR3 } from "jest-matcher-utils";
|
|
853
|
+
var UnmetExpectations = class extends Error {
|
|
936
854
|
constructor(expectations) {
|
|
937
|
-
super(
|
|
855
|
+
super(
|
|
856
|
+
DIM_COLOR3(`There are unmet expectations:
|
|
938
857
|
|
|
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)];
|
|
858
|
+
- ${expectations.map((e) => e.toString()).join("\n - ")}`)
|
|
859
|
+
);
|
|
955
860
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
861
|
+
};
|
|
862
|
+
var mergeCalls = (callMap) => new Map(
|
|
863
|
+
Array.from(callMap.entries()).map(([property, calls]) => {
|
|
864
|
+
const hasMethodCalls = calls.some((call) => call.arguments);
|
|
865
|
+
const hasPropertyAccesses = calls.some((call) => !call.arguments);
|
|
866
|
+
if (hasMethodCalls && hasPropertyAccesses) {
|
|
867
|
+
return [property, calls.filter((call) => call.arguments)];
|
|
868
|
+
}
|
|
869
|
+
return [property, calls];
|
|
870
|
+
})
|
|
871
|
+
);
|
|
872
|
+
var UnexpectedCalls = class extends Error {
|
|
959
873
|
constructor(unexpectedCalls, expectations) {
|
|
960
|
-
const printedCalls = Array.from(mergeCalls(unexpectedCalls).entries()).map(
|
|
961
|
-
|
|
874
|
+
const printedCalls = Array.from(mergeCalls(unexpectedCalls).entries()).map(
|
|
875
|
+
([property, calls]) => calls.map((call) => printCall(property, call.arguments)).join("\n - ")
|
|
876
|
+
).join("\n - ");
|
|
877
|
+
super(
|
|
878
|
+
DIM_COLOR3(`The following calls were unexpected:
|
|
962
879
|
|
|
963
880
|
- ${printedCalls}
|
|
964
881
|
|
|
965
|
-
${printRemainingExpectations(expectations)}`)
|
|
882
|
+
${printRemainingExpectations(expectations)}`)
|
|
883
|
+
);
|
|
966
884
|
}
|
|
967
|
-
}
|
|
885
|
+
};
|
|
968
886
|
|
|
969
|
-
|
|
887
|
+
// src/verify/verify.ts
|
|
888
|
+
var verifyRepo = (repository) => {
|
|
970
889
|
const unmetExpectations = repository.getUnmet();
|
|
971
890
|
if (unmetExpectations.length) {
|
|
972
891
|
throw new UnmetExpectations(unmetExpectations);
|
|
@@ -976,213 +895,161 @@ const verifyRepo = repository => {
|
|
|
976
895
|
throw new UnexpectedCalls(callStats.unexpected, unmetExpectations);
|
|
977
896
|
}
|
|
978
897
|
};
|
|
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);
|
|
898
|
+
var verify = (mock2) => {
|
|
899
|
+
const { repository } = getMockState(mock2);
|
|
1000
900
|
verifyRepo(repository);
|
|
1001
901
|
};
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
* @see verify
|
|
1006
|
-
*/
|
|
1007
|
-
const verifyAll = () => {
|
|
1008
|
-
getAllMocks().forEach(([mock]) => {
|
|
1009
|
-
verify(mock);
|
|
902
|
+
var verifyAll = () => {
|
|
903
|
+
getAllMocks().forEach(([mock2]) => {
|
|
904
|
+
verify(mock2);
|
|
1010
905
|
});
|
|
1011
906
|
};
|
|
1012
907
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
908
|
+
// src/matchers/it.ts
|
|
909
|
+
var it_exports = {};
|
|
910
|
+
__export(it_exports, {
|
|
911
|
+
containsObject: () => containsObject,
|
|
912
|
+
deepEquals: () => deepEquals,
|
|
913
|
+
is: () => is,
|
|
914
|
+
isAny: () => isAny,
|
|
915
|
+
isArray: () => isArray,
|
|
916
|
+
isNumber: () => isNumber,
|
|
917
|
+
isPlainObject: () => isPlainObject,
|
|
918
|
+
isString: () => isString,
|
|
919
|
+
matches: () => matches,
|
|
920
|
+
willCapture: () => willCapture
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// src/matchers/is.ts
|
|
924
|
+
var is = (expected) => matches((actual) => Object.is(actual, expected), {
|
|
1021
925
|
toString: () => `${printValue(expected)}`,
|
|
1022
|
-
getDiff: actual => ({
|
|
1023
|
-
actual,
|
|
1024
|
-
expected
|
|
1025
|
-
})
|
|
926
|
+
getDiff: (actual) => ({ actual, expected })
|
|
1026
927
|
});
|
|
1027
928
|
|
|
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>'
|
|
929
|
+
// src/matchers/is-any.ts
|
|
930
|
+
var isAny = () => matches(() => true, {
|
|
931
|
+
toString: () => "Matcher<any>"
|
|
1039
932
|
});
|
|
1040
933
|
|
|
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);
|
|
934
|
+
// src/matchers/is-array.ts
|
|
935
|
+
var isArray = (containing) => matches(
|
|
936
|
+
(actual) => {
|
|
937
|
+
if (!Array.isArray(actual)) {
|
|
938
|
+
return false;
|
|
1071
939
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
940
|
+
if (!containing) {
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
return containing.every(
|
|
944
|
+
(x) => actual.find((y) => {
|
|
945
|
+
if (isMatcher(x)) {
|
|
946
|
+
return x.matches(y);
|
|
947
|
+
}
|
|
948
|
+
return deepEquals(x).matches(y);
|
|
949
|
+
}) !== void 0
|
|
950
|
+
);
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
toString: () => containing ? `array([${containing.map((v) => printValue(v)).join(", ")}])` : "array",
|
|
954
|
+
getDiff: (actual) => {
|
|
955
|
+
if (containing) {
|
|
956
|
+
return {
|
|
957
|
+
actual,
|
|
958
|
+
expected: `Matcher<array>([${containing.map((value) => {
|
|
959
|
+
if (isMatcher(value)) {
|
|
960
|
+
return value.toString();
|
|
961
|
+
}
|
|
962
|
+
return value;
|
|
963
|
+
}).join(", ")}])`
|
|
964
|
+
};
|
|
965
|
+
}
|
|
1078
966
|
return {
|
|
1079
|
-
actual
|
|
1080
|
-
expected:
|
|
1081
|
-
if (isMatcher(value)) {
|
|
1082
|
-
return value.toString();
|
|
1083
|
-
}
|
|
1084
|
-
return value;
|
|
1085
|
-
}).join(', ')}])`
|
|
967
|
+
actual: `${printValue(actual)} (${typeof actual})`,
|
|
968
|
+
expected: "Matcher<array>"
|
|
1086
969
|
};
|
|
1087
970
|
}
|
|
1088
|
-
return {
|
|
1089
|
-
actual: `${printValue(actual)} (${typeof actual})`,
|
|
1090
|
-
expected: 'Matcher<array>'
|
|
1091
|
-
};
|
|
1092
971
|
}
|
|
1093
|
-
|
|
972
|
+
);
|
|
1094
973
|
|
|
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 => ({
|
|
974
|
+
// src/matchers/is-number.ts
|
|
975
|
+
var isNumber = () => matches((actual) => typeof actual === "number" && !Number.isNaN(actual), {
|
|
976
|
+
toString: () => "Matcher<number>",
|
|
977
|
+
getDiff: (actual) => ({
|
|
1108
978
|
actual: `${printValue(actual)} (${typeof actual})`,
|
|
1109
|
-
expected:
|
|
979
|
+
expected: "Matcher<number>"
|
|
1110
980
|
})
|
|
1111
981
|
});
|
|
1112
982
|
|
|
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;
|
|
983
|
+
// src/matchers/is-plain-object.ts
|
|
984
|
+
import isObjectLike2 from "lodash/isObjectLike.js";
|
|
985
|
+
import isPlainObjectLodash from "lodash/isPlainObject.js";
|
|
986
|
+
var isPlainObject = () => matches((actual) => isPlainObjectLodash(actual), {
|
|
987
|
+
toString: () => "Matcher<object>",
|
|
988
|
+
getDiff: (actual) => {
|
|
989
|
+
const type = isObjectLike2(actual) ? "object-like" : typeof actual;
|
|
1129
990
|
return {
|
|
1130
991
|
actual: `${printValue(actual)} (${type})`,
|
|
1131
|
-
expected:
|
|
992
|
+
expected: "Matcher<object>"
|
|
1132
993
|
};
|
|
1133
994
|
}
|
|
1134
995
|
});
|
|
1135
996
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
997
|
+
// src/matchers/contains-object.ts
|
|
998
|
+
import isPlainObject2 from "lodash/isPlainObject.js";
|
|
999
|
+
var looksLikeObject = (value) => isPlainObject2(value);
|
|
1000
|
+
var getExpectedObjectDiff = (actual, expected) => Object.fromEntries(
|
|
1001
|
+
getKeys(expected).map((key) => {
|
|
1002
|
+
const expectedValue = getKey2(expected, key);
|
|
1003
|
+
const actualValue = getKey2(actual, key);
|
|
1004
|
+
if (isMatcher(expectedValue)) {
|
|
1005
|
+
return [key, expectedValue.getDiff(actualValue).expected];
|
|
1006
|
+
}
|
|
1007
|
+
if (looksLikeObject(expectedValue)) {
|
|
1008
|
+
return [key, getExpectedObjectDiff(actualValue, expectedValue)];
|
|
1009
|
+
}
|
|
1010
|
+
return [key, expectedValue];
|
|
1011
|
+
})
|
|
1012
|
+
);
|
|
1013
|
+
var getActualObjectDiff = (actual, expected) => {
|
|
1149
1014
|
const actualKeys = getKeys(actual);
|
|
1150
1015
|
const expectedKeys = new Set(getKeys(expected));
|
|
1151
|
-
const commonKeys = actualKeys.filter(key => expectedKeys.has(key));
|
|
1016
|
+
const commonKeys = actualKeys.filter((key) => expectedKeys.has(key));
|
|
1152
1017
|
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
1018
|
return actual;
|
|
1156
1019
|
}
|
|
1157
|
-
return Object.fromEntries(
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1020
|
+
return Object.fromEntries(
|
|
1021
|
+
commonKeys.map((key) => {
|
|
1022
|
+
const expectedValue = getKey2(expected, key);
|
|
1023
|
+
const actualValue = getKey2(actual, key);
|
|
1024
|
+
if (isMatcher(expectedValue)) {
|
|
1025
|
+
return [key, expectedValue.getDiff(actualValue).actual];
|
|
1026
|
+
}
|
|
1027
|
+
if (looksLikeObject(expectedValue)) {
|
|
1028
|
+
return [key, getActualObjectDiff(actualValue, expectedValue)];
|
|
1029
|
+
}
|
|
1030
|
+
return [key, actualValue];
|
|
1031
|
+
})
|
|
1032
|
+
);
|
|
1168
1033
|
};
|
|
1169
|
-
|
|
1170
|
-
if (typeof value ===
|
|
1034
|
+
var getKeys = (value) => {
|
|
1035
|
+
if (typeof value === "object" && value !== null) {
|
|
1171
1036
|
return Reflect.ownKeys(value);
|
|
1172
1037
|
}
|
|
1173
1038
|
return [];
|
|
1174
1039
|
};
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1040
|
+
var getKey2 = (value, key) => (
|
|
1041
|
+
// @ts-expect-error because we're fine with a runtime undefined value
|
|
1042
|
+
value == null ? void 0 : value[key]
|
|
1043
|
+
);
|
|
1044
|
+
var isMatch = (actual, expected) => {
|
|
1178
1045
|
const actualKeys = getKeys(actual);
|
|
1179
1046
|
const expectedKeys = getKeys(expected);
|
|
1180
1047
|
if (!isArray(expectedKeys).matches(actualKeys)) {
|
|
1181
1048
|
return false;
|
|
1182
1049
|
}
|
|
1183
|
-
return expectedKeys.every(key => {
|
|
1184
|
-
const expectedValue =
|
|
1185
|
-
const actualValue =
|
|
1050
|
+
return expectedKeys.every((key) => {
|
|
1051
|
+
const expectedValue = getKey2(expected, key);
|
|
1052
|
+
const actualValue = getKey2(actual, key);
|
|
1186
1053
|
if (isMatcher(expectedValue)) {
|
|
1187
1054
|
return expectedValue.matches(actualValue);
|
|
1188
1055
|
}
|
|
@@ -1192,114 +1059,61 @@ const isMatch = (actual, expected) => {
|
|
|
1192
1059
|
return deepEquals(expectedValue).matches(actualValue);
|
|
1193
1060
|
});
|
|
1194
1061
|
};
|
|
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 => ({
|
|
1062
|
+
var containsObject = (partial) => matches((actual) => isMatch(actual, partial), {
|
|
1063
|
+
toString: () => `Matcher<object>(${printValue(deepPrint(partial))})`,
|
|
1064
|
+
getDiff: (actual) => ({
|
|
1226
1065
|
actual: getActualObjectDiff(actual, partial),
|
|
1227
1066
|
expected: getExpectedObjectDiff(actual, partial)
|
|
1228
1067
|
})
|
|
1229
1068
|
});
|
|
1230
1069
|
|
|
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})`;
|
|
1070
|
+
// src/matchers/is-string.ts
|
|
1071
|
+
var isString = (matching) => matches(
|
|
1072
|
+
(actual) => {
|
|
1073
|
+
if (typeof actual !== "string") {
|
|
1074
|
+
return false;
|
|
1259
1075
|
}
|
|
1260
|
-
|
|
1076
|
+
if (!matching) {
|
|
1077
|
+
return true;
|
|
1078
|
+
}
|
|
1079
|
+
if (typeof matching === "string") {
|
|
1080
|
+
return actual.indexOf(matching) !== -1;
|
|
1081
|
+
}
|
|
1082
|
+
return matching.test(actual);
|
|
1261
1083
|
},
|
|
1262
|
-
|
|
1263
|
-
|
|
1084
|
+
{
|
|
1085
|
+
toString: () => {
|
|
1086
|
+
if (matching) {
|
|
1087
|
+
return `Matcher<string>(${matching})`;
|
|
1088
|
+
}
|
|
1089
|
+
return "Matcher<string>";
|
|
1090
|
+
},
|
|
1091
|
+
getDiff: (actual) => {
|
|
1092
|
+
if (matching) {
|
|
1093
|
+
return {
|
|
1094
|
+
expected: `Matcher<string>(${matching})`,
|
|
1095
|
+
actual
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1264
1098
|
return {
|
|
1265
|
-
expected:
|
|
1266
|
-
actual
|
|
1099
|
+
expected: "Matcher<string>",
|
|
1100
|
+
actual: `${actual} (${typeof actual})`
|
|
1267
1101
|
};
|
|
1268
1102
|
}
|
|
1269
|
-
return {
|
|
1270
|
-
expected: 'Matcher<string>',
|
|
1271
|
-
actual: `${actual} (${typeof actual})`
|
|
1272
|
-
};
|
|
1273
1103
|
}
|
|
1274
|
-
|
|
1104
|
+
);
|
|
1275
1105
|
|
|
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 => {
|
|
1106
|
+
// src/matchers/will-capture.ts
|
|
1107
|
+
var willCapture = (name) => {
|
|
1294
1108
|
let capturedValue;
|
|
1295
1109
|
const matcher = {
|
|
1296
1110
|
[MATCHER_SYMBOL]: true,
|
|
1297
|
-
matches: actual => {
|
|
1111
|
+
matches: (actual) => {
|
|
1298
1112
|
capturedValue = actual;
|
|
1299
1113
|
return true;
|
|
1300
1114
|
},
|
|
1301
|
-
toString: () => name ? `Capture(${name})` :
|
|
1302
|
-
getDiff: actual => ({
|
|
1115
|
+
toString: () => name ? `Capture(${name})` : "Capture",
|
|
1116
|
+
getDiff: (actual) => ({
|
|
1303
1117
|
actual,
|
|
1304
1118
|
expected: actual
|
|
1305
1119
|
}),
|
|
@@ -1309,29 +1123,15 @@ const willCapture = name => {
|
|
|
1309
1123
|
};
|
|
1310
1124
|
return matcher;
|
|
1311
1125
|
};
|
|
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
|
|
1126
|
+
export {
|
|
1127
|
+
it_exports as It,
|
|
1128
|
+
UnexpectedProperty,
|
|
1129
|
+
mock,
|
|
1130
|
+
reset,
|
|
1131
|
+
resetAll,
|
|
1132
|
+
setDefaults,
|
|
1133
|
+
verify,
|
|
1134
|
+
verifyAll,
|
|
1135
|
+
when
|
|
1327
1136
|
};
|
|
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
|
|
1137
|
+
/* c8 ignore next 3 this is not expected in practice -- @preserve */
|