@vitest/expect 4.0.0-beta.9 → 4.0.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/dist/index.d.ts +32 -46
- package/dist/index.js +73 -28
- package/package.json +7 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { MockInstance } from '@vitest/spy';
|
|
2
|
-
import {
|
|
2
|
+
import { Constructable } from '@vitest/utils';
|
|
3
3
|
import { Formatter } from 'tinyrainbow';
|
|
4
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
5
|
import { diff, printDiffOrStringify } from '@vitest/utils/diff';
|
|
5
6
|
export { DiffOptions } from '@vitest/utils/diff';
|
|
7
|
+
import { stringify } from '@vitest/utils/display';
|
|
6
8
|
import * as chai from 'chai';
|
|
7
9
|
export { chai };
|
|
8
10
|
|
|
@@ -11,10 +13,8 @@ declare const JEST_MATCHERS_OBJECT: unique symbol;
|
|
|
11
13
|
declare const GLOBAL_EXPECT: unique symbol;
|
|
12
14
|
declare const ASYMMETRIC_MATCHERS_OBJECT: unique symbol;
|
|
13
15
|
|
|
14
|
-
/* eslint-disable unicorn/no-instanceof-builtins -- we check both */
|
|
15
|
-
|
|
16
16
|
interface AsymmetricMatcherInterface {
|
|
17
|
-
asymmetricMatch: (other: unknown) => boolean;
|
|
17
|
+
asymmetricMatch: (other: unknown, customTesters?: Array<Tester>) => boolean;
|
|
18
18
|
toString: () => string;
|
|
19
19
|
getExpectedType?: () => string;
|
|
20
20
|
toAsymmetricMatcher?: () => string;
|
|
@@ -25,11 +25,10 @@ declare abstract class AsymmetricMatcher<
|
|
|
25
25
|
> implements AsymmetricMatcherInterface {
|
|
26
26
|
protected sample: T;
|
|
27
27
|
protected inverse: boolean;
|
|
28
|
-
// should have "jest" to be compatible with its ecosystem
|
|
29
28
|
$$typeof: symbol;
|
|
30
29
|
constructor(sample: T, inverse?: boolean);
|
|
31
30
|
protected getMatcherContext(expect?: Chai.ExpectStatic): State;
|
|
32
|
-
abstract asymmetricMatch(other: unknown): boolean;
|
|
31
|
+
abstract asymmetricMatch(other: unknown, customTesters?: Array<Tester>): boolean;
|
|
33
32
|
abstract toString(): string;
|
|
34
33
|
getExpectedType?(): string;
|
|
35
34
|
toAsymmetricMatcher?(): string;
|
|
@@ -50,13 +49,13 @@ declare class ObjectContaining extends AsymmetricMatcher<Record<string | symbol
|
|
|
50
49
|
getPrototype(obj: object): any;
|
|
51
50
|
hasProperty(obj: object | null, property: string | symbol): boolean;
|
|
52
51
|
getProperties(obj: object): (string | symbol)[];
|
|
53
|
-
asymmetricMatch(other: any): boolean;
|
|
52
|
+
asymmetricMatch(other: any, customTesters?: Array<Tester>): boolean;
|
|
54
53
|
toString(): string;
|
|
55
54
|
getExpectedType(): string;
|
|
56
55
|
}
|
|
57
56
|
declare class ArrayContaining<T = unknown> extends AsymmetricMatcher<Array<T>> {
|
|
58
57
|
constructor(sample: Array<T>, inverse?: boolean);
|
|
59
|
-
asymmetricMatch(other: Array<T>): boolean;
|
|
58
|
+
asymmetricMatch(other: Array<T>, customTesters?: Array<Tester>): boolean;
|
|
60
59
|
toString(): string;
|
|
61
60
|
getExpectedType(): string;
|
|
62
61
|
}
|
|
@@ -74,6 +73,14 @@ declare class StringMatching extends AsymmetricMatcher<RegExp> {
|
|
|
74
73
|
toString(): string;
|
|
75
74
|
getExpectedType(): string;
|
|
76
75
|
}
|
|
76
|
+
declare class SchemaMatching extends AsymmetricMatcher<StandardSchemaV1<unknown, unknown>> {
|
|
77
|
+
private result;
|
|
78
|
+
constructor(sample: StandardSchemaV1<unknown, unknown>, inverse?: boolean);
|
|
79
|
+
asymmetricMatch(other: unknown): boolean;
|
|
80
|
+
toString(): string;
|
|
81
|
+
getExpectedType(): string;
|
|
82
|
+
toAsymmetricMatcher(): string;
|
|
83
|
+
}
|
|
77
84
|
declare const JestAsymmetricMatchers: ChaiPlugin;
|
|
78
85
|
|
|
79
86
|
declare function matcherHint(matcherName: string, received?: string, expected?: string, options?: MatcherHintOptions): string;
|
|
@@ -132,9 +139,7 @@ interface MatcherState {
|
|
|
132
139
|
isExpectingAssertions?: boolean;
|
|
133
140
|
isExpectingAssertionsError?: Error | null;
|
|
134
141
|
isNot: boolean;
|
|
135
|
-
// environment: VitestEnvironment
|
|
136
142
|
promise: string;
|
|
137
|
-
// snapshotState: SnapshotState
|
|
138
143
|
suppressedErrors: Array<Error>;
|
|
139
144
|
testPath?: string;
|
|
140
145
|
utils: ReturnType<typeof getMatcherUtils> & {
|
|
@@ -160,9 +165,6 @@ interface RawMatcherFn<
|
|
|
160
165
|
> {
|
|
161
166
|
(this: T, received: any, ...expected: E): ExpectationResult;
|
|
162
167
|
}
|
|
163
|
-
// Allow unused `T` to preserve its name for extensions.
|
|
164
|
-
// Type parameter names must be identical when extending those types.
|
|
165
|
-
// eslint-disable-next-line
|
|
166
168
|
interface Matchers<T = any> {}
|
|
167
169
|
type MatchersObject<T extends MatcherState = MatcherState> = Record<string, RawMatcherFn<T>> & ThisType<T> & { [K in keyof Matchers<T>]? : RawMatcherFn<T, Parameters<Matchers<T>[K]>> };
|
|
168
170
|
interface ExpectStatic extends Chai.ExpectStatic, Matchers, AsymmetricMatchersContaining {
|
|
@@ -237,6 +239,16 @@ interface AsymmetricMatchersContaining extends CustomMatcher {
|
|
|
237
239
|
* expect(5.11).toEqual(expect.closeTo(5.12)); // with default precision
|
|
238
240
|
*/
|
|
239
241
|
closeTo: (expected: number, precision?: number) => any;
|
|
242
|
+
/**
|
|
243
|
+
* Matches if the received value validates against a Standard Schema.
|
|
244
|
+
*
|
|
245
|
+
* @param schema - A Standard Schema V1 compatible schema object
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* expect(user).toEqual(expect.schemaMatching(z.object({ name: z.string() })))
|
|
249
|
+
* expect(['hello', 'world']).toEqual([expect.schemaMatching(z.string()), expect.schemaMatching(z.string())])
|
|
250
|
+
*/
|
|
251
|
+
schemaMatching: (schema: unknown) => any;
|
|
240
252
|
}
|
|
241
253
|
type WithAsymmetricMatcher<T> = T | AsymmetricMatcher<unknown>;
|
|
242
254
|
type DeeplyAllowMatchers<T> = T extends Array<infer Element> ? WithAsymmetricMatcher<T> | DeeplyAllowMatchers<Element>[] : T extends object ? WithAsymmetricMatcher<T> | { [K in keyof T] : DeeplyAllowMatchers<T[K]> } : WithAsymmetricMatcher<T>;
|
|
@@ -746,52 +758,22 @@ interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAss
|
|
|
746
758
|
rejects: PromisifyAssertion<T>;
|
|
747
759
|
}
|
|
748
760
|
declare global {
|
|
749
|
-
// support augmenting jest.Matchers by other libraries
|
|
750
|
-
// eslint-disable-next-line ts/no-namespace
|
|
751
761
|
namespace jest {
|
|
752
|
-
|
|
753
|
-
interface Matchers<
|
|
762
|
+
interface Matchers<
|
|
754
763
|
R,
|
|
755
764
|
T = {}
|
|
756
765
|
> {}
|
|
757
766
|
}
|
|
758
767
|
}
|
|
759
768
|
|
|
760
|
-
// selectively ported from https://github.com/jest-community/jest-extended
|
|
761
769
|
declare const customMatchers: MatchersObject;
|
|
762
770
|
|
|
763
|
-
// Jest Expect Compact
|
|
764
771
|
declare const JestChaiExpect: ChaiPlugin;
|
|
765
772
|
|
|
766
773
|
declare const JestExtend: ChaiPlugin;
|
|
767
774
|
|
|
768
|
-
/*
|
|
769
|
-
Copyright (c) 2008-2016 Pivotal Labs
|
|
770
|
-
|
|
771
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
772
|
-
a copy of this software and associated documentation files (the
|
|
773
|
-
"Software"), to deal in the Software without restriction, including
|
|
774
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
775
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
776
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
777
|
-
the following conditions:
|
|
778
|
-
|
|
779
|
-
The above copyright notice and this permission notice shall be
|
|
780
|
-
included in all copies or substantial portions of the Software.
|
|
781
|
-
|
|
782
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
783
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
784
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
785
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
786
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
787
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
788
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
789
|
-
|
|
790
|
-
*/
|
|
791
|
-
|
|
792
|
-
// Extracted out of jasmine 2.5.2
|
|
793
775
|
declare function equals(a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean): boolean;
|
|
794
|
-
declare function isAsymmetric(obj: any):
|
|
776
|
+
declare function isAsymmetric(obj: any): obj is AsymmetricMatcher<any>;
|
|
795
777
|
declare function hasAsymmetric(obj: any, seen?: Set<any>): boolean;
|
|
796
778
|
declare function isA(typeName: string, value: unknown): boolean;
|
|
797
779
|
declare function fnNameFor(func: Function): string;
|
|
@@ -810,9 +792,13 @@ declare function getObjectSubset(object: any, subset: any, customTesters: Array<
|
|
|
810
792
|
subset: any;
|
|
811
793
|
stripped: number;
|
|
812
794
|
};
|
|
795
|
+
/**
|
|
796
|
+
* Detects if an object is a Standard Schema V1 compatible schema
|
|
797
|
+
*/
|
|
798
|
+
declare function isStandardSchema(obj: any): obj is StandardSchemaV1;
|
|
813
799
|
|
|
814
800
|
declare function getState<State extends MatcherState = MatcherState>(expect: ExpectStatic): State;
|
|
815
801
|
declare function setState<State extends MatcherState = MatcherState>(state: Partial<State>, expect: ExpectStatic): void;
|
|
816
802
|
|
|
817
|
-
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|
|
803
|
+
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, SchemaMatching, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, isStandardSchema, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|
|
818
804
|
export type { Assertion, AsymmetricMatcherInterface, AsymmetricMatchersContaining, AsyncExpectationResult, ChaiPlugin, DeeplyAllowMatchers, ExpectStatic, ExpectationResult, JestAssertion, MatcherHintOptions, MatcherState, Matchers, MatchersObject, PromisifyAssertion, RawMatcherFn, SyncExpectationResult, Tester, TesterContext };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { getType, stringify, isObject, noop, assertTypes } from '@vitest/utils';
|
|
2
1
|
import { printDiffOrStringify, diff } from '@vitest/utils/diff';
|
|
2
|
+
import { stringify } from '@vitest/utils/display';
|
|
3
|
+
import { getType, isObject, noop, assertTypes } from '@vitest/utils/helpers';
|
|
3
4
|
import c from 'tinyrainbow';
|
|
4
5
|
import { isMockFunction } from '@vitest/spy';
|
|
5
6
|
import { processError } from '@vitest/utils/error';
|
|
@@ -180,24 +181,24 @@ function hasAsymmetric(obj, seen = new Set()) {
|
|
|
180
181
|
}
|
|
181
182
|
return false;
|
|
182
183
|
}
|
|
183
|
-
function asymmetricMatch(a, b) {
|
|
184
|
+
function asymmetricMatch(a, b, customTesters) {
|
|
184
185
|
const asymmetricA = isAsymmetric(a);
|
|
185
186
|
const asymmetricB = isAsymmetric(b);
|
|
186
187
|
if (asymmetricA && asymmetricB) {
|
|
187
188
|
return undefined;
|
|
188
189
|
}
|
|
189
190
|
if (asymmetricA) {
|
|
190
|
-
return a.asymmetricMatch(b);
|
|
191
|
+
return a.asymmetricMatch(b, customTesters);
|
|
191
192
|
}
|
|
192
193
|
if (asymmetricB) {
|
|
193
|
-
return b.asymmetricMatch(a);
|
|
194
|
+
return b.asymmetricMatch(a, customTesters);
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
197
|
// Equality function lovingly adapted from isEqual in
|
|
197
198
|
// [Underscore](http://underscorejs.org)
|
|
198
199
|
function eq(a, b, aStack, bStack, customTesters, hasKey) {
|
|
199
200
|
let result = true;
|
|
200
|
-
const asymmetricResult = asymmetricMatch(a, b);
|
|
201
|
+
const asymmetricResult = asymmetricMatch(a, b, customTesters);
|
|
201
202
|
if (asymmetricResult !== undefined) {
|
|
202
203
|
return asymmetricResult;
|
|
203
204
|
}
|
|
@@ -341,7 +342,7 @@ function hasDefinedKey(obj, key) {
|
|
|
341
342
|
return hasKey(obj, key) && obj[key] !== undefined;
|
|
342
343
|
}
|
|
343
344
|
function hasKey(obj, key) {
|
|
344
|
-
return Object.
|
|
345
|
+
return Object.hasOwn(obj, key);
|
|
345
346
|
}
|
|
346
347
|
function isA(typeName, value) {
|
|
347
348
|
return Object.prototype.toString.apply(value) === `[object ${typeName}]`;
|
|
@@ -369,7 +370,7 @@ function hasProperty(obj, property) {
|
|
|
369
370
|
if (!obj) {
|
|
370
371
|
return false;
|
|
371
372
|
}
|
|
372
|
-
if (Object.
|
|
373
|
+
if (Object.hasOwn(obj, property)) {
|
|
373
374
|
return true;
|
|
374
375
|
}
|
|
375
376
|
return hasProperty(getPrototype(obj), property);
|
|
@@ -516,7 +517,7 @@ function hasPropertyInObject(object, key) {
|
|
|
516
517
|
if (shouldTerminate) {
|
|
517
518
|
return false;
|
|
518
519
|
}
|
|
519
|
-
return Object.
|
|
520
|
+
return Object.hasOwn(object, key) || hasPropertyInObject(Object.getPrototypeOf(object), key);
|
|
520
521
|
}
|
|
521
522
|
function isObjectWithKeys(a) {
|
|
522
523
|
return isObject(a) && !(a instanceof Error) && !Array.isArray(a) && !(a instanceof Date);
|
|
@@ -659,8 +660,14 @@ function getObjectSubset(object, subset, customTesters) {
|
|
|
659
660
|
stripped
|
|
660
661
|
};
|
|
661
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Detects if an object is a Standard Schema V1 compatible schema
|
|
665
|
+
*/
|
|
666
|
+
function isStandardSchema(obj) {
|
|
667
|
+
return !!obj && typeof obj === "object" && obj["~standard"] && typeof obj["~standard"].validate === "function";
|
|
668
|
+
}
|
|
662
669
|
|
|
663
|
-
if (!Object.
|
|
670
|
+
if (!Object.hasOwn(globalThis, MATCHERS_OBJECT)) {
|
|
664
671
|
const globalState = new WeakMap();
|
|
665
672
|
const matchers = Object.create(null);
|
|
666
673
|
const customEqualityTesters = [];
|
|
@@ -782,12 +789,11 @@ class ObjectContaining extends AsymmetricMatcher {
|
|
|
782
789
|
return (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(obj, s)) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.enumerable;
|
|
783
790
|
})];
|
|
784
791
|
}
|
|
785
|
-
asymmetricMatch(other) {
|
|
792
|
+
asymmetricMatch(other, customTesters) {
|
|
786
793
|
if (typeof this.sample !== "object") {
|
|
787
794
|
throw new TypeError(`You must provide an object to ${this.toString()}, not '${typeof this.sample}'.`);
|
|
788
795
|
}
|
|
789
796
|
let result = true;
|
|
790
|
-
const matcherContext = this.getMatcherContext();
|
|
791
797
|
const properties = this.getProperties(this.sample);
|
|
792
798
|
for (const property of properties) {
|
|
793
799
|
var _Object$getOwnPropert2, _Object$getOwnPropert3;
|
|
@@ -797,7 +803,7 @@ class ObjectContaining extends AsymmetricMatcher {
|
|
|
797
803
|
}
|
|
798
804
|
const value = ((_Object$getOwnPropert2 = Object.getOwnPropertyDescriptor(this.sample, property)) === null || _Object$getOwnPropert2 === void 0 ? void 0 : _Object$getOwnPropert2.value) ?? this.sample[property];
|
|
799
805
|
const otherValue = ((_Object$getOwnPropert3 = Object.getOwnPropertyDescriptor(other, property)) === null || _Object$getOwnPropert3 === void 0 ? void 0 : _Object$getOwnPropert3.value) ?? other[property];
|
|
800
|
-
if (!equals(value, otherValue,
|
|
806
|
+
if (!equals(value, otherValue, customTesters)) {
|
|
801
807
|
result = false;
|
|
802
808
|
break;
|
|
803
809
|
}
|
|
@@ -815,12 +821,11 @@ class ArrayContaining extends AsymmetricMatcher {
|
|
|
815
821
|
constructor(sample, inverse = false) {
|
|
816
822
|
super(sample, inverse);
|
|
817
823
|
}
|
|
818
|
-
asymmetricMatch(other) {
|
|
824
|
+
asymmetricMatch(other, customTesters) {
|
|
819
825
|
if (!Array.isArray(this.sample)) {
|
|
820
826
|
throw new TypeError(`You must provide an array to ${this.toString()}, not '${typeof this.sample}'.`);
|
|
821
827
|
}
|
|
822
|
-
const
|
|
823
|
-
const result = this.sample.length === 0 || Array.isArray(other) && this.sample.every((item) => other.some((another) => equals(item, another, matcherContext.customTesters)));
|
|
828
|
+
const result = this.sample.length === 0 || Array.isArray(other) && this.sample.every((item) => other.some((another) => equals(item, another, customTesters)));
|
|
824
829
|
return this.inverse ? !result : result;
|
|
825
830
|
}
|
|
826
831
|
toString() {
|
|
@@ -953,6 +958,40 @@ class CloseTo extends AsymmetricMatcher {
|
|
|
953
958
|
].join(" ");
|
|
954
959
|
}
|
|
955
960
|
}
|
|
961
|
+
class SchemaMatching extends AsymmetricMatcher {
|
|
962
|
+
result;
|
|
963
|
+
constructor(sample, inverse = false) {
|
|
964
|
+
if (!isStandardSchema(sample)) {
|
|
965
|
+
throw new TypeError("SchemaMatching expected to receive a Standard Schema.");
|
|
966
|
+
}
|
|
967
|
+
super(sample, inverse);
|
|
968
|
+
}
|
|
969
|
+
asymmetricMatch(other) {
|
|
970
|
+
const result = this.sample["~standard"].validate(other);
|
|
971
|
+
// Check if the result is a Promise (async validation)
|
|
972
|
+
if (result instanceof Promise) {
|
|
973
|
+
throw new TypeError("Async schema validation is not supported in asymmetric matchers.");
|
|
974
|
+
}
|
|
975
|
+
this.result = result;
|
|
976
|
+
const pass = !this.result.issues || this.result.issues.length === 0;
|
|
977
|
+
return this.inverse ? !pass : pass;
|
|
978
|
+
}
|
|
979
|
+
toString() {
|
|
980
|
+
return `Schema${this.inverse ? "Not" : ""}Matching`;
|
|
981
|
+
}
|
|
982
|
+
getExpectedType() {
|
|
983
|
+
return "object";
|
|
984
|
+
}
|
|
985
|
+
toAsymmetricMatcher() {
|
|
986
|
+
var _this$result;
|
|
987
|
+
const { utils } = this.getMatcherContext();
|
|
988
|
+
const issues = ((_this$result = this.result) === null || _this$result === void 0 ? void 0 : _this$result.issues) || [];
|
|
989
|
+
if (issues.length > 0) {
|
|
990
|
+
return `${this.toString()} ${utils.stringify(this.result, undefined, { printBasicPrototype: false })}`;
|
|
991
|
+
}
|
|
992
|
+
return this.toString();
|
|
993
|
+
}
|
|
994
|
+
}
|
|
956
995
|
const JestAsymmetricMatchers = (chai, utils) => {
|
|
957
996
|
utils.addMethod(chai.expect, "anything", () => new Anything());
|
|
958
997
|
utils.addMethod(chai.expect, "any", (expected) => new Any(expected));
|
|
@@ -961,13 +1000,15 @@ const JestAsymmetricMatchers = (chai, utils) => {
|
|
|
961
1000
|
utils.addMethod(chai.expect, "arrayContaining", (expected) => new ArrayContaining(expected));
|
|
962
1001
|
utils.addMethod(chai.expect, "stringMatching", (expected) => new StringMatching(expected));
|
|
963
1002
|
utils.addMethod(chai.expect, "closeTo", (expected, precision) => new CloseTo(expected, precision));
|
|
1003
|
+
utils.addMethod(chai.expect, "schemaMatching", (expected) => new SchemaMatching(expected));
|
|
964
1004
|
// defineProperty does not work
|
|
965
1005
|
chai.expect.not = {
|
|
966
1006
|
stringContaining: (expected) => new StringContaining(expected, true),
|
|
967
1007
|
objectContaining: (expected) => new ObjectContaining(expected, true),
|
|
968
1008
|
arrayContaining: (expected) => new ArrayContaining(expected, true),
|
|
969
1009
|
stringMatching: (expected) => new StringMatching(expected, true),
|
|
970
|
-
closeTo: (expected, precision) => new CloseTo(expected, precision, true)
|
|
1010
|
+
closeTo: (expected, precision) => new CloseTo(expected, precision, true),
|
|
1011
|
+
schemaMatching: (expected) => new SchemaMatching(expected, true)
|
|
971
1012
|
};
|
|
972
1013
|
};
|
|
973
1014
|
|
|
@@ -1284,7 +1325,7 @@ const JestChaiExpect = (chai, utils) => {
|
|
|
1284
1325
|
const actual = this._obj;
|
|
1285
1326
|
const [propertyName, expected] = args;
|
|
1286
1327
|
const getValue = () => {
|
|
1287
|
-
const hasOwn = Object.
|
|
1328
|
+
const hasOwn = Object.hasOwn(actual, propertyName);
|
|
1288
1329
|
if (hasOwn) {
|
|
1289
1330
|
return {
|
|
1290
1331
|
value: actual[propertyName],
|
|
@@ -1403,7 +1444,7 @@ const JestChaiExpect = (chai, utils) => {
|
|
|
1403
1444
|
def(["toHaveBeenLastCalledWith", "lastCalledWith"], function(...args) {
|
|
1404
1445
|
const spy = getSpy(this);
|
|
1405
1446
|
const spyName = spy.getMockName();
|
|
1406
|
-
const lastCall = spy.mock.calls
|
|
1447
|
+
const lastCall = spy.mock.calls.at(-1);
|
|
1407
1448
|
this.assert(lastCall && equalsArgumentArray(lastCall, args), `expected last "${spyName}" call to have been called with #{exp}`, `expected last "${spyName}" call to not have been called with #{exp}`, args, lastCall);
|
|
1408
1449
|
});
|
|
1409
1450
|
/**
|
|
@@ -1542,22 +1583,22 @@ const JestChaiExpect = (chai, utils) => {
|
|
|
1542
1583
|
[{
|
|
1543
1584
|
name: "toHaveLastResolvedWith",
|
|
1544
1585
|
condition: (spy, value) => {
|
|
1545
|
-
const result = spy.mock.settledResults
|
|
1546
|
-
return result && result.type === "fulfilled" && equals(result.value, value);
|
|
1586
|
+
const result = spy.mock.settledResults.at(-1);
|
|
1587
|
+
return Boolean(result && result.type === "fulfilled" && equals(result.value, value));
|
|
1547
1588
|
},
|
|
1548
1589
|
action: "resolve"
|
|
1549
1590
|
}, {
|
|
1550
1591
|
name: ["toHaveLastReturnedWith", "lastReturnedWith"],
|
|
1551
1592
|
condition: (spy, value) => {
|
|
1552
|
-
const result = spy.mock.results
|
|
1553
|
-
return result && result.type === "return" && equals(result.value, value);
|
|
1593
|
+
const result = spy.mock.results.at(-1);
|
|
1594
|
+
return Boolean(result && result.type === "return" && equals(result.value, value));
|
|
1554
1595
|
},
|
|
1555
1596
|
action: "return"
|
|
1556
1597
|
}].forEach(({ name, condition, action }) => {
|
|
1557
1598
|
def(name, function(value) {
|
|
1558
1599
|
const spy = getSpy(this);
|
|
1559
1600
|
const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
|
|
1560
|
-
const result = results
|
|
1601
|
+
const result = results.at(-1);
|
|
1561
1602
|
const spyName = spy.getMockName();
|
|
1562
1603
|
this.assert(condition(spy, value), `expected last "${spyName}" call to ${action} #{exp}`, `expected last "${spyName}" call to not ${action} #{exp}`, value, result === null || result === void 0 ? void 0 : result.value);
|
|
1563
1604
|
});
|
|
@@ -1715,6 +1756,7 @@ function getMatcherState(assertion, expect) {
|
|
|
1715
1756
|
const obj = assertion._obj;
|
|
1716
1757
|
const isNot = util.flag(assertion, "negate");
|
|
1717
1758
|
const promise = util.flag(assertion, "promise") || "";
|
|
1759
|
+
const customMessage = util.flag(assertion, "message");
|
|
1718
1760
|
const jestUtils = {
|
|
1719
1761
|
...getMatcherUtils(),
|
|
1720
1762
|
diff,
|
|
@@ -1736,7 +1778,8 @@ function getMatcherState(assertion, expect) {
|
|
|
1736
1778
|
return {
|
|
1737
1779
|
state: matcherState,
|
|
1738
1780
|
isNot,
|
|
1739
|
-
obj
|
|
1781
|
+
obj,
|
|
1782
|
+
customMessage
|
|
1740
1783
|
};
|
|
1741
1784
|
}
|
|
1742
1785
|
class JestExtendError extends Error {
|
|
@@ -1750,19 +1793,21 @@ function JestExtendPlugin(c, expect, matchers) {
|
|
|
1750
1793
|
return (_, utils) => {
|
|
1751
1794
|
Object.entries(matchers).forEach(([expectAssertionName, expectAssertion]) => {
|
|
1752
1795
|
function expectWrapper(...args) {
|
|
1753
|
-
const { state, isNot, obj } = getMatcherState(this, expect);
|
|
1796
|
+
const { state, isNot, obj, customMessage } = getMatcherState(this, expect);
|
|
1754
1797
|
const result = expectAssertion.call(state, obj, ...args);
|
|
1755
1798
|
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
1756
1799
|
const thenable = result;
|
|
1757
1800
|
return thenable.then(({ pass, message, actual, expected }) => {
|
|
1758
1801
|
if (pass && isNot || !pass && !isNot) {
|
|
1759
|
-
|
|
1802
|
+
const errorMessage = customMessage != null ? customMessage : message();
|
|
1803
|
+
throw new JestExtendError(errorMessage, actual, expected);
|
|
1760
1804
|
}
|
|
1761
1805
|
});
|
|
1762
1806
|
}
|
|
1763
1807
|
const { pass, message, actual, expected } = result;
|
|
1764
1808
|
if (pass && isNot || !pass && !isNot) {
|
|
1765
|
-
|
|
1809
|
+
const errorMessage = customMessage != null ? customMessage : message();
|
|
1810
|
+
throw new JestExtendError(errorMessage, actual, expected);
|
|
1766
1811
|
}
|
|
1767
1812
|
}
|
|
1768
1813
|
const softWrapper = wrapAssertion(utils, expectAssertionName, expectWrapper);
|
|
@@ -1816,4 +1861,4 @@ const JestExtend = (chai, utils) => {
|
|
|
1816
1861
|
});
|
|
1817
1862
|
};
|
|
1818
1863
|
|
|
1819
|
-
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|
|
1864
|
+
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, SchemaMatching, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, isStandardSchema, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest/expect",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0.0
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"description": "Jest's expect matchers as a Chai plugin",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
|
@@ -29,17 +29,18 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@standard-schema/spec": "^1.0.0",
|
|
32
33
|
"@types/chai": "^5.2.2",
|
|
33
34
|
"chai": "^6.0.1",
|
|
34
|
-
"tinyrainbow": "^
|
|
35
|
-
"@vitest/
|
|
36
|
-
"@vitest/
|
|
35
|
+
"tinyrainbow": "^3.0.3",
|
|
36
|
+
"@vitest/utils": "4.0.0",
|
|
37
|
+
"@vitest/spy": "4.0.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
|
-
"@vitest/runner": "4.0.0
|
|
40
|
+
"@vitest/runner": "4.0.0"
|
|
40
41
|
},
|
|
41
42
|
"scripts": {
|
|
42
|
-
"build": "
|
|
43
|
+
"build": "premove dist && rollup -c",
|
|
43
44
|
"dev": "rollup -c --watch"
|
|
44
45
|
}
|
|
45
46
|
}
|