vitest 4.1.2 → 4.1.4

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 (40) 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.Cv_yNPUJ.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.wyYWMVI-.js} +19 -7
  6. package/dist/chunks/{cli-api.Bxr1Nn49.js → cli-api.lDy4N9kC.js} +45 -18
  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.Da5gzbsu.js} +16 -2
  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.BVDtJR67.js} +3 -3
  11. package/dist/chunks/{index.0GYC6HAu.js → index.BMXTnDNz.js} +11 -2
  12. package/dist/chunks/{index.DOa3dzoN.js → index.C-zNJvRx.js} +2 -1
  13. package/dist/chunks/{index.nZ2xqFgD.js → index.C3MK_gXn.js} +2 -2
  14. package/dist/chunks/{plugin.d.BWbK_Jpw.d.ts → plugin.d.CEihBODF.d.ts} +1 -1
  15. package/dist/chunks/{reporters.d.B0uk8id2.d.ts → reporters.d.BwkR0iL5.d.ts} +16 -3
  16. package/dist/chunks/{setup-common.2wZXQUjS.js → setup-common.BDwxwUWG.js} +1 -1
  17. package/dist/chunks/{test.p_J6dB8a.js → test.D1JkM1w4.js} +488 -335
  18. package/dist/chunks/{utils.DK8FXp4T.js → utils.BS4fH3nR.js} +1 -1
  19. package/dist/chunks/{vm.BvVhnZPV.js → vm.DVLYObm9.js} +5 -4
  20. package/dist/chunks/{worker.d.BT5j8dyR.d.ts → worker.d.CckNUvI5.d.ts} +1 -1
  21. package/dist/cli.js +1 -1
  22. package/dist/config.d.ts +6 -6
  23. package/dist/coverage.d.ts +4 -4
  24. package/dist/coverage.js +2 -1
  25. package/dist/index.d.ts +99 -10
  26. package/dist/index.js +3 -3
  27. package/dist/node.d.ts +8 -8
  28. package/dist/node.js +7 -7
  29. package/dist/reporters.d.ts +4 -4
  30. package/dist/reporters.js +2 -2
  31. package/dist/runners.d.ts +1 -1
  32. package/dist/runners.js +2 -2
  33. package/dist/worker.d.ts +2 -2
  34. package/dist/worker.js +5 -5
  35. package/dist/workers/forks.js +5 -5
  36. package/dist/workers/runVmTests.js +4 -4
  37. package/dist/workers/threads.js +5 -5
  38. package/dist/workers/vmForks.js +1 -1
  39. package/dist/workers/vmThreads.js +1 -1
  40. 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,488 @@ 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
+ // injected so that domain snapshot can take over poll implementation.
3719
+ chai.util.flag(assertion, "_poll.fn", fn);
3720
+ chai.util.flag(assertion, "_poll.timeout", timeout);
3721
+ chai.util.flag(assertion, "_poll.interval", interval);
3722
+ const test = chai.util.flag(assertion, "vitest-test");
3723
+ if (!test) throw new Error("expect.poll() must be called inside a test");
3724
+ const proxy = new Proxy(assertion, { get(target, key, receiver) {
3725
+ const assertionFunction = Reflect.get(target, key, receiver);
3726
+ if (typeof assertionFunction !== "function") return assertionFunction instanceof chai.Assertion ? proxy : assertionFunction;
3727
+ if (key === "assert") return assertionFunction;
3728
+ 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.`);
3729
+ // Core poll stack-trace trick:
3730
+ // 1. capture STACK_TRACE_ERROR here before entering the async poll loop
3731
+ // 2. when the matcher eventually fails, rethrow via throwWithCause()
3732
+ // so the final error keeps this earlier stack
3733
+ //
3734
+ // For example, when user writes:
3735
+ // await expect.poll(...).toBeSomething()
3736
+ // STACK_TRACE_ERROR.stack would look like
3737
+ // at ...(more internal stacks)...
3738
+ // at __VITEST_POLL_CHAIN__ .../packages/vitest/dist/...
3739
+ // at .../my-file.test.ts:12:3 (this points to `toBeSomething()` callsite in user test file)
3740
+ // Vitest later filters out internal stacks from `vitest/dist`, so the reported errors correctly
3741
+ // points to the user callsite for poll assertion errors.
3742
+ //
3743
+ // Inline snapshots piggyback on the same idea. We pass
3744
+ // STACK_TRACE_ERROR through `chai.util.flag(assertion, 'error', ...)`.
3745
+ // Inline snapshot assertion access the same error stack for
3746
+ // extracting inline snapshot location to validate and update new snapshots.
3747
+ return function __VITEST_POLL_CHAIN__(...args) {
3748
+ const STACK_TRACE_ERROR = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
3749
+ const promise = async () => {
3750
+ chai.util.flag(assertion, "_name", key);
3751
+ chai.util.flag(assertion, "error", STACK_TRACE_ERROR);
3752
+ const onSettled = chai.util.flag(assertion, "_poll.onSettled");
3753
+ if (Object.getOwnPropertyDescriptor(assertionFunction, "__vitest_poll_takeover__")?.value) try {
3754
+ const output = await assertionFunction.call(assertion, ...args);
3755
+ await onSettled?.({
3756
+ assertion,
3757
+ status: "pass"
3758
+ });
3759
+ return output;
3760
+ } catch (err) {
3761
+ await onSettled?.({
3762
+ assertion,
3763
+ status: "fail"
3764
+ });
3765
+ throwWithCause(err, STACK_TRACE_ERROR);
3766
+ }
3767
+ const { setTimeout, clearTimeout } = getSafeTimers();
3768
+ let executionPhase = "fn";
3769
+ let hasTimedOut = false;
3770
+ const timerId = setTimeout(() => {
3771
+ hasTimedOut = true;
3772
+ }, timeout);
3773
+ try {
3774
+ while (true) {
3775
+ const isLastAttempt = hasTimedOut;
3776
+ if (isLastAttempt) chai.util.flag(assertion, "_isLastPollAttempt", true);
3777
+ try {
3778
+ executionPhase = "fn";
3779
+ const obj = await fn();
3780
+ chai.util.flag(assertion, "object", obj);
3781
+ executionPhase = "assertion";
3782
+ const output = await assertionFunction.call(assertion, ...args);
3783
+ await onSettled?.({
3784
+ assertion,
3785
+ status: "pass"
3786
+ });
3787
+ return output;
3788
+ } catch (err) {
3789
+ if (isLastAttempt || executionPhase === "assertion" && chai.util.flag(assertion, "_poll.assert_once")) {
3790
+ await onSettled?.({
3791
+ assertion,
3792
+ status: "fail"
3793
+ });
3794
+ throwWithCause(err, STACK_TRACE_ERROR);
3795
+ }
3796
+ await delay(interval, setTimeout);
3797
+ if (vi.isFakeTimers()) vi.advanceTimersByTime(interval);
3798
+ }
3799
+ }
3800
+ } finally {
3801
+ clearTimeout(timerId);
3802
+ }
3803
+ };
3804
+ let awaited = false;
3805
+ test.onFinished ??= [];
3806
+ test.onFinished.push(() => {
3807
+ if (!awaited) {
3808
+ const negated = chai.util.flag(assertion, "negate") ? "not." : "";
3809
+ const assertionString = `expect.${chai.util.flag(assertion, "_poll.element") ? "element(locator)" : "poll(assertion)"}.${negated}${String(key)}()`;
3810
+ 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);
3811
+ }
3812
+ });
3813
+ let resultPromise;
3814
+ // only .then is enough to check awaited, but we type this as `Promise<void>` in global types
3815
+ // so let's follow it
3816
+ return {
3817
+ then(onFulfilled, onRejected) {
3818
+ awaited = true;
3819
+ return (resultPromise ||= promise()).then(onFulfilled, onRejected);
3820
+ },
3821
+ catch(onRejected) {
3822
+ awaited = true;
3823
+ return (resultPromise ||= promise()).catch(onRejected);
3824
+ },
3825
+ finally(onFinally) {
3826
+ awaited = true;
3827
+ return (resultPromise ||= promise()).finally(onFinally);
3828
+ },
3829
+ [Symbol.toStringTag]: "Promise"
3830
+ };
3831
+ };
3832
+ } });
3833
+ return proxy;
3834
+ };
3835
+ }
3836
+ function copyStackTrace(target, source) {
3837
+ if (source.stack !== void 0) target.stack = source.stack.replace(source.message, target.message);
3838
+ return target;
3839
+ }
3840
+
3841
+ let _client;
3842
+ function getSnapshotClient() {
3843
+ if (!_client) _client = new SnapshotClient({ isEqual: (received, expected) => {
3844
+ return equals(received, expected, [iterableEquality, subsetEquality]);
3845
+ } });
3846
+ return _client;
3847
+ }
3848
+ function getError(expected, promise) {
3849
+ if (typeof expected !== "function") {
3850
+ if (!promise) throw new Error(`expected must be a function, received ${typeof expected}`);
3851
+ // when "promised", it receives thrown error
3852
+ return expected;
3853
+ }
3854
+ try {
3855
+ expected();
3856
+ } catch (e) {
3857
+ return e;
3858
+ }
3859
+ throw new Error("snapshot function didn't throw");
3860
+ }
3861
+ function getTestNames(test) {
3862
+ return {
3863
+ filepath: test.file.filepath,
3864
+ name: getNames(test).slice(1).join(" > "),
3865
+ testId: test.id
3866
+ };
3867
+ }
3868
+ function getAssertionName(assertion) {
3869
+ const name = chai.util.flag(assertion, "_name");
3870
+ if (!name) throw new Error("Assertion name is not set. This is a bug in Vitest. Please, open a new issue with reproduction.");
3871
+ return name;
3872
+ }
3873
+ function getTest(obj) {
3874
+ const test = chai.util.flag(obj, "vitest-test");
3875
+ if (!test) throw new Error(`'${getAssertionName(obj)}' cannot be used without test context`);
3876
+ return test;
3877
+ }
3878
+ function validateAssertion(assertion) {
3879
+ if (chai.util.flag(assertion, "negate")) throw new Error(`${getAssertionName(assertion)} cannot be used with "not"`);
3880
+ }
3881
+ const SnapshotPlugin = (chai, utils) => {
3882
+ for (const key of ["matchSnapshot", "toMatchSnapshot"]) utils.addMethod(chai.Assertion.prototype, key, wrapAssertion(utils, key, function(propertiesOrHint, hint) {
3883
+ return assertMatchResult(toMatchSnapshotImpl({
3884
+ assertion: this,
3885
+ received: utils.flag(this, "object"),
3886
+ ...normalizeArguments(propertiesOrHint, hint)
3887
+ }), chai.util.flag(this, "message"));
3888
+ }));
3889
+ utils.addMethod(chai.Assertion.prototype, "toMatchFileSnapshot", function(filepath, hint) {
3890
+ // set name manually since it's not wrapped by wrapAssertion
3891
+ utils.flag(this, "_name", "toMatchFileSnapshot");
3892
+ // validate early synchronously just not to break some existing tests
3893
+ validateAssertion(this);
3894
+ const assertPromise = toMatchFileSnapshotImpl({
3895
+ assertion: this,
3896
+ received: utils.flag(this, "object"),
3897
+ filepath,
3898
+ hint
3899
+ }).then((result) => assertMatchResult(result, chai.util.flag(this, "message")));
3900
+ return recordAsyncExpect(getTest(this), assertPromise, createAssertionMessage(utils, this, true), /* @__PURE__ */ new Error("resolves"), utils.flag(this, "soft"));
3901
+ });
3902
+ utils.addMethod(chai.Assertion.prototype, "toMatchInlineSnapshot", wrapAssertion(utils, "toMatchInlineSnapshot", function __INLINE_SNAPSHOT_OFFSET_3__(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint) {
3903
+ return assertMatchResult(toMatchSnapshotImpl({
3904
+ assertion: this,
3905
+ received: utils.flag(this, "object"),
3906
+ isInline: true,
3907
+ ...normalizeInlineArguments(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint)
3908
+ }), chai.util.flag(this, "message"));
3909
+ }));
3910
+ utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingSnapshot", wrapAssertion(utils, "toThrowErrorMatchingSnapshot", function(propertiesOrHint, hint) {
3911
+ validateAssertion(this);
3912
+ const received = utils.flag(this, "object");
3913
+ const promise = utils.flag(this, "promise");
3914
+ return assertMatchResult(toMatchSnapshotImpl({
3915
+ assertion: this,
3916
+ received: getError(received, promise),
3917
+ ...normalizeArguments(propertiesOrHint, hint)
3918
+ }), chai.util.flag(this, "message"));
3919
+ }));
3920
+ utils.addMethod(chai.Assertion.prototype, "toThrowErrorMatchingInlineSnapshot", wrapAssertion(utils, "toThrowErrorMatchingInlineSnapshot", function __INLINE_SNAPSHOT_OFFSET_3__(inlineSnapshotOrHint, hint) {
3921
+ validateAssertion(this);
3922
+ const received = utils.flag(this, "object");
3923
+ const promise = utils.flag(this, "promise");
3924
+ return assertMatchResult(toMatchSnapshotImpl({
3925
+ assertion: this,
3926
+ received: getError(received, promise),
3927
+ isInline: true,
3928
+ ...normalizeInlineArguments(void 0, inlineSnapshotOrHint, hint)
3929
+ }), chai.util.flag(this, "message"));
3930
+ }));
3931
+ utils.addMethod(chai.expect, "addSnapshotSerializer", addSerializer);
3932
+ };
3933
+ function toMatchDomainSnapshotImpl(opts) {
3934
+ const { assertion } = opts;
3935
+ validateAssertion(assertion);
3936
+ const assertionName = getAssertionName(assertion);
3937
+ const test = getTest(assertion);
3938
+ let { inlineSnapshot } = opts;
3939
+ if (inlineSnapshot) inlineSnapshot = stripSnapshotIndentation(inlineSnapshot);
3940
+ const pollFn = chai.util.flag(assertion, "_poll.fn");
3941
+ if (pollFn) return getSnapshotClient().pollMatchDomain({
3942
+ poll: pollFn,
3943
+ adapter: opts.adapter,
3944
+ message: opts.hint,
3945
+ isInline: opts.isInline,
3946
+ errorMessage: chai.util.flag(assertion, "message"),
3947
+ timeout: chai.util.flag(assertion, "_poll.timeout"),
3948
+ interval: chai.util.flag(assertion, "_poll.interval"),
3949
+ assertionName,
3950
+ inlineSnapshot,
3951
+ error: chai.util.flag(assertion, "error"),
3952
+ ...getTestNames(test)
3953
+ });
3954
+ return getSnapshotClient().matchDomain({
3955
+ received: opts.received,
3956
+ adapter: opts.adapter,
3957
+ message: opts.hint,
3958
+ isInline: opts.isInline,
3959
+ errorMessage: chai.util.flag(assertion, "message"),
3960
+ assertionName,
3961
+ inlineSnapshot,
3962
+ error: chai.util.flag(assertion, "error"),
3963
+ ...getTestNames(test)
3964
+ });
3965
+ }
3966
+ // toMatchSnapshot(propertiesOrHint?, hint?)
3967
+ function normalizeArguments(propertiesOrHint, hint) {
3968
+ if (typeof propertiesOrHint === "string") return { hint: propertiesOrHint };
3969
+ return {
3970
+ properties: propertiesOrHint,
3971
+ hint
3972
+ };
3973
+ }
3974
+ // toMatchInlineSnapshot(propertiesOrInlineSnapshot?, inlineSnapshotOrHint?, hint?)
3975
+ function normalizeInlineArguments(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint) {
3976
+ let inlineSnapshot;
3977
+ if (typeof propertiesOrInlineSnapshot === "string") {
3978
+ inlineSnapshot = stripSnapshotIndentation(propertiesOrInlineSnapshot);
3979
+ return {
3980
+ inlineSnapshot,
3981
+ hint: inlineSnapshotOrHint
3982
+ };
3983
+ }
3984
+ if (inlineSnapshotOrHint) inlineSnapshot = stripSnapshotIndentation(inlineSnapshotOrHint);
3985
+ return {
3986
+ properties: propertiesOrInlineSnapshot,
3987
+ inlineSnapshot,
3988
+ hint
3989
+ };
3990
+ }
3991
+ function toMatchSnapshotImpl(options) {
3992
+ const { assertion } = options;
3993
+ validateAssertion(assertion);
3994
+ const assertionName = getAssertionName(assertion);
3995
+ const test = getTest(assertion);
3996
+ return getSnapshotClient().match({
3997
+ received: options.received,
3998
+ properties: options.properties,
3999
+ message: options.hint,
4000
+ isInline: options.isInline,
4001
+ inlineSnapshot: options.inlineSnapshot,
4002
+ assertionName,
4003
+ error: chai.util.flag(assertion, "error"),
4004
+ ...getTestNames(test)
4005
+ });
4006
+ }
4007
+ async function toMatchFileSnapshotImpl(options) {
4008
+ const { assertion } = options;
4009
+ validateAssertion(assertion);
4010
+ const testNames = getTestNames(getTest(assertion));
4011
+ const snapshotState = getSnapshotClient().getSnapshotState(testNames.filepath);
4012
+ const rawSnapshotFile = await snapshotState.environment.resolveRawPath(testNames.filepath, options.filepath);
4013
+ const rawSnapshotContent = await snapshotState.environment.readSnapshotFile(rawSnapshotFile);
4014
+ return getSnapshotClient().match({
4015
+ received: options.received,
4016
+ message: options.hint,
4017
+ rawSnapshot: {
4018
+ file: rawSnapshotFile,
4019
+ content: rawSnapshotContent ?? void 0
4020
+ },
4021
+ ...testNames
4022
+ });
4023
+ }
4024
+ function assertMatchResult(result, customMessage) {
4025
+ if (!result.pass) {
4026
+ const errorMessage = (customMessage ? `${customMessage}: ` : "") + result.message();
4027
+ throw Object.assign(new Error(errorMessage), {
4028
+ actual: result.actual,
4029
+ expected: result.expected,
4030
+ diffOptions: { expand: getWorkerState().config.snapshotOptions.expand }
4031
+ });
4032
+ }
4033
+ }
4034
+ /**
4035
+ * Composable snapshot matcher helpers for building custom snapshot matchers
4036
+ * with `expect.extend`.
4037
+ *
4038
+ * @experimental
4039
+ * @see https://vitest.dev/guide/snapshot.html#custom-snapshot-matchers
4040
+ */
4041
+ const Snapshots = {
4042
+ toMatchSnapshot(received, propertiesOrHint, hint) {
4043
+ return toMatchSnapshotImpl({
4044
+ assertion: this.assertion,
4045
+ received,
4046
+ ...normalizeArguments(propertiesOrHint, hint)
4047
+ });
4048
+ },
4049
+ toMatchInlineSnapshot(received, propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint) {
4050
+ return toMatchSnapshotImpl({
4051
+ assertion: this.assertion,
4052
+ received,
4053
+ isInline: true,
4054
+ ...normalizeInlineArguments(propertiesOrInlineSnapshot, inlineSnapshotOrHint, hint)
4055
+ });
4056
+ },
4057
+ toMatchFileSnapshot(received, filepath, hint) {
4058
+ return toMatchFileSnapshotImpl({
4059
+ assertion: this.assertion,
4060
+ received,
4061
+ filepath,
4062
+ hint
4063
+ });
4064
+ },
4065
+ toMatchDomainSnapshot(domain, received) {
4066
+ return toMatchDomainSnapshotImpl({
4067
+ assertion: this.assertion,
4068
+ adapter: domain,
4069
+ received
4070
+ });
4071
+ },
4072
+ toMatchDomainInlineSnapshot(domain, received, inlineSnapshot) {
4073
+ return toMatchDomainSnapshotImpl({
4074
+ assertion: this.assertion,
4075
+ adapter: domain,
4076
+ received,
4077
+ isInline: true,
4078
+ inlineSnapshot
4079
+ });
4080
+ }
4081
+ };
4082
+
4083
+ chai.use(JestExtend);
4084
+ chai.use(JestChaiExpect);
4085
+ chai.use(ChaiStyleAssertions);
4086
+ chai.use(SnapshotPlugin);
4087
+ chai.use(JestAsymmetricMatchers);
4088
+
4089
+ function createExpect(test) {
4090
+ const expect = ((value, message) => {
4091
+ const { assertionCalls } = getState(expect);
4092
+ setState({ assertionCalls: assertionCalls + 1 }, expect);
4093
+ const assert = chai.expect(value, message);
4094
+ const _test = test || getCurrentTest();
4095
+ if (_test)
4096
+ // @ts-expect-error internal
4097
+ return assert.withTest(_test);
4098
+ else return assert;
4099
+ });
4100
+ Object.assign(expect, chai.expect);
4101
+ Object.assign(expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
4102
+ expect.getState = () => getState(expect);
4103
+ expect.setState = (state) => setState(state, expect);
4104
+ // @ts-expect-error global is not typed
4105
+ const globalState = getState(globalThis[GLOBAL_EXPECT]) || {};
4106
+ setState({
4107
+ ...globalState,
4108
+ assertionCalls: 0,
4109
+ isExpectingAssertions: false,
4110
+ isExpectingAssertionsError: null,
4111
+ expectedAssertionsNumber: null,
4112
+ expectedAssertionsNumberErrorGen: null,
4113
+ get testPath() {
4114
+ return getWorkerState().filepath;
4115
+ },
4116
+ currentTestName: test ? test.fullTestName ?? "" : globalState.currentTestName
4117
+ }, expect);
4118
+ expect.assert = chai.assert;
4119
+ // @ts-expect-error untyped
4120
+ expect.extend = (matchers) => chai.expect.extend(expect, matchers);
4121
+ expect.addEqualityTesters = (customTesters) => addCustomEqualityTesters(customTesters);
4122
+ expect.soft = (...args) => {
4123
+ // @ts-expect-error private soft access
4124
+ return expect(...args).withContext({ soft: true });
4125
+ };
4126
+ expect.poll = createExpectPoll(expect);
4127
+ expect.unreachable = (message) => {
4128
+ chai.assert.fail(`expected${message ? ` "${message}" ` : " "}not to be reached`);
4129
+ };
4130
+ function assertions(expected) {
4131
+ const errorGen = () => /* @__PURE__ */ new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`);
4132
+ if (Error.captureStackTrace) Error.captureStackTrace(errorGen(), assertions);
4133
+ expect.setState({
4134
+ expectedAssertionsNumber: expected,
4135
+ expectedAssertionsNumberErrorGen: errorGen
4136
+ });
4137
+ }
4138
+ function hasAssertions() {
4139
+ const error = /* @__PURE__ */ new Error("expected any number of assertion, but got none");
4140
+ if (Error.captureStackTrace) Error.captureStackTrace(error, hasAssertions);
4141
+ expect.setState({
4142
+ isExpectingAssertions: true,
4143
+ isExpectingAssertionsError: error
4144
+ });
4145
+ }
4146
+ chai.util.addMethod(expect, "assertions", assertions);
4147
+ chai.util.addMethod(expect, "hasAssertions", hasAssertions);
4148
+ expect.extend(customMatchers);
4149
+ return expect;
4150
+ }
4151
+ const globalExpect = createExpect();
4152
+ Object.defineProperty(globalThis, GLOBAL_EXPECT, {
4153
+ value: globalExpect,
4154
+ writable: true,
4155
+ configurable: true
4156
+ });
4157
+ const assert = chai.assert;
4158
+ const should = chai.should;
4159
+
4160
+ /**
4161
+ * Gives access to injected context provided from the main thread.
4162
+ * This usually returns a value provided by `globalSetup` or an external library.
4163
+ */
4164
+ function inject(key) {
4165
+ return getWorkerState().providedContext[key];
4166
+ }
4167
+
4015
4168
  function createBenchmarkResult(name) {
4016
4169
  return {
4017
4170
  name,
@@ -4274,4 +4427,4 @@ function clearModuleMocks(config) {
4274
4427
  if (unstubGlobals) vi.unstubAllGlobals();
4275
4428
  }
4276
4429
 
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 };
4430
+ 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 };