@vitest/expect 4.1.0-beta.3 → 4.1.0-beta.5

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,6 +1,5 @@
1
1
  import { Test } from '@vitest/runner';
2
2
  import { MockInstance } from '@vitest/spy';
3
- import { Constructable } from '@vitest/utils';
4
3
  import { Formatter } from 'tinyrainbow';
5
4
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
5
  import { diff, printDiffOrStringify } from '@vitest/utils/diff';
@@ -459,6 +458,7 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
459
458
  *
460
459
  * @example
461
460
  * expect(mockFunc).toBeCalledTimes(2);
461
+ * @deprecated Use `toHaveBeenCalledTimes` instead
462
462
  */
463
463
  toBeCalledTimes: (times: number) => void;
464
464
  /**
@@ -477,6 +477,7 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
477
477
  *
478
478
  * @example
479
479
  * expect(mockFunc).toBeCalled();
480
+ * @deprecated Use `toHaveBeenCalled` instead
480
481
  */
481
482
  toBeCalled: () => void;
482
483
  /**
@@ -495,6 +496,7 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
495
496
  *
496
497
  * @example
497
498
  * expect(mockFunc).toBeCalledWith('arg1', 42);
499
+ * @deprecated Use `toHaveBeenCalledWith` instead
498
500
  */
499
501
  toBeCalledWith: <E extends any[]>(...args: E) => void;
500
502
  /**
@@ -507,15 +509,6 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
507
509
  */
508
510
  toHaveBeenNthCalledWith: <E extends any[]>(n: number, ...args: E) => void;
509
511
  /**
510
- * Ensure that a mock function is called with specific arguments on an Nth call.
511
- *
512
- * Alias for `expect.toHaveBeenNthCalledWith`.
513
- *
514
- * @example
515
- * expect(mockFunc).nthCalledWith(2, 'secondArg');
516
- */
517
- nthCalledWith: <E extends any[]>(nthCall: number, ...args: E) => void;
518
- /**
519
512
  * If you have a mock function, you can use `.toHaveBeenLastCalledWith`
520
513
  * to test what arguments it was last called with.
521
514
  *
@@ -526,16 +519,6 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
526
519
  */
527
520
  toHaveBeenLastCalledWith: <E extends any[]>(...args: E) => void;
528
521
  /**
529
- * If you have a mock function, you can use `.lastCalledWith`
530
- * to test what arguments it was last called with.
531
- *
532
- * Alias for `expect.toHaveBeenLastCalledWith`.
533
- *
534
- * @example
535
- * expect(mockFunc).lastCalledWith('lastArg');
536
- */
537
- lastCalledWith: <E extends any[]>(...args: E) => void;
538
- /**
539
522
  * Used to test that a function throws when it is called.
540
523
  *
541
524
  * Also under the alias `expect.toThrowError`.
@@ -543,8 +526,9 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
543
526
  * @example
544
527
  * expect(() => functionWithError()).toThrow('Error message');
545
528
  * expect(() => parseJSON('invalid')).toThrow(SyntaxError);
529
+ * expect(() => { throw 42 }).toThrow(42);
546
530
  */
547
- toThrow: (expected?: string | Constructable | RegExp | Error) => void;
531
+ toThrow: (expected?: any) => void;
548
532
  /**
549
533
  * Used to test that a function throws when it is called.
550
534
  *
@@ -553,8 +537,10 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
553
537
  * @example
554
538
  * expect(() => functionWithError()).toThrowError('Error message');
555
539
  * expect(() => parseJSON('invalid')).toThrowError(SyntaxError);
540
+ * expect(() => { throw 42 }).toThrowError(42);
541
+ * @deprecated Use `toThrow` instead
556
542
  */
557
- toThrowError: (expected?: string | Constructable | RegExp | Error) => void;
543
+ toThrowError: (expected?: any) => void;
558
544
  /**
559
545
  * Use to test that the mock function successfully returned (i.e., did not throw an error) at least one time
560
546
  *
@@ -562,6 +548,7 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
562
548
  *
563
549
  * @example
564
550
  * expect(mockFunc).toReturn();
551
+ * @deprecated Use `toHaveReturned` instead
565
552
  */
566
553
  toReturn: () => void;
567
554
  /**
@@ -581,6 +568,7 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
581
568
  *
582
569
  * @example
583
570
  * expect(mockFunc).toReturnTimes(3);
571
+ * @deprecated Use `toHaveReturnedTimes` instead
584
572
  */
585
573
  toReturnTimes: (times: number) => void;
586
574
  /**
@@ -600,6 +588,7 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
600
588
  *
601
589
  * @example
602
590
  * expect(mockFunc).toReturnWith('returnValue');
591
+ * @deprecated Use `toHaveReturnedWith` instead
603
592
  */
604
593
  toReturnWith: <E>(value: E) => void;
605
594
  /**
@@ -623,17 +612,6 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
623
612
  */
624
613
  toHaveLastReturnedWith: <E>(value: E) => void;
625
614
  /**
626
- * Use to test the specific value that a mock function last returned.
627
- * If the last call to the mock function threw an error, then this matcher will fail
628
- * no matter what value you provided as the expected return value.
629
- *
630
- * Alias for `expect.toHaveLastReturnedWith`.
631
- *
632
- * @example
633
- * expect(mockFunc).lastReturnedWith('lastValue');
634
- */
635
- lastReturnedWith: <E>(value: E) => void;
636
- /**
637
615
  * Use to test the specific value that a mock function returned for the nth call.
638
616
  * If the nth call to the mock function threw an error, then this matcher will fail
639
617
  * no matter what value you provided as the expected return value.
@@ -644,17 +622,6 @@ interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
644
622
  * expect(mockFunc).toHaveNthReturnedWith(2, 'nthValue');
645
623
  */
646
624
  toHaveNthReturnedWith: <E>(nthCall: number, value: E) => void;
647
- /**
648
- * Use to test the specific value that a mock function returned for the nth call.
649
- * If the nth call to the mock function threw an error, then this matcher will fail
650
- * no matter what value you provided as the expected return value.
651
- *
652
- * Alias for `expect.toHaveNthReturnedWith`.
653
- *
654
- * @example
655
- * expect(mockFunc).nthReturnedWith(2, 'nthValue');
656
- */
657
- nthReturnedWith: <E>(nthCall: number, value: E) => void;
658
625
  }
659
626
  type VitestAssertion<
660
627
  A,
@@ -925,6 +892,7 @@ declare const JestExtend: ChaiPlugin;
925
892
  declare function equals(a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean): boolean;
926
893
  declare function isAsymmetric(obj: any): obj is AsymmetricMatcher<any>;
927
894
  declare function hasAsymmetric(obj: any, seen?: Set<any>): boolean;
895
+ declare function isError(value: unknown): value is Error;
928
896
  declare function isA(typeName: string, value: unknown): boolean;
929
897
  declare function fnNameFor(func: Function): string;
930
898
  declare function hasProperty(obj: object | null, property: string): boolean;
@@ -950,5 +918,9 @@ declare function isStandardSchema(obj: any): obj is StandardSchemaV1;
950
918
  declare function getState<State extends MatcherState = MatcherState>(expect: ExpectStatic): State;
951
919
  declare function setState<State extends MatcherState = MatcherState>(state: Partial<State>, expect: ExpectStatic): void;
952
920
 
953
- export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, ChaiStyleAssertions, 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 };
921
+ declare function createAssertionMessage(util: Chai.ChaiUtils, assertion: Assertion, hasArgs: boolean): string;
922
+ declare function recordAsyncExpect(_test: any, promise: Promise<any>, assertion: string, error: Error, isSoft?: boolean): Promise<any>;
923
+ declare function wrapAssertion(utils: Chai.ChaiUtils, name: string, fn: (this: Chai.AssertionStatic & Assertion, ...args: any[]) => void | PromiseLike<void>): (this: Chai.AssertionStatic & Assertion, ...args: any[]) => void | PromiseLike<void>;
924
+
925
+ export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, ChaiStyleAssertions, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, SchemaMatching, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, createAssertionMessage, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isError, isImmutableUnorderedKeyed, isImmutableUnorderedSet, isStandardSchema, iterableEquality, pluralize, recordAsyncExpect, setState, sparseArrayEquality, subsetEquality, typeEquality, wrapAssertion };
954
926
  export type { Assertion, AsymmetricMatcherInterface, AsymmetricMatchersContaining, AsyncExpectationResult, ChaiMockAssertion, ChaiPlugin, DeeplyAllowMatchers, ExpectStatic, ExpectationResult, JestAssertion, MatcherHintOptions, MatcherState, Matchers, MatchersObject, PromisifyAssertion, RawMatcherFn, SyncExpectationResult, Tester, TesterContext };
package/dist/index.js CHANGED
@@ -244,6 +244,18 @@ function asymmetricMatch(a, b, customTesters) {
244
244
  return b.asymmetricMatch(a, customTesters);
245
245
  }
246
246
  }
247
+ // https://github.com/jestjs/jest/blob/905bcbced3d40cdf7aadc4cdf6fb731c4bb3dbe3/packages/expect-utils/src/utils.ts#L509
248
+ function isError(value) {
249
+ if (typeof Error.isError === "function") {
250
+ return Error.isError(value);
251
+ }
252
+ switch (Object.prototype.toString.call(value)) {
253
+ case "[object Error]":
254
+ case "[object Exception]":
255
+ case "[object DOMException]": return true;
256
+ default: return value instanceof Error;
257
+ }
258
+ }
247
259
  // Equality function lovingly adapted from isEqual in
248
260
  // [Underscore](http://underscorejs.org)
249
261
  function eq(a, b, aStack, bStack, customTesters, hasKey) {
@@ -332,7 +344,7 @@ function eq(a, b, aStack, bStack, customTesters, hasKey) {
332
344
  if (className === "[object Array]" && a.length !== b.length) {
333
345
  return false;
334
346
  }
335
- if (a instanceof Error && b instanceof Error) {
347
+ if (isError(a) && isError(b)) {
336
348
  try {
337
349
  return isErrorEqual(a, b, aStack, bStack, customTesters, hasKey);
338
350
  } finally {
@@ -366,17 +378,17 @@ function isErrorEqual(a, b, aStack, bStack, customTesters, hasKey) {
366
378
  // - [[Prototype]] of objects are compared using the === operator.
367
379
  // - Only enumerable "own" properties are considered.
368
380
  // - Error names, messages, causes, and errors are always compared, even if these are not enumerable properties. errors is also compared.
369
- let result = Object.getPrototypeOf(a) === Object.getPrototypeOf(b) && a.name === b.name && a.message === b.message;
381
+ let result = Object.prototype.toString.call(a) === Object.prototype.toString.call(b) && a.name === b.name && a.message === b.message;
370
382
  // check Error.cause asymmetrically
371
383
  if (typeof b.cause !== "undefined") {
372
- result && (result = eq(a.cause, b.cause, aStack, bStack, customTesters, hasKey));
384
+ result &&= eq(a.cause, b.cause, aStack, bStack, customTesters, hasKey);
373
385
  }
374
386
  // AggregateError.errors
375
387
  if (a instanceof AggregateError && b instanceof AggregateError) {
376
- result && (result = eq(a.errors, b.errors, aStack, bStack, customTesters, hasKey));
388
+ result &&= eq(a.errors, b.errors, aStack, bStack, customTesters, hasKey);
377
389
  }
378
390
  // spread to compare enumerable properties
379
- result && (result = eq({ ...a }, { ...b }, aStack, bStack, customTesters, hasKey));
391
+ result &&= eq({ ...a }, { ...b }, aStack, bStack, customTesters, hasKey);
380
392
  return result;
381
393
  }
382
394
  function keys(obj, hasKey) {
@@ -570,7 +582,7 @@ function hasPropertyInObject(object, key) {
570
582
  return Object.hasOwn(object, key) || hasPropertyInObject(Object.getPrototypeOf(object), key);
571
583
  }
572
584
  function isObjectWithKeys(a) {
573
- return isObject(a) && !(a instanceof Error) && !Array.isArray(a) && !(a instanceof Date) && !(a instanceof Set) && !(a instanceof Map);
585
+ return isObject(a) && !isError(a) && !Array.isArray(a) && !(a instanceof Date) && !(a instanceof Set) && !(a instanceof Map);
574
586
  }
575
587
  function subsetEquality(object, subset, customTesters = []) {
576
588
  const filteredCustomTesters = customTesters.filter((t) => t !== subsetEquality);
@@ -653,10 +665,7 @@ function pluralize(word, count) {
653
665
  return `${count} ${word}${count === 1 ? "" : "s"}`;
654
666
  }
655
667
  function getObjectKeys(object) {
656
- return [...Object.keys(object), ...Object.getOwnPropertySymbols(object).filter((s) => {
657
- var _Object$getOwnPropert;
658
- return (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(object, s)) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.enumerable;
659
- })];
668
+ return [...Object.keys(object), ...Object.getOwnPropertySymbols(object).filter((s) => Object.getOwnPropertyDescriptor(object, s)?.enumerable)];
660
669
  }
661
670
  function getObjectSubset(object, subset, customTesters) {
662
671
  let stripped = 0;
@@ -834,10 +843,7 @@ class ObjectContaining extends AsymmetricMatcher {
834
843
  return this.hasProperty(this.getPrototype(obj), property);
835
844
  }
836
845
  getProperties(obj) {
837
- return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj).filter((s) => {
838
- var _Object$getOwnPropert;
839
- return (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(obj, s)) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.enumerable;
840
- })];
846
+ return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj).filter((s) => Object.getOwnPropertyDescriptor(obj, s)?.enumerable)];
841
847
  }
842
848
  asymmetricMatch(other, customTesters) {
843
849
  if (typeof this.sample !== "object") {
@@ -1032,9 +1038,8 @@ class SchemaMatching extends AsymmetricMatcher {
1032
1038
  return "object";
1033
1039
  }
1034
1040
  toAsymmetricMatcher() {
1035
- var _this$result;
1036
1041
  const { utils } = this.getMatcherContext();
1037
- const issues = ((_this$result = this.result) === null || _this$result === void 0 ? void 0 : _this$result.issues) || [];
1042
+ const issues = this.result?.issues || [];
1038
1043
  if (issues.length > 0) {
1039
1044
  return `${this.toString()} ${utils.stringify(this.result, undefined, { printBasicPrototype: false })}`;
1040
1045
  }
@@ -1062,13 +1067,14 @@ const JestAsymmetricMatchers = (chai, utils) => {
1062
1067
  };
1063
1068
 
1064
1069
  function createAssertionMessage(util, assertion, hasArgs) {
1070
+ const soft = util.flag(assertion, "soft") ? ".soft" : "";
1065
1071
  const not = util.flag(assertion, "negate") ? "not." : "";
1066
1072
  const name = `${util.flag(assertion, "_name")}(${hasArgs ? "expected" : ""})`;
1067
1073
  const promiseName = util.flag(assertion, "promise");
1068
1074
  const promise = promiseName ? `.${promiseName}` : "";
1069
- return `expect(actual)${promise}.${not}${name}`;
1075
+ return `expect${soft}(actual)${promise}.${not}${name}`;
1070
1076
  }
1071
- function recordAsyncExpect(_test, promise, assertion, error) {
1077
+ function recordAsyncExpect(_test, promise, assertion, error, isSoft) {
1072
1078
  const test = _test;
1073
1079
  // record promise for test, that resolves before test ends
1074
1080
  if (test && promise instanceof Promise) {
@@ -1086,17 +1092,23 @@ function recordAsyncExpect(_test, promise, assertion, error) {
1086
1092
  if (!test.promises) {
1087
1093
  test.promises = [];
1088
1094
  }
1095
+ // setup `expect.soft` handler here instead of `wrapAssertion`
1096
+ // to avoid double error tracking while keeping non-await promise detection.
1097
+ if (isSoft) {
1098
+ promise = promise.then(noop, (err) => {
1099
+ handleTestError(test, err);
1100
+ });
1101
+ }
1089
1102
  test.promises.push(promise);
1090
1103
  let resolved = false;
1091
- test.onFinished ?? (test.onFinished = []);
1104
+ test.onFinished ??= [];
1092
1105
  test.onFinished.push(() => {
1093
1106
  if (!resolved) {
1094
- var _vitest_worker__;
1095
- const processor = ((_vitest_worker__ = globalThis.__vitest_worker__) === null || _vitest_worker__ === void 0 ? void 0 : _vitest_worker__.onFilterStackTrace) || ((s) => s || "");
1107
+ const processor = globalThis.__vitest_worker__?.onFilterStackTrace || ((s) => s || "");
1096
1108
  const stack = processor(error.stack);
1097
1109
  console.warn([
1098
1110
  `Promise returned by \`${assertion}\` was not awaited. `,
1099
- "Vitest currently auto-awaits hanging assertions at the end of the test, but this will cause the test to fail in Vitest 3. ",
1111
+ "Vitest currently auto-awaits hanging assertions at the end of the test, but this will cause the test to fail in the next Vitest major. ",
1100
1112
  "Please remember to await the assertion.\n",
1101
1113
  stack
1102
1114
  ].join(""));
@@ -1119,10 +1131,9 @@ function recordAsyncExpect(_test, promise, assertion, error) {
1119
1131
  return promise;
1120
1132
  }
1121
1133
  function handleTestError(test, err) {
1122
- var _test$result;
1123
- test.result || (test.result = { state: "fail" });
1134
+ test.result ||= { state: "fail" };
1124
1135
  test.result.state = "fail";
1125
- (_test$result = test.result).errors || (_test$result.errors = []);
1136
+ test.result.errors ||= [];
1126
1137
  test.result.errors.push(processError(err));
1127
1138
  }
1128
1139
  function wrapAssertion(utils, name, fn) {
@@ -1132,7 +1143,11 @@ function wrapAssertion(utils, name, fn) {
1132
1143
  utils.flag(this, "_name", name);
1133
1144
  }
1134
1145
  if (!utils.flag(this, "soft")) {
1135
- return fn.apply(this, args);
1146
+ // avoid WebKit's proper tail call to preserve stacktrace offset for inline snapshot
1147
+ // https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit
1148
+ try {
1149
+ return fn.apply(this, args);
1150
+ } finally {}
1136
1151
  }
1137
1152
  const test = utils.flag(this, "vitest-test");
1138
1153
  if (!test) {
@@ -1482,7 +1497,7 @@ const JestChaiExpect = (chai, utils) => {
1482
1497
  throw new AssertionError(formatCalls(spy, msg, args));
1483
1498
  }
1484
1499
  });
1485
- def(["toHaveBeenNthCalledWith", "nthCalledWith"], function(times, ...args) {
1500
+ def("toHaveBeenNthCalledWith", function(times, ...args) {
1486
1501
  const spy = getSpy(this);
1487
1502
  const spyName = spy.getMockName();
1488
1503
  const nthCall = spy.mock.calls[times - 1];
@@ -1490,7 +1505,7 @@ const JestChaiExpect = (chai, utils) => {
1490
1505
  const isCalled = times <= callCount;
1491
1506
  this.assert(nthCall && equalsArgumentArray(nthCall, args), `expected ${ordinalOf(times)} "${spyName}" call to have been called with #{exp}${isCalled ? `` : `, but called only ${callCount} times`}`, `expected ${ordinalOf(times)} "${spyName}" call to not have been called with #{exp}`, args, nthCall, isCalled);
1492
1507
  });
1493
- def(["toHaveBeenLastCalledWith", "lastCalledWith"], function(...args) {
1508
+ def("toHaveBeenLastCalledWith", function(...args) {
1494
1509
  const spy = getSpy(this);
1495
1510
  const spyName = spy.getMockName();
1496
1511
  const lastCall = spy.mock.calls.at(-1);
@@ -1561,7 +1576,7 @@ const JestChaiExpect = (chai, utils) => {
1561
1576
  const name = expected.name || expected.prototype.constructor.name;
1562
1577
  return this.assert(thrown && thrown instanceof expected, `expected error to be instance of ${name}`, `expected error not to be instance of ${name}`, expected, thrown);
1563
1578
  }
1564
- if (expected instanceof Error) {
1579
+ if (isError(expected)) {
1565
1580
  const equal = equals(thrown, expected, [...customTesters, iterableEquality]);
1566
1581
  return this.assert(equal, "expected a thrown error to be #{exp}", "expected a thrown error not to be #{exp}", expected, thrown);
1567
1582
  }
@@ -1569,7 +1584,8 @@ const JestChaiExpect = (chai, utils) => {
1569
1584
  const matcher = expected;
1570
1585
  return this.assert(thrown && matcher.asymmetricMatch(thrown), "expected error to match asymmetric matcher", "expected error not to match asymmetric matcher", matcher, thrown);
1571
1586
  }
1572
- throw new Error(`"toThrow" expects string, RegExp, function, Error instance or asymmetric matcher, got "${typeof expected}"`);
1587
+ const equal = equals(thrown, expected, [...customTesters, iterableEquality]);
1588
+ return this.assert(equal, "expected a thrown value to equal #{exp}", "expected a thrown value not to equal #{exp}", expected, thrown);
1573
1589
  });
1574
1590
  [{
1575
1591
  name: "toHaveResolved",
@@ -1637,7 +1653,7 @@ const JestChaiExpect = (chai, utils) => {
1637
1653
  },
1638
1654
  action: "resolve"
1639
1655
  }, {
1640
- name: ["toHaveLastReturnedWith", "lastReturnedWith"],
1656
+ name: "toHaveLastReturnedWith",
1641
1657
  condition: (spy, value) => {
1642
1658
  const result = spy.mock.results.at(-1);
1643
1659
  return Boolean(result && result.type === "return" && equals(result.value, value));
@@ -1649,7 +1665,7 @@ const JestChaiExpect = (chai, utils) => {
1649
1665
  const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
1650
1666
  const result = results.at(-1);
1651
1667
  const spyName = spy.getMockName();
1652
- 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);
1668
+ this.assert(condition(spy, value), `expected last "${spyName}" call to ${action} #{exp}`, `expected last "${spyName}" call to not ${action} #{exp}`, value, result?.value);
1653
1669
  });
1654
1670
  });
1655
1671
  [{
@@ -1660,7 +1676,7 @@ const JestChaiExpect = (chai, utils) => {
1660
1676
  },
1661
1677
  action: "resolve"
1662
1678
  }, {
1663
- name: ["toHaveNthReturnedWith", "nthReturnedWith"],
1679
+ name: "toHaveNthReturnedWith",
1664
1680
  condition: (spy, index, value) => {
1665
1681
  const result = spy.mock.results[index - 1];
1666
1682
  return result && result.type === "return" && equals(result.value, value);
@@ -1673,7 +1689,7 @@ const JestChaiExpect = (chai, utils) => {
1673
1689
  const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
1674
1690
  const result = results[nthCall - 1];
1675
1691
  const ordinalCall = `${ordinalOf(nthCall)} call`;
1676
- this.assert(condition(spy, nthCall, value), `expected ${ordinalCall} "${spyName}" call to ${action} #{exp}`, `expected ${ordinalCall} "${spyName}" call to not ${action} #{exp}`, value, result === null || result === void 0 ? void 0 : result.value);
1692
+ this.assert(condition(spy, nthCall, value), `expected ${ordinalCall} "${spyName}" call to ${action} #{exp}`, `expected ${ordinalCall} "${spyName}" call to not ${action} #{exp}`, value, result?.value);
1677
1693
  });
1678
1694
  });
1679
1695
  // @ts-expect-error @internal
@@ -1692,7 +1708,7 @@ const JestChaiExpect = (chai, utils) => {
1692
1708
  if (utils.flag(this, "poll")) {
1693
1709
  throw new SyntaxError(`expect.poll() is not supported in combination with .resolves`);
1694
1710
  }
1695
- if (typeof (obj === null || obj === void 0 ? void 0 : obj.then) !== "function") {
1711
+ if (typeof obj?.then !== "function") {
1696
1712
  throw new TypeError(`You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`);
1697
1713
  }
1698
1714
  const proxy = new Proxy(this, { get: (target, key, receiver) => {
@@ -1702,14 +1718,18 @@ const JestChaiExpect = (chai, utils) => {
1702
1718
  }
1703
1719
  return (...args) => {
1704
1720
  utils.flag(this, "_name", key);
1705
- const promise = obj.then((value) => {
1721
+ const promise = Promise.resolve(obj).then((value) => {
1706
1722
  utils.flag(this, "object", value);
1707
1723
  return result.call(this, ...args);
1708
1724
  }, (err) => {
1709
1725
  const _error = new AssertionError(`promise rejected "${utils.inspect(err)}" instead of resolving`, { showDiff: false });
1710
1726
  _error.cause = err;
1711
- _error.stack = error.stack.replace(error.message, _error.message);
1712
1727
  throw _error;
1728
+ }).catch((err) => {
1729
+ if (isError(err) && error.stack) {
1730
+ err.stack = error.stack.replace(error.message, err.message);
1731
+ }
1732
+ throw err;
1713
1733
  });
1714
1734
  return recordAsyncExpect(test, promise, createAssertionMessage(utils, this, !!args.length), error);
1715
1735
  };
@@ -1726,7 +1746,7 @@ const JestChaiExpect = (chai, utils) => {
1726
1746
  if (utils.flag(this, "poll")) {
1727
1747
  throw new SyntaxError(`expect.poll() is not supported in combination with .rejects`);
1728
1748
  }
1729
- if (typeof (wrapper === null || wrapper === void 0 ? void 0 : wrapper.then) !== "function") {
1749
+ if (typeof wrapper?.then !== "function") {
1730
1750
  throw new TypeError(`You must provide a Promise to expect() when using .rejects, not '${typeof wrapper}'.`);
1731
1751
  }
1732
1752
  const proxy = new Proxy(this, { get: (target, key, receiver) => {
@@ -1736,17 +1756,21 @@ const JestChaiExpect = (chai, utils) => {
1736
1756
  }
1737
1757
  return (...args) => {
1738
1758
  utils.flag(this, "_name", key);
1739
- const promise = wrapper.then((value) => {
1759
+ const promise = Promise.resolve(wrapper).then((value) => {
1740
1760
  const _error = new AssertionError(`promise resolved "${utils.inspect(value)}" instead of rejecting`, {
1741
1761
  showDiff: true,
1742
1762
  expected: new Error("rejected promise"),
1743
1763
  actual: value
1744
1764
  });
1745
- _error.stack = error.stack.replace(error.message, _error.message);
1746
1765
  throw _error;
1747
1766
  }, (err) => {
1748
1767
  utils.flag(this, "object", err);
1749
1768
  return result.call(this, ...args);
1769
+ }).catch((err) => {
1770
+ if (isError(err) && error.stack) {
1771
+ err.stack = error.stack.replace(error.message, err.message);
1772
+ }
1773
+ throw err;
1750
1774
  });
1751
1775
  return recordAsyncExpect(test, promise, createAssertionMessage(utils, this, !!args.length), error);
1752
1776
  };
@@ -1770,7 +1794,7 @@ function ordinalOf(i) {
1770
1794
  }
1771
1795
  function formatCalls(spy, msg, showActualCall) {
1772
1796
  if (spy.mock.calls.length) {
1773
- msg += c.gray(`\n\nReceived: \n\n${spy.mock.calls.map((callArg, i) => {
1797
+ msg += c.gray(`\n\nReceived:\n\n${spy.mock.calls.map((callArg, i) => {
1774
1798
  let methodCall = c.bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call:\n\n`);
1775
1799
  if (showActualCall) {
1776
1800
  methodCall += diff(showActualCall, callArg, { omitAnnotationLines: true });
@@ -1786,7 +1810,7 @@ function formatCalls(spy, msg, showActualCall) {
1786
1810
  }
1787
1811
  function formatReturns(spy, results, msg, showActualReturn) {
1788
1812
  if (results.length) {
1789
- msg += c.gray(`\n\nReceived: \n\n${results.map((callReturn, i) => {
1813
+ msg += c.gray(`\n\nReceived:\n\n${results.map((callReturn, i) => {
1790
1814
  let methodCall = c.bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call return:\n\n`);
1791
1815
  if (showActualReturn) {
1792
1816
  methodCall += diff(showActualReturn, callReturn.value, { omitAnnotationLines: true });
@@ -1814,8 +1838,8 @@ function getMatcherState(assertion, expect) {
1814
1838
  subsetEquality
1815
1839
  };
1816
1840
  let task = util.flag(assertion, "vitest-test");
1817
- const currentTestName = (task === null || task === void 0 ? void 0 : task.fullTestName) ?? "";
1818
- if ((task === null || task === void 0 ? void 0 : task.type) !== "test") {
1841
+ const currentTestName = task?.fullTestName ?? "";
1842
+ if (task?.type !== "test") {
1819
1843
  task = undefined;
1820
1844
  }
1821
1845
  const matcherState = {
@@ -1917,4 +1941,4 @@ const JestExtend = (chai, utils) => {
1917
1941
  });
1918
1942
  };
1919
1943
 
1920
- export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, ChaiStyleAssertions, 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 };
1944
+ export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, ChaiStyleAssertions, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, SchemaMatching, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, createAssertionMessage, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isError, isImmutableUnorderedKeyed, isImmutableUnorderedSet, isStandardSchema, iterableEquality, pluralize, recordAsyncExpect, setState, sparseArrayEquality, subsetEquality, typeEquality, wrapAssertion };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/expect",
3
3
  "type": "module",
4
- "version": "4.1.0-beta.3",
4
+ "version": "4.1.0-beta.5",
5
5
  "description": "Jest's expect matchers as a Chai plugin",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -33,11 +33,11 @@
33
33
  "@types/chai": "^5.2.2",
34
34
  "chai": "^6.2.2",
35
35
  "tinyrainbow": "^3.0.3",
36
- "@vitest/spy": "4.1.0-beta.3",
37
- "@vitest/utils": "4.1.0-beta.3"
36
+ "@vitest/spy": "4.1.0-beta.5",
37
+ "@vitest/utils": "4.1.0-beta.5"
38
38
  },
39
39
  "devDependencies": {
40
- "@vitest/runner": "4.1.0-beta.3"
40
+ "@vitest/runner": "4.1.0-beta.5"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "premove dist && rollup -c",