@vitest/expect 3.0.0-beta.1 → 3.0.0-beta.2

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
@@ -97,7 +97,20 @@ interface ExpectStatic extends Chai.ExpectStatic, AsymmetricMatchersContaining {
97
97
  setState: (state: Partial<MatcherState>) => void;
98
98
  not: AsymmetricMatchersContaining;
99
99
  }
100
- interface AsymmetricMatchersContaining {
100
+ interface CustomMatcher {
101
+ /**
102
+ * Checks that a value satisfies a custom matcher function.
103
+ *
104
+ * @param matcher - A function returning a boolean based on the custom condition
105
+ * @param message - Optional custom error message on failure
106
+ *
107
+ * @example
108
+ * expect(age).toSatisfy(val => val >= 18, 'Age must be at least 18');
109
+ * expect(age).toEqual(expect.toSatisfy(val => val >= 18, 'Age must be at least 18'));
110
+ */
111
+ toSatisfy: (matcher: (value: any) => boolean, message?: string) => any;
112
+ }
113
+ interface AsymmetricMatchersContaining extends CustomMatcher {
101
114
  /**
102
115
  * Matches if the received string contains the expected substring.
103
116
  *
@@ -139,7 +152,7 @@ interface AsymmetricMatchersContaining {
139
152
  */
140
153
  closeTo: (expected: number, precision?: number) => any;
141
154
  }
142
- interface JestAssertion<T = any> extends jest.Matchers<void, T> {
155
+ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
143
156
  /**
144
157
  * Used when you want to check that two objects have the same value.
145
158
  * This matcher recursively checks the equality of all fields, rather than checking for object identity.
@@ -558,16 +571,6 @@ interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAss
558
571
  * expect(mockFunc).toHaveBeenCalledExactlyOnceWith('arg1', 42);
559
572
  */
560
573
  toHaveBeenCalledExactlyOnceWith: <E extends any[]>(...args: E) => void;
561
- /**
562
- * Checks that a value satisfies a custom matcher function.
563
- *
564
- * @param matcher - A function returning a boolean based on the custom condition
565
- * @param message - Optional custom error message on failure
566
- *
567
- * @example
568
- * expect(age).toSatisfy(val => val >= 18, 'Age must be at least 18');
569
- */
570
- toSatisfy: <E>(matcher: (value: E) => boolean, message?: string) => void;
571
574
  /**
572
575
  * This assertion checks if a `Mock` was called before another `Mock`.
573
576
  * @param mock - A mock function created by `vi.spyOn` or `vi.fn`
@@ -655,6 +658,8 @@ declare global {
655
658
  }
656
659
  }
657
660
 
661
+ declare const customMatchers: MatchersObject;
662
+
658
663
  interface AsymmetricMatcherInterface {
659
664
  asymmetricMatch: (other: unknown) => boolean;
660
665
  toString: () => string;
@@ -741,4 +746,4 @@ declare function getObjectSubset(object: any, subset: any, customTesters: Array<
741
746
  declare function getState<State extends MatcherState = MatcherState>(expect: ExpectStatic): State;
742
747
  declare function setState<State extends MatcherState = MatcherState>(state: Partial<State>, expect: ExpectStatic): void;
743
748
 
744
- export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, type Assertion, AsymmetricMatcher, type AsymmetricMatcherInterface, type AsymmetricMatchersContaining, type AsyncExpectationResult, type ChaiPlugin, type ExpectStatic, type ExpectationResult, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, type JestAssertion, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, type MatcherHintOptions, type MatcherState, type MatchersObject, ObjectContaining, type PromisifyAssertion, type RawMatcherFn, StringContaining, StringMatching, type SyncExpectationResult, type Tester, type TesterContext, addCustomEqualityTesters, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
749
+ export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, type Assertion, AsymmetricMatcher, type AsymmetricMatcherInterface, type AsymmetricMatchersContaining, type AsyncExpectationResult, type ChaiPlugin, type ExpectStatic, type ExpectationResult, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, type JestAssertion, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, type MatcherHintOptions, type MatcherState, type MatchersObject, ObjectContaining, type PromisifyAssertion, type RawMatcherFn, StringContaining, StringMatching, type SyncExpectationResult, type Tester, type TesterContext, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
package/dist/index.js CHANGED
@@ -12,6 +12,28 @@ const ASYMMETRIC_MATCHERS_OBJECT = Symbol.for(
12
12
  "asymmetric-matchers-object"
13
13
  );
14
14
 
15
+ const customMatchers = {
16
+ toSatisfy(actual, expected, message) {
17
+ const { printReceived, printExpected, matcherHint } = this.utils;
18
+ const pass = expected(actual);
19
+ return {
20
+ pass,
21
+ message: () => pass ? `${matcherHint(".not.toSatisfy", "received", "")}
22
+
23
+ Expected value to not satisfy:
24
+ ${message || printExpected(expected)}
25
+ Received:
26
+ ${printReceived(actual)}` : `${matcherHint(".toSatisfy", "received", "")}
27
+
28
+ Expected value to satisfy:
29
+ ${message || printExpected(expected)}
30
+
31
+ Received:
32
+ ${printReceived(actual)}`
33
+ };
34
+ }
35
+ };
36
+
15
37
  const EXPECTED_COLOR = c.green;
16
38
  const RECEIVED_COLOR = c.red;
17
39
  const INVERTED_COLOR = c.inverse;
@@ -164,9 +186,6 @@ function eq(a, b, aStack, bStack, customTesters, hasKey2) {
164
186
  return customTesterResult;
165
187
  }
166
188
  }
167
- if (a instanceof Error && b instanceof Error) {
168
- return a.message === b.message;
169
- }
170
189
  if (typeof URL === "function" && a instanceof URL && b instanceof URL) {
171
190
  return a.href === b.href;
172
191
  }
@@ -219,6 +238,14 @@ function eq(a, b, aStack, bStack, customTesters, hasKey2) {
219
238
  if (className === "[object Array]" && a.length !== b.length) {
220
239
  return false;
221
240
  }
241
+ if (a instanceof Error && b instanceof Error) {
242
+ try {
243
+ return isErrorEqual(a, b, aStack, bStack, customTesters, hasKey2);
244
+ } finally {
245
+ aStack.pop();
246
+ bStack.pop();
247
+ }
248
+ }
222
249
  const aKeys = keys(a, hasKey2);
223
250
  let key;
224
251
  let size = aKeys.length;
@@ -236,6 +263,17 @@ function eq(a, b, aStack, bStack, customTesters, hasKey2) {
236
263
  bStack.pop();
237
264
  return result;
238
265
  }
266
+ function isErrorEqual(a, b, aStack, bStack, customTesters, hasKey2) {
267
+ let result = Object.getPrototypeOf(a) === Object.getPrototypeOf(b) && a.name === b.name && a.message === b.message;
268
+ if (typeof b.cause !== "undefined") {
269
+ result && (result = eq(a.cause, b.cause, aStack, bStack, customTesters, hasKey2));
270
+ }
271
+ if (a instanceof AggregateError && b instanceof AggregateError) {
272
+ result && (result = eq(a.errors, b.errors, aStack, bStack, customTesters, hasKey2));
273
+ }
274
+ result && (result = eq({ ...a }, { ...b }, aStack, bStack, customTesters, hasKey2));
275
+ return result;
276
+ }
239
277
  function keys(obj, hasKey2) {
240
278
  const keys2 = [];
241
279
  for (const key in obj) {
@@ -1625,12 +1663,16 @@ const JestChaiExpect = (chai, utils) => {
1625
1663
  );
1626
1664
  }
1627
1665
  if (expected instanceof Error) {
1666
+ const equal = equals(thrown, expected, [
1667
+ ...customTesters,
1668
+ iterableEquality
1669
+ ]);
1628
1670
  return this.assert(
1629
- thrown && expected.message === thrown.message,
1630
- `expected error to have message: ${expected.message}`,
1631
- `expected error not to have message: ${expected.message}`,
1632
- expected.message,
1633
- thrown && thrown.message
1671
+ equal,
1672
+ "expected a thrown error to be #{exp}",
1673
+ "expected a thrown error not to be #{exp}",
1674
+ expected,
1675
+ thrown
1634
1676
  );
1635
1677
  }
1636
1678
  if (typeof expected === "object" && "asymmetricMatch" in expected && typeof expected.asymmetricMatch === "function") {
@@ -1804,9 +1846,6 @@ const JestChaiExpect = (chai, utils) => {
1804
1846
  );
1805
1847
  });
1806
1848
  });
1807
- def("toSatisfy", function(matcher, message) {
1808
- return this.be.satisfy(matcher, message);
1809
- });
1810
1849
  def("withContext", function(context) {
1811
1850
  for (const key in context) {
1812
1851
  utils.flag(this, key, context[key]);
@@ -2140,4 +2179,4 @@ const JestExtend = (chai, utils) => {
2140
2179
  );
2141
2180
  };
2142
2181
 
2143
- export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
2182
+ 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 };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/expect",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.1",
4
+ "version": "3.0.0-beta.2",
5
5
  "description": "Jest's expect matchers as a Chai plugin",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -32,13 +32,13 @@
32
32
  "dependencies": {
33
33
  "chai": "^5.1.2",
34
34
  "tinyrainbow": "^1.2.0",
35
- "@vitest/utils": "3.0.0-beta.1",
36
- "@vitest/spy": "3.0.0-beta.1"
35
+ "@vitest/spy": "3.0.0-beta.2",
36
+ "@vitest/utils": "3.0.0-beta.2"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/chai": "4.3.6",
40
40
  "rollup-plugin-copy": "^3.5.0",
41
- "@vitest/runner": "3.0.0-beta.1"
41
+ "@vitest/runner": "3.0.0-beta.2"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "rimraf dist && rollup -c",