@vitest/expect 2.0.0-beta.1 → 2.0.0-beta.11
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 +5 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +826 -512
- package/package.json +5 -5
package/dist/index.js
CHANGED
@@ -8,7 +8,9 @@ import { use, util } from 'chai';
|
|
8
8
|
const MATCHERS_OBJECT = Symbol.for("matchers-object");
|
9
9
|
const JEST_MATCHERS_OBJECT = Symbol.for("$$jest-matchers-object");
|
10
10
|
const GLOBAL_EXPECT = Symbol.for("expect-global");
|
11
|
-
const ASYMMETRIC_MATCHERS_OBJECT = Symbol.for(
|
11
|
+
const ASYMMETRIC_MATCHERS_OBJECT = Symbol.for(
|
12
|
+
"asymmetric-matchers-object"
|
13
|
+
);
|
12
14
|
|
13
15
|
if (!Object.prototype.hasOwnProperty.call(globalThis, MATCHERS_OBJECT)) {
|
14
16
|
const globalState = /* @__PURE__ */ new WeakMap();
|
@@ -83,14 +85,17 @@ function getMatcherUtils() {
|
|
83
85
|
dimString += "()";
|
84
86
|
} else {
|
85
87
|
hint += DIM_COLOR(`${dimString}(`) + expectedColor(expected);
|
86
|
-
if (secondArgument)
|
88
|
+
if (secondArgument) {
|
87
89
|
hint += DIM_COLOR(", ") + secondArgumentColor(secondArgument);
|
90
|
+
}
|
88
91
|
dimString = ")";
|
89
92
|
}
|
90
|
-
if (comment !== "")
|
93
|
+
if (comment !== "") {
|
91
94
|
dimString += ` // ${comment}`;
|
92
|
-
|
95
|
+
}
|
96
|
+
if (dimString !== "") {
|
93
97
|
hint += DIM_COLOR(dimString);
|
98
|
+
}
|
94
99
|
return hint;
|
95
100
|
}
|
96
101
|
const SPACE_SYMBOL = "\xB7";
|
@@ -133,51 +138,71 @@ function isAsymmetric(obj) {
|
|
133
138
|
return !!obj && typeof obj === "object" && "asymmetricMatch" in obj && isA("Function", obj.asymmetricMatch);
|
134
139
|
}
|
135
140
|
function hasAsymmetric(obj, seen = /* @__PURE__ */ new Set()) {
|
136
|
-
if (seen.has(obj))
|
141
|
+
if (seen.has(obj)) {
|
137
142
|
return false;
|
143
|
+
}
|
138
144
|
seen.add(obj);
|
139
|
-
if (isAsymmetric(obj))
|
145
|
+
if (isAsymmetric(obj)) {
|
140
146
|
return true;
|
141
|
-
|
147
|
+
}
|
148
|
+
if (Array.isArray(obj)) {
|
142
149
|
return obj.some((i) => hasAsymmetric(i, seen));
|
143
|
-
|
150
|
+
}
|
151
|
+
if (obj instanceof Set) {
|
144
152
|
return Array.from(obj).some((i) => hasAsymmetric(i, seen));
|
145
|
-
|
153
|
+
}
|
154
|
+
if (isObject(obj)) {
|
146
155
|
return Object.values(obj).some((v) => hasAsymmetric(v, seen));
|
156
|
+
}
|
147
157
|
return false;
|
148
158
|
}
|
149
159
|
function asymmetricMatch(a, b) {
|
150
160
|
const asymmetricA = isAsymmetric(a);
|
151
161
|
const asymmetricB = isAsymmetric(b);
|
152
|
-
if (asymmetricA && asymmetricB)
|
162
|
+
if (asymmetricA && asymmetricB) {
|
153
163
|
return void 0;
|
154
|
-
|
164
|
+
}
|
165
|
+
if (asymmetricA) {
|
155
166
|
return a.asymmetricMatch(b);
|
156
|
-
|
167
|
+
}
|
168
|
+
if (asymmetricB) {
|
157
169
|
return b.asymmetricMatch(a);
|
170
|
+
}
|
158
171
|
}
|
159
172
|
function eq(a, b, aStack, bStack, customTesters, hasKey2) {
|
160
173
|
let result = true;
|
161
174
|
const asymmetricResult = asymmetricMatch(a, b);
|
162
|
-
if (asymmetricResult !== void 0)
|
175
|
+
if (asymmetricResult !== void 0) {
|
163
176
|
return asymmetricResult;
|
177
|
+
}
|
164
178
|
const testerContext = { equals };
|
165
179
|
for (let i = 0; i < customTesters.length; i++) {
|
166
|
-
const customTesterResult = customTesters[i].call(
|
167
|
-
|
180
|
+
const customTesterResult = customTesters[i].call(
|
181
|
+
testerContext,
|
182
|
+
a,
|
183
|
+
b,
|
184
|
+
customTesters
|
185
|
+
);
|
186
|
+
if (customTesterResult !== void 0) {
|
168
187
|
return customTesterResult;
|
188
|
+
}
|
169
189
|
}
|
170
|
-
if (a instanceof Error && b instanceof Error)
|
190
|
+
if (a instanceof Error && b instanceof Error) {
|
171
191
|
return a.message === b.message;
|
172
|
-
|
192
|
+
}
|
193
|
+
if (typeof URL === "function" && a instanceof URL && b instanceof URL) {
|
173
194
|
return a.href === b.href;
|
174
|
-
|
195
|
+
}
|
196
|
+
if (Object.is(a, b)) {
|
175
197
|
return true;
|
176
|
-
|
198
|
+
}
|
199
|
+
if (a === null || b === null) {
|
177
200
|
return a === b;
|
201
|
+
}
|
178
202
|
const className = Object.prototype.toString.call(a);
|
179
|
-
if (className !== Object.prototype.toString.call(b))
|
203
|
+
if (className !== Object.prototype.toString.call(b)) {
|
180
204
|
return false;
|
205
|
+
}
|
181
206
|
switch (className) {
|
182
207
|
case "[object Boolean]":
|
183
208
|
case "[object String]":
|
@@ -197,31 +222,37 @@ function eq(a, b, aStack, bStack, customTesters, hasKey2) {
|
|
197
222
|
case "[object RegExp]":
|
198
223
|
return a.source === b.source && a.flags === b.flags;
|
199
224
|
}
|
200
|
-
if (typeof a !== "object" || typeof b !== "object")
|
225
|
+
if (typeof a !== "object" || typeof b !== "object") {
|
201
226
|
return false;
|
202
|
-
|
227
|
+
}
|
228
|
+
if (isDomNode(a) && isDomNode(b)) {
|
203
229
|
return a.isEqualNode(b);
|
230
|
+
}
|
204
231
|
let length = aStack.length;
|
205
232
|
while (length--) {
|
206
|
-
if (aStack[length] === a)
|
233
|
+
if (aStack[length] === a) {
|
207
234
|
return bStack[length] === b;
|
208
|
-
else if (bStack[length] === b)
|
235
|
+
} else if (bStack[length] === b) {
|
209
236
|
return false;
|
237
|
+
}
|
210
238
|
}
|
211
239
|
aStack.push(a);
|
212
240
|
bStack.push(b);
|
213
|
-
if (className === "[object Array]" && a.length !== b.length)
|
241
|
+
if (className === "[object Array]" && a.length !== b.length) {
|
214
242
|
return false;
|
243
|
+
}
|
215
244
|
const aKeys = keys(a, hasKey2);
|
216
245
|
let key;
|
217
246
|
let size = aKeys.length;
|
218
|
-
if (keys(b, hasKey2).length !== size)
|
247
|
+
if (keys(b, hasKey2).length !== size) {
|
219
248
|
return false;
|
249
|
+
}
|
220
250
|
while (size--) {
|
221
251
|
key = aKeys[size];
|
222
252
|
result = hasKey2(b, key) && eq(a[key], b[key], aStack, bStack, customTesters, hasKey2);
|
223
|
-
if (!result)
|
253
|
+
if (!result) {
|
224
254
|
return false;
|
255
|
+
}
|
225
256
|
}
|
226
257
|
aStack.pop();
|
227
258
|
bStack.pop();
|
@@ -230,8 +261,9 @@ function eq(a, b, aStack, bStack, customTesters, hasKey2) {
|
|
230
261
|
function keys(obj, hasKey2) {
|
231
262
|
const keys2 = [];
|
232
263
|
for (const key in obj) {
|
233
|
-
if (hasKey2(obj, key))
|
264
|
+
if (hasKey2(obj, key)) {
|
234
265
|
keys2.push(key);
|
266
|
+
}
|
235
267
|
}
|
236
268
|
return keys2.concat(
|
237
269
|
Object.getOwnPropertySymbols(obj).filter(
|
@@ -252,23 +284,28 @@ function isDomNode(obj) {
|
|
252
284
|
return obj !== null && typeof obj === "object" && "nodeType" in obj && typeof obj.nodeType === "number" && "nodeName" in obj && typeof obj.nodeName === "string" && "isEqualNode" in obj && typeof obj.isEqualNode === "function";
|
253
285
|
}
|
254
286
|
function fnNameFor(func) {
|
255
|
-
if (func.name)
|
287
|
+
if (func.name) {
|
256
288
|
return func.name;
|
257
|
-
|
289
|
+
}
|
290
|
+
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s*(?:\*\s*)?([\w$]+)\s*\(/);
|
258
291
|
return matches ? matches[1] : "<anonymous>";
|
259
292
|
}
|
260
293
|
function getPrototype(obj) {
|
261
|
-
if (Object.getPrototypeOf)
|
294
|
+
if (Object.getPrototypeOf) {
|
262
295
|
return Object.getPrototypeOf(obj);
|
263
|
-
|
296
|
+
}
|
297
|
+
if (obj.constructor.prototype === obj) {
|
264
298
|
return null;
|
299
|
+
}
|
265
300
|
return obj.constructor.prototype;
|
266
301
|
}
|
267
302
|
function hasProperty(obj, property) {
|
268
|
-
if (!obj)
|
303
|
+
if (!obj) {
|
269
304
|
return false;
|
270
|
-
|
305
|
+
}
|
306
|
+
if (Object.prototype.hasOwnProperty.call(obj, property)) {
|
271
307
|
return true;
|
308
|
+
}
|
272
309
|
return hasProperty(getPrototype(obj), property);
|
273
310
|
}
|
274
311
|
const IS_KEYED_SENTINEL = "@@__IMMUTABLE_KEYED__@@";
|
@@ -306,14 +343,17 @@ function hasIterator(object) {
|
|
306
343
|
return !!(object != null && object[IteratorSymbol]);
|
307
344
|
}
|
308
345
|
function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
|
309
|
-
if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b) || !hasIterator(a) || !hasIterator(b))
|
346
|
+
if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b) || !hasIterator(a) || !hasIterator(b)) {
|
310
347
|
return void 0;
|
311
|
-
|
348
|
+
}
|
349
|
+
if (a.constructor !== b.constructor) {
|
312
350
|
return false;
|
351
|
+
}
|
313
352
|
let length = aStack.length;
|
314
353
|
while (length--) {
|
315
|
-
if (aStack[length] === a)
|
354
|
+
if (aStack[length] === a) {
|
316
355
|
return bStack[length] === b;
|
356
|
+
}
|
317
357
|
}
|
318
358
|
aStack.push(a);
|
319
359
|
bStack.push(b);
|
@@ -322,13 +362,7 @@ function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
|
|
322
362
|
iterableEqualityWithStack
|
323
363
|
];
|
324
364
|
function iterableEqualityWithStack(a2, b2) {
|
325
|
-
return iterableEquality(
|
326
|
-
a2,
|
327
|
-
b2,
|
328
|
-
[...customTesters],
|
329
|
-
[...aStack],
|
330
|
-
[...bStack]
|
331
|
-
);
|
365
|
+
return iterableEquality(a2, b2, [...customTesters], [...aStack], [...bStack]);
|
332
366
|
}
|
333
367
|
if (a.size !== void 0) {
|
334
368
|
if (a.size !== b.size) {
|
@@ -340,8 +374,9 @@ function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
|
|
340
374
|
let has = false;
|
341
375
|
for (const bValue of b) {
|
342
376
|
const isEqual = equals(aValue, bValue, filteredCustomTesters);
|
343
|
-
if (isEqual === true)
|
377
|
+
if (isEqual === true) {
|
344
378
|
has = true;
|
379
|
+
}
|
345
380
|
}
|
346
381
|
if (has === false) {
|
347
382
|
allFound = false;
|
@@ -358,12 +393,22 @@ function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
|
|
358
393
|
if (!b.has(aEntry[0]) || !equals(aEntry[1], b.get(aEntry[0]), filteredCustomTesters)) {
|
359
394
|
let has = false;
|
360
395
|
for (const bEntry of b) {
|
361
|
-
const matchedKey = equals(
|
396
|
+
const matchedKey = equals(
|
397
|
+
aEntry[0],
|
398
|
+
bEntry[0],
|
399
|
+
filteredCustomTesters
|
400
|
+
);
|
362
401
|
let matchedValue = false;
|
363
|
-
if (matchedKey === true)
|
364
|
-
matchedValue = equals(
|
365
|
-
|
402
|
+
if (matchedKey === true) {
|
403
|
+
matchedValue = equals(
|
404
|
+
aEntry[1],
|
405
|
+
bEntry[1],
|
406
|
+
filteredCustomTesters
|
407
|
+
);
|
408
|
+
}
|
409
|
+
if (matchedValue === true) {
|
366
410
|
has = true;
|
411
|
+
}
|
367
412
|
}
|
368
413
|
if (has === false) {
|
369
414
|
allFound = false;
|
@@ -379,16 +424,19 @@ function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
|
|
379
424
|
const bIterator = b[IteratorSymbol]();
|
380
425
|
for (const aValue of a) {
|
381
426
|
const nextB = bIterator.next();
|
382
|
-
if (nextB.done || !equals(aValue, nextB.value, filteredCustomTesters))
|
427
|
+
if (nextB.done || !equals(aValue, nextB.value, filteredCustomTesters)) {
|
383
428
|
return false;
|
429
|
+
}
|
384
430
|
}
|
385
|
-
if (!bIterator.next().done)
|
431
|
+
if (!bIterator.next().done) {
|
386
432
|
return false;
|
433
|
+
}
|
387
434
|
if (!isImmutableList(a) && !isImmutableOrderedKeyed(a) && !isImmutableOrderedSet(a) && !isImmutableRecord(a)) {
|
388
435
|
const aEntries = Object.entries(a);
|
389
436
|
const bEntries = Object.entries(b);
|
390
|
-
if (!equals(aEntries, bEntries))
|
437
|
+
if (!equals(aEntries, bEntries)) {
|
391
438
|
return false;
|
439
|
+
}
|
392
440
|
}
|
393
441
|
aStack.pop();
|
394
442
|
bStack.pop();
|
@@ -396,22 +444,27 @@ function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
|
|
396
444
|
}
|
397
445
|
function hasPropertyInObject(object, key) {
|
398
446
|
const shouldTerminate = !object || typeof object !== "object" || object === Object.prototype;
|
399
|
-
if (shouldTerminate)
|
447
|
+
if (shouldTerminate) {
|
400
448
|
return false;
|
449
|
+
}
|
401
450
|
return Object.prototype.hasOwnProperty.call(object, key) || hasPropertyInObject(Object.getPrototypeOf(object), key);
|
402
451
|
}
|
403
452
|
function isObjectWithKeys(a) {
|
404
453
|
return isObject(a) && !(a instanceof Error) && !Array.isArray(a) && !(a instanceof Date);
|
405
454
|
}
|
406
455
|
function subsetEquality(object, subset, customTesters = []) {
|
407
|
-
const filteredCustomTesters = customTesters.filter(
|
456
|
+
const filteredCustomTesters = customTesters.filter(
|
457
|
+
(t) => t !== subsetEquality
|
458
|
+
);
|
408
459
|
const subsetEqualityWithContext = (seenReferences = /* @__PURE__ */ new WeakMap()) => (object2, subset2) => {
|
409
|
-
if (!isObjectWithKeys(subset2))
|
460
|
+
if (!isObjectWithKeys(subset2)) {
|
410
461
|
return void 0;
|
462
|
+
}
|
411
463
|
return Object.keys(subset2).every((key) => {
|
412
464
|
if (subset2[key] != null && typeof subset2[key] === "object") {
|
413
|
-
if (seenReferences.has(subset2[key]))
|
465
|
+
if (seenReferences.has(subset2[key])) {
|
414
466
|
return equals(object2[key], subset2[key], filteredCustomTesters);
|
467
|
+
}
|
415
468
|
seenReferences.set(subset2[key], true);
|
416
469
|
}
|
417
470
|
const result = object2 != null && hasPropertyInObject(object2, key) && equals(object2[key], subset2[key], [
|
@@ -425,16 +478,18 @@ function subsetEquality(object, subset, customTesters = []) {
|
|
425
478
|
return subsetEqualityWithContext()(object, subset);
|
426
479
|
}
|
427
480
|
function typeEquality(a, b) {
|
428
|
-
if (a == null || b == null || a.constructor === b.constructor)
|
481
|
+
if (a == null || b == null || a.constructor === b.constructor) {
|
429
482
|
return void 0;
|
483
|
+
}
|
430
484
|
return false;
|
431
485
|
}
|
432
486
|
function arrayBufferEquality(a, b) {
|
433
487
|
let dataViewA = a;
|
434
488
|
let dataViewB = b;
|
435
489
|
if (!(a instanceof DataView && b instanceof DataView)) {
|
436
|
-
if (!(a instanceof ArrayBuffer) || !(b instanceof ArrayBuffer))
|
490
|
+
if (!(a instanceof ArrayBuffer) || !(b instanceof ArrayBuffer)) {
|
437
491
|
return void 0;
|
492
|
+
}
|
438
493
|
try {
|
439
494
|
dataViewA = new DataView(a);
|
440
495
|
dataViewB = new DataView(b);
|
@@ -442,25 +497,30 @@ function arrayBufferEquality(a, b) {
|
|
442
497
|
return void 0;
|
443
498
|
}
|
444
499
|
}
|
445
|
-
if (dataViewA.byteLength !== dataViewB.byteLength)
|
500
|
+
if (dataViewA.byteLength !== dataViewB.byteLength) {
|
446
501
|
return false;
|
502
|
+
}
|
447
503
|
for (let i = 0; i < dataViewA.byteLength; i++) {
|
448
|
-
if (dataViewA.getUint8(i) !== dataViewB.getUint8(i))
|
504
|
+
if (dataViewA.getUint8(i) !== dataViewB.getUint8(i)) {
|
449
505
|
return false;
|
506
|
+
}
|
450
507
|
}
|
451
508
|
return true;
|
452
509
|
}
|
453
510
|
function sparseArrayEquality(a, b, customTesters = []) {
|
454
|
-
if (!Array.isArray(a) || !Array.isArray(b))
|
511
|
+
if (!Array.isArray(a) || !Array.isArray(b)) {
|
455
512
|
return void 0;
|
513
|
+
}
|
456
514
|
const aKeys = Object.keys(a);
|
457
515
|
const bKeys = Object.keys(b);
|
458
|
-
const filteredCustomTesters = customTesters.filter(
|
516
|
+
const filteredCustomTesters = customTesters.filter(
|
517
|
+
(t) => t !== sparseArrayEquality
|
518
|
+
);
|
459
519
|
return equals(a, b, filteredCustomTesters, true) && equals(aKeys, bKeys);
|
460
520
|
}
|
461
521
|
function generateToBeMessage(deepEqualityName, expected = "#{this}", actual = "#{exp}") {
|
462
522
|
const toBeMessage = `expected ${expected} to be ${actual} // Object.is equality`;
|
463
|
-
if (["toStrictEqual", "toEqual"].includes(deepEqualityName))
|
523
|
+
if (["toStrictEqual", "toEqual"].includes(deepEqualityName)) {
|
464
524
|
return `${toBeMessage}
|
465
525
|
|
466
526
|
If it should pass with deep equality, replace "toBe" with "${deepEqualityName}"
|
@@ -468,6 +528,7 @@ If it should pass with deep equality, replace "toBe" with "${deepEqualityName}"
|
|
468
528
|
Expected: ${expected}
|
469
529
|
Received: serializes to the same string
|
470
530
|
`;
|
531
|
+
}
|
471
532
|
return toBeMessage;
|
472
533
|
}
|
473
534
|
function pluralize(word, count) {
|
@@ -507,18 +568,26 @@ function getObjectSubset(object, subset, customTesters = []) {
|
|
507
568
|
seenReferences.set(object2, trimmed);
|
508
569
|
for (const key of getObjectKeys(object2)) {
|
509
570
|
if (hasPropertyInObject(subset2, key)) {
|
510
|
-
trimmed[key] = seenReferences.has(object2[key]) ? seenReferences.get(object2[key]) : getObjectSubsetWithContext(seenReferences)(
|
571
|
+
trimmed[key] = seenReferences.has(object2[key]) ? seenReferences.get(object2[key]) : getObjectSubsetWithContext(seenReferences)(
|
572
|
+
object2[key],
|
573
|
+
subset2[key]
|
574
|
+
);
|
511
575
|
} else {
|
512
576
|
if (!seenReferences.has(object2[key])) {
|
513
577
|
stripped += 1;
|
514
|
-
if (isObject(object2[key]))
|
578
|
+
if (isObject(object2[key])) {
|
515
579
|
stripped += getObjectKeys(object2[key]).length;
|
516
|
-
|
580
|
+
}
|
581
|
+
getObjectSubsetWithContext(seenReferences)(
|
582
|
+
object2[key],
|
583
|
+
subset2[key]
|
584
|
+
);
|
517
585
|
}
|
518
586
|
}
|
519
587
|
}
|
520
|
-
if (getObjectKeys(trimmed).length > 0)
|
588
|
+
if (getObjectKeys(trimmed).length > 0) {
|
521
589
|
return trimmed;
|
590
|
+
}
|
522
591
|
}
|
523
592
|
return object2;
|
524
593
|
};
|
@@ -551,15 +620,17 @@ class AsymmetricMatcher {
|
|
551
620
|
// https://github.com/chaijs/loupe/blob/9b8a6deabcd50adc056a64fb705896194710c5c6/src/index.ts#L29
|
552
621
|
[Symbol.for("chai/inspect")](options) {
|
553
622
|
const result = stringify(this, options.depth, { min: true });
|
554
|
-
if (result.length <= options.truncate)
|
623
|
+
if (result.length <= options.truncate) {
|
555
624
|
return result;
|
625
|
+
}
|
556
626
|
return `${this.toString()}{\u2026}`;
|
557
627
|
}
|
558
628
|
}
|
559
629
|
class StringContaining extends AsymmetricMatcher {
|
560
630
|
constructor(sample, inverse = false) {
|
561
|
-
if (!isA("String", sample))
|
631
|
+
if (!isA("String", sample)) {
|
562
632
|
throw new Error("Expected is not a string");
|
633
|
+
}
|
563
634
|
super(sample, inverse);
|
564
635
|
}
|
565
636
|
asymmetricMatch(other) {
|
@@ -589,17 +660,21 @@ class ObjectContaining extends AsymmetricMatcher {
|
|
589
660
|
super(sample, inverse);
|
590
661
|
}
|
591
662
|
getPrototype(obj) {
|
592
|
-
if (Object.getPrototypeOf)
|
663
|
+
if (Object.getPrototypeOf) {
|
593
664
|
return Object.getPrototypeOf(obj);
|
594
|
-
|
665
|
+
}
|
666
|
+
if (obj.constructor.prototype === obj) {
|
595
667
|
return null;
|
668
|
+
}
|
596
669
|
return obj.constructor.prototype;
|
597
670
|
}
|
598
671
|
hasProperty(obj, property) {
|
599
|
-
if (!obj)
|
672
|
+
if (!obj) {
|
600
673
|
return false;
|
601
|
-
|
674
|
+
}
|
675
|
+
if (Object.prototype.hasOwnProperty.call(obj, property)) {
|
602
676
|
return true;
|
677
|
+
}
|
603
678
|
return this.hasProperty(this.getPrototype(obj), property);
|
604
679
|
}
|
605
680
|
asymmetricMatch(other) {
|
@@ -611,7 +686,11 @@ class ObjectContaining extends AsymmetricMatcher {
|
|
611
686
|
let result = true;
|
612
687
|
const matcherContext = this.getMatcherContext();
|
613
688
|
for (const property in this.sample) {
|
614
|
-
if (!this.hasProperty(other, property) || !equals(
|
689
|
+
if (!this.hasProperty(other, property) || !equals(
|
690
|
+
this.sample[property],
|
691
|
+
other[property],
|
692
|
+
matcherContext.customTesters
|
693
|
+
)) {
|
615
694
|
result = false;
|
616
695
|
break;
|
617
696
|
}
|
@@ -637,7 +716,9 @@ class ArrayContaining extends AsymmetricMatcher {
|
|
637
716
|
}
|
638
717
|
const matcherContext = this.getMatcherContext();
|
639
718
|
const result = this.sample.length === 0 || Array.isArray(other) && this.sample.every(
|
640
|
-
(item) => other.some(
|
719
|
+
(item) => other.some(
|
720
|
+
(another) => equals(item, another, matcherContext.customTesters)
|
721
|
+
)
|
641
722
|
);
|
642
723
|
return this.inverse ? !result : result;
|
643
724
|
}
|
@@ -658,43 +739,56 @@ class Any extends AsymmetricMatcher {
|
|
658
739
|
super(sample);
|
659
740
|
}
|
660
741
|
fnNameFor(func) {
|
661
|
-
if (func.name)
|
742
|
+
if (func.name) {
|
662
743
|
return func.name;
|
744
|
+
}
|
663
745
|
const functionToString = Function.prototype.toString;
|
664
|
-
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s
|
746
|
+
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s*(?:\*\s*)?([\w$]+)\s*\(/);
|
665
747
|
return matches ? matches[1] : "<anonymous>";
|
666
748
|
}
|
667
749
|
asymmetricMatch(other) {
|
668
|
-
if (this.sample === String)
|
750
|
+
if (this.sample === String) {
|
669
751
|
return typeof other == "string" || other instanceof String;
|
670
|
-
|
752
|
+
}
|
753
|
+
if (this.sample === Number) {
|
671
754
|
return typeof other == "number" || other instanceof Number;
|
672
|
-
|
755
|
+
}
|
756
|
+
if (this.sample === Function) {
|
673
757
|
return typeof other == "function" || other instanceof Function;
|
674
|
-
|
758
|
+
}
|
759
|
+
if (this.sample === Boolean) {
|
675
760
|
return typeof other == "boolean" || other instanceof Boolean;
|
676
|
-
|
761
|
+
}
|
762
|
+
if (this.sample === BigInt) {
|
677
763
|
return typeof other == "bigint" || other instanceof BigInt;
|
678
|
-
|
764
|
+
}
|
765
|
+
if (this.sample === Symbol) {
|
679
766
|
return typeof other == "symbol" || other instanceof Symbol;
|
680
|
-
|
767
|
+
}
|
768
|
+
if (this.sample === Object) {
|
681
769
|
return typeof other == "object";
|
770
|
+
}
|
682
771
|
return other instanceof this.sample;
|
683
772
|
}
|
684
773
|
toString() {
|
685
774
|
return "Any";
|
686
775
|
}
|
687
776
|
getExpectedType() {
|
688
|
-
if (this.sample === String)
|
777
|
+
if (this.sample === String) {
|
689
778
|
return "string";
|
690
|
-
|
779
|
+
}
|
780
|
+
if (this.sample === Number) {
|
691
781
|
return "number";
|
692
|
-
|
782
|
+
}
|
783
|
+
if (this.sample === Function) {
|
693
784
|
return "function";
|
694
|
-
|
785
|
+
}
|
786
|
+
if (this.sample === Object) {
|
695
787
|
return "object";
|
696
|
-
|
788
|
+
}
|
789
|
+
if (this.sample === Boolean) {
|
697
790
|
return "boolean";
|
791
|
+
}
|
698
792
|
return this.fnNameFor(this.sample);
|
699
793
|
}
|
700
794
|
toAsymmetricMatcher() {
|
@@ -703,8 +797,9 @@ class Any extends AsymmetricMatcher {
|
|
703
797
|
}
|
704
798
|
class StringMatching extends AsymmetricMatcher {
|
705
799
|
constructor(sample, inverse = false) {
|
706
|
-
if (!isA("String", sample) && !isA("RegExp", sample))
|
800
|
+
if (!isA("String", sample) && !isA("RegExp", sample)) {
|
707
801
|
throw new Error("Expected is not a String or a RegExp");
|
802
|
+
}
|
708
803
|
super(new RegExp(sample), inverse);
|
709
804
|
}
|
710
805
|
asymmetricMatch(other) {
|
@@ -721,17 +816,20 @@ class StringMatching extends AsymmetricMatcher {
|
|
721
816
|
class CloseTo extends AsymmetricMatcher {
|
722
817
|
precision;
|
723
818
|
constructor(sample, precision = 2, inverse = false) {
|
724
|
-
if (!isA("Number", sample))
|
819
|
+
if (!isA("Number", sample)) {
|
725
820
|
throw new Error("Expected is not a Number");
|
726
|
-
|
821
|
+
}
|
822
|
+
if (!isA("Number", precision)) {
|
727
823
|
throw new Error("Precision is not a Number");
|
824
|
+
}
|
728
825
|
super(sample);
|
729
826
|
this.inverse = inverse;
|
730
827
|
this.precision = precision;
|
731
828
|
}
|
732
829
|
asymmetricMatch(other) {
|
733
|
-
if (!isA("Number", other))
|
830
|
+
if (!isA("Number", other)) {
|
734
831
|
return false;
|
832
|
+
}
|
735
833
|
let result = false;
|
736
834
|
if (other === Number.POSITIVE_INFINITY && this.sample === Number.POSITIVE_INFINITY) {
|
737
835
|
result = true;
|
@@ -757,16 +855,8 @@ class CloseTo extends AsymmetricMatcher {
|
|
757
855
|
}
|
758
856
|
}
|
759
857
|
const JestAsymmetricMatchers = (chai, utils) => {
|
760
|
-
utils.addMethod(
|
761
|
-
|
762
|
-
"anything",
|
763
|
-
() => new Anything()
|
764
|
-
);
|
765
|
-
utils.addMethod(
|
766
|
-
chai.expect,
|
767
|
-
"any",
|
768
|
-
(expected) => new Any(expected)
|
769
|
-
);
|
858
|
+
utils.addMethod(chai.expect, "anything", () => new Anything());
|
859
|
+
utils.addMethod(chai.expect, "any", (expected) => new Any(expected));
|
770
860
|
utils.addMethod(
|
771
861
|
chai.expect,
|
772
862
|
"stringContaining",
|
@@ -805,11 +895,13 @@ function recordAsyncExpect(test, promise) {
|
|
805
895
|
if (test && promise instanceof Promise) {
|
806
896
|
promise = promise.finally(() => {
|
807
897
|
const index = test.promises.indexOf(promise);
|
808
|
-
if (index !== -1)
|
898
|
+
if (index !== -1) {
|
809
899
|
test.promises.splice(index, 1);
|
900
|
+
}
|
810
901
|
});
|
811
|
-
if (!test.promises)
|
902
|
+
if (!test.promises) {
|
812
903
|
test.promises = [];
|
904
|
+
}
|
813
905
|
test.promises.push(promise);
|
814
906
|
}
|
815
907
|
return promise;
|
@@ -817,12 +909,13 @@ function recordAsyncExpect(test, promise) {
|
|
817
909
|
function wrapSoft(utils, fn) {
|
818
910
|
return function(...args) {
|
819
911
|
var _a;
|
820
|
-
|
821
|
-
const state = (test == null ? void 0 : test.context._local) ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
|
822
|
-
if (!state.soft)
|
912
|
+
if (!utils.flag(this, "soft")) {
|
823
913
|
return fn.apply(this, args);
|
824
|
-
|
914
|
+
}
|
915
|
+
const test = utils.flag(this, "vitest-test");
|
916
|
+
if (!test) {
|
825
917
|
throw new Error("expect.soft() can only be used inside a test");
|
918
|
+
}
|
826
919
|
try {
|
827
920
|
return fn.apply(this, args);
|
828
921
|
} catch (err) {
|
@@ -842,12 +935,17 @@ const JestChaiExpect = (chai, utils) => {
|
|
842
935
|
const addMethod = (n) => {
|
843
936
|
const softWrapper = wrapSoft(utils, fn);
|
844
937
|
utils.addMethod(chai.Assertion.prototype, n, softWrapper);
|
845
|
-
utils.addMethod(
|
938
|
+
utils.addMethod(
|
939
|
+
globalThis[JEST_MATCHERS_OBJECT].matchers,
|
940
|
+
n,
|
941
|
+
softWrapper
|
942
|
+
);
|
846
943
|
};
|
847
|
-
if (Array.isArray(name))
|
944
|
+
if (Array.isArray(name)) {
|
848
945
|
name.forEach((n) => addMethod(n));
|
849
|
-
else
|
946
|
+
} else {
|
850
947
|
addMethod(name);
|
948
|
+
}
|
851
949
|
}
|
852
950
|
["throw", "throws", "Throw"].forEach((m) => {
|
853
951
|
utils.overwriteMethod(chai.Assertion.prototype, m, (_super) => {
|
@@ -880,11 +978,10 @@ const JestChaiExpect = (chai, utils) => {
|
|
880
978
|
});
|
881
979
|
def("toEqual", function(expected) {
|
882
980
|
const actual = utils.flag(this, "object");
|
883
|
-
const equal = equals(
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
);
|
981
|
+
const equal = equals(actual, expected, [
|
982
|
+
...customTesters,
|
983
|
+
iterableEquality
|
984
|
+
]);
|
888
985
|
return this.assert(
|
889
986
|
equal,
|
890
987
|
"expected #{this} to deeply equal #{exp}",
|
@@ -935,13 +1032,13 @@ const JestChaiExpect = (chai, utils) => {
|
|
935
1032
|
if (toStrictEqualPass) {
|
936
1033
|
deepEqualityName = "toStrictEqual";
|
937
1034
|
} else {
|
938
|
-
const toEqualPass = equals(
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
)
|
943
|
-
if (toEqualPass)
|
1035
|
+
const toEqualPass = equals(actual, expected, [
|
1036
|
+
...customTesters,
|
1037
|
+
iterableEquality
|
1038
|
+
]);
|
1039
|
+
if (toEqualPass) {
|
944
1040
|
deepEqualityName = "toEqual";
|
1041
|
+
}
|
945
1042
|
}
|
946
1043
|
}
|
947
1044
|
return this.assert(
|
@@ -954,30 +1051,41 @@ const JestChaiExpect = (chai, utils) => {
|
|
954
1051
|
});
|
955
1052
|
def("toMatchObject", function(expected) {
|
956
1053
|
const actual = this._obj;
|
957
|
-
const pass = equals(actual, expected, [
|
1054
|
+
const pass = equals(actual, expected, [
|
1055
|
+
...customTesters,
|
1056
|
+
iterableEquality,
|
1057
|
+
subsetEquality
|
1058
|
+
]);
|
958
1059
|
const isNot = utils.flag(this, "negate");
|
959
|
-
const { subset: actualSubset, stripped } = getObjectSubset(
|
1060
|
+
const { subset: actualSubset, stripped } = getObjectSubset(
|
1061
|
+
actual,
|
1062
|
+
expected
|
1063
|
+
);
|
960
1064
|
if (pass && isNot || !pass && !isNot) {
|
961
|
-
const msg = utils.getMessage(
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
false
|
970
|
-
]
|
971
|
-
);
|
1065
|
+
const msg = utils.getMessage(this, [
|
1066
|
+
pass,
|
1067
|
+
"expected #{this} to match object #{exp}",
|
1068
|
+
"expected #{this} to not match object #{exp}",
|
1069
|
+
expected,
|
1070
|
+
actualSubset,
|
1071
|
+
false
|
1072
|
+
]);
|
972
1073
|
const message = stripped === 0 ? msg : `${msg}
|
973
1074
|
(${stripped} matching ${stripped === 1 ? "property" : "properties"} omitted from actual)`;
|
974
|
-
throw new AssertionError(message, {
|
1075
|
+
throw new AssertionError(message, {
|
1076
|
+
showDiff: true,
|
1077
|
+
expected,
|
1078
|
+
actual: actualSubset
|
1079
|
+
});
|
975
1080
|
}
|
976
1081
|
});
|
977
1082
|
def("toMatch", function(expected) {
|
978
1083
|
const actual = this._obj;
|
979
|
-
if (typeof actual !== "string")
|
980
|
-
throw new TypeError(
|
1084
|
+
if (typeof actual !== "string") {
|
1085
|
+
throw new TypeError(
|
1086
|
+
`.toMatch() expects to receive a string, but got ${typeof actual}`
|
1087
|
+
);
|
1088
|
+
}
|
981
1089
|
return this.assert(
|
982
1090
|
typeof expected === "string" ? actual.includes(expected) : actual.match(expected),
|
983
1091
|
`expected #{this} to match #{exp}`,
|
@@ -989,8 +1097,11 @@ const JestChaiExpect = (chai, utils) => {
|
|
989
1097
|
def("toContain", function(item) {
|
990
1098
|
const actual = this._obj;
|
991
1099
|
if (typeof Node !== "undefined" && actual instanceof Node) {
|
992
|
-
if (!(item instanceof Node))
|
993
|
-
throw new TypeError(
|
1100
|
+
if (!(item instanceof Node)) {
|
1101
|
+
throw new TypeError(
|
1102
|
+
`toContain() expected a DOM node as the argument, but got ${typeof item}`
|
1103
|
+
);
|
1104
|
+
}
|
994
1105
|
return this.assert(
|
995
1106
|
actual.contains(item),
|
996
1107
|
"expected #{this} to contain element #{exp}",
|
@@ -1020,8 +1131,9 @@ const JestChaiExpect = (chai, utils) => {
|
|
1020
1131
|
actual
|
1021
1132
|
);
|
1022
1133
|
}
|
1023
|
-
if (actual != null && typeof actual !== "string")
|
1134
|
+
if (actual != null && typeof actual !== "string") {
|
1024
1135
|
utils.flag(this, "object", Array.from(actual));
|
1136
|
+
}
|
1025
1137
|
return this.contain(item);
|
1026
1138
|
});
|
1027
1139
|
def("toContainEqual", function(expected) {
|
@@ -1120,49 +1232,61 @@ const JestChaiExpect = (chai, utils) => {
|
|
1120
1232
|
def("toBeDefined", function() {
|
1121
1233
|
const negate = utils.flag(this, "negate");
|
1122
1234
|
utils.flag(this, "negate", false);
|
1123
|
-
if (negate)
|
1235
|
+
if (negate) {
|
1124
1236
|
return this.be.undefined;
|
1237
|
+
}
|
1125
1238
|
return this.not.be.undefined;
|
1126
1239
|
});
|
1127
|
-
def(
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
equal
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1240
|
+
def(
|
1241
|
+
"toBeTypeOf",
|
1242
|
+
function(expected) {
|
1243
|
+
const actual = typeof this._obj;
|
1244
|
+
const equal = expected === actual;
|
1245
|
+
return this.assert(
|
1246
|
+
equal,
|
1247
|
+
"expected #{this} to be type of #{exp}",
|
1248
|
+
"expected #{this} not to be type of #{exp}",
|
1249
|
+
expected,
|
1250
|
+
actual
|
1251
|
+
);
|
1252
|
+
}
|
1253
|
+
);
|
1138
1254
|
def("toBeInstanceOf", function(obj) {
|
1139
1255
|
return this.instanceOf(obj);
|
1140
1256
|
});
|
1141
1257
|
def("toHaveLength", function(length) {
|
1142
1258
|
return this.have.length(length);
|
1143
1259
|
});
|
1144
|
-
def(
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
const
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
exists
|
1164
|
-
|
1165
|
-
|
1260
|
+
def(
|
1261
|
+
"toHaveProperty",
|
1262
|
+
function(...args) {
|
1263
|
+
if (Array.isArray(args[0])) {
|
1264
|
+
args[0] = args[0].map((key) => String(key).replace(/([.[\]])/g, "\\$1")).join(".");
|
1265
|
+
}
|
1266
|
+
const actual = this._obj;
|
1267
|
+
const [propertyName, expected] = args;
|
1268
|
+
const getValue = () => {
|
1269
|
+
const hasOwn = Object.prototype.hasOwnProperty.call(
|
1270
|
+
actual,
|
1271
|
+
propertyName
|
1272
|
+
);
|
1273
|
+
if (hasOwn) {
|
1274
|
+
return { value: actual[propertyName], exists: true };
|
1275
|
+
}
|
1276
|
+
return utils.getPathInfo(actual, propertyName);
|
1277
|
+
};
|
1278
|
+
const { value, exists } = getValue();
|
1279
|
+
const pass = exists && (args.length === 1 || equals(expected, value, customTesters));
|
1280
|
+
const valueString = args.length === 1 ? "" : ` with value ${utils.objDisplay(expected)}`;
|
1281
|
+
return this.assert(
|
1282
|
+
pass,
|
1283
|
+
`expected #{this} to have property "${propertyName}"${valueString}`,
|
1284
|
+
`expected #{this} to not have property "${propertyName}"${valueString}`,
|
1285
|
+
expected,
|
1286
|
+
exists ? value : void 0
|
1287
|
+
);
|
1288
|
+
}
|
1289
|
+
);
|
1166
1290
|
def("toBeCloseTo", function(received, precision = 2) {
|
1167
1291
|
const expected = this._obj;
|
1168
1292
|
let pass = false;
|
@@ -1187,8 +1311,11 @@ const JestChaiExpect = (chai, utils) => {
|
|
1187
1311
|
);
|
1188
1312
|
});
|
1189
1313
|
const assertIsMock = (assertion) => {
|
1190
|
-
if (!isMockFunction(assertion._obj))
|
1191
|
-
throw new TypeError(
|
1314
|
+
if (!isMockFunction(assertion._obj)) {
|
1315
|
+
throw new TypeError(
|
1316
|
+
`${utils.inspect(assertion._obj)} is not a spy or a call to a spy!`
|
1317
|
+
);
|
1318
|
+
}
|
1192
1319
|
};
|
1193
1320
|
const getSpy = (assertion) => {
|
1194
1321
|
assertIsMock(assertion);
|
@@ -1197,58 +1324,79 @@ const JestChaiExpect = (chai, utils) => {
|
|
1197
1324
|
const ordinalOf = (i) => {
|
1198
1325
|
const j = i % 10;
|
1199
1326
|
const k = i % 100;
|
1200
|
-
if (j === 1 && k !== 11)
|
1327
|
+
if (j === 1 && k !== 11) {
|
1201
1328
|
return `${i}st`;
|
1202
|
-
|
1329
|
+
}
|
1330
|
+
if (j === 2 && k !== 12) {
|
1203
1331
|
return `${i}nd`;
|
1204
|
-
|
1332
|
+
}
|
1333
|
+
if (j === 3 && k !== 13) {
|
1205
1334
|
return `${i}rd`;
|
1335
|
+
}
|
1206
1336
|
return `${i}th`;
|
1207
1337
|
};
|
1208
|
-
const formatCalls = (spy, msg,
|
1338
|
+
const formatCalls = (spy, msg, showActualCall) => {
|
1209
1339
|
if (spy.mock.calls) {
|
1210
|
-
msg += c().gray(
|
1340
|
+
msg += c().gray(
|
1341
|
+
`
|
1211
1342
|
|
1212
1343
|
Received:
|
1213
1344
|
|
1214
1345
|
${spy.mock.calls.map((callArg, i) => {
|
1215
|
-
|
1346
|
+
let methodCall = c().bold(
|
1347
|
+
` ${ordinalOf(i + 1)} ${spy.getMockName()} call:
|
1216
1348
|
|
1217
|
-
`
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1349
|
+
`
|
1350
|
+
);
|
1351
|
+
if (showActualCall) {
|
1352
|
+
methodCall += diff(showActualCall, callArg, {
|
1353
|
+
omitAnnotationLines: true
|
1354
|
+
});
|
1355
|
+
} else {
|
1356
|
+
methodCall += stringify(callArg).split("\n").map((line) => ` ${line}`).join("\n");
|
1357
|
+
}
|
1358
|
+
methodCall += "\n";
|
1359
|
+
return methodCall;
|
1360
|
+
}).join("\n")}`
|
1361
|
+
);
|
1225
1362
|
}
|
1226
|
-
msg += c().gray(
|
1363
|
+
msg += c().gray(
|
1364
|
+
`
|
1227
1365
|
|
1228
1366
|
Number of calls: ${c().bold(spy.mock.calls.length)}
|
1229
|
-
`
|
1367
|
+
`
|
1368
|
+
);
|
1230
1369
|
return msg;
|
1231
1370
|
};
|
1232
|
-
const formatReturns = (spy, msg,
|
1233
|
-
msg += c().gray(
|
1371
|
+
const formatReturns = (spy, results, msg, showActualReturn) => {
|
1372
|
+
msg += c().gray(
|
1373
|
+
`
|
1234
1374
|
|
1235
1375
|
Received:
|
1236
1376
|
|
1237
|
-
${
|
1238
|
-
|
1377
|
+
${results.map((callReturn, i) => {
|
1378
|
+
let methodCall = c().bold(
|
1379
|
+
` ${ordinalOf(i + 1)} ${spy.getMockName()} call return:
|
1239
1380
|
|
1240
|
-
`
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
}).join("\n")
|
1248
|
-
|
1381
|
+
`
|
1382
|
+
);
|
1383
|
+
if (showActualReturn) {
|
1384
|
+
methodCall += diff(showActualReturn, callReturn.value, {
|
1385
|
+
omitAnnotationLines: true
|
1386
|
+
});
|
1387
|
+
} else {
|
1388
|
+
methodCall += stringify(callReturn).split("\n").map((line) => ` ${line}`).join("\n");
|
1389
|
+
}
|
1390
|
+
methodCall += "\n";
|
1391
|
+
return methodCall;
|
1392
|
+
}).join("\n")}`
|
1393
|
+
);
|
1394
|
+
msg += c().gray(
|
1395
|
+
`
|
1249
1396
|
|
1250
1397
|
Number of calls: ${c().bold(spy.mock.calls.length)}
|
1251
|
-
`
|
1398
|
+
`
|
1399
|
+
);
|
1252
1400
|
return msg;
|
1253
1401
|
};
|
1254
1402
|
def(["toHaveBeenCalledTimes", "toBeCalledTimes"], function(number) {
|
@@ -1283,277 +1431,421 @@ Number of calls: ${c().bold(spy.mock.calls.length)}
|
|
1283
1431
|
const callCount = spy.mock.calls.length;
|
1284
1432
|
const called = callCount > 0;
|
1285
1433
|
const isNot = utils.flag(this, "negate");
|
1286
|
-
let msg = utils.getMessage(
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
]
|
1295
|
-
);
|
1296
|
-
if (called && isNot)
|
1434
|
+
let msg = utils.getMessage(this, [
|
1435
|
+
called,
|
1436
|
+
`expected "${spyName}" to be called at least once`,
|
1437
|
+
`expected "${spyName}" to not be called at all, but actually been called ${callCount} times`,
|
1438
|
+
true,
|
1439
|
+
called
|
1440
|
+
]);
|
1441
|
+
if (called && isNot) {
|
1297
1442
|
msg = formatCalls(spy, msg);
|
1298
|
-
|
1443
|
+
}
|
1444
|
+
if (called && isNot || !called && !isNot) {
|
1299
1445
|
throw new AssertionError(msg);
|
1446
|
+
}
|
1300
1447
|
});
|
1301
1448
|
def(["toHaveBeenCalledWith", "toBeCalledWith"], function(...args) {
|
1302
1449
|
const spy = getSpy(this);
|
1303
1450
|
const spyName = spy.getMockName();
|
1304
|
-
const pass = spy.mock.calls.some(
|
1305
|
-
|
1306
|
-
const msg = utils.getMessage(
|
1307
|
-
this,
|
1308
|
-
[
|
1309
|
-
pass,
|
1310
|
-
`expected "${spyName}" to be called with arguments: #{exp}`,
|
1311
|
-
`expected "${spyName}" to not be called with arguments: #{exp}`,
|
1312
|
-
args
|
1313
|
-
]
|
1451
|
+
const pass = spy.mock.calls.some(
|
1452
|
+
(callArg) => equals(callArg, args, [...customTesters, iterableEquality])
|
1314
1453
|
);
|
1315
|
-
|
1454
|
+
const isNot = utils.flag(this, "negate");
|
1455
|
+
const msg = utils.getMessage(this, [
|
1456
|
+
pass,
|
1457
|
+
`expected "${spyName}" to be called with arguments: #{exp}`,
|
1458
|
+
`expected "${spyName}" to not be called with arguments: #{exp}`,
|
1459
|
+
args
|
1460
|
+
]);
|
1461
|
+
if (pass && isNot || !pass && !isNot) {
|
1316
1462
|
throw new AssertionError(formatCalls(spy, msg, args));
|
1463
|
+
}
|
1317
1464
|
});
|
1318
|
-
def(
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1465
|
+
def(
|
1466
|
+
["toHaveBeenNthCalledWith", "nthCalledWith"],
|
1467
|
+
function(times, ...args) {
|
1468
|
+
const spy = getSpy(this);
|
1469
|
+
const spyName = spy.getMockName();
|
1470
|
+
const nthCall = spy.mock.calls[times - 1];
|
1471
|
+
const callCount = spy.mock.calls.length;
|
1472
|
+
const isCalled = times <= callCount;
|
1473
|
+
this.assert(
|
1474
|
+
equals(nthCall, args, [...customTesters, iterableEquality]),
|
1475
|
+
`expected ${ordinalOf(
|
1476
|
+
times
|
1477
|
+
)} "${spyName}" call to have been called with #{exp}${isCalled ? `` : `, but called only ${callCount} times`}`,
|
1478
|
+
`expected ${ordinalOf(
|
1479
|
+
times
|
1480
|
+
)} "${spyName}" call to not have been called with #{exp}`,
|
1481
|
+
args,
|
1482
|
+
nthCall,
|
1483
|
+
isCalled
|
1484
|
+
);
|
1485
|
+
}
|
1486
|
+
);
|
1487
|
+
def(
|
1488
|
+
["toHaveBeenLastCalledWith", "lastCalledWith"],
|
1489
|
+
function(...args) {
|
1490
|
+
const spy = getSpy(this);
|
1491
|
+
const spyName = spy.getMockName();
|
1492
|
+
const lastCall = spy.mock.calls[spy.mock.calls.length - 1];
|
1493
|
+
this.assert(
|
1494
|
+
equals(lastCall, args, [...customTesters, iterableEquality]),
|
1495
|
+
`expected last "${spyName}" call to have been called with #{exp}`,
|
1496
|
+
`expected last "${spyName}" call to not have been called with #{exp}`,
|
1497
|
+
args,
|
1498
|
+
lastCall
|
1499
|
+
);
|
1500
|
+
}
|
1501
|
+
);
|
1502
|
+
def(
|
1503
|
+
["toThrow", "toThrowError"],
|
1504
|
+
function(expected) {
|
1505
|
+
if (typeof expected === "string" || typeof expected === "undefined" || expected instanceof RegExp) {
|
1506
|
+
return this.throws(expected);
|
1507
|
+
}
|
1508
|
+
const obj = this._obj;
|
1509
|
+
const promise = utils.flag(this, "promise");
|
1510
|
+
const isNot = utils.flag(this, "negate");
|
1511
|
+
let thrown = null;
|
1512
|
+
if (promise === "rejects") {
|
1513
|
+
thrown = obj;
|
1514
|
+
} else if (promise === "resolves" && typeof obj !== "function") {
|
1515
|
+
if (!isNot) {
|
1516
|
+
const message = utils.flag(this, "message") || "expected promise to throw an error, but it didn't";
|
1517
|
+
const error = {
|
1518
|
+
showDiff: false
|
1519
|
+
};
|
1520
|
+
throw new AssertionError(message, error, utils.flag(this, "ssfi"));
|
1521
|
+
} else {
|
1522
|
+
return;
|
1523
|
+
}
|
1361
1524
|
} else {
|
1362
|
-
|
1525
|
+
let isThrow = false;
|
1526
|
+
try {
|
1527
|
+
obj();
|
1528
|
+
} catch (err) {
|
1529
|
+
isThrow = true;
|
1530
|
+
thrown = err;
|
1531
|
+
}
|
1532
|
+
if (!isThrow && !isNot) {
|
1533
|
+
const message = utils.flag(this, "message") || "expected function to throw an error, but it didn't";
|
1534
|
+
const error = {
|
1535
|
+
showDiff: false
|
1536
|
+
};
|
1537
|
+
throw new AssertionError(message, error, utils.flag(this, "ssfi"));
|
1538
|
+
}
|
1363
1539
|
}
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1540
|
+
if (typeof expected === "function") {
|
1541
|
+
const name = expected.name || expected.prototype.constructor.name;
|
1542
|
+
return this.assert(
|
1543
|
+
thrown && thrown instanceof expected,
|
1544
|
+
`expected error to be instance of ${name}`,
|
1545
|
+
`expected error not to be instance of ${name}`,
|
1546
|
+
expected,
|
1547
|
+
thrown
|
1548
|
+
);
|
1371
1549
|
}
|
1372
|
-
if (
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1550
|
+
if (expected instanceof Error) {
|
1551
|
+
return this.assert(
|
1552
|
+
thrown && expected.message === thrown.message,
|
1553
|
+
`expected error to have message: ${expected.message}`,
|
1554
|
+
`expected error not to have message: ${expected.message}`,
|
1555
|
+
expected.message,
|
1556
|
+
thrown && thrown.message
|
1557
|
+
);
|
1378
1558
|
}
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1559
|
+
if (typeof expected === "object" && "asymmetricMatch" in expected && typeof expected.asymmetricMatch === "function") {
|
1560
|
+
const matcher = expected;
|
1561
|
+
return this.assert(
|
1562
|
+
thrown && matcher.asymmetricMatch(thrown),
|
1563
|
+
"expected error to match asymmetric matcher",
|
1564
|
+
"expected error not to match asymmetric matcher",
|
1565
|
+
matcher,
|
1566
|
+
thrown
|
1567
|
+
);
|
1568
|
+
}
|
1569
|
+
throw new Error(
|
1570
|
+
`"toThrow" expects string, RegExp, function, Error instance or asymmetric matcher, got "${typeof expected}"`
|
1388
1571
|
);
|
1389
1572
|
}
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1573
|
+
);
|
1574
|
+
[
|
1575
|
+
{
|
1576
|
+
name: "toHaveResolved",
|
1577
|
+
condition: (spy) => spy.mock.settledResults.length > 0 && spy.mock.settledResults.some(({ type }) => type === "fulfilled"),
|
1578
|
+
action: "resolved"
|
1579
|
+
},
|
1580
|
+
{
|
1581
|
+
name: ["toHaveReturned", "toReturn"],
|
1582
|
+
condition: (spy) => spy.mock.calls.length > 0 && spy.mock.results.some(({ type }) => type !== "throw"),
|
1583
|
+
action: "called"
|
1398
1584
|
}
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1585
|
+
].forEach(({ name, condition, action }) => {
|
1586
|
+
def(name, function() {
|
1587
|
+
const spy = getSpy(this);
|
1588
|
+
const spyName = spy.getMockName();
|
1589
|
+
const pass = condition(spy);
|
1590
|
+
this.assert(
|
1591
|
+
pass,
|
1592
|
+
`expected "${spyName}" to be successfully ${action} at least once`,
|
1593
|
+
`expected "${spyName}" to not be successfully ${action}`,
|
1594
|
+
pass,
|
1595
|
+
!pass,
|
1596
|
+
false
|
1407
1597
|
);
|
1408
|
-
}
|
1409
|
-
throw new Error(`"toThrow" expects string, RegExp, function, Error instance or asymmetric matcher, got "${typeof expected}"`);
|
1410
|
-
});
|
1411
|
-
def(["toHaveReturned", "toReturn"], function() {
|
1412
|
-
const spy = getSpy(this);
|
1413
|
-
const spyName = spy.getMockName();
|
1414
|
-
const calledAndNotThrew = spy.mock.calls.length > 0 && spy.mock.results.some(({ type }) => type !== "throw");
|
1415
|
-
this.assert(
|
1416
|
-
calledAndNotThrew,
|
1417
|
-
`expected "${spyName}" to be successfully called at least once`,
|
1418
|
-
`expected "${spyName}" to not be successfully called`,
|
1419
|
-
calledAndNotThrew,
|
1420
|
-
!calledAndNotThrew,
|
1421
|
-
false
|
1422
|
-
);
|
1423
|
-
});
|
1424
|
-
def(["toHaveReturnedTimes", "toReturnTimes"], function(times) {
|
1425
|
-
const spy = getSpy(this);
|
1426
|
-
const spyName = spy.getMockName();
|
1427
|
-
const successfulReturns = spy.mock.results.reduce((success, { type }) => type === "throw" ? success : ++success, 0);
|
1428
|
-
this.assert(
|
1429
|
-
successfulReturns === times,
|
1430
|
-
`expected "${spyName}" to be successfully called ${times} times`,
|
1431
|
-
`expected "${spyName}" to not be successfully called ${times} times`,
|
1432
|
-
`expected number of returns: ${times}`,
|
1433
|
-
`received number of returns: ${successfulReturns}`,
|
1434
|
-
false
|
1435
|
-
);
|
1598
|
+
});
|
1436
1599
|
});
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1600
|
+
[
|
1601
|
+
{
|
1602
|
+
name: "toHaveResolvedTimes",
|
1603
|
+
condition: (spy, times) => spy.mock.settledResults.reduce(
|
1604
|
+
(s, { type }) => type === "fulfilled" ? ++s : s,
|
1605
|
+
0
|
1606
|
+
) === times,
|
1607
|
+
action: "resolved"
|
1608
|
+
},
|
1609
|
+
{
|
1610
|
+
name: ["toHaveReturnedTimes", "toReturnTimes"],
|
1611
|
+
condition: (spy, times) => spy.mock.results.reduce(
|
1612
|
+
(s, { type }) => type === "throw" ? s : ++s,
|
1613
|
+
0
|
1614
|
+
) === times,
|
1615
|
+
action: "called"
|
1616
|
+
}
|
1617
|
+
].forEach(({ name, condition, action }) => {
|
1618
|
+
def(name, function(times) {
|
1619
|
+
const spy = getSpy(this);
|
1620
|
+
const spyName = spy.getMockName();
|
1621
|
+
const pass = condition(spy, times);
|
1622
|
+
this.assert(
|
1445
1623
|
pass,
|
1446
|
-
`expected "${spyName}" to
|
1447
|
-
`expected "${spyName}" to not
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1624
|
+
`expected "${spyName}" to be successfully ${action} ${times} times`,
|
1625
|
+
`expected "${spyName}" to not be successfully ${action} ${times} times`,
|
1626
|
+
`expected resolved times: ${times}`,
|
1627
|
+
`received resolved times: ${pass}`,
|
1628
|
+
false
|
1629
|
+
);
|
1630
|
+
});
|
1453
1631
|
});
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1632
|
+
[
|
1633
|
+
{
|
1634
|
+
name: "toHaveResolvedWith",
|
1635
|
+
condition: (spy, value) => spy.mock.settledResults.some(
|
1636
|
+
({ type, value: result }) => type === "fulfilled" && equals(value, result)
|
1637
|
+
),
|
1638
|
+
action: "resolve"
|
1639
|
+
},
|
1640
|
+
{
|
1641
|
+
name: ["toHaveReturnedWith", "toReturnWith"],
|
1642
|
+
condition: (spy, value) => spy.mock.results.some(
|
1643
|
+
({ type, value: result }) => type === "return" && equals(value, result)
|
1644
|
+
),
|
1645
|
+
action: "return"
|
1646
|
+
}
|
1647
|
+
].forEach(({ name, condition, action }) => {
|
1648
|
+
def(name, function(value) {
|
1649
|
+
const spy = getSpy(this);
|
1650
|
+
const pass = condition(spy, value);
|
1651
|
+
const isNot = utils.flag(this, "negate");
|
1652
|
+
if (pass && isNot || !pass && !isNot) {
|
1653
|
+
const spyName = spy.getMockName();
|
1654
|
+
const msg = utils.getMessage(this, [
|
1655
|
+
pass,
|
1656
|
+
`expected "${spyName}" to ${action} with: #{exp} at least once`,
|
1657
|
+
`expected "${spyName}" to not ${action} with: #{exp}`,
|
1658
|
+
value
|
1659
|
+
]);
|
1660
|
+
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
1661
|
+
throw new AssertionError(formatReturns(spy, results, msg, value));
|
1662
|
+
}
|
1663
|
+
});
|
1466
1664
|
});
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1665
|
+
[
|
1666
|
+
{
|
1667
|
+
name: "toHaveLastResolvedWith",
|
1668
|
+
condition: (spy, value) => {
|
1669
|
+
const result = spy.mock.settledResults[spy.mock.settledResults.length - 1];
|
1670
|
+
return result && result.type === "fulfilled" && equals(result.value, value);
|
1671
|
+
},
|
1672
|
+
action: "resolve"
|
1673
|
+
},
|
1674
|
+
{
|
1675
|
+
name: ["toHaveLastReturnedWith", "lastReturnedWith"],
|
1676
|
+
condition: (spy, value) => {
|
1677
|
+
const result = spy.mock.results[spy.mock.results.length - 1];
|
1678
|
+
return result && result.type === "return" && equals(result.value, value);
|
1679
|
+
},
|
1680
|
+
action: "return"
|
1681
|
+
}
|
1682
|
+
].forEach(({ name, condition, action }) => {
|
1683
|
+
def(name, function(value) {
|
1684
|
+
const spy = getSpy(this);
|
1685
|
+
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
1686
|
+
const result = results[results.length - 1];
|
1687
|
+
const spyName = spy.getMockName();
|
1688
|
+
this.assert(
|
1689
|
+
condition(spy, value),
|
1690
|
+
`expected last "${spyName}" call to ${action} #{exp}`,
|
1691
|
+
`expected last "${spyName}" call to not ${action} #{exp}`,
|
1692
|
+
value,
|
1693
|
+
result == null ? void 0 : result.value
|
1694
|
+
);
|
1695
|
+
});
|
1696
|
+
});
|
1697
|
+
[
|
1698
|
+
{
|
1699
|
+
name: "toHaveNthResolvedWith",
|
1700
|
+
condition: (spy, index, value) => {
|
1701
|
+
const result = spy.mock.settledResults[index - 1];
|
1702
|
+
return result && result.type === "fulfilled" && equals(result.value, value);
|
1703
|
+
},
|
1704
|
+
action: "resolve"
|
1705
|
+
},
|
1706
|
+
{
|
1707
|
+
name: ["toHaveNthReturnedWith", "nthReturnedWith"],
|
1708
|
+
condition: (spy, index, value) => {
|
1709
|
+
const result = spy.mock.results[index - 1];
|
1710
|
+
return result && result.type === "return" && equals(result.value, value);
|
1711
|
+
},
|
1712
|
+
action: "return"
|
1713
|
+
}
|
1714
|
+
].forEach(({ name, condition, action }) => {
|
1715
|
+
def(name, function(nthCall, value) {
|
1716
|
+
const spy = getSpy(this);
|
1717
|
+
const spyName = spy.getMockName();
|
1718
|
+
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
1719
|
+
const result = results[nthCall - 1];
|
1720
|
+
const ordinalCall = `${ordinalOf(nthCall)} call`;
|
1721
|
+
this.assert(
|
1722
|
+
condition(spy, nthCall, value),
|
1723
|
+
`expected ${ordinalCall} "${spyName}" call to ${action} #{exp}`,
|
1724
|
+
`expected ${ordinalCall} "${spyName}" call to not ${action} #{exp}`,
|
1725
|
+
value,
|
1726
|
+
result == null ? void 0 : result.value
|
1727
|
+
);
|
1728
|
+
});
|
1483
1729
|
});
|
1484
1730
|
def("toSatisfy", function(matcher, message) {
|
1485
1731
|
return this.be.satisfy(matcher, message);
|
1486
1732
|
});
|
1487
|
-
|
1488
|
-
const
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
const obj = utils.flag(this, "object");
|
1493
|
-
if (typeof (obj == null ? void 0 : obj.then) !== "function")
|
1494
|
-
throw new TypeError(`You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`);
|
1495
|
-
const proxy = new Proxy(this, {
|
1496
|
-
get: (target, key, receiver) => {
|
1497
|
-
const result = Reflect.get(target, key, receiver);
|
1498
|
-
if (typeof result !== "function")
|
1499
|
-
return result instanceof chai.Assertion ? proxy : result;
|
1500
|
-
return async (...args) => {
|
1501
|
-
const promise = obj.then(
|
1502
|
-
(value) => {
|
1503
|
-
utils.flag(this, "object", value);
|
1504
|
-
return result.call(this, ...args);
|
1505
|
-
},
|
1506
|
-
(err) => {
|
1507
|
-
const _error = new AssertionError(
|
1508
|
-
`promise rejected "${utils.inspect(err)}" instead of resolving`,
|
1509
|
-
{ showDiff: false }
|
1510
|
-
);
|
1511
|
-
_error.cause = err;
|
1512
|
-
_error.stack = error.stack.replace(error.message, _error.message);
|
1513
|
-
throw _error;
|
1514
|
-
}
|
1515
|
-
);
|
1516
|
-
return recordAsyncExpect(test, promise);
|
1517
|
-
};
|
1518
|
-
}
|
1519
|
-
});
|
1520
|
-
return proxy;
|
1733
|
+
def("withContext", function(context) {
|
1734
|
+
for (const key in context) {
|
1735
|
+
utils.flag(this, key, context[key]);
|
1736
|
+
}
|
1737
|
+
return this;
|
1521
1738
|
});
|
1522
|
-
utils.addProperty(
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
return result instanceof chai.Assertion ? proxy : result;
|
1536
|
-
return async (...args) => {
|
1537
|
-
const promise = wrapper.then(
|
1538
|
-
(value) => {
|
1539
|
-
const _error = new AssertionError(
|
1540
|
-
`promise resolved "${utils.inspect(value)}" instead of rejecting`,
|
1541
|
-
{ showDiff: true, expected: new Error("rejected promise"), actual: value }
|
1542
|
-
);
|
1543
|
-
_error.stack = error.stack.replace(error.message, _error.message);
|
1544
|
-
throw _error;
|
1545
|
-
},
|
1546
|
-
(err) => {
|
1547
|
-
utils.flag(this, "object", err);
|
1548
|
-
return result.call(this, ...args);
|
1549
|
-
}
|
1550
|
-
);
|
1551
|
-
return recordAsyncExpect(test, promise);
|
1552
|
-
};
|
1739
|
+
utils.addProperty(
|
1740
|
+
chai.Assertion.prototype,
|
1741
|
+
"resolves",
|
1742
|
+
function __VITEST_RESOLVES__() {
|
1743
|
+
const error = new Error("resolves");
|
1744
|
+
utils.flag(this, "promise", "resolves");
|
1745
|
+
utils.flag(this, "error", error);
|
1746
|
+
const test = utils.flag(this, "vitest-test");
|
1747
|
+
const obj = utils.flag(this, "object");
|
1748
|
+
if (utils.flag(this, "poll")) {
|
1749
|
+
throw new SyntaxError(
|
1750
|
+
`expect.poll() is not supported in combination with .resolves`
|
1751
|
+
);
|
1553
1752
|
}
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1753
|
+
if (typeof (obj == null ? void 0 : obj.then) !== "function") {
|
1754
|
+
throw new TypeError(
|
1755
|
+
`You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`
|
1756
|
+
);
|
1757
|
+
}
|
1758
|
+
const proxy = new Proxy(this, {
|
1759
|
+
get: (target, key, receiver) => {
|
1760
|
+
const result = Reflect.get(target, key, receiver);
|
1761
|
+
if (typeof result !== "function") {
|
1762
|
+
return result instanceof chai.Assertion ? proxy : result;
|
1763
|
+
}
|
1764
|
+
return async (...args) => {
|
1765
|
+
const promise = obj.then(
|
1766
|
+
(value) => {
|
1767
|
+
utils.flag(this, "object", value);
|
1768
|
+
return result.call(this, ...args);
|
1769
|
+
},
|
1770
|
+
(err) => {
|
1771
|
+
const _error = new AssertionError(
|
1772
|
+
`promise rejected "${utils.inspect(
|
1773
|
+
err
|
1774
|
+
)}" instead of resolving`,
|
1775
|
+
{ showDiff: false }
|
1776
|
+
);
|
1777
|
+
_error.cause = err;
|
1778
|
+
_error.stack = error.stack.replace(
|
1779
|
+
error.message,
|
1780
|
+
_error.message
|
1781
|
+
);
|
1782
|
+
throw _error;
|
1783
|
+
}
|
1784
|
+
);
|
1785
|
+
return recordAsyncExpect(test, promise);
|
1786
|
+
};
|
1787
|
+
}
|
1788
|
+
});
|
1789
|
+
return proxy;
|
1790
|
+
}
|
1791
|
+
);
|
1792
|
+
utils.addProperty(
|
1793
|
+
chai.Assertion.prototype,
|
1794
|
+
"rejects",
|
1795
|
+
function __VITEST_REJECTS__() {
|
1796
|
+
const error = new Error("rejects");
|
1797
|
+
utils.flag(this, "promise", "rejects");
|
1798
|
+
utils.flag(this, "error", error);
|
1799
|
+
const test = utils.flag(this, "vitest-test");
|
1800
|
+
const obj = utils.flag(this, "object");
|
1801
|
+
const wrapper = typeof obj === "function" ? obj() : obj;
|
1802
|
+
if (utils.flag(this, "poll")) {
|
1803
|
+
throw new SyntaxError(
|
1804
|
+
`expect.poll() is not supported in combination with .rejects`
|
1805
|
+
);
|
1806
|
+
}
|
1807
|
+
if (typeof (wrapper == null ? void 0 : wrapper.then) !== "function") {
|
1808
|
+
throw new TypeError(
|
1809
|
+
`You must provide a Promise to expect() when using .rejects, not '${typeof wrapper}'.`
|
1810
|
+
);
|
1811
|
+
}
|
1812
|
+
const proxy = new Proxy(this, {
|
1813
|
+
get: (target, key, receiver) => {
|
1814
|
+
const result = Reflect.get(target, key, receiver);
|
1815
|
+
if (typeof result !== "function") {
|
1816
|
+
return result instanceof chai.Assertion ? proxy : result;
|
1817
|
+
}
|
1818
|
+
return async (...args) => {
|
1819
|
+
const promise = wrapper.then(
|
1820
|
+
(value) => {
|
1821
|
+
const _error = new AssertionError(
|
1822
|
+
`promise resolved "${utils.inspect(
|
1823
|
+
value
|
1824
|
+
)}" instead of rejecting`,
|
1825
|
+
{
|
1826
|
+
showDiff: true,
|
1827
|
+
expected: new Error("rejected promise"),
|
1828
|
+
actual: value
|
1829
|
+
}
|
1830
|
+
);
|
1831
|
+
_error.stack = error.stack.replace(
|
1832
|
+
error.message,
|
1833
|
+
_error.message
|
1834
|
+
);
|
1835
|
+
throw _error;
|
1836
|
+
},
|
1837
|
+
(err) => {
|
1838
|
+
utils.flag(this, "object", err);
|
1839
|
+
return result.call(this, ...args);
|
1840
|
+
}
|
1841
|
+
);
|
1842
|
+
return recordAsyncExpect(test, promise);
|
1843
|
+
};
|
1844
|
+
}
|
1845
|
+
});
|
1846
|
+
return proxy;
|
1847
|
+
}
|
1848
|
+
);
|
1557
1849
|
};
|
1558
1850
|
|
1559
1851
|
function getMatcherState(assertion, expect) {
|
@@ -1575,7 +1867,9 @@ function getMatcherState(assertion, expect) {
|
|
1575
1867
|
promise,
|
1576
1868
|
equals,
|
1577
1869
|
// needed for built-in jest-snapshots, but we don't use it
|
1578
|
-
suppressedErrors: []
|
1870
|
+
suppressedErrors: [],
|
1871
|
+
soft: util.flag(assertion, "soft"),
|
1872
|
+
poll: util.flag(assertion, "poll")
|
1579
1873
|
};
|
1580
1874
|
return {
|
1581
1875
|
state: matcherState,
|
@@ -1592,71 +1886,91 @@ class JestExtendError extends Error {
|
|
1592
1886
|
}
|
1593
1887
|
function JestExtendPlugin(c, expect, matchers) {
|
1594
1888
|
return (_, utils) => {
|
1595
|
-
Object.entries(matchers).forEach(
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
utils.addMethod(c.Assertion.prototype, expectAssertionName, softWrapper);
|
1612
|
-
class CustomMatcher extends AsymmetricMatcher {
|
1613
|
-
constructor(inverse = false, ...sample) {
|
1614
|
-
super(sample, inverse);
|
1615
|
-
}
|
1616
|
-
asymmetricMatch(other) {
|
1617
|
-
const { pass } = expectAssertion.call(
|
1618
|
-
this.getMatcherContext(expect),
|
1619
|
-
other,
|
1620
|
-
...this.sample
|
1621
|
-
);
|
1622
|
-
return this.inverse ? !pass : pass;
|
1623
|
-
}
|
1624
|
-
toString() {
|
1625
|
-
return `${this.inverse ? "not." : ""}${expectAssertionName}`;
|
1626
|
-
}
|
1627
|
-
getExpectedType() {
|
1628
|
-
return "any";
|
1889
|
+
Object.entries(matchers).forEach(
|
1890
|
+
([expectAssertionName, expectAssertion]) => {
|
1891
|
+
function expectWrapper(...args) {
|
1892
|
+
const { state, isNot, obj } = getMatcherState(this, expect);
|
1893
|
+
const result = expectAssertion.call(state, obj, ...args);
|
1894
|
+
if (result && typeof result === "object" && result instanceof Promise) {
|
1895
|
+
return result.then(({ pass: pass2, message: message2, actual: actual2, expected: expected2 }) => {
|
1896
|
+
if (pass2 && isNot || !pass2 && !isNot) {
|
1897
|
+
throw new JestExtendError(message2(), actual2, expected2);
|
1898
|
+
}
|
1899
|
+
});
|
1900
|
+
}
|
1901
|
+
const { pass, message, actual, expected } = result;
|
1902
|
+
if (pass && isNot || !pass && !isNot) {
|
1903
|
+
throw new JestExtendError(message(), actual, expected);
|
1904
|
+
}
|
1629
1905
|
}
|
1630
|
-
|
1631
|
-
|
1906
|
+
const softWrapper = wrapSoft(utils, expectWrapper);
|
1907
|
+
utils.addMethod(
|
1908
|
+
globalThis[JEST_MATCHERS_OBJECT].matchers,
|
1909
|
+
expectAssertionName,
|
1910
|
+
softWrapper
|
1911
|
+
);
|
1912
|
+
utils.addMethod(
|
1913
|
+
c.Assertion.prototype,
|
1914
|
+
expectAssertionName,
|
1915
|
+
softWrapper
|
1916
|
+
);
|
1917
|
+
class CustomMatcher extends AsymmetricMatcher {
|
1918
|
+
constructor(inverse = false, ...sample) {
|
1919
|
+
super(sample, inverse);
|
1920
|
+
}
|
1921
|
+
asymmetricMatch(other) {
|
1922
|
+
const { pass } = expectAssertion.call(
|
1923
|
+
this.getMatcherContext(expect),
|
1924
|
+
other,
|
1925
|
+
...this.sample
|
1926
|
+
);
|
1927
|
+
return this.inverse ? !pass : pass;
|
1928
|
+
}
|
1929
|
+
toString() {
|
1930
|
+
return `${this.inverse ? "not." : ""}${expectAssertionName}`;
|
1931
|
+
}
|
1932
|
+
getExpectedType() {
|
1933
|
+
return "any";
|
1934
|
+
}
|
1935
|
+
toAsymmetricMatcher() {
|
1936
|
+
return `${this.toString()}<${this.sample.map(String).join(", ")}>`;
|
1937
|
+
}
|
1632
1938
|
}
|
1939
|
+
const customMatcher = (...sample) => new CustomMatcher(false, ...sample);
|
1940
|
+
Object.defineProperty(expect, expectAssertionName, {
|
1941
|
+
configurable: true,
|
1942
|
+
enumerable: true,
|
1943
|
+
value: customMatcher,
|
1944
|
+
writable: true
|
1945
|
+
});
|
1946
|
+
Object.defineProperty(expect.not, expectAssertionName, {
|
1947
|
+
configurable: true,
|
1948
|
+
enumerable: true,
|
1949
|
+
value: (...sample) => new CustomMatcher(true, ...sample),
|
1950
|
+
writable: true
|
1951
|
+
});
|
1952
|
+
Object.defineProperty(
|
1953
|
+
globalThis[ASYMMETRIC_MATCHERS_OBJECT],
|
1954
|
+
expectAssertionName,
|
1955
|
+
{
|
1956
|
+
configurable: true,
|
1957
|
+
enumerable: true,
|
1958
|
+
value: customMatcher,
|
1959
|
+
writable: true
|
1960
|
+
}
|
1961
|
+
);
|
1633
1962
|
}
|
1634
|
-
|
1635
|
-
Object.defineProperty(expect, expectAssertionName, {
|
1636
|
-
configurable: true,
|
1637
|
-
enumerable: true,
|
1638
|
-
value: customMatcher,
|
1639
|
-
writable: true
|
1640
|
-
});
|
1641
|
-
Object.defineProperty(expect.not, expectAssertionName, {
|
1642
|
-
configurable: true,
|
1643
|
-
enumerable: true,
|
1644
|
-
value: (...sample) => new CustomMatcher(true, ...sample),
|
1645
|
-
writable: true
|
1646
|
-
});
|
1647
|
-
Object.defineProperty(globalThis[ASYMMETRIC_MATCHERS_OBJECT], expectAssertionName, {
|
1648
|
-
configurable: true,
|
1649
|
-
enumerable: true,
|
1650
|
-
value: customMatcher,
|
1651
|
-
writable: true
|
1652
|
-
});
|
1653
|
-
});
|
1963
|
+
);
|
1654
1964
|
};
|
1655
1965
|
}
|
1656
1966
|
const JestExtend = (chai, utils) => {
|
1657
|
-
utils.addMethod(
|
1658
|
-
|
1659
|
-
|
1967
|
+
utils.addMethod(
|
1968
|
+
chai.expect,
|
1969
|
+
"extend",
|
1970
|
+
(expect, expects) => {
|
1971
|
+
use(JestExtendPlugin(chai, expect, expects));
|
1972
|
+
}
|
1973
|
+
);
|
1660
1974
|
};
|
1661
1975
|
|
1662
1976
|
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|