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