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