@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 CHANGED
@@ -1,18 +1,20 @@
1
1
  import { MockInstance } from '@vitest/spy';
2
- import { stringify, Constructable } from '@vitest/utils';
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
- // eslint-disable-next-line unused-imports/no-unused-vars, ts/no-empty-object-type
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): boolean;
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.prototype.hasOwnProperty.call(obj, key);
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.prototype.hasOwnProperty.call(obj, property)) {
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.prototype.hasOwnProperty.call(object, key) || hasPropertyInObject(Object.getPrototypeOf(object), key);
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.prototype.hasOwnProperty.call(globalThis, MATCHERS_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, matcherContext.customTesters)) {
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 matcherContext = this.getMatcherContext();
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.prototype.hasOwnProperty.call(actual, propertyName);
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[spy.mock.calls.length - 1];
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[spy.mock.settledResults.length - 1];
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[spy.mock.results.length - 1];
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[results.length - 1];
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
- throw new JestExtendError(message(), actual, expected);
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
- throw new JestExtendError(message(), actual, expected);
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-beta.8",
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": "^5.2.1",
34
- "tinyrainbow": "^2.0.0",
35
- "@vitest/spy": "4.0.0-beta.8",
36
- "@vitest/utils": "4.0.0-beta.8"
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
- "rollup-plugin-copy": "^3.5.0",
40
- "@vitest/runner": "4.0.0-beta.8"
40
+ "@vitest/runner": "4.0.0"
41
41
  },
42
42
  "scripts": {
43
- "build": "rimraf dist && rollup -c",
43
+ "build": "premove dist && rollup -c",
44
44
  "dev": "rollup -c --watch"
45
45
  }
46
46
  }