vitest 4.1.2 → 4.1.3

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.
Files changed (39) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{base.BPik1OqN.js → base.C3wvLFNM.js} +4 -4
  4. package/dist/chunks/{browser.d.BMOr_Kmk.d.ts → browser.d.C0zGu1u9.d.ts} +1 -1
  5. package/dist/chunks/{cac.DRKYQDPl.js → cac.Bb7YBzMA.js} +17 -5
  6. package/dist/chunks/{cli-api.Bxr1Nn49.js → cli-api.CaPRsymo.js} +42 -11
  7. package/dist/chunks/{config.d.Cz9kPrQs.d.ts → config.d.ChUh6-ad.d.ts} +1 -0
  8. package/dist/chunks/{coverage.kqM80boz.js → coverage.CwUlQe0s.js} +1 -0
  9. package/dist/chunks/{global.d.x-ILCfAE.d.ts → global.d.D74z04P1.d.ts} +2 -0
  10. package/dist/chunks/{globals.CVqIbOyt.js → globals.7B-4LHAF.js} +3 -3
  11. package/dist/chunks/{index.DOa3dzoN.js → index.4L3g53iW.js} +2 -1
  12. package/dist/chunks/{index.nZ2xqFgD.js → index.Cj9kDiDi.js} +2 -2
  13. package/dist/chunks/{index.0GYC6HAu.js → index.DICur-LY.js} +1 -0
  14. package/dist/chunks/{plugin.d.BWbK_Jpw.d.ts → plugin.d.BssAumYw.d.ts} +1 -1
  15. package/dist/chunks/{reporters.d.B0uk8id2.d.ts → reporters.d.yJ2fBir5.d.ts} +14 -3
  16. package/dist/chunks/{setup-common.2wZXQUjS.js → setup-common.NdrZGMhw.js} +1 -1
  17. package/dist/chunks/{test.p_J6dB8a.js → test.BmQO5GaM.js} +401 -335
  18. package/dist/chunks/{vm.BvVhnZPV.js → vm.DVLYObm9.js} +5 -4
  19. package/dist/chunks/{worker.d.BT5j8dyR.d.ts → worker.d.CckNUvI5.d.ts} +1 -1
  20. package/dist/cli.js +1 -1
  21. package/dist/config.d.ts +6 -6
  22. package/dist/coverage.d.ts +4 -4
  23. package/dist/coverage.js +1 -1
  24. package/dist/index.d.ts +79 -9
  25. package/dist/index.js +3 -3
  26. package/dist/node.d.ts +8 -8
  27. package/dist/node.js +6 -6
  28. package/dist/reporters.d.ts +4 -4
  29. package/dist/reporters.js +1 -1
  30. package/dist/runners.d.ts +1 -1
  31. package/dist/runners.js +2 -2
  32. package/dist/worker.d.ts +2 -2
  33. package/dist/worker.js +5 -5
  34. package/dist/workers/forks.js +5 -5
  35. package/dist/workers/runVmTests.js +4 -4
  36. package/dist/workers/threads.js +5 -5
  37. package/dist/workers/vmForks.js +1 -1
  38. package/dist/workers/vmThreads.js +1 -1
  39. package/package.json +20 -12
@@ -2,346 +2,17 @@ import { getCurrentTest, updateTask, createTaskCollector, getCurrentSuite, getHo
2
2
  import { assertTypes, createSimpleStackTrace, createDefer } from '@vitest/utils/helpers';
3
3
  import { getSafeTimers, delay } from '@vitest/utils/timers';
4
4
  import { a as getBenchOptions, g as getBenchFn } from './benchmark.CX_oY03V.js';
5
- import { g as getWorkerState, i as isChildProcess, w as waitForImportsToResolve, r as resetModules } from './utils.BX5Fg8C4.js';
5
+ import { i as isChildProcess, w as waitForImportsToResolve, r as resetModules, g as getWorkerState } from './utils.BX5Fg8C4.js';
6
6
  import { chai, wrapAssertion, recordAsyncExpect, createAssertionMessage, equals, iterableEquality, subsetEquality, JestExtend, JestChaiExpect, ChaiStyleAssertions, JestAsymmetricMatchers, GLOBAL_EXPECT, ASYMMETRIC_MATCHERS_OBJECT, getState, setState, addCustomEqualityTesters, customMatchers } from '@vitest/expect';
7
7
  import { getNames, getTests, getTestName, createChainable, matchesTags } from '@vitest/runner/utils';
8
8
  import { processError } from '@vitest/utils/error';
9
9
  import { normalize } from 'pathe';
10
- import { stripSnapshotIndentation, addSerializer, SnapshotClient } from '@vitest/snapshot';
11
10
  import { fn, spyOn, restoreAllMocks, resetAllMocks, clearAllMocks, isMockFunction } from '@vitest/spy';
12
11
  import '@vitest/utils/offset';
13
12
  import { parseSingleStack } from '@vitest/utils/source-map';
14
13
  import { c as commonjsGlobal } from './_commonjsHelpers.D26ty3Ew.js';
15
14
  import { R as RealDate, b as resetDate, m as mockDate, r as rpc } from './rpc.MzXet3jl.js';
16
-
17
- // these matchers are not supported because they don't make sense with poll
18
- const unsupported = [
19
- "matchSnapshot",
20
- "toMatchSnapshot",
21
- "toMatchInlineSnapshot",
22
- "toThrowErrorMatchingSnapshot",
23
- "toThrowErrorMatchingInlineSnapshot",
24
- "throws",
25
- "Throw",
26
- "throw",
27
- "toThrow",
28
- "toThrowError"
29
- ];
30
- /**
31
- * Attaches a `cause` property to the error if missing, copies the stack trace from the source, and throws.
32
- *
33
- * @param error - The error to throw
34
- * @param source - Error to copy the stack trace from
35
- *
36
- * @throws Always throws the provided error with an amended stack trace
37
- */
38
- function throwWithCause(error, source) {
39
- if (error.cause == null) error.cause = /* @__PURE__ */ new Error("Matcher did not succeed in time.");
40
- throw copyStackTrace$1(error, source);
41
- }
42
- function createExpectPoll(expect) {
43
- return function poll(fn, options = {}) {
44
- const defaults = getWorkerState().config.expect?.poll ?? {};
45
- const { interval = defaults.interval ?? 50, timeout = defaults.timeout ?? 1e3, message } = options;
46
- // @ts-expect-error private poll access
47
- const assertion = expect(null, message).withContext({ poll: true });
48
- fn = fn.bind(assertion);
49
- const test = chai.util.flag(assertion, "vitest-test");
50
- if (!test) throw new Error("expect.poll() must be called inside a test");
51
- const proxy = new Proxy(assertion, { get(target, key, receiver) {
52
- const assertionFunction = Reflect.get(target, key, receiver);
53
- if (typeof assertionFunction !== "function") return assertionFunction instanceof chai.Assertion ? proxy : assertionFunction;
54
- if (key === "assert") return assertionFunction;
55
- if (typeof key === "string" && unsupported.includes(key)) throw new SyntaxError(`expect.poll() is not supported in combination with .${key}(). Use vi.waitFor() if your assertion condition is unstable.`);
56
- return function(...args) {
57
- const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
58
- const promise = async () => {
59
- const { setTimeout, clearTimeout } = getSafeTimers();
60
- let executionPhase = "fn";
61
- let hasTimedOut = false;
62
- const timerId = setTimeout(() => {
63
- hasTimedOut = true;
64
- }, timeout);
65
- chai.util.flag(assertion, "_name", key);
66
- const onSettled = chai.util.flag(assertion, "_poll.onSettled");
67
- try {
68
- while (true) {
69
- const isLastAttempt = hasTimedOut;
70
- if (isLastAttempt) chai.util.flag(assertion, "_isLastPollAttempt", true);
71
- try {
72
- executionPhase = "fn";
73
- const obj = await fn();
74
- chai.util.flag(assertion, "object", obj);
75
- executionPhase = "assertion";
76
- const output = await assertionFunction.call(assertion, ...args);
77
- await onSettled?.({
78
- assertion,
79
- status: "pass"
80
- });
81
- return output;
82
- } catch (err) {
83
- if (isLastAttempt || executionPhase === "assertion" && chai.util.flag(assertion, "_poll.assert_once")) {
84
- await onSettled?.({
85
- assertion,
86
- status: "fail"
87
- });
88
- throwWithCause(err, STACK_TRACE_ERROR);
89
- }
90
- await delay(interval, setTimeout);
91
- }
92
- }
93
- } finally {
94
- clearTimeout(timerId);
95
- }
96
- };
97
- let awaited = false;
98
- test.onFinished ??= [];
99
- test.onFinished.push(() => {
100
- if (!awaited) {
101
- const negated = chai.util.flag(assertion, "negate") ? "not." : "";
102
- const assertionString = `expect.${chai.util.flag(assertion, "_poll.element") ? "element(locator)" : "poll(assertion)"}.${negated}${String(key)}()`;
103
- throw copyStackTrace$1(/* @__PURE__ */ new Error(`${assertionString} was not awaited. This assertion is asynchronous and must be awaited; otherwise, it is not executed to avoid unhandled rejections:\n\nawait ${assertionString}\n`), STACK_TRACE_ERROR);
104
- }
105
- });
106
- let resultPromise;
107
- // only .then is enough to check awaited, but we type this as `Promise<void>` in global types
108
- // so let's follow it
109
- return {
110
- then(onFulfilled, onRejected) {
111
- awaited = true;
112
- return (resultPromise ||= promise()).then(onFulfilled, onRejected);
113
- },
114
- catch(onRejected) {
115
- awaited = true;
116
- return (resultPromise ||= promise()).catch(onRejected);
117
- },
118
- finally(onFinally) {
119
- awaited = true;
120
- return (resultPromise ||= promise()).finally(onFinally);
121
- },
122
- [Symbol.toStringTag]: "Promise"
123
- };
124
- };
125
- } });
126
- return proxy;
127
- };
128
- }
129
- function copyStackTrace$1(target, source) {
130
- if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
131
- return target;
132
- }
133
-
134
- let _client;
135
- function getSnapshotClient() {
136
- if (!_client) _client = new SnapshotClient({ isEqual: (received, expected) => {
137
- return equals(received, expected, [iterableEquality, subsetEquality]);
138
- } });
139
- return _client;
140
- }
141
- function getError(expected, promise) {
142
- if (typeof expected !== "function") {
143
- if (!promise) throw new Error(`expected must be a function, received ${typeof expected}`);
144
- // when "promised", it receives thrown error
145
- return expected;
146
- }
147
- try {
148
- expected();
149
- } catch (e) {
150
- return e;
151
- }
152
- throw new Error("snapshot function didn't throw");
153
- }
154
- function getTestNames(test) {
155
- return {
156
- filepath: test.file.filepath,
157
- name: getNames(test).slice(1).join(" > "),
158
- testId: test.id
159
- };
160
- }
161
- const SnapshotPlugin = (chai, utils) => {
162
- function getTest(assertionName, obj) {
163
- const test = utils.flag(obj, "vitest-test");
164
- if (!test) throw new Error(`'${assertionName}' cannot be used without test context`);
165
- return test;
166
- }
167
- for (const key of ["matchSnapshot", "toMatchSnapshot"]) utils.addMethod(chai.Assertion.prototype, key, wrapAssertion(utils, key, function(properties, message) {
168
- utils.flag(this, "_name", key);
169
- if (utils.flag(this, "negate")) throw new Error(`${key} cannot be used with "not"`);
170
- const expected = utils.flag(this, "object");
171
- const test = getTest(key, this);
172
- if (typeof properties === "string" && typeof message === "undefined") {
173
- message = properties;
174
- properties = void 0;
175
- }
176
- const errorMessage = utils.flag(this, "message");
177
- getSnapshotClient().assert({
178
- received: expected,
179
- message,
180
- isInline: false,
181
- properties,
182
- errorMessage,
183
- ...getTestNames(test)
184
- });
185
- }));
186
- utils.addMethod(chai.Assertion.prototype, "toMatchFileSnapshot", function(file, message) {
187
- utils.flag(this, "_name", "toMatchFileSnapshot");
188
- if (utils.flag(this, "negate")) throw new Error("toMatchFileSnapshot cannot be used with \"not\"");
189
- const error = /* @__PURE__ */ new Error("resolves");
190
- const expected = utils.flag(this, "object");
191
- const test = getTest("toMatchFileSnapshot", this);
192
- const errorMessage = utils.flag(this, "message");
193
- return recordAsyncExpect(test, getSnapshotClient().assertRaw({
194
- received: expected,
195
- message,
196
- isInline: false,
197
- rawSnapshot: { file },
198
- errorMessage,
199
- ...getTestNames(test)
200
- }), createAssertionMessage(utils, this, true), error, utils.flag(this, "soft"));
201
- });
202
- utils.addMethod(chai.Assertion.prototype, "toMatchInlineSnapshot", wrapAssertion(utils, "toMatchInlineSnapshot", function __INLINE_SNAPSHOT_OFFSET_3__(properties, inlineSnapshot, message) {
203
- utils.flag(this, "_name", "toMatchInlineSnapshot");
204
- if (utils.flag(this, "negate")) throw new Error("toMatchInlineSnapshot cannot be used with \"not\"");
205
- const test = getTest("toMatchInlineSnapshot", this);
206
- const expected = utils.flag(this, "object");
207
- const error = utils.flag(this, "error");
208
- if (typeof properties === "string") {
209
- message = inlineSnapshot;
210
- inlineSnapshot = properties;
211
- properties = void 0;
212
- }
213
- if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
214
- const errorMessage = utils.flag(this, "message");
215
- getSnapshotClient().assert({
216
- received: expected,
217
- message,
218
- isInline: true,
219
- properties,
220
- inlineSnapshot,
221
- error,
222
- errorMessage,
223
- ...getTestNames(test)
224
- });
225
- }));
226
- utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingSnapshot", wrapAssertion(utils, "toThrowErrorMatchingSnapshot", function(properties, message) {
227
- utils.flag(this, "_name", "toThrowErrorMatchingSnapshot");
228
- if (utils.flag(this, "negate")) throw new Error("toThrowErrorMatchingSnapshot cannot be used with \"not\"");
229
- const expected = utils.flag(this, "object");
230
- const test = getTest("toThrowErrorMatchingSnapshot", this);
231
- const promise = utils.flag(this, "promise");
232
- const errorMessage = utils.flag(this, "message");
233
- getSnapshotClient().assert({
234
- received: getError(expected, promise),
235
- message,
236
- errorMessage,
237
- ...getTestNames(test)
238
- });
239
- }));
240
- utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingInlineSnapshot", wrapAssertion(utils, "toThrowErrorMatchingInlineSnapshot", function __INLINE_SNAPSHOT_OFFSET_3__(inlineSnapshot, message) {
241
- if (utils.flag(this, "negate")) throw new Error("toThrowErrorMatchingInlineSnapshot cannot be used with \"not\"");
242
- const test = getTest("toThrowErrorMatchingInlineSnapshot", this);
243
- const expected = utils.flag(this, "object");
244
- const error = utils.flag(this, "error");
245
- const promise = utils.flag(this, "promise");
246
- const errorMessage = utils.flag(this, "message");
247
- if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
248
- getSnapshotClient().assert({
249
- received: getError(expected, promise),
250
- message,
251
- inlineSnapshot,
252
- isInline: true,
253
- error,
254
- errorMessage,
255
- ...getTestNames(test)
256
- });
257
- }));
258
- utils.addMethod(chai.expect, "addSnapshotSerializer", addSerializer);
259
- };
260
-
261
- chai.use(JestExtend);
262
- chai.use(JestChaiExpect);
263
- chai.use(ChaiStyleAssertions);
264
- chai.use(SnapshotPlugin);
265
- chai.use(JestAsymmetricMatchers);
266
-
267
- function createExpect(test) {
268
- const expect = ((value, message) => {
269
- const { assertionCalls } = getState(expect);
270
- setState({ assertionCalls: assertionCalls + 1 }, expect);
271
- const assert = chai.expect(value, message);
272
- const _test = test || getCurrentTest();
273
- if (_test)
274
- // @ts-expect-error internal
275
- return assert.withTest(_test);
276
- else return assert;
277
- });
278
- Object.assign(expect, chai.expect);
279
- Object.assign(expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
280
- expect.getState = () => getState(expect);
281
- expect.setState = (state) => setState(state, expect);
282
- // @ts-expect-error global is not typed
283
- const globalState = getState(globalThis[GLOBAL_EXPECT]) || {};
284
- setState({
285
- ...globalState,
286
- assertionCalls: 0,
287
- isExpectingAssertions: false,
288
- isExpectingAssertionsError: null,
289
- expectedAssertionsNumber: null,
290
- expectedAssertionsNumberErrorGen: null,
291
- get testPath() {
292
- return getWorkerState().filepath;
293
- },
294
- currentTestName: test ? test.fullTestName ?? "" : globalState.currentTestName
295
- }, expect);
296
- expect.assert = chai.assert;
297
- // @ts-expect-error untyped
298
- expect.extend = (matchers) => chai.expect.extend(expect, matchers);
299
- expect.addEqualityTesters = (customTesters) => addCustomEqualityTesters(customTesters);
300
- expect.soft = (...args) => {
301
- // @ts-expect-error private soft access
302
- return expect(...args).withContext({ soft: true });
303
- };
304
- expect.poll = createExpectPoll(expect);
305
- expect.unreachable = (message) => {
306
- chai.assert.fail(`expected${message ? ` "${message}" ` : " "}not to be reached`);
307
- };
308
- function assertions(expected) {
309
- const errorGen = () => /* @__PURE__ */ new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`);
310
- if (Error.captureStackTrace) Error.captureStackTrace(errorGen(), assertions);
311
- expect.setState({
312
- expectedAssertionsNumber: expected,
313
- expectedAssertionsNumberErrorGen: errorGen
314
- });
315
- }
316
- function hasAssertions() {
317
- const error = /* @__PURE__ */ new Error("expected any number of assertion, but got none");
318
- if (Error.captureStackTrace) Error.captureStackTrace(error, hasAssertions);
319
- expect.setState({
320
- isExpectingAssertions: true,
321
- isExpectingAssertionsError: error
322
- });
323
- }
324
- chai.util.addMethod(expect, "assertions", assertions);
325
- chai.util.addMethod(expect, "hasAssertions", hasAssertions);
326
- expect.extend(customMatchers);
327
- return expect;
328
- }
329
- const globalExpect = createExpect();
330
- Object.defineProperty(globalThis, GLOBAL_EXPECT, {
331
- value: globalExpect,
332
- writable: true,
333
- configurable: true
334
- });
335
- const assert = chai.assert;
336
- const should = chai.should;
337
-
338
- /**
339
- * Gives access to injected context provided from the main thread.
340
- * This usually returns a value provided by `globalSetup` or an external library.
341
- */
342
- function inject(key) {
343
- return getWorkerState().providedContext[key];
344
- }
15
+ import { addSerializer, stripSnapshotIndentation, SnapshotClient } from '@vitest/snapshot';
345
16
 
346
17
  var fakeTimersSrc = {};
347
18
 
@@ -3681,7 +3352,7 @@ class FakeTimers {
3681
3352
  }
3682
3353
  }
3683
3354
 
3684
- function copyStackTrace(target, source) {
3355
+ function copyStackTrace$1(target, source) {
3685
3356
  if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
3686
3357
  return target;
3687
3358
  }
@@ -3702,7 +3373,7 @@ function waitFor(callback, options = {}) {
3702
3373
  const handleTimeout = () => {
3703
3374
  if (intervalId) clearInterval(intervalId);
3704
3375
  let error = lastError;
3705
- if (!error) error = copyStackTrace(/* @__PURE__ */ new Error("Timed out in waitFor!"), STACK_TRACE_ERROR);
3376
+ if (!error) error = copyStackTrace$1(/* @__PURE__ */ new Error("Timed out in waitFor!"), STACK_TRACE_ERROR);
3706
3377
  reject(error);
3707
3378
  };
3708
3379
  const checkCallback = () => {
@@ -3743,7 +3414,7 @@ function waitUntil(callback, options = {}) {
3743
3414
  let intervalId;
3744
3415
  const onReject = (error) => {
3745
3416
  if (intervalId) clearInterval(intervalId);
3746
- if (!error) error = copyStackTrace(/* @__PURE__ */ new Error("Timed out in waitUntil!"), STACK_TRACE_ERROR);
3417
+ if (!error) error = copyStackTrace$1(/* @__PURE__ */ new Error("Timed out in waitUntil!"), STACK_TRACE_ERROR);
3747
3418
  reject(error);
3748
3419
  };
3749
3420
  const onResolve = (result) => {
@@ -4012,6 +3683,401 @@ function getImporter(name) {
4012
3683
  }) + 1])?.file || "";
4013
3684
  }
4014
3685
 
3686
+ // these matchers are not supported because they don't make sense with poll
3687
+ const unsupported = [
3688
+ "matchSnapshot",
3689
+ "toMatchSnapshot",
3690
+ "toMatchInlineSnapshot",
3691
+ "toThrowErrorMatchingSnapshot",
3692
+ "toThrowErrorMatchingInlineSnapshot",
3693
+ "throws",
3694
+ "Throw",
3695
+ "throw",
3696
+ "toThrow",
3697
+ "toThrowError"
3698
+ ];
3699
+ /**
3700
+ * Attaches a `cause` property to the error if missing, copies the stack trace from the source, and throws.
3701
+ *
3702
+ * @param error - The error to throw
3703
+ * @param source - Error to copy the stack trace from
3704
+ *
3705
+ * @throws Always throws the provided error with an amended stack trace
3706
+ */
3707
+ function throwWithCause(error, source) {
3708
+ if (error.cause == null) error.cause = /* @__PURE__ */ new Error("Matcher did not succeed in time.");
3709
+ throw copyStackTrace(error, source);
3710
+ }
3711
+ function createExpectPoll(expect) {
3712
+ return function poll(fn, options = {}) {
3713
+ const defaults = getWorkerState().config.expect?.poll ?? {};
3714
+ const { interval = defaults.interval ?? 50, timeout = defaults.timeout ?? 1e3, message } = options;
3715
+ // @ts-expect-error private poll access
3716
+ const assertion = expect(null, message).withContext({ poll: true });
3717
+ fn = fn.bind(assertion);
3718
+ const test = chai.util.flag(assertion, "vitest-test");
3719
+ if (!test) throw new Error("expect.poll() must be called inside a test");
3720
+ const proxy = new Proxy(assertion, { get(target, key, receiver) {
3721
+ const assertionFunction = Reflect.get(target, key, receiver);
3722
+ if (typeof assertionFunction !== "function") return assertionFunction instanceof chai.Assertion ? proxy : assertionFunction;
3723
+ if (key === "assert") return assertionFunction;
3724
+ if (typeof key === "string" && unsupported.includes(key)) throw new SyntaxError(`expect.poll() is not supported in combination with .${key}(). Use vi.waitFor() if your assertion condition is unstable.`);
3725
+ return function(...args) {
3726
+ const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
3727
+ const promise = async () => {
3728
+ const { setTimeout, clearTimeout } = getSafeTimers();
3729
+ let executionPhase = "fn";
3730
+ let hasTimedOut = false;
3731
+ const timerId = setTimeout(() => {
3732
+ hasTimedOut = true;
3733
+ }, timeout);
3734
+ chai.util.flag(assertion, "_name", key);
3735
+ const onSettled = chai.util.flag(assertion, "_poll.onSettled");
3736
+ try {
3737
+ while (true) {
3738
+ const isLastAttempt = hasTimedOut;
3739
+ if (isLastAttempt) chai.util.flag(assertion, "_isLastPollAttempt", true);
3740
+ try {
3741
+ executionPhase = "fn";
3742
+ const obj = await fn();
3743
+ chai.util.flag(assertion, "object", obj);
3744
+ executionPhase = "assertion";
3745
+ const output = await assertionFunction.call(assertion, ...args);
3746
+ await onSettled?.({
3747
+ assertion,
3748
+ status: "pass"
3749
+ });
3750
+ return output;
3751
+ } catch (err) {
3752
+ if (isLastAttempt || executionPhase === "assertion" && chai.util.flag(assertion, "_poll.assert_once")) {
3753
+ await onSettled?.({
3754
+ assertion,
3755
+ status: "fail"
3756
+ });
3757
+ throwWithCause(err, STACK_TRACE_ERROR);
3758
+ }
3759
+ await delay(interval, setTimeout);
3760
+ if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
3761
+ }
3762
+ }
3763
+ } finally {
3764
+ clearTimeout(timerId);
3765
+ }
3766
+ };
3767
+ let awaited = false;
3768
+ test.onFinished ??= [];
3769
+ test.onFinished.push(() => {
3770
+ if (!awaited) {
3771
+ const negated = chai.util.flag(assertion, "negate") ? "not." : "";
3772
+ const assertionString = `expect.${chai.util.flag(assertion, "_poll.element") ? "element(locator)" : "poll(assertion)"}.${negated}${String(key)}()`;
3773
+ throw copyStackTrace(/* @__PURE__ */ new Error(`${assertionString} was not awaited. This assertion is asynchronous and must be awaited; otherwise, it is not executed to avoid unhandled rejections:\n\nawait ${assertionString}\n`), STACK_TRACE_ERROR);
3774
+ }
3775
+ });
3776
+ let resultPromise;
3777
+ // only .then is enough to check awaited, but we type this as `Promise<void>` in global types
3778
+ // so let's follow it
3779
+ return {
3780
+ then(onFulfilled, onRejected) {
3781
+ awaited = true;
3782
+ return (resultPromise ||= promise()).then(onFulfilled, onRejected);
3783
+ },
3784
+ catch(onRejected) {
3785
+ awaited = true;
3786
+ return (resultPromise ||= promise()).catch(onRejected);
3787
+ },
3788
+ finally(onFinally) {
3789
+ awaited = true;
3790
+ return (resultPromise ||= promise()).finally(onFinally);
3791
+ },
3792
+ [Symbol.toStringTag]: "Promise"
3793
+ };
3794
+ };
3795
+ } });
3796
+ return proxy;
3797
+ };
3798
+ }
3799
+ function copyStackTrace(target, source) {
3800
+ if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
3801
+ return target;
3802
+ }
3803
+
3804
+ let _client;
3805
+ function getSnapshotClient() {
3806
+ if (!_client) _client = new SnapshotClient({ isEqual: (received, expected) => {
3807
+ return equals(received, expected, [iterableEquality, subsetEquality]);
3808
+ } });
3809
+ return _client;
3810
+ }
3811
+ function getError(expected, promise) {
3812
+ if (typeof expected !== "function") {
3813
+ if (!promise) throw new Error(`expected must be a function, received ${typeof expected}`);
3814
+ // when "promised", it receives thrown error
3815
+ return expected;
3816
+ }
3817
+ try {
3818
+ expected();
3819
+ } catch (e) {
3820
+ return e;
3821
+ }
3822
+ throw new Error("snapshot function didn't throw");
3823
+ }
3824
+ function getTestNames(test) {
3825
+ return {
3826
+ filepath: test.file.filepath,
3827
+ name: getNames(test).slice(1).join(" > "),
3828
+ testId: test.id
3829
+ };
3830
+ }
3831
+ function getAssertionName(assertion) {
3832
+ const name = chai.util.flag(assertion, "_name");
3833
+ if (!name) throw new Error("Assertion name is not set. This is a bug in Vitest. Please, open a new issue with reproduction.");
3834
+ return name;
3835
+ }
3836
+ function getTest(obj) {
3837
+ const test = chai.util.flag(obj, "vitest-test");
3838
+ if (!test) throw new Error(`'${getAssertionName(obj)}' cannot be used without test context`);
3839
+ return test;
3840
+ }
3841
+ function validateAssertion(assertion) {
3842
+ if (chai.util.flag(assertion, "negate")) throw new Error(`${getAssertionName(assertion)} cannot be used with "not"`);
3843
+ }
3844
+ const SnapshotPlugin = (chai, utils) => {
3845
+ for (const key of ["matchSnapshot", "toMatchSnapshot"]) utils.addMethod(chai.Assertion.prototype, key, wrapAssertion(utils, key, function(propertiesOrHint, hint) {
3846
+ return assertMatchResult(toMatchSnapshotImpl({
3847
+ assertion: this,
3848
+ received: utils.flag(this, "object"),
3849
+ ...normalizeArguments(propertiesOrHint, hint)
3850
+ }));
3851
+ }));
3852
+ utils.addMethod(chai.Assertion.prototype, "toMatchFileSnapshot", function(filepath, hint) {
3853
+ // set name manually since it's not wrapped by wrapAssertion
3854
+ utils.flag(this, "_name", "toMatchFileSnapshot");
3855
+ // validate early synchronously just not to break some existing tests
3856
+ validateAssertion(this);
3857
+ const assertPromise = toMatchFileSnapshotImpl({
3858
+ assertion: this,
3859
+ received: utils.flag(this, "object"),
3860
+ filepath,
3861
+ hint
3862
+ }).then((result) => assertMatchResult(result));
3863
+ return recordAsyncExpect(getTest(this), assertPromise, createAssertionMessage(utils, this, true), /* @__PURE__ */ new Error("resolves"), utils.flag(this, "soft"));
3864
+ });
3865
+ utils.addMethod(chai.Assertion.prototype, "toMatchInlineSnapshot", wrapAssertion(utils, "toMatchInlineSnapshot", function __INLINE_SNAPSHOT_OFFSET_3__(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint) {
3866
+ return assertMatchResult(toMatchSnapshotImpl({
3867
+ assertion: this,
3868
+ received: utils.flag(this, "object"),
3869
+ isInline: true,
3870
+ ...normalizeInlineArguments(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint)
3871
+ }));
3872
+ }));
3873
+ utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingSnapshot", wrapAssertion(utils, "toThrowErrorMatchingSnapshot", function(propertiesOrHint, hint) {
3874
+ validateAssertion(this);
3875
+ const received = utils.flag(this, "object");
3876
+ const promise = utils.flag(this, "promise");
3877
+ return assertMatchResult(toMatchSnapshotImpl({
3878
+ assertion: this,
3879
+ received: getError(received, promise),
3880
+ ...normalizeArguments(propertiesOrHint, hint)
3881
+ }));
3882
+ }));
3883
+ utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingInlineSnapshot", wrapAssertion(utils, "toThrowErrorMatchingInlineSnapshot", function __INLINE_SNAPSHOT_OFFSET_3__(inlineSnapshotOrHint, hint) {
3884
+ validateAssertion(this);
3885
+ const received = utils.flag(this, "object");
3886
+ const promise = utils.flag(this, "promise");
3887
+ return assertMatchResult(toMatchSnapshotImpl({
3888
+ assertion: this,
3889
+ received: getError(received, promise),
3890
+ isInline: true,
3891
+ ...normalizeInlineArguments(void 0, inlineSnapshotOrHint, hint)
3892
+ }));
3893
+ }));
3894
+ utils.addMethod(chai.expect, "addSnapshotSerializer", addSerializer);
3895
+ };
3896
+ // toMatchSnapshot(propertiesOrHint?, hint?)
3897
+ function normalizeArguments(propertiesOrHint, hint) {
3898
+ if (typeof propertiesOrHint === "string") return { hint: propertiesOrHint };
3899
+ return {
3900
+ properties: propertiesOrHint,
3901
+ hint
3902
+ };
3903
+ }
3904
+ // toMatchInlineSnapshot(propertiesOrInlineSnapshot?, inlineSnapshotOrHint?, hint?)
3905
+ function normalizeInlineArguments(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint) {
3906
+ let inlineSnapshot;
3907
+ if (typeof propertiesOrInlineSnapshot === "string") {
3908
+ inlineSnapshot = stripSnapshotIndentation(propertiesOrInlineSnapshot);
3909
+ return {
3910
+ inlineSnapshot,
3911
+ hint: inlineSnapshotOrHint
3912
+ };
3913
+ }
3914
+ if (inlineSnapshotOrHint) inlineSnapshot = stripSnapshotIndentation(inlineSnapshotOrHint);
3915
+ return {
3916
+ properties: propertiesOrInlineSnapshot,
3917
+ inlineSnapshot,
3918
+ hint
3919
+ };
3920
+ }
3921
+ function toMatchSnapshotImpl(options) {
3922
+ const { assertion } = options;
3923
+ validateAssertion(assertion);
3924
+ const assertionName = getAssertionName(assertion);
3925
+ const test = getTest(assertion);
3926
+ return getSnapshotClient().match({
3927
+ received: options.received,
3928
+ properties: options.properties,
3929
+ message: options.hint,
3930
+ isInline: options.isInline,
3931
+ inlineSnapshot: options.inlineSnapshot,
3932
+ errorMessage: chai.util.flag(assertion, "message"),
3933
+ assertionName,
3934
+ error: chai.util.flag(assertion, "error"),
3935
+ ...getTestNames(test)
3936
+ });
3937
+ }
3938
+ async function toMatchFileSnapshotImpl(options) {
3939
+ const { assertion } = options;
3940
+ validateAssertion(assertion);
3941
+ const testNames = getTestNames(getTest(assertion));
3942
+ const snapshotState = getSnapshotClient().getSnapshotState(testNames.filepath);
3943
+ const rawSnapshotFile = await snapshotState.environment.resolveRawPath(testNames.filepath, options.filepath);
3944
+ const rawSnapshotContent = await snapshotState.environment.readSnapshotFile(rawSnapshotFile);
3945
+ return getSnapshotClient().match({
3946
+ received: options.received,
3947
+ message: options.hint,
3948
+ errorMessage: chai.util.flag(assertion, "message"),
3949
+ rawSnapshot: {
3950
+ file: rawSnapshotFile,
3951
+ content: rawSnapshotContent ?? void 0
3952
+ },
3953
+ ...testNames
3954
+ });
3955
+ }
3956
+ function assertMatchResult(result) {
3957
+ if (!result.pass) throw Object.assign(new Error(result.message()), {
3958
+ actual: result.actual,
3959
+ expected: result.expected,
3960
+ diffOptions: { expand: getWorkerState().config.snapshotOptions.expand }
3961
+ });
3962
+ }
3963
+ /**
3964
+ * Composable snapshot matcher helpers for building custom snapshot matchers
3965
+ * with `expect.extend`.
3966
+ *
3967
+ * @experimental
3968
+ * @see https://vitest.dev/guide/snapshot.html#custom-snapshot-matchers
3969
+ */
3970
+ const Snapshots = {
3971
+ toMatchSnapshot(received, propertiesOrHint, hint) {
3972
+ return toMatchSnapshotImpl({
3973
+ assertion: this.__vitest_assertion__,
3974
+ received,
3975
+ ...normalizeArguments(propertiesOrHint, hint)
3976
+ });
3977
+ },
3978
+ toMatchInlineSnapshot(received, propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint) {
3979
+ return toMatchSnapshotImpl({
3980
+ assertion: this.__vitest_assertion__,
3981
+ received,
3982
+ isInline: true,
3983
+ ...normalizeInlineArguments(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint)
3984
+ });
3985
+ },
3986
+ toMatchFileSnapshot(received, filepath, hint) {
3987
+ return toMatchFileSnapshotImpl({
3988
+ assertion: this.__vitest_assertion__,
3989
+ received,
3990
+ filepath,
3991
+ hint
3992
+ });
3993
+ }
3994
+ };
3995
+
3996
+ chai.use(JestExtend);
3997
+ chai.use(JestChaiExpect);
3998
+ chai.use(ChaiStyleAssertions);
3999
+ chai.use(SnapshotPlugin);
4000
+ chai.use(JestAsymmetricMatchers);
4001
+
4002
+ function createExpect(test) {
4003
+ const expect = ((value, message) => {
4004
+ const { assertionCalls } = getState(expect);
4005
+ setState({ assertionCalls: assertionCalls + 1 }, expect);
4006
+ const assert = chai.expect(value, message);
4007
+ const _test = test || getCurrentTest();
4008
+ if (_test)
4009
+ // @ts-expect-error internal
4010
+ return assert.withTest(_test);
4011
+ else return assert;
4012
+ });
4013
+ Object.assign(expect, chai.expect);
4014
+ Object.assign(expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
4015
+ expect.getState = () => getState(expect);
4016
+ expect.setState = (state) => setState(state, expect);
4017
+ // @ts-expect-error global is not typed
4018
+ const globalState = getState(globalThis[GLOBAL_EXPECT]) || {};
4019
+ setState({
4020
+ ...globalState,
4021
+ assertionCalls: 0,
4022
+ isExpectingAssertions: false,
4023
+ isExpectingAssertionsError: null,
4024
+ expectedAssertionsNumber: null,
4025
+ expectedAssertionsNumberErrorGen: null,
4026
+ get testPath() {
4027
+ return getWorkerState().filepath;
4028
+ },
4029
+ currentTestName: test ? test.fullTestName ?? "" : globalState.currentTestName
4030
+ }, expect);
4031
+ expect.assert = chai.assert;
4032
+ // @ts-expect-error untyped
4033
+ expect.extend = (matchers) => chai.expect.extend(expect, matchers);
4034
+ expect.addEqualityTesters = (customTesters) => addCustomEqualityTesters(customTesters);
4035
+ expect.soft = (...args) => {
4036
+ // @ts-expect-error private soft access
4037
+ return expect(...args).withContext({ soft: true });
4038
+ };
4039
+ expect.poll = createExpectPoll(expect);
4040
+ expect.unreachable = (message) => {
4041
+ chai.assert.fail(`expected${message ? ` "${message}" ` : " "}not to be reached`);
4042
+ };
4043
+ function assertions(expected) {
4044
+ const errorGen = () => /* @__PURE__ */ new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`);
4045
+ if (Error.captureStackTrace) Error.captureStackTrace(errorGen(), assertions);
4046
+ expect.setState({
4047
+ expectedAssertionsNumber: expected,
4048
+ expectedAssertionsNumberErrorGen: errorGen
4049
+ });
4050
+ }
4051
+ function hasAssertions() {
4052
+ const error = /* @__PURE__ */ new Error("expected any number of assertion, but got none");
4053
+ if (Error.captureStackTrace) Error.captureStackTrace(error, hasAssertions);
4054
+ expect.setState({
4055
+ isExpectingAssertions: true,
4056
+ isExpectingAssertionsError: error
4057
+ });
4058
+ }
4059
+ chai.util.addMethod(expect, "assertions", assertions);
4060
+ chai.util.addMethod(expect, "hasAssertions", hasAssertions);
4061
+ expect.extend(customMatchers);
4062
+ return expect;
4063
+ }
4064
+ const globalExpect = createExpect();
4065
+ Object.defineProperty(globalThis, GLOBAL_EXPECT, {
4066
+ value: globalExpect,
4067
+ writable: true,
4068
+ configurable: true
4069
+ });
4070
+ const assert = chai.assert;
4071
+ const should = chai.should;
4072
+
4073
+ /**
4074
+ * Gives access to injected context provided from the main thread.
4075
+ * This usually returns a value provided by `globalSetup` or an external library.
4076
+ */
4077
+ function inject(key) {
4078
+ return getWorkerState().providedContext[key];
4079
+ }
4080
+
4015
4081
  function createBenchmarkResult(name) {
4016
4082
  return {
4017
4083
  name,
@@ -4274,4 +4340,4 @@ function clearModuleMocks(config) {
4274
4340
  if (unstubGlobals) vi.unstubAllGlobals();
4275
4341
  }
4276
4342
 
4277
- export { NodeBenchmarkRunner as N, TestRunner as T, assert as a, vitest as b, createExpect as c, globalExpect as g, inject as i, should as s, vi as v };
4343
+ export { NodeBenchmarkRunner as N, Snapshots as S, TestRunner as T, assert as a, vitest as b, createExpect as c, globalExpect as g, inject as i, should as s, vi as v };