@vitest/expect 2.0.0-beta.2 → 2.0.0-beta.4
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/dist/index.d.ts +10 -8
- package/dist/index.js +167 -81
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
@@ -65,6 +65,7 @@ interface MatcherState {
|
|
65
65
|
subsetEquality: Tester;
|
66
66
|
};
|
67
67
|
soft?: boolean;
|
68
|
+
poll?: boolean;
|
68
69
|
}
|
69
70
|
interface SyncExpectationResult {
|
70
71
|
pass: boolean;
|
@@ -80,12 +81,7 @@ interface RawMatcherFn<T extends MatcherState = MatcherState> {
|
|
80
81
|
type MatchersObject<T extends MatcherState = MatcherState> = Record<string, RawMatcherFn<T>>;
|
81
82
|
interface ExpectStatic extends Chai.ExpectStatic, AsymmetricMatchersContaining {
|
82
83
|
<T>(actual: T, message?: string): Assertion<T>;
|
83
|
-
unreachable: (message?: string) => never;
|
84
|
-
soft: <T>(actual: T, message?: string) => Assertion<T>;
|
85
84
|
extend: (expects: MatchersObject) => void;
|
86
|
-
addEqualityTesters: (testers: Array<Tester>) => void;
|
87
|
-
assertions: (expected: number) => void;
|
88
|
-
hasAssertions: () => void;
|
89
85
|
anything: () => any;
|
90
86
|
any: (constructor: unknown) => any;
|
91
87
|
getState: () => MatcherState;
|
@@ -150,12 +146,18 @@ type VitestAssertion<A, T> = {
|
|
150
146
|
type Promisify<O> = {
|
151
147
|
[K in keyof O]: O[K] extends (...args: infer A) => infer R ? O extends R ? Promisify<O[K]> : (...args: A) => Promise<R> : O[K];
|
152
148
|
};
|
149
|
+
type PromisifyAssertion<T> = Promisify<Assertion<T>>;
|
153
150
|
interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAssertion<T> {
|
154
151
|
toBeTypeOf: (expected: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => void;
|
155
152
|
toHaveBeenCalledOnce: () => void;
|
156
153
|
toSatisfy: <E>(matcher: (value: E) => boolean, message?: string) => void;
|
157
|
-
|
158
|
-
|
154
|
+
toHaveResolved: () => void;
|
155
|
+
toHaveResolvedWith: <E>(value: E) => void;
|
156
|
+
toHaveResolvedTimes: (times: number) => void;
|
157
|
+
toHaveLastResolvedWith: <E>(value: E) => void;
|
158
|
+
toHaveNthResolvedWith: <E>(nthCall: number, value: E) => void;
|
159
|
+
resolves: PromisifyAssertion<T>;
|
160
|
+
rejects: PromisifyAssertion<T>;
|
159
161
|
}
|
160
162
|
declare global {
|
161
163
|
namespace jest {
|
@@ -255,4 +257,4 @@ declare const JestChaiExpect: ChaiPlugin;
|
|
255
257
|
|
256
258
|
declare const JestExtend: ChaiPlugin;
|
257
259
|
|
258
|
-
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, type Assertion, AsymmetricMatcher, type AsymmetricMatcherInterface, type AsymmetricMatchersContaining, type AsyncExpectationResult, type ChaiPlugin, type ExpectStatic, type ExpectationResult, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, type JestAssertion, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, type MatcherHintOptions, type MatcherState, type MatchersObject, ObjectContaining, type RawMatcherFn, StringContaining, StringMatching, type SyncExpectationResult, type Tester, type TesterContext, addCustomEqualityTesters, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|
260
|
+
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, type Assertion, AsymmetricMatcher, type AsymmetricMatcherInterface, type AsymmetricMatchersContaining, type AsyncExpectationResult, type ChaiPlugin, type ExpectStatic, type ExpectationResult, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, type JestAssertion, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, type MatcherHintOptions, type MatcherState, type MatchersObject, ObjectContaining, type PromisifyAssertion, type RawMatcherFn, StringContaining, StringMatching, type SyncExpectationResult, type Tester, type TesterContext, addCustomEqualityTesters, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|
package/dist/index.js
CHANGED
@@ -254,7 +254,7 @@ function isDomNode(obj) {
|
|
254
254
|
function fnNameFor(func) {
|
255
255
|
if (func.name)
|
256
256
|
return func.name;
|
257
|
-
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s
|
257
|
+
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s*(?:\*\s*)?([\w$]+)\s*\(/);
|
258
258
|
return matches ? matches[1] : "<anonymous>";
|
259
259
|
}
|
260
260
|
function getPrototype(obj) {
|
@@ -661,7 +661,7 @@ class Any extends AsymmetricMatcher {
|
|
661
661
|
if (func.name)
|
662
662
|
return func.name;
|
663
663
|
const functionToString = Function.prototype.toString;
|
664
|
-
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s
|
664
|
+
const matches = functionToString.call(func).match(/^(?:async)?\s*function\s*(?:\*\s*)?([\w$]+)\s*\(/);
|
665
665
|
return matches ? matches[1] : "<anonymous>";
|
666
666
|
}
|
667
667
|
asymmetricMatch(other) {
|
@@ -817,10 +817,9 @@ function recordAsyncExpect(test, promise) {
|
|
817
817
|
function wrapSoft(utils, fn) {
|
818
818
|
return function(...args) {
|
819
819
|
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)
|
820
|
+
if (!utils.flag(this, "soft"))
|
823
821
|
return fn.apply(this, args);
|
822
|
+
const test = utils.flag(this, "vitest-test");
|
824
823
|
if (!test)
|
825
824
|
throw new Error("expect.soft() can only be used inside a test");
|
826
825
|
try {
|
@@ -1205,7 +1204,7 @@ const JestChaiExpect = (chai, utils) => {
|
|
1205
1204
|
return `${i}rd`;
|
1206
1205
|
return `${i}th`;
|
1207
1206
|
};
|
1208
|
-
const formatCalls = (spy, msg,
|
1207
|
+
const formatCalls = (spy, msg, showActualCall) => {
|
1209
1208
|
if (spy.mock.calls) {
|
1210
1209
|
msg += c().gray(`
|
1211
1210
|
|
@@ -1215,8 +1214,8 @@ ${spy.mock.calls.map((callArg, i) => {
|
|
1215
1214
|
let methodCall = c().bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call:
|
1216
1215
|
|
1217
1216
|
`);
|
1218
|
-
if (
|
1219
|
-
methodCall += diff(
|
1217
|
+
if (showActualCall)
|
1218
|
+
methodCall += diff(showActualCall, callArg, { omitAnnotationLines: true });
|
1220
1219
|
else
|
1221
1220
|
methodCall += stringify(callArg).split("\n").map((line) => ` ${line}`).join("\n");
|
1222
1221
|
methodCall += "\n";
|
@@ -1229,17 +1228,17 @@ Number of calls: ${c().bold(spy.mock.calls.length)}
|
|
1229
1228
|
`);
|
1230
1229
|
return msg;
|
1231
1230
|
};
|
1232
|
-
const formatReturns = (spy, msg,
|
1231
|
+
const formatReturns = (spy, results, msg, showActualReturn) => {
|
1233
1232
|
msg += c().gray(`
|
1234
1233
|
|
1235
1234
|
Received:
|
1236
1235
|
|
1237
|
-
${
|
1236
|
+
${results.map((callReturn, i) => {
|
1238
1237
|
let methodCall = c().bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call return:
|
1239
1238
|
|
1240
1239
|
`);
|
1241
|
-
if (
|
1242
|
-
methodCall += diff(
|
1240
|
+
if (showActualReturn)
|
1241
|
+
methodCall += diff(showActualReturn, callReturn.value, { omitAnnotationLines: true });
|
1243
1242
|
else
|
1244
1243
|
methodCall += stringify(callReturn).split("\n").map((line) => ` ${line}`).join("\n");
|
1245
1244
|
methodCall += "\n";
|
@@ -1408,88 +1407,171 @@ Number of calls: ${c().bold(spy.mock.calls.length)}
|
|
1408
1407
|
}
|
1409
1408
|
throw new Error(`"toThrow" expects string, RegExp, function, Error instance or asymmetric matcher, got "${typeof expected}"`);
|
1410
1409
|
});
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
);
|
1410
|
+
[
|
1411
|
+
{
|
1412
|
+
name: "toHaveResolved",
|
1413
|
+
condition: (spy) => spy.mock.settledResults.length > 0 && spy.mock.settledResults.some(({ type }) => type === "fulfilled"),
|
1414
|
+
action: "resolved"
|
1415
|
+
},
|
1416
|
+
{
|
1417
|
+
name: ["toHaveReturned", "toReturn"],
|
1418
|
+
condition: (spy) => spy.mock.calls.length > 0 && spy.mock.results.some(({ type }) => type !== "throw"),
|
1419
|
+
action: "called"
|
1420
|
+
}
|
1421
|
+
].forEach(({ name, condition, action }) => {
|
1422
|
+
def(name, function() {
|
1423
|
+
const spy = getSpy(this);
|
1424
|
+
const spyName = spy.getMockName();
|
1425
|
+
const pass = condition(spy);
|
1426
|
+
this.assert(
|
1427
|
+
pass,
|
1428
|
+
`expected "${spyName}" to be successfully ${action} at least once`,
|
1429
|
+
`expected "${spyName}" to not be successfully ${action}`,
|
1430
|
+
pass,
|
1431
|
+
!pass,
|
1432
|
+
false
|
1433
|
+
);
|
1434
|
+
});
|
1436
1435
|
});
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
[
|
1436
|
+
[
|
1437
|
+
{
|
1438
|
+
name: "toHaveResolvedTimes",
|
1439
|
+
condition: (spy, times) => spy.mock.settledResults.reduce((s, { type }) => type === "fulfilled" ? ++s : s, 0) === times,
|
1440
|
+
action: "resolved"
|
1441
|
+
},
|
1442
|
+
{
|
1443
|
+
name: ["toHaveReturnedTimes", "toReturnTimes"],
|
1444
|
+
condition: (spy, times) => spy.mock.results.reduce((s, { type }) => type === "throw" ? s : ++s, 0) === times,
|
1445
|
+
action: "called"
|
1446
|
+
}
|
1447
|
+
].forEach(({ name, condition, action }) => {
|
1448
|
+
def(name, function(times) {
|
1449
|
+
const spy = getSpy(this);
|
1450
|
+
const spyName = spy.getMockName();
|
1451
|
+
const pass = condition(spy, times);
|
1452
|
+
this.assert(
|
1445
1453
|
pass,
|
1446
|
-
`expected "${spyName}" to
|
1447
|
-
`expected "${spyName}" to not
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1454
|
+
`expected "${spyName}" to be successfully ${action} ${times} times`,
|
1455
|
+
`expected "${spyName}" to not be successfully ${action} ${times} times`,
|
1456
|
+
`expected resolved times: ${times}`,
|
1457
|
+
`received resolved times: ${pass}`,
|
1458
|
+
false
|
1459
|
+
);
|
1460
|
+
});
|
1453
1461
|
});
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1462
|
+
[
|
1463
|
+
{
|
1464
|
+
name: "toHaveResolvedWith",
|
1465
|
+
condition: (spy, value) => spy.mock.settledResults.some(({ type, value: result }) => type === "fulfilled" && equals(value, result)),
|
1466
|
+
action: "resolve"
|
1467
|
+
},
|
1468
|
+
{
|
1469
|
+
name: ["toHaveReturnedWith", "toReturnWith"],
|
1470
|
+
condition: (spy, value) => spy.mock.results.some(({ type, value: result }) => type === "return" && equals(value, result)),
|
1471
|
+
action: "return"
|
1472
|
+
}
|
1473
|
+
].forEach(({ name, condition, action }) => {
|
1474
|
+
def(name, function(value) {
|
1475
|
+
const spy = getSpy(this);
|
1476
|
+
const pass = condition(spy, value);
|
1477
|
+
const isNot = utils.flag(this, "negate");
|
1478
|
+
if (pass && isNot || !pass && !isNot) {
|
1479
|
+
const spyName = spy.getMockName();
|
1480
|
+
const msg = utils.getMessage(
|
1481
|
+
this,
|
1482
|
+
[
|
1483
|
+
pass,
|
1484
|
+
`expected "${spyName}" to ${action} with: #{exp} at least once`,
|
1485
|
+
`expected "${spyName}" to not ${action} with: #{exp}`,
|
1486
|
+
value
|
1487
|
+
]
|
1488
|
+
);
|
1489
|
+
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
1490
|
+
throw new AssertionError(formatReturns(spy, results, msg, value));
|
1491
|
+
}
|
1492
|
+
});
|
1466
1493
|
});
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1494
|
+
[
|
1495
|
+
{
|
1496
|
+
name: "toHaveLastResolvedWith",
|
1497
|
+
condition: (spy, value) => {
|
1498
|
+
const result = spy.mock.settledResults[spy.mock.settledResults.length - 1];
|
1499
|
+
return result && result.type === "fulfilled" && equals(result.value, value);
|
1500
|
+
},
|
1501
|
+
action: "resolve"
|
1502
|
+
},
|
1503
|
+
{
|
1504
|
+
name: ["toHaveLastReturnedWith", "lastReturnedWith"],
|
1505
|
+
condition: (spy, value) => {
|
1506
|
+
const result = spy.mock.results[spy.mock.results.length - 1];
|
1507
|
+
return result && result.type === "return" && equals(result.value, value);
|
1508
|
+
},
|
1509
|
+
action: "return"
|
1510
|
+
}
|
1511
|
+
].forEach(({ name, condition, action }) => {
|
1512
|
+
def(name, function(value) {
|
1513
|
+
const spy = getSpy(this);
|
1514
|
+
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
1515
|
+
const result = results[results.length - 1];
|
1516
|
+
const spyName = spy.getMockName();
|
1517
|
+
this.assert(
|
1518
|
+
condition(spy, value),
|
1519
|
+
`expected last "${spyName}" call to ${action} #{exp}`,
|
1520
|
+
`expected last "${spyName}" call to not ${action} #{exp}`,
|
1521
|
+
value,
|
1522
|
+
result == null ? void 0 : result.value
|
1523
|
+
);
|
1524
|
+
});
|
1525
|
+
});
|
1526
|
+
[
|
1527
|
+
{
|
1528
|
+
name: "toHaveNthResolvedWith",
|
1529
|
+
condition: (spy, index, value) => {
|
1530
|
+
const result = spy.mock.settledResults[index - 1];
|
1531
|
+
return result && result.type === "fulfilled" && equals(result.value, value);
|
1532
|
+
},
|
1533
|
+
action: "resolve"
|
1534
|
+
},
|
1535
|
+
{
|
1536
|
+
name: ["toHaveNthReturnedWith", "nthReturnedWith"],
|
1537
|
+
condition: (spy, index, value) => {
|
1538
|
+
const result = spy.mock.results[index - 1];
|
1539
|
+
return result && result.type === "return" && equals(result.value, value);
|
1540
|
+
},
|
1541
|
+
action: "return"
|
1542
|
+
}
|
1543
|
+
].forEach(({ name, condition, action }) => {
|
1544
|
+
def(name, function(nthCall, value) {
|
1545
|
+
const spy = getSpy(this);
|
1546
|
+
const spyName = spy.getMockName();
|
1547
|
+
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
1548
|
+
const result = results[nthCall - 1];
|
1549
|
+
const ordinalCall = `${ordinalOf(nthCall)} call`;
|
1550
|
+
this.assert(
|
1551
|
+
condition(spy, nthCall, value),
|
1552
|
+
`expected ${ordinalCall} "${spyName}" call to ${action} #{exp}`,
|
1553
|
+
`expected ${ordinalCall} "${spyName}" call to not ${action} #{exp}`,
|
1554
|
+
value,
|
1555
|
+
result == null ? void 0 : result.value
|
1556
|
+
);
|
1557
|
+
});
|
1483
1558
|
});
|
1484
1559
|
def("toSatisfy", function(matcher, message) {
|
1485
1560
|
return this.be.satisfy(matcher, message);
|
1486
1561
|
});
|
1562
|
+
def("withContext", function(context) {
|
1563
|
+
for (const key in context)
|
1564
|
+
utils.flag(this, key, context[key]);
|
1565
|
+
return this;
|
1566
|
+
});
|
1487
1567
|
utils.addProperty(chai.Assertion.prototype, "resolves", function __VITEST_RESOLVES__() {
|
1488
1568
|
const error = new Error("resolves");
|
1489
1569
|
utils.flag(this, "promise", "resolves");
|
1490
1570
|
utils.flag(this, "error", error);
|
1491
1571
|
const test = utils.flag(this, "vitest-test");
|
1492
1572
|
const obj = utils.flag(this, "object");
|
1573
|
+
if (utils.flag(this, "poll"))
|
1574
|
+
throw new SyntaxError(`expect.poll() is not supported in combination with .resolves`);
|
1493
1575
|
if (typeof (obj == null ? void 0 : obj.then) !== "function")
|
1494
1576
|
throw new TypeError(`You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`);
|
1495
1577
|
const proxy = new Proxy(this, {
|
@@ -1526,6 +1608,8 @@ Number of calls: ${c().bold(spy.mock.calls.length)}
|
|
1526
1608
|
const test = utils.flag(this, "vitest-test");
|
1527
1609
|
const obj = utils.flag(this, "object");
|
1528
1610
|
const wrapper = typeof obj === "function" ? obj() : obj;
|
1611
|
+
if (utils.flag(this, "poll"))
|
1612
|
+
throw new SyntaxError(`expect.poll() is not supported in combination with .rejects`);
|
1529
1613
|
if (typeof (wrapper == null ? void 0 : wrapper.then) !== "function")
|
1530
1614
|
throw new TypeError(`You must provide a Promise to expect() when using .rejects, not '${typeof wrapper}'.`);
|
1531
1615
|
const proxy = new Proxy(this, {
|
@@ -1575,7 +1659,9 @@ function getMatcherState(assertion, expect) {
|
|
1575
1659
|
promise,
|
1576
1660
|
equals,
|
1577
1661
|
// needed for built-in jest-snapshots, but we don't use it
|
1578
|
-
suppressedErrors: []
|
1662
|
+
suppressedErrors: [],
|
1663
|
+
soft: util.flag(assertion, "soft"),
|
1664
|
+
poll: util.flag(assertion, "poll")
|
1579
1665
|
};
|
1580
1666
|
return {
|
1581
1667
|
state: matcherState,
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitest/expect",
|
3
3
|
"type": "module",
|
4
|
-
"version": "2.0.0-beta.
|
4
|
+
"version": "2.0.0-beta.4",
|
5
5
|
"description": "Jest's expect matchers as a Chai plugin",
|
6
6
|
"license": "MIT",
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
@@ -31,14 +31,14 @@
|
|
31
31
|
],
|
32
32
|
"dependencies": {
|
33
33
|
"chai": "^5.1.1",
|
34
|
-
"@vitest/
|
35
|
-
"@vitest/
|
34
|
+
"@vitest/spy": "2.0.0-beta.4",
|
35
|
+
"@vitest/utils": "2.0.0-beta.4"
|
36
36
|
},
|
37
37
|
"devDependencies": {
|
38
38
|
"@types/chai": "4.3.6",
|
39
39
|
"picocolors": "^1.0.0",
|
40
40
|
"rollup-plugin-copy": "^3.5.0",
|
41
|
-
"@vitest/runner": "2.0.0-beta.
|
41
|
+
"@vitest/runner": "2.0.0-beta.4"
|
42
42
|
},
|
43
43
|
"scripts": {
|
44
44
|
"build": "rimraf dist && rollup -c",
|