@vitest/runner 3.1.0-beta.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getSafeTimers, isObject, createDefer, toArray, isNegativeNaN, format, objectAttr, objDisplay, assertTypes, shuffle } from '@vitest/utils';
1
+ import { isObject, createDefer, toArray, isNegativeNaN, format, objectAttr, objDisplay, getSafeTimers, assertTypes, shuffle } from '@vitest/utils';
2
2
  import { parseSingleStack } from '@vitest/utils/source-map';
3
3
  import { c as createChainable, b as createFileTask, a as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, l as limitConcurrency, p as partitionSuiteChildren, o as hasTests, n as hasFailed } from './chunk-tasks.js';
4
4
  import { processError } from '@vitest/utils/error';
@@ -6,1443 +6,1564 @@ export { processError } from '@vitest/utils/error';
6
6
  import 'pathe';
7
7
 
8
8
  class PendingError extends Error {
9
- constructor(message, task, note) {
10
- super(message);
11
- this.message = message;
12
- this.note = note;
13
- this.taskId = task.id;
14
- }
15
- code = "VITEST_PENDING";
16
- taskId;
9
+ code = "VITEST_PENDING";
10
+ taskId;
11
+ constructor(message, task, note) {
12
+ super(message);
13
+ this.message = message;
14
+ this.note = note;
15
+ this.taskId = task.id;
16
+ }
17
17
  }
18
18
 
19
- const now$2 = Date.now;
20
- const collectorContext = {
21
- tasks: [],
22
- currentSuite: null
23
- };
24
- function collectTask(task) {
25
- var _a;
26
- (_a = collectorContext.currentSuite) == null ? void 0 : _a.tasks.push(task);
27
- }
28
- async function runWithSuite(suite, fn) {
29
- const prev = collectorContext.currentSuite;
30
- collectorContext.currentSuite = suite;
31
- await fn();
32
- collectorContext.currentSuite = prev;
33
- }
34
- function withTimeout(fn, timeout, isHook = false, stackTraceError) {
35
- if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY) {
36
- return fn;
37
- }
38
- const { setTimeout, clearTimeout } = getSafeTimers();
39
- return function runWithTimeout(...args) {
40
- const startTime = now$2();
41
- return new Promise((resolve_, reject_) => {
42
- var _a;
43
- const timer = setTimeout(() => {
44
- clearTimeout(timer);
45
- rejectTimeoutError();
46
- }, timeout);
47
- (_a = timer.unref) == null ? void 0 : _a.call(timer);
48
- function rejectTimeoutError() {
49
- reject_(makeTimeoutError(isHook, timeout, stackTraceError));
50
- }
51
- function resolve(result) {
52
- clearTimeout(timer);
53
- if (now$2() - startTime >= timeout) {
54
- rejectTimeoutError();
55
- return;
56
- }
57
- resolve_(result);
58
- }
59
- function reject(error) {
60
- clearTimeout(timer);
61
- reject_(error);
62
- }
63
- try {
64
- const result = fn(...args);
65
- if (typeof result === "object" && result != null && typeof result.then === "function") {
66
- result.then(resolve, reject);
67
- } else {
68
- resolve(result);
69
- }
70
- } catch (error) {
71
- reject(error);
72
- }
73
- });
74
- };
75
- }
76
- function createTestContext(test, runner) {
77
- var _a;
78
- const context = function() {
79
- throw new Error("done() callback is deprecated, use promise instead");
80
- };
81
- context.task = test;
82
- context.skip = (condition, note) => {
83
- if (condition === false) {
84
- return void 0;
85
- }
86
- test.result ?? (test.result = { state: "skip" });
87
- test.result.pending = true;
88
- throw new PendingError(
89
- "test is skipped; abort execution",
90
- test,
91
- typeof condition === "string" ? condition : note
92
- );
93
- };
94
- context.onTestFailed = (handler, timeout) => {
95
- test.onFailed || (test.onFailed = []);
96
- test.onFailed.push(
97
- withTimeout(handler, timeout ?? runner.config.hookTimeout, true, new Error("STACK_TRACE_ERROR"))
98
- );
99
- };
100
- context.onTestFinished = (handler, timeout) => {
101
- test.onFinished || (test.onFinished = []);
102
- test.onFinished.push(
103
- withTimeout(handler, timeout ?? runner.config.hookTimeout, true, new Error("STACK_TRACE_ERROR"))
104
- );
105
- };
106
- return ((_a = runner.extendTaskContext) == null ? void 0 : _a.call(runner, context)) || context;
107
- }
108
- function makeTimeoutError(isHook, timeout, stackTraceError) {
109
- const message = `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.
110
- If this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
111
- const error = new Error(message);
112
- if (stackTraceError == null ? void 0 : stackTraceError.stack) {
113
- error.stack = stackTraceError.stack.replace(error.message, stackTraceError.message);
114
- }
115
- return error;
116
- }
117
-
118
- const fnMap = /* @__PURE__ */ new WeakMap();
119
- const fixtureMap = /* @__PURE__ */ new WeakMap();
120
- const hooksMap = /* @__PURE__ */ new WeakMap();
19
+ const fnMap = new WeakMap();
20
+ const testFixtureMap = new WeakMap();
21
+ const hooksMap = new WeakMap();
121
22
  function setFn(key, fn) {
122
- fnMap.set(key, fn);
23
+ fnMap.set(key, fn);
123
24
  }
124
25
  function getFn(key) {
125
- return fnMap.get(key);
26
+ return fnMap.get(key);
126
27
  }
127
- function setFixture(key, fixture) {
128
- fixtureMap.set(key, fixture);
28
+ function setTestFixture(key, fixture) {
29
+ testFixtureMap.set(key, fixture);
129
30
  }
130
- function getFixture(key) {
131
- return fixtureMap.get(key);
31
+ function getTestFixture(key) {
32
+ return testFixtureMap.get(key);
132
33
  }
133
34
  function setHooks(key, hooks) {
134
- hooksMap.set(key, hooks);
35
+ hooksMap.set(key, hooks);
135
36
  }
136
37
  function getHooks(key) {
137
- return hooksMap.get(key);
38
+ return hooksMap.get(key);
138
39
  }
139
40
 
41
+ function mergeScopedFixtures(testFixtures, scopedFixtures) {
42
+ const scopedFixturesMap = scopedFixtures.reduce((map, fixture) => {
43
+ map[fixture.prop] = fixture;
44
+ return map;
45
+ }, {});
46
+ const newFixtures = {};
47
+ testFixtures.forEach((fixture) => {
48
+ const useFixture = scopedFixturesMap[fixture.prop] || { ...fixture };
49
+ newFixtures[useFixture.prop] = useFixture;
50
+ });
51
+ for (const fixtureKep in newFixtures) {
52
+ var _fixture$deps;
53
+ const fixture = newFixtures[fixtureKep];
54
+ fixture.deps = (_fixture$deps = fixture.deps) === null || _fixture$deps === void 0 ? void 0 : _fixture$deps.map((dep) => newFixtures[dep.prop]);
55
+ }
56
+ return Object.values(newFixtures);
57
+ }
140
58
  function mergeContextFixtures(fixtures, context, inject) {
141
- const fixtureOptionKeys = ["auto", "injected"];
142
- const fixtureArray = Object.entries(fixtures).map(
143
- ([prop, value]) => {
144
- const fixtureItem = { value };
145
- if (Array.isArray(value) && value.length >= 2 && isObject(value[1]) && Object.keys(value[1]).some((key) => fixtureOptionKeys.includes(key))) {
146
- Object.assign(fixtureItem, value[1]);
147
- const userValue = value[0];
148
- fixtureItem.value = fixtureItem.injected ? inject(prop) ?? userValue : userValue;
149
- }
150
- fixtureItem.prop = prop;
151
- fixtureItem.isFn = typeof fixtureItem.value === "function";
152
- return fixtureItem;
153
- }
154
- );
155
- if (Array.isArray(context.fixtures)) {
156
- context.fixtures = context.fixtures.concat(fixtureArray);
157
- } else {
158
- context.fixtures = fixtureArray;
159
- }
160
- fixtureArray.forEach((fixture) => {
161
- if (fixture.isFn) {
162
- const usedProps = getUsedProps(fixture.value);
163
- if (usedProps.length) {
164
- fixture.deps = context.fixtures.filter(
165
- ({ prop }) => prop !== fixture.prop && usedProps.includes(prop)
166
- );
167
- }
168
- }
169
- });
170
- return context;
171
- }
172
- const fixtureValueMaps = /* @__PURE__ */ new Map();
173
- const cleanupFnArrayMap = /* @__PURE__ */ new Map();
59
+ const fixtureOptionKeys = ["auto", "injected"];
60
+ const fixtureArray = Object.entries(fixtures).map(([prop, value]) => {
61
+ const fixtureItem = { value };
62
+ if (Array.isArray(value) && value.length >= 2 && isObject(value[1]) && Object.keys(value[1]).some((key) => fixtureOptionKeys.includes(key))) {
63
+ Object.assign(fixtureItem, value[1]);
64
+ const userValue = value[0];
65
+ fixtureItem.value = fixtureItem.injected ? inject(prop) ?? userValue : userValue;
66
+ }
67
+ fixtureItem.prop = prop;
68
+ fixtureItem.isFn = typeof fixtureItem.value === "function";
69
+ return fixtureItem;
70
+ });
71
+ if (Array.isArray(context.fixtures)) {
72
+ context.fixtures = context.fixtures.concat(fixtureArray);
73
+ } else {
74
+ context.fixtures = fixtureArray;
75
+ }
76
+ fixtureArray.forEach((fixture) => {
77
+ if (fixture.isFn) {
78
+ const usedProps = getUsedProps(fixture.value);
79
+ if (usedProps.length) {
80
+ fixture.deps = context.fixtures.filter(({ prop }) => prop !== fixture.prop && usedProps.includes(prop));
81
+ }
82
+ }
83
+ });
84
+ return context;
85
+ }
86
+ const fixtureValueMaps = new Map();
87
+ const cleanupFnArrayMap = new Map();
174
88
  async function callFixtureCleanup(context) {
175
- const cleanupFnArray = cleanupFnArrayMap.get(context) ?? [];
176
- for (const cleanup of cleanupFnArray.reverse()) {
177
- await cleanup();
178
- }
179
- cleanupFnArrayMap.delete(context);
89
+ const cleanupFnArray = cleanupFnArrayMap.get(context) ?? [];
90
+ for (const cleanup of cleanupFnArray.reverse()) {
91
+ await cleanup();
92
+ }
93
+ cleanupFnArrayMap.delete(context);
180
94
  }
181
95
  function withFixtures(fn, testContext) {
182
- return (hookContext) => {
183
- const context = hookContext || testContext;
184
- if (!context) {
185
- return fn({});
186
- }
187
- const fixtures = getFixture(context);
188
- if (!(fixtures == null ? void 0 : fixtures.length)) {
189
- return fn(context);
190
- }
191
- const usedProps = getUsedProps(fn);
192
- const hasAutoFixture = fixtures.some(({ auto }) => auto);
193
- if (!usedProps.length && !hasAutoFixture) {
194
- return fn(context);
195
- }
196
- if (!fixtureValueMaps.get(context)) {
197
- fixtureValueMaps.set(context, /* @__PURE__ */ new Map());
198
- }
199
- const fixtureValueMap = fixtureValueMaps.get(context);
200
- if (!cleanupFnArrayMap.has(context)) {
201
- cleanupFnArrayMap.set(context, []);
202
- }
203
- const cleanupFnArray = cleanupFnArrayMap.get(context);
204
- const usedFixtures = fixtures.filter(
205
- ({ prop, auto }) => auto || usedProps.includes(prop)
206
- );
207
- const pendingFixtures = resolveDeps(usedFixtures);
208
- if (!pendingFixtures.length) {
209
- return fn(context);
210
- }
211
- async function resolveFixtures() {
212
- for (const fixture of pendingFixtures) {
213
- if (fixtureValueMap.has(fixture)) {
214
- continue;
215
- }
216
- const resolvedValue = fixture.isFn ? await resolveFixtureFunction(fixture.value, context, cleanupFnArray) : fixture.value;
217
- context[fixture.prop] = resolvedValue;
218
- fixtureValueMap.set(fixture, resolvedValue);
219
- cleanupFnArray.unshift(() => {
220
- fixtureValueMap.delete(fixture);
221
- });
222
- }
223
- }
224
- return resolveFixtures().then(() => fn(context));
225
- };
96
+ return (hookContext) => {
97
+ const context = hookContext || testContext;
98
+ if (!context) {
99
+ return fn({});
100
+ }
101
+ const fixtures = getTestFixture(context);
102
+ if (!(fixtures === null || fixtures === void 0 ? void 0 : fixtures.length)) {
103
+ return fn(context);
104
+ }
105
+ const usedProps = getUsedProps(fn);
106
+ const hasAutoFixture = fixtures.some(({ auto }) => auto);
107
+ if (!usedProps.length && !hasAutoFixture) {
108
+ return fn(context);
109
+ }
110
+ if (!fixtureValueMaps.get(context)) {
111
+ fixtureValueMaps.set(context, new Map());
112
+ }
113
+ const fixtureValueMap = fixtureValueMaps.get(context);
114
+ if (!cleanupFnArrayMap.has(context)) {
115
+ cleanupFnArrayMap.set(context, []);
116
+ }
117
+ const cleanupFnArray = cleanupFnArrayMap.get(context);
118
+ const usedFixtures = fixtures.filter(({ prop, auto }) => auto || usedProps.includes(prop));
119
+ const pendingFixtures = resolveDeps(usedFixtures);
120
+ if (!pendingFixtures.length) {
121
+ return fn(context);
122
+ }
123
+ async function resolveFixtures() {
124
+ for (const fixture of pendingFixtures) {
125
+ if (fixtureValueMap.has(fixture)) {
126
+ continue;
127
+ }
128
+ const resolvedValue = fixture.isFn ? await resolveFixtureFunction(fixture.value, context, cleanupFnArray) : fixture.value;
129
+ context[fixture.prop] = resolvedValue;
130
+ fixtureValueMap.set(fixture, resolvedValue);
131
+ cleanupFnArray.unshift(() => {
132
+ fixtureValueMap.delete(fixture);
133
+ });
134
+ }
135
+ }
136
+ return resolveFixtures().then(() => fn(context));
137
+ };
226
138
  }
227
139
  async function resolveFixtureFunction(fixtureFn, context, cleanupFnArray) {
228
- const useFnArgPromise = createDefer();
229
- let isUseFnArgResolved = false;
230
- const fixtureReturn = fixtureFn(context, async (useFnArg) => {
231
- isUseFnArgResolved = true;
232
- useFnArgPromise.resolve(useFnArg);
233
- const useReturnPromise = createDefer();
234
- cleanupFnArray.push(async () => {
235
- useReturnPromise.resolve();
236
- await fixtureReturn;
237
- });
238
- await useReturnPromise;
239
- }).catch((e) => {
240
- if (!isUseFnArgResolved) {
241
- useFnArgPromise.reject(e);
242
- return;
243
- }
244
- throw e;
245
- });
246
- return useFnArgPromise;
247
- }
248
- function resolveDeps(fixtures, depSet = /* @__PURE__ */ new Set(), pendingFixtures = []) {
249
- fixtures.forEach((fixture) => {
250
- if (pendingFixtures.includes(fixture)) {
251
- return;
252
- }
253
- if (!fixture.isFn || !fixture.deps) {
254
- pendingFixtures.push(fixture);
255
- return;
256
- }
257
- if (depSet.has(fixture)) {
258
- throw new Error(
259
- `Circular fixture dependency detected: ${fixture.prop} <- ${[...depSet].reverse().map((d) => d.prop).join(" <- ")}`
260
- );
261
- }
262
- depSet.add(fixture);
263
- resolveDeps(fixture.deps, depSet, pendingFixtures);
264
- pendingFixtures.push(fixture);
265
- depSet.clear();
266
- });
267
- return pendingFixtures;
140
+ const useFnArgPromise = createDefer();
141
+ let isUseFnArgResolved = false;
142
+ const fixtureReturn = fixtureFn(context, async (useFnArg) => {
143
+ isUseFnArgResolved = true;
144
+ useFnArgPromise.resolve(useFnArg);
145
+ const useReturnPromise = createDefer();
146
+ cleanupFnArray.push(async () => {
147
+ useReturnPromise.resolve();
148
+ await fixtureReturn;
149
+ });
150
+ await useReturnPromise;
151
+ }).catch((e) => {
152
+ if (!isUseFnArgResolved) {
153
+ useFnArgPromise.reject(e);
154
+ return;
155
+ }
156
+ throw e;
157
+ });
158
+ return useFnArgPromise;
159
+ }
160
+ function resolveDeps(fixtures, depSet = new Set(), pendingFixtures = []) {
161
+ fixtures.forEach((fixture) => {
162
+ if (pendingFixtures.includes(fixture)) {
163
+ return;
164
+ }
165
+ if (!fixture.isFn || !fixture.deps) {
166
+ pendingFixtures.push(fixture);
167
+ return;
168
+ }
169
+ if (depSet.has(fixture)) {
170
+ throw new Error(`Circular fixture dependency detected: ${fixture.prop} <- ${[...depSet].reverse().map((d) => d.prop).join(" <- ")}`);
171
+ }
172
+ depSet.add(fixture);
173
+ resolveDeps(fixture.deps, depSet, pendingFixtures);
174
+ pendingFixtures.push(fixture);
175
+ depSet.clear();
176
+ });
177
+ return pendingFixtures;
268
178
  }
269
179
  function getUsedProps(fn) {
270
- let fnString = fn.toString();
271
- if (/__async\(this, (?:null|arguments|\[[_0-9, ]*\]), function\*/.test(fnString)) {
272
- fnString = fnString.split("__async(this,")[1];
273
- }
274
- const match = fnString.match(/[^(]*\(([^)]*)/);
275
- if (!match) {
276
- return [];
277
- }
278
- const args = splitByComma(match[1]);
279
- if (!args.length) {
280
- return [];
281
- }
282
- let first = args[0];
283
- if ("__VITEST_FIXTURE_INDEX__" in fn) {
284
- first = args[fn.__VITEST_FIXTURE_INDEX__];
285
- if (!first) {
286
- return [];
287
- }
288
- }
289
- if (!(first.startsWith("{") && first.endsWith("}"))) {
290
- throw new Error(
291
- `The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "${first}".`
292
- );
293
- }
294
- const _first = first.slice(1, -1).replace(/\s/g, "");
295
- const props = splitByComma(_first).map((prop) => {
296
- return prop.replace(/:.*|=.*/g, "");
297
- });
298
- const last = props.at(-1);
299
- if (last && last.startsWith("...")) {
300
- throw new Error(
301
- `Rest parameters are not supported in fixtures, received "${last}".`
302
- );
303
- }
304
- return props;
180
+ let fnString = fn.toString();
181
+ if (/__async\(this, (?:null|arguments|\[[_0-9, ]*\]), function\*/.test(fnString)) {
182
+ fnString = fnString.split("__async(this,")[1];
183
+ }
184
+ const match = fnString.match(/[^(]*\(([^)]*)/);
185
+ if (!match) {
186
+ return [];
187
+ }
188
+ const args = splitByComma(match[1]);
189
+ if (!args.length) {
190
+ return [];
191
+ }
192
+ let first = args[0];
193
+ if ("__VITEST_FIXTURE_INDEX__" in fn) {
194
+ first = args[fn.__VITEST_FIXTURE_INDEX__];
195
+ if (!first) {
196
+ return [];
197
+ }
198
+ }
199
+ if (!(first.startsWith("{") && first.endsWith("}"))) {
200
+ throw new Error(`The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "${first}".`);
201
+ }
202
+ const _first = first.slice(1, -1).replace(/\s/g, "");
203
+ const props = splitByComma(_first).map((prop) => {
204
+ return prop.replace(/:.*|=.*/g, "");
205
+ });
206
+ const last = props.at(-1);
207
+ if (last && last.startsWith("...")) {
208
+ throw new Error(`Rest parameters are not supported in fixtures, received "${last}".`);
209
+ }
210
+ return props;
305
211
  }
306
212
  function splitByComma(s) {
307
- const result = [];
308
- const stack = [];
309
- let start = 0;
310
- for (let i = 0; i < s.length; i++) {
311
- if (s[i] === "{" || s[i] === "[") {
312
- stack.push(s[i] === "{" ? "}" : "]");
313
- } else if (s[i] === stack[stack.length - 1]) {
314
- stack.pop();
315
- } else if (!stack.length && s[i] === ",") {
316
- const token = s.substring(start, i).trim();
317
- if (token) {
318
- result.push(token);
319
- }
320
- start = i + 1;
321
- }
322
- }
323
- const lastToken = s.substring(start).trim();
324
- if (lastToken) {
325
- result.push(lastToken);
326
- }
327
- return result;
213
+ const result = [];
214
+ const stack = [];
215
+ let start = 0;
216
+ for (let i = 0; i < s.length; i++) {
217
+ if (s[i] === "{" || s[i] === "[") {
218
+ stack.push(s[i] === "{" ? "}" : "]");
219
+ } else if (s[i] === stack[stack.length - 1]) {
220
+ stack.pop();
221
+ } else if (!stack.length && s[i] === ",") {
222
+ const token = s.substring(start, i).trim();
223
+ if (token) {
224
+ result.push(token);
225
+ }
226
+ start = i + 1;
227
+ }
228
+ }
229
+ const lastToken = s.substring(start).trim();
230
+ if (lastToken) {
231
+ result.push(lastToken);
232
+ }
233
+ return result;
328
234
  }
329
235
 
330
236
  let _test;
331
237
  function setCurrentTest(test) {
332
- _test = test;
238
+ _test = test;
333
239
  }
334
240
  function getCurrentTest() {
335
- return _test;
241
+ return _test;
336
242
  }
337
243
 
244
+ /**
245
+ * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
246
+ * Suites can contain both tests and other suites, enabling complex test structures.
247
+ *
248
+ * @param {string} name - The name of the suite, used for identification and reporting.
249
+ * @param {Function} fn - A function that defines the tests and suites within this suite.
250
+ * @example
251
+ * ```ts
252
+ * // Define a suite with two tests
253
+ * suite('Math operations', () => {
254
+ * test('should add two numbers', () => {
255
+ * expect(add(1, 2)).toBe(3);
256
+ * });
257
+ *
258
+ * test('should subtract two numbers', () => {
259
+ * expect(subtract(5, 2)).toBe(3);
260
+ * });
261
+ * });
262
+ * ```
263
+ * @example
264
+ * ```ts
265
+ * // Define nested suites
266
+ * suite('String operations', () => {
267
+ * suite('Trimming', () => {
268
+ * test('should trim whitespace from start and end', () => {
269
+ * expect(' hello '.trim()).toBe('hello');
270
+ * });
271
+ * });
272
+ *
273
+ * suite('Concatenation', () => {
274
+ * test('should concatenate two strings', () => {
275
+ * expect('hello' + ' ' + 'world').toBe('hello world');
276
+ * });
277
+ * });
278
+ * });
279
+ * ```
280
+ */
338
281
  const suite = createSuite();
282
+ /**
283
+ * Defines a test case with a given name and test function. The test function can optionally be configured with test options.
284
+ *
285
+ * @param {string | Function} name - The name of the test or a function that will be used as a test name.
286
+ * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
287
+ * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
288
+ * @throws {Error} If called inside another test function.
289
+ * @example
290
+ * ```ts
291
+ * // Define a simple test
292
+ * test('should add two numbers', () => {
293
+ * expect(add(1, 2)).toBe(3);
294
+ * });
295
+ * ```
296
+ * @example
297
+ * ```ts
298
+ * // Define a test with options
299
+ * test('should subtract two numbers', { retry: 3 }, () => {
300
+ * expect(subtract(5, 2)).toBe(3);
301
+ * });
302
+ * ```
303
+ */
339
304
  const test = createTest(function(name, optionsOrFn, optionsOrTest) {
340
- if (getCurrentTest()) {
341
- throw new Error(
342
- 'Calling the test function inside another test function is not allowed. Please put it inside "describe" or "suite" so it can be properly collected.'
343
- );
344
- }
345
- getCurrentSuite().test.fn.call(
346
- this,
347
- formatName(name),
348
- optionsOrFn,
349
- optionsOrTest
350
- );
305
+ if (getCurrentTest()) {
306
+ throw new Error("Calling the test function inside another test function is not allowed. Please put it inside \"describe\" or \"suite\" so it can be properly collected.");
307
+ }
308
+ getCurrentSuite().test.fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
351
309
  });
310
+ /**
311
+ * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
312
+ * Suites can contain both tests and other suites, enabling complex test structures.
313
+ *
314
+ * @param {string} name - The name of the suite, used for identification and reporting.
315
+ * @param {Function} fn - A function that defines the tests and suites within this suite.
316
+ * @example
317
+ * ```ts
318
+ * // Define a suite with two tests
319
+ * describe('Math operations', () => {
320
+ * test('should add two numbers', () => {
321
+ * expect(add(1, 2)).toBe(3);
322
+ * });
323
+ *
324
+ * test('should subtract two numbers', () => {
325
+ * expect(subtract(5, 2)).toBe(3);
326
+ * });
327
+ * });
328
+ * ```
329
+ * @example
330
+ * ```ts
331
+ * // Define nested suites
332
+ * describe('String operations', () => {
333
+ * describe('Trimming', () => {
334
+ * test('should trim whitespace from start and end', () => {
335
+ * expect(' hello '.trim()).toBe('hello');
336
+ * });
337
+ * });
338
+ *
339
+ * describe('Concatenation', () => {
340
+ * test('should concatenate two strings', () => {
341
+ * expect('hello' + ' ' + 'world').toBe('hello world');
342
+ * });
343
+ * });
344
+ * });
345
+ * ```
346
+ */
352
347
  const describe = suite;
348
+ /**
349
+ * Defines a test case with a given name and test function. The test function can optionally be configured with test options.
350
+ *
351
+ * @param {string | Function} name - The name of the test or a function that will be used as a test name.
352
+ * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
353
+ * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
354
+ * @throws {Error} If called inside another test function.
355
+ * @example
356
+ * ```ts
357
+ * // Define a simple test
358
+ * it('adds two numbers', () => {
359
+ * expect(add(1, 2)).toBe(3);
360
+ * });
361
+ * ```
362
+ * @example
363
+ * ```ts
364
+ * // Define a test with options
365
+ * it('subtracts two numbers', { retry: 3 }, () => {
366
+ * expect(subtract(5, 2)).toBe(3);
367
+ * });
368
+ * ```
369
+ */
353
370
  const it = test;
354
371
  let runner;
355
372
  let defaultSuite;
356
373
  let currentTestFilepath;
357
374
  function assert(condition, message) {
358
- if (!condition) {
359
- throw new Error(`Vitest failed to find ${message}. This is a bug in Vitest. Please, open an issue with reproduction.`);
360
- }
375
+ if (!condition) {
376
+ throw new Error(`Vitest failed to find ${message}. This is a bug in Vitest. Please, open an issue with reproduction.`);
377
+ }
361
378
  }
362
379
  function getDefaultSuite() {
363
- assert(defaultSuite, "the default suite");
364
- return defaultSuite;
380
+ assert(defaultSuite, "the default suite");
381
+ return defaultSuite;
365
382
  }
366
383
  function getTestFilepath() {
367
- return currentTestFilepath;
384
+ return currentTestFilepath;
368
385
  }
369
386
  function getRunner() {
370
- assert(runner, "the runner");
371
- return runner;
387
+ assert(runner, "the runner");
388
+ return runner;
372
389
  }
373
- function createDefaultSuite(runner2) {
374
- const config = runner2.config.sequence;
375
- const collector = suite("", { concurrent: config.concurrent }, () => {
376
- });
377
- delete collector.suite;
378
- return collector;
390
+ function createDefaultSuite(runner) {
391
+ const config = runner.config.sequence;
392
+ const collector = suite("", { concurrent: config.concurrent }, () => {});
393
+ delete collector.suite;
394
+ return collector;
379
395
  }
380
396
  function clearCollectorContext(filepath, currentRunner) {
381
- if (!defaultSuite) {
382
- defaultSuite = createDefaultSuite(currentRunner);
383
- }
384
- runner = currentRunner;
385
- currentTestFilepath = filepath;
386
- collectorContext.tasks.length = 0;
387
- defaultSuite.clear();
388
- collectorContext.currentSuite = defaultSuite;
397
+ if (!defaultSuite) {
398
+ defaultSuite = createDefaultSuite(currentRunner);
399
+ }
400
+ runner = currentRunner;
401
+ currentTestFilepath = filepath;
402
+ collectorContext.tasks.length = 0;
403
+ defaultSuite.clear();
404
+ collectorContext.currentSuite = defaultSuite;
389
405
  }
390
406
  function getCurrentSuite() {
391
- const currentSuite = collectorContext.currentSuite || defaultSuite;
392
- assert(currentSuite, "the current suite");
393
- return currentSuite;
407
+ const currentSuite = collectorContext.currentSuite || defaultSuite;
408
+ assert(currentSuite, "the current suite");
409
+ return currentSuite;
394
410
  }
395
411
  function createSuiteHooks() {
396
- return {
397
- beforeAll: [],
398
- afterAll: [],
399
- beforeEach: [],
400
- afterEach: []
401
- };
412
+ return {
413
+ beforeAll: [],
414
+ afterAll: [],
415
+ beforeEach: [],
416
+ afterEach: []
417
+ };
402
418
  }
403
419
  function parseArguments(optionsOrFn, optionsOrTest) {
404
- let options = {};
405
- let fn = () => {
406
- };
407
- if (typeof optionsOrTest === "object") {
408
- if (typeof optionsOrFn === "object") {
409
- throw new TypeError(
410
- "Cannot use two objects as arguments. Please provide options and a function callback in that order."
411
- );
412
- }
413
- console.warn(
414
- "Using an object as a third argument is deprecated. Vitest 4 will throw an error if the third argument is not a timeout number. Please use the second argument for options. See more at https://vitest.dev/guide/migration"
415
- );
416
- options = optionsOrTest;
417
- } else if (typeof optionsOrTest === "number") {
418
- options = { timeout: optionsOrTest };
419
- } else if (typeof optionsOrFn === "object") {
420
- options = optionsOrFn;
421
- }
422
- if (typeof optionsOrFn === "function") {
423
- if (typeof optionsOrTest === "function") {
424
- throw new TypeError(
425
- "Cannot use two functions as arguments. Please use the second argument for options."
426
- );
427
- }
428
- fn = optionsOrFn;
429
- } else if (typeof optionsOrTest === "function") {
430
- fn = optionsOrTest;
431
- }
432
- return {
433
- options,
434
- handler: fn
435
- };
436
- }
437
- function createSuiteCollector(name, factory = () => {
438
- }, mode, each, suiteOptions) {
439
- const tasks = [];
440
- let suite2;
441
- initSuite(true);
442
- const task = function(name2 = "", options = {}) {
443
- var _a;
444
- const timeout = (options == null ? void 0 : options.timeout) ?? runner.config.testTimeout;
445
- const task2 = {
446
- id: "",
447
- name: name2,
448
- suite: (_a = collectorContext.currentSuite) == null ? void 0 : _a.suite,
449
- each: options.each,
450
- fails: options.fails,
451
- context: void 0,
452
- type: "test",
453
- file: void 0,
454
- timeout,
455
- retry: options.retry ?? runner.config.retry,
456
- repeats: options.repeats,
457
- mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
458
- meta: options.meta ?? /* @__PURE__ */ Object.create(null)
459
- };
460
- const handler = options.handler;
461
- if (options.concurrent || !options.sequential && runner.config.sequence.concurrent) {
462
- task2.concurrent = true;
463
- }
464
- task2.shuffle = suiteOptions == null ? void 0 : suiteOptions.shuffle;
465
- const context = createTestContext(task2, runner);
466
- Object.defineProperty(task2, "context", {
467
- value: context,
468
- enumerable: false
469
- });
470
- setFixture(context, options.fixtures);
471
- if (handler) {
472
- setFn(
473
- task2,
474
- withTimeout(
475
- withAwaitAsyncAssertions(withFixtures(handler, context), task2),
476
- timeout
477
- )
478
- );
479
- }
480
- if (runner.config.includeTaskLocation) {
481
- const limit = Error.stackTraceLimit;
482
- Error.stackTraceLimit = 15;
483
- const error = new Error("stacktrace").stack;
484
- Error.stackTraceLimit = limit;
485
- const stack = findTestFileStackTrace(error, task2.each ?? false);
486
- if (stack) {
487
- task2.location = stack;
488
- }
489
- }
490
- tasks.push(task2);
491
- return task2;
492
- };
493
- const test2 = createTest(function(name2, optionsOrFn, optionsOrTest) {
494
- let { options, handler } = parseArguments(optionsOrFn, optionsOrTest);
495
- if (typeof suiteOptions === "object") {
496
- options = Object.assign({}, suiteOptions, options);
497
- }
498
- options.concurrent = this.concurrent || !this.sequential && (options == null ? void 0 : options.concurrent);
499
- options.sequential = this.sequential || !this.concurrent && (options == null ? void 0 : options.sequential);
500
- const test3 = task(formatName(name2), {
501
- ...this,
502
- ...options,
503
- handler
504
- });
505
- test3.type = "test";
506
- });
507
- const collector = {
508
- type: "collector",
509
- name,
510
- mode,
511
- suite: suite2,
512
- options: suiteOptions,
513
- test: test2,
514
- tasks,
515
- collect,
516
- task,
517
- clear,
518
- on: addHook
519
- };
520
- function addHook(name2, ...fn) {
521
- getHooks(suite2)[name2].push(...fn);
522
- }
523
- function initSuite(includeLocation) {
524
- var _a;
525
- if (typeof suiteOptions === "number") {
526
- suiteOptions = { timeout: suiteOptions };
527
- }
528
- suite2 = {
529
- id: "",
530
- type: "suite",
531
- name,
532
- suite: (_a = collectorContext.currentSuite) == null ? void 0 : _a.suite,
533
- mode,
534
- each,
535
- file: void 0,
536
- shuffle: suiteOptions == null ? void 0 : suiteOptions.shuffle,
537
- tasks: [],
538
- meta: /* @__PURE__ */ Object.create(null),
539
- concurrent: suiteOptions == null ? void 0 : suiteOptions.concurrent
540
- };
541
- if (runner && includeLocation && runner.config.includeTaskLocation) {
542
- const limit = Error.stackTraceLimit;
543
- Error.stackTraceLimit = 15;
544
- const error = new Error("stacktrace").stack;
545
- Error.stackTraceLimit = limit;
546
- const stack = findTestFileStackTrace(error, suite2.each ?? false);
547
- if (stack) {
548
- suite2.location = stack;
549
- }
550
- }
551
- setHooks(suite2, createSuiteHooks());
552
- }
553
- function clear() {
554
- tasks.length = 0;
555
- initSuite(false);
556
- }
557
- async function collect(file) {
558
- if (!file) {
559
- throw new TypeError("File is required to collect tasks.");
560
- }
561
- if (factory) {
562
- await runWithSuite(collector, () => factory(test2));
563
- }
564
- const allChildren = [];
565
- for (const i of tasks) {
566
- allChildren.push(i.type === "collector" ? await i.collect(file) : i);
567
- }
568
- suite2.file = file;
569
- suite2.tasks = allChildren;
570
- allChildren.forEach((task2) => {
571
- task2.file = file;
572
- });
573
- return suite2;
574
- }
575
- collectTask(collector);
576
- return collector;
420
+ let options = {};
421
+ let fn = () => {};
422
+ if (typeof optionsOrTest === "object") {
423
+ if (typeof optionsOrFn === "object") {
424
+ throw new TypeError("Cannot use two objects as arguments. Please provide options and a function callback in that order.");
425
+ }
426
+ console.warn("Using an object as a third argument is deprecated. Vitest 4 will throw an error if the third argument is not a timeout number. Please use the second argument for options. See more at https://vitest.dev/guide/migration");
427
+ options = optionsOrTest;
428
+ } else if (typeof optionsOrTest === "number") {
429
+ options = { timeout: optionsOrTest };
430
+ } else if (typeof optionsOrFn === "object") {
431
+ options = optionsOrFn;
432
+ }
433
+ if (typeof optionsOrFn === "function") {
434
+ if (typeof optionsOrTest === "function") {
435
+ throw new TypeError("Cannot use two functions as arguments. Please use the second argument for options.");
436
+ }
437
+ fn = optionsOrFn;
438
+ } else if (typeof optionsOrTest === "function") {
439
+ fn = optionsOrTest;
440
+ }
441
+ return {
442
+ options,
443
+ handler: fn
444
+ };
445
+ }
446
+ function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions) {
447
+ const tasks = [];
448
+ let suite;
449
+ initSuite(true);
450
+ const task = function(name = "", options = {}) {
451
+ var _collectorContext$cur;
452
+ const timeout = (options === null || options === void 0 ? void 0 : options.timeout) ?? runner.config.testTimeout;
453
+ const task = {
454
+ id: "",
455
+ name,
456
+ suite: (_collectorContext$cur = collectorContext.currentSuite) === null || _collectorContext$cur === void 0 ? void 0 : _collectorContext$cur.suite,
457
+ each: options.each,
458
+ fails: options.fails,
459
+ context: undefined,
460
+ type: "test",
461
+ file: undefined,
462
+ timeout,
463
+ retry: options.retry ?? runner.config.retry,
464
+ repeats: options.repeats,
465
+ mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
466
+ meta: options.meta ?? Object.create(null)
467
+ };
468
+ const handler = options.handler;
469
+ if (options.concurrent || !options.sequential && runner.config.sequence.concurrent) {
470
+ task.concurrent = true;
471
+ }
472
+ task.shuffle = suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.shuffle;
473
+ const context = createTestContext(task, runner);
474
+ Object.defineProperty(task, "context", {
475
+ value: context,
476
+ enumerable: false
477
+ });
478
+ setTestFixture(context, options.fixtures);
479
+ if (handler) {
480
+ setFn(task, withTimeout(withAwaitAsyncAssertions(withFixtures(handler, context), task), timeout));
481
+ }
482
+ if (runner.config.includeTaskLocation) {
483
+ const limit = Error.stackTraceLimit;
484
+ Error.stackTraceLimit = 15;
485
+ const error = new Error("stacktrace").stack;
486
+ Error.stackTraceLimit = limit;
487
+ const stack = findTestFileStackTrace(error, task.each ?? false);
488
+ if (stack) {
489
+ task.location = stack;
490
+ }
491
+ }
492
+ tasks.push(task);
493
+ return task;
494
+ };
495
+ const test = createTest(function(name, optionsOrFn, optionsOrTest) {
496
+ let { options, handler } = parseArguments(optionsOrFn, optionsOrTest);
497
+ if (typeof suiteOptions === "object") {
498
+ options = Object.assign({}, suiteOptions, options);
499
+ }
500
+ options.concurrent = this.concurrent || !this.sequential && (options === null || options === void 0 ? void 0 : options.concurrent);
501
+ options.sequential = this.sequential || !this.concurrent && (options === null || options === void 0 ? void 0 : options.sequential);
502
+ const test = task(formatName(name), {
503
+ ...this,
504
+ ...options,
505
+ handler
506
+ });
507
+ test.type = "test";
508
+ });
509
+ let collectorFixtures;
510
+ const collector = {
511
+ type: "collector",
512
+ name,
513
+ mode,
514
+ suite,
515
+ options: suiteOptions,
516
+ test,
517
+ tasks,
518
+ collect,
519
+ task,
520
+ clear,
521
+ on: addHook,
522
+ fixtures() {
523
+ return collectorFixtures;
524
+ },
525
+ scoped(fixtures) {
526
+ const parsed = mergeContextFixtures(fixtures, { fixtures: collectorFixtures }, (key) => {
527
+ var _getRunner$injectValu, _getRunner;
528
+ return (_getRunner$injectValu = (_getRunner = getRunner()).injectValue) === null || _getRunner$injectValu === void 0 ? void 0 : _getRunner$injectValu.call(_getRunner, key);
529
+ });
530
+ if (parsed.fixtures) {
531
+ collectorFixtures = parsed.fixtures;
532
+ }
533
+ }
534
+ };
535
+ function addHook(name, ...fn) {
536
+ getHooks(suite)[name].push(...fn);
537
+ }
538
+ function initSuite(includeLocation) {
539
+ var _collectorContext$cur2;
540
+ if (typeof suiteOptions === "number") {
541
+ suiteOptions = { timeout: suiteOptions };
542
+ }
543
+ suite = {
544
+ id: "",
545
+ type: "suite",
546
+ name,
547
+ suite: (_collectorContext$cur2 = collectorContext.currentSuite) === null || _collectorContext$cur2 === void 0 ? void 0 : _collectorContext$cur2.suite,
548
+ mode,
549
+ each,
550
+ file: undefined,
551
+ shuffle: suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.shuffle,
552
+ tasks: [],
553
+ meta: Object.create(null),
554
+ concurrent: suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.concurrent
555
+ };
556
+ if (runner && includeLocation && runner.config.includeTaskLocation) {
557
+ const limit = Error.stackTraceLimit;
558
+ Error.stackTraceLimit = 15;
559
+ const error = new Error("stacktrace").stack;
560
+ Error.stackTraceLimit = limit;
561
+ const stack = findTestFileStackTrace(error, suite.each ?? false);
562
+ if (stack) {
563
+ suite.location = stack;
564
+ }
565
+ }
566
+ setHooks(suite, createSuiteHooks());
567
+ }
568
+ function clear() {
569
+ tasks.length = 0;
570
+ initSuite(false);
571
+ }
572
+ async function collect(file) {
573
+ if (!file) {
574
+ throw new TypeError("File is required to collect tasks.");
575
+ }
576
+ if (factory) {
577
+ await runWithSuite(collector, () => factory(test));
578
+ }
579
+ const allChildren = [];
580
+ for (const i of tasks) {
581
+ allChildren.push(i.type === "collector" ? await i.collect(file) : i);
582
+ }
583
+ suite.file = file;
584
+ suite.tasks = allChildren;
585
+ allChildren.forEach((task) => {
586
+ task.file = file;
587
+ });
588
+ return suite;
589
+ }
590
+ collectTask(collector);
591
+ return collector;
577
592
  }
578
593
  function withAwaitAsyncAssertions(fn, task) {
579
- return async (...args) => {
580
- const fnResult = await fn(...args);
581
- if (task.promises) {
582
- const result = await Promise.allSettled(task.promises);
583
- const errors = result.map((r) => r.status === "rejected" ? r.reason : void 0).filter(Boolean);
584
- if (errors.length) {
585
- throw errors;
586
- }
587
- }
588
- return fnResult;
589
- };
594
+ return async (...args) => {
595
+ const fnResult = await fn(...args);
596
+ if (task.promises) {
597
+ const result = await Promise.allSettled(task.promises);
598
+ const errors = result.map((r) => r.status === "rejected" ? r.reason : undefined).filter(Boolean);
599
+ if (errors.length) {
600
+ throw errors;
601
+ }
602
+ }
603
+ return fnResult;
604
+ };
590
605
  }
591
606
  function createSuite() {
592
- function suiteFn(name, factoryOrOptions, optionsOrFactory) {
593
- var _a;
594
- const mode = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
595
- const currentSuite = collectorContext.currentSuite || defaultSuite;
596
- let { options, handler: factory } = parseArguments(
597
- factoryOrOptions,
598
- optionsOrFactory
599
- );
600
- const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
601
- const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
602
- options = {
603
- ...currentSuite == null ? void 0 : currentSuite.options,
604
- ...options,
605
- shuffle: this.shuffle ?? options.shuffle ?? ((_a = currentSuite == null ? void 0 : currentSuite.options) == null ? void 0 : _a.shuffle) ?? (runner == null ? void 0 : runner.config.sequence.shuffle)
606
- };
607
- const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
608
- const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
609
- options.concurrent = isConcurrent && !isSequential;
610
- options.sequential = isSequential && !isConcurrent;
611
- return createSuiteCollector(
612
- formatName(name),
613
- factory,
614
- mode,
615
- this.each,
616
- options
617
- );
618
- }
619
- suiteFn.each = function(cases, ...args) {
620
- const suite2 = this.withContext();
621
- this.setContext("each", true);
622
- if (Array.isArray(cases) && args.length) {
623
- cases = formatTemplateString(cases, args);
624
- }
625
- return (name, optionsOrFn, fnOrOptions) => {
626
- const _name = formatName(name);
627
- const arrayOnlyCases = cases.every(Array.isArray);
628
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
629
- const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
630
- cases.forEach((i, idx) => {
631
- const items = Array.isArray(i) ? i : [i];
632
- if (fnFirst) {
633
- if (arrayOnlyCases) {
634
- suite2(
635
- formatTitle(_name, items, idx),
636
- () => handler(...items),
637
- options
638
- );
639
- } else {
640
- suite2(formatTitle(_name, items, idx), () => handler(i), options);
641
- }
642
- } else {
643
- if (arrayOnlyCases) {
644
- suite2(formatTitle(_name, items, idx), options, () => handler(...items));
645
- } else {
646
- suite2(formatTitle(_name, items, idx), options, () => handler(i));
647
- }
648
- }
649
- });
650
- this.setContext("each", void 0);
651
- };
652
- };
653
- suiteFn.for = function(cases, ...args) {
654
- if (Array.isArray(cases) && args.length) {
655
- cases = formatTemplateString(cases, args);
656
- }
657
- return (name, optionsOrFn, fnOrOptions) => {
658
- const name_ = formatName(name);
659
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
660
- cases.forEach((item, idx) => {
661
- suite(formatTitle(name_, toArray(item), idx), options, () => handler(item));
662
- });
663
- };
664
- };
665
- suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
666
- suiteFn.runIf = (condition) => condition ? suite : suite.skip;
667
- return createChainable(
668
- ["concurrent", "sequential", "shuffle", "skip", "only", "todo"],
669
- suiteFn
670
- );
607
+ function suiteFn(name, factoryOrOptions, optionsOrFactory) {
608
+ var _currentSuite$options;
609
+ const mode = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
610
+ const currentSuite = collectorContext.currentSuite || defaultSuite;
611
+ let { options, handler: factory } = parseArguments(factoryOrOptions, optionsOrFactory);
612
+ const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
613
+ const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
614
+ options = {
615
+ ...currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.options,
616
+ ...options,
617
+ shuffle: this.shuffle ?? options.shuffle ?? (currentSuite === null || currentSuite === void 0 || (_currentSuite$options = currentSuite.options) === null || _currentSuite$options === void 0 ? void 0 : _currentSuite$options.shuffle) ?? (runner === null || runner === void 0 ? void 0 : runner.config.sequence.shuffle)
618
+ };
619
+ const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
620
+ const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
621
+ options.concurrent = isConcurrent && !isSequential;
622
+ options.sequential = isSequential && !isConcurrent;
623
+ return createSuiteCollector(formatName(name), factory, mode, this.each, options);
624
+ }
625
+ suiteFn.each = function(cases, ...args) {
626
+ const suite = this.withContext();
627
+ this.setContext("each", true);
628
+ if (Array.isArray(cases) && args.length) {
629
+ cases = formatTemplateString(cases, args);
630
+ }
631
+ return (name, optionsOrFn, fnOrOptions) => {
632
+ const _name = formatName(name);
633
+ const arrayOnlyCases = cases.every(Array.isArray);
634
+ const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
635
+ const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
636
+ cases.forEach((i, idx) => {
637
+ const items = Array.isArray(i) ? i : [i];
638
+ if (fnFirst) {
639
+ if (arrayOnlyCases) {
640
+ suite(formatTitle(_name, items, idx), () => handler(...items), options);
641
+ } else {
642
+ suite(formatTitle(_name, items, idx), () => handler(i), options);
643
+ }
644
+ } else {
645
+ if (arrayOnlyCases) {
646
+ suite(formatTitle(_name, items, idx), options, () => handler(...items));
647
+ } else {
648
+ suite(formatTitle(_name, items, idx), options, () => handler(i));
649
+ }
650
+ }
651
+ });
652
+ this.setContext("each", undefined);
653
+ };
654
+ };
655
+ suiteFn.for = function(cases, ...args) {
656
+ if (Array.isArray(cases) && args.length) {
657
+ cases = formatTemplateString(cases, args);
658
+ }
659
+ return (name, optionsOrFn, fnOrOptions) => {
660
+ const name_ = formatName(name);
661
+ const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
662
+ cases.forEach((item, idx) => {
663
+ suite(formatTitle(name_, toArray(item), idx), options, () => handler(item));
664
+ });
665
+ };
666
+ };
667
+ suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
668
+ suiteFn.runIf = (condition) => condition ? suite : suite.skip;
669
+ return createChainable([
670
+ "concurrent",
671
+ "sequential",
672
+ "shuffle",
673
+ "skip",
674
+ "only",
675
+ "todo"
676
+ ], suiteFn);
671
677
  }
672
678
  function createTaskCollector(fn, context) {
673
- const taskFn = fn;
674
- taskFn.each = function(cases, ...args) {
675
- const test2 = this.withContext();
676
- this.setContext("each", true);
677
- if (Array.isArray(cases) && args.length) {
678
- cases = formatTemplateString(cases, args);
679
- }
680
- return (name, optionsOrFn, fnOrOptions) => {
681
- const _name = formatName(name);
682
- const arrayOnlyCases = cases.every(Array.isArray);
683
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
684
- const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
685
- cases.forEach((i, idx) => {
686
- const items = Array.isArray(i) ? i : [i];
687
- if (fnFirst) {
688
- if (arrayOnlyCases) {
689
- test2(
690
- formatTitle(_name, items, idx),
691
- () => handler(...items),
692
- options
693
- );
694
- } else {
695
- test2(formatTitle(_name, items, idx), () => handler(i), options);
696
- }
697
- } else {
698
- if (arrayOnlyCases) {
699
- test2(formatTitle(_name, items, idx), options, () => handler(...items));
700
- } else {
701
- test2(formatTitle(_name, items, idx), options, () => handler(i));
702
- }
703
- }
704
- });
705
- this.setContext("each", void 0);
706
- };
707
- };
708
- taskFn.for = function(cases, ...args) {
709
- const test2 = this.withContext();
710
- if (Array.isArray(cases) && args.length) {
711
- cases = formatTemplateString(cases, args);
712
- }
713
- return (name, optionsOrFn, fnOrOptions) => {
714
- const _name = formatName(name);
715
- const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
716
- cases.forEach((item, idx) => {
717
- const handlerWrapper = (ctx) => handler(item, ctx);
718
- handlerWrapper.__VITEST_FIXTURE_INDEX__ = 1;
719
- handlerWrapper.toString = () => handler.toString();
720
- test2(formatTitle(_name, toArray(item), idx), options, handlerWrapper);
721
- });
722
- };
723
- };
724
- taskFn.skipIf = function(condition) {
725
- return condition ? this.skip : this;
726
- };
727
- taskFn.runIf = function(condition) {
728
- return condition ? this : this.skip;
729
- };
730
- taskFn.extend = function(fixtures) {
731
- const _context = mergeContextFixtures(
732
- fixtures,
733
- context || {},
734
- (key) => {
735
- var _a, _b;
736
- return (_b = (_a = getRunner()).injectValue) == null ? void 0 : _b.call(_a, key);
737
- }
738
- );
739
- return createTest(function fn2(name, optionsOrFn, optionsOrTest) {
740
- getCurrentSuite().test.fn.call(
741
- this,
742
- formatName(name),
743
- optionsOrFn,
744
- optionsOrTest
745
- );
746
- }, _context);
747
- };
748
- const _test = createChainable(
749
- ["concurrent", "sequential", "skip", "only", "todo", "fails"],
750
- taskFn
751
- );
752
- if (context) {
753
- _test.mergeContext(context);
754
- }
755
- return _test;
679
+ const taskFn = fn;
680
+ taskFn.each = function(cases, ...args) {
681
+ const test = this.withContext();
682
+ this.setContext("each", true);
683
+ if (Array.isArray(cases) && args.length) {
684
+ cases = formatTemplateString(cases, args);
685
+ }
686
+ return (name, optionsOrFn, fnOrOptions) => {
687
+ const _name = formatName(name);
688
+ const arrayOnlyCases = cases.every(Array.isArray);
689
+ const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
690
+ const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
691
+ cases.forEach((i, idx) => {
692
+ const items = Array.isArray(i) ? i : [i];
693
+ if (fnFirst) {
694
+ if (arrayOnlyCases) {
695
+ test(formatTitle(_name, items, idx), () => handler(...items), options);
696
+ } else {
697
+ test(formatTitle(_name, items, idx), () => handler(i), options);
698
+ }
699
+ } else {
700
+ if (arrayOnlyCases) {
701
+ test(formatTitle(_name, items, idx), options, () => handler(...items));
702
+ } else {
703
+ test(formatTitle(_name, items, idx), options, () => handler(i));
704
+ }
705
+ }
706
+ });
707
+ this.setContext("each", undefined);
708
+ };
709
+ };
710
+ taskFn.for = function(cases, ...args) {
711
+ const test = this.withContext();
712
+ if (Array.isArray(cases) && args.length) {
713
+ cases = formatTemplateString(cases, args);
714
+ }
715
+ return (name, optionsOrFn, fnOrOptions) => {
716
+ const _name = formatName(name);
717
+ const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
718
+ cases.forEach((item, idx) => {
719
+ const handlerWrapper = (ctx) => handler(item, ctx);
720
+ handlerWrapper.__VITEST_FIXTURE_INDEX__ = 1;
721
+ handlerWrapper.toString = () => handler.toString();
722
+ test(formatTitle(_name, toArray(item), idx), options, handlerWrapper);
723
+ });
724
+ };
725
+ };
726
+ taskFn.skipIf = function(condition) {
727
+ return condition ? this.skip : this;
728
+ };
729
+ taskFn.runIf = function(condition) {
730
+ return condition ? this : this.skip;
731
+ };
732
+ taskFn.scoped = function(fixtures) {
733
+ const collector = getCurrentSuite();
734
+ collector.scoped(fixtures);
735
+ };
736
+ taskFn.extend = function(fixtures) {
737
+ const _context = mergeContextFixtures(fixtures, context || {}, (key) => {
738
+ var _getRunner$injectValu2, _getRunner2;
739
+ return (_getRunner$injectValu2 = (_getRunner2 = getRunner()).injectValue) === null || _getRunner$injectValu2 === void 0 ? void 0 : _getRunner$injectValu2.call(_getRunner2, key);
740
+ });
741
+ return createTest(function fn(name, optionsOrFn, optionsOrTest) {
742
+ const collector = getCurrentSuite();
743
+ const scopedFixtures = collector.fixtures();
744
+ if (scopedFixtures) {
745
+ this.fixtures = mergeScopedFixtures(this.fixtures || [], scopedFixtures);
746
+ }
747
+ collector.test.fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
748
+ }, _context);
749
+ };
750
+ const _test = createChainable([
751
+ "concurrent",
752
+ "sequential",
753
+ "skip",
754
+ "only",
755
+ "todo",
756
+ "fails"
757
+ ], taskFn);
758
+ if (context) {
759
+ _test.mergeContext(context);
760
+ }
761
+ return _test;
756
762
  }
757
763
  function createTest(fn, context) {
758
- return createTaskCollector(fn, context);
764
+ return createTaskCollector(fn, context);
759
765
  }
760
766
  function formatName(name) {
761
- return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
767
+ return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
762
768
  }
763
769
  function formatTitle(template, items, idx) {
764
- if (template.includes("%#") || template.includes("%$")) {
765
- template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
766
- }
767
- const count = template.split("%").length - 1;
768
- if (template.includes("%f")) {
769
- const placeholders = template.match(/%f/g) || [];
770
- placeholders.forEach((_, i) => {
771
- if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
772
- let occurrence = 0;
773
- template = template.replace(/%f/g, (match) => {
774
- occurrence++;
775
- return occurrence === i + 1 ? "-%f" : match;
776
- });
777
- }
778
- });
779
- }
780
- let formatted = format(template, ...items.slice(0, count));
781
- const isObjectItem = isObject(items[0]);
782
- formatted = formatted.replace(
783
- /\$([$\w.]+)/g,
784
- (_, key) => {
785
- var _a, _b;
786
- const isArrayKey = /^\d+$/.test(key);
787
- if (!isObjectItem && !isArrayKey) {
788
- return `$${key}`;
789
- }
790
- const arrayElement = isArrayKey ? objectAttr(items, key) : void 0;
791
- const value = isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement;
792
- return objDisplay(value, {
793
- truncate: (_b = (_a = runner == null ? void 0 : runner.config) == null ? void 0 : _a.chaiConfig) == null ? void 0 : _b.truncateThreshold
794
- });
795
- }
796
- );
797
- return formatted;
770
+ if (template.includes("%#") || template.includes("%$")) {
771
+ template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
772
+ }
773
+ const count = template.split("%").length - 1;
774
+ if (template.includes("%f")) {
775
+ const placeholders = template.match(/%f/g) || [];
776
+ placeholders.forEach((_, i) => {
777
+ if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
778
+ let occurrence = 0;
779
+ template = template.replace(/%f/g, (match) => {
780
+ occurrence++;
781
+ return occurrence === i + 1 ? "-%f" : match;
782
+ });
783
+ }
784
+ });
785
+ }
786
+ let formatted = format(template, ...items.slice(0, count));
787
+ const isObjectItem = isObject(items[0]);
788
+ formatted = formatted.replace(/\$([$\w.]+)/g, (_, key) => {
789
+ var _runner$config;
790
+ const isArrayKey = /^\d+$/.test(key);
791
+ if (!isObjectItem && !isArrayKey) {
792
+ return `$${key}`;
793
+ }
794
+ const arrayElement = isArrayKey ? objectAttr(items, key) : undefined;
795
+ const value = isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement;
796
+ return objDisplay(value, { truncate: runner === null || runner === void 0 || (_runner$config = runner.config) === null || _runner$config === void 0 || (_runner$config = _runner$config.chaiConfig) === null || _runner$config === void 0 ? void 0 : _runner$config.truncateThreshold });
797
+ });
798
+ return formatted;
798
799
  }
799
800
  function formatTemplateString(cases, args) {
800
- const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
801
- const res = [];
802
- for (let i = 0; i < Math.floor(args.length / header.length); i++) {
803
- const oneCase = {};
804
- for (let j = 0; j < header.length; j++) {
805
- oneCase[header[j]] = args[i * header.length + j];
806
- }
807
- res.push(oneCase);
808
- }
809
- return res;
801
+ const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
802
+ const res = [];
803
+ for (let i = 0; i < Math.floor(args.length / header.length); i++) {
804
+ const oneCase = {};
805
+ for (let j = 0; j < header.length; j++) {
806
+ oneCase[header[j]] = args[i * header.length + j];
807
+ }
808
+ res.push(oneCase);
809
+ }
810
+ return res;
810
811
  }
811
812
  function findTestFileStackTrace(error, each) {
812
- const lines = error.split("\n").slice(1);
813
- for (const line of lines) {
814
- const stack = parseSingleStack(line);
815
- if (stack && stack.file === getTestFilepath()) {
816
- return {
817
- line: stack.line,
818
- /**
819
- * test.each([1, 2])('name')
820
- * ^ leads here, but should
821
- * ^ lead here
822
- * in source maps it's the same boundary, so it just points to the start of it
823
- */
824
- column: each ? stack.column + 1 : stack.column
825
- };
826
- }
827
- }
813
+ const lines = error.split("\n").slice(1);
814
+ for (const line of lines) {
815
+ const stack = parseSingleStack(line);
816
+ if (stack && stack.file === getTestFilepath()) {
817
+ return {
818
+ line: stack.line,
819
+ column: each ? stack.column + 1 : stack.column
820
+ };
821
+ }
822
+ }
823
+ }
824
+
825
+ const now$2 = Date.now;
826
+ const collectorContext = {
827
+ tasks: [],
828
+ currentSuite: null
829
+ };
830
+ function collectTask(task) {
831
+ var _collectorContext$cur;
832
+ (_collectorContext$cur = collectorContext.currentSuite) === null || _collectorContext$cur === void 0 ? void 0 : _collectorContext$cur.tasks.push(task);
833
+ }
834
+ async function runWithSuite(suite, fn) {
835
+ const prev = collectorContext.currentSuite;
836
+ collectorContext.currentSuite = suite;
837
+ await fn();
838
+ collectorContext.currentSuite = prev;
839
+ }
840
+ function withTimeout(fn, timeout, isHook = false, stackTraceError) {
841
+ if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY) {
842
+ return fn;
843
+ }
844
+ const { setTimeout, clearTimeout } = getSafeTimers();
845
+ return function runWithTimeout(...args) {
846
+ const startTime = now$2();
847
+ const runner = getRunner();
848
+ runner._currentTaskStartTime = startTime;
849
+ runner._currentTaskTimeout = timeout;
850
+ return new Promise((resolve_, reject_) => {
851
+ var _timer$unref;
852
+ const timer = setTimeout(() => {
853
+ clearTimeout(timer);
854
+ rejectTimeoutError();
855
+ }, timeout);
856
+ (_timer$unref = timer.unref) === null || _timer$unref === void 0 ? void 0 : _timer$unref.call(timer);
857
+ function rejectTimeoutError() {
858
+ reject_(makeTimeoutError(isHook, timeout, stackTraceError));
859
+ }
860
+ function resolve(result) {
861
+ runner._currentTaskStartTime = undefined;
862
+ runner._currentTaskTimeout = undefined;
863
+ clearTimeout(timer);
864
+ if (now$2() - startTime >= timeout) {
865
+ rejectTimeoutError();
866
+ return;
867
+ }
868
+ resolve_(result);
869
+ }
870
+ function reject(error) {
871
+ runner._currentTaskStartTime = undefined;
872
+ runner._currentTaskTimeout = undefined;
873
+ clearTimeout(timer);
874
+ reject_(error);
875
+ }
876
+ try {
877
+ const result = fn(...args);
878
+ if (typeof result === "object" && result != null && typeof result.then === "function") {
879
+ result.then(resolve, reject);
880
+ } else {
881
+ resolve(result);
882
+ }
883
+ } catch (error) {
884
+ reject(error);
885
+ }
886
+ });
887
+ };
888
+ }
889
+ function createTestContext(test, runner) {
890
+ var _runner$extendTaskCon;
891
+ const context = function() {
892
+ throw new Error("done() callback is deprecated, use promise instead");
893
+ };
894
+ context.task = test;
895
+ context.skip = (condition, note) => {
896
+ if (condition === false) {
897
+ return undefined;
898
+ }
899
+ test.result ?? (test.result = { state: "skip" });
900
+ test.result.pending = true;
901
+ throw new PendingError("test is skipped; abort execution", test, typeof condition === "string" ? condition : note);
902
+ };
903
+ context.onTestFailed = (handler, timeout) => {
904
+ test.onFailed || (test.onFailed = []);
905
+ test.onFailed.push(withTimeout(handler, timeout ?? runner.config.hookTimeout, true, new Error("STACK_TRACE_ERROR")));
906
+ };
907
+ context.onTestFinished = (handler, timeout) => {
908
+ test.onFinished || (test.onFinished = []);
909
+ test.onFinished.push(withTimeout(handler, timeout ?? runner.config.hookTimeout, true, new Error("STACK_TRACE_ERROR")));
910
+ };
911
+ return ((_runner$extendTaskCon = runner.extendTaskContext) === null || _runner$extendTaskCon === void 0 ? void 0 : _runner$extendTaskCon.call(runner, context)) || context;
912
+ }
913
+ function makeTimeoutError(isHook, timeout, stackTraceError) {
914
+ const message = `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.\nIf this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
915
+ const error = new Error(message);
916
+ if (stackTraceError === null || stackTraceError === void 0 ? void 0 : stackTraceError.stack) {
917
+ error.stack = stackTraceError.stack.replace(error.message, stackTraceError.message);
918
+ }
919
+ return error;
828
920
  }
829
921
 
830
922
  function getDefaultHookTimeout() {
831
- return getRunner().config.hookTimeout;
923
+ return getRunner().config.hookTimeout;
832
924
  }
833
925
  const CLEANUP_TIMEOUT_KEY = Symbol.for("VITEST_CLEANUP_TIMEOUT");
834
926
  const CLEANUP_STACK_TRACE_KEY = Symbol.for("VITEST_CLEANUP_STACK_TRACE");
835
927
  function getBeforeHookCleanupCallback(hook, result) {
836
- if (typeof result === "function") {
837
- const timeout = CLEANUP_TIMEOUT_KEY in hook && typeof hook[CLEANUP_TIMEOUT_KEY] === "number" ? hook[CLEANUP_TIMEOUT_KEY] : getDefaultHookTimeout();
838
- const stackTraceError = CLEANUP_STACK_TRACE_KEY in hook && hook[CLEANUP_STACK_TRACE_KEY] instanceof Error ? hook[CLEANUP_STACK_TRACE_KEY] : void 0;
839
- return withTimeout(result, timeout, true, stackTraceError);
840
- }
841
- }
928
+ if (typeof result === "function") {
929
+ const timeout = CLEANUP_TIMEOUT_KEY in hook && typeof hook[CLEANUP_TIMEOUT_KEY] === "number" ? hook[CLEANUP_TIMEOUT_KEY] : getDefaultHookTimeout();
930
+ const stackTraceError = CLEANUP_STACK_TRACE_KEY in hook && hook[CLEANUP_STACK_TRACE_KEY] instanceof Error ? hook[CLEANUP_STACK_TRACE_KEY] : undefined;
931
+ return withTimeout(result, timeout, true, stackTraceError);
932
+ }
933
+ }
934
+ /**
935
+ * Registers a callback function to be executed once before all tests within the current suite.
936
+ * This hook is useful for scenarios where you need to perform setup operations that are common to all tests in a suite, such as initializing a database connection or setting up a test environment.
937
+ *
938
+ * **Note:** The `beforeAll` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
939
+ *
940
+ * @param {Function} fn - The callback function to be executed before all tests.
941
+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
942
+ * @returns {void}
943
+ * @example
944
+ * ```ts
945
+ * // Example of using beforeAll to set up a database connection
946
+ * beforeAll(async () => {
947
+ * await database.connect();
948
+ * });
949
+ * ```
950
+ */
842
951
  function beforeAll(fn, timeout = getDefaultHookTimeout()) {
843
- assertTypes(fn, '"beforeAll" callback', ["function"]);
844
- const stackTraceError = new Error("STACK_TRACE_ERROR");
845
- return getCurrentSuite().on(
846
- "beforeAll",
847
- Object.assign(
848
- withTimeout(
849
- fn,
850
- timeout,
851
- true,
852
- stackTraceError
853
- ),
854
- {
855
- [CLEANUP_TIMEOUT_KEY]: timeout,
856
- [CLEANUP_STACK_TRACE_KEY]: stackTraceError
857
- }
858
- )
859
- );
860
- }
952
+ assertTypes(fn, "\"beforeAll\" callback", ["function"]);
953
+ const stackTraceError = new Error("STACK_TRACE_ERROR");
954
+ return getCurrentSuite().on("beforeAll", Object.assign(withTimeout(fn, timeout, true, stackTraceError), {
955
+ [CLEANUP_TIMEOUT_KEY]: timeout,
956
+ [CLEANUP_STACK_TRACE_KEY]: stackTraceError
957
+ }));
958
+ }
959
+ /**
960
+ * Registers a callback function to be executed once after all tests within the current suite have completed.
961
+ * This hook is useful for scenarios where you need to perform cleanup operations after all tests in a suite have run, such as closing database connections or cleaning up temporary files.
962
+ *
963
+ * **Note:** The `afterAll` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
964
+ *
965
+ * @param {Function} fn - The callback function to be executed after all tests.
966
+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
967
+ * @returns {void}
968
+ * @example
969
+ * ```ts
970
+ * // Example of using afterAll to close a database connection
971
+ * afterAll(async () => {
972
+ * await database.disconnect();
973
+ * });
974
+ * ```
975
+ */
861
976
  function afterAll(fn, timeout) {
862
- assertTypes(fn, '"afterAll" callback', ["function"]);
863
- return getCurrentSuite().on(
864
- "afterAll",
865
- withTimeout(
866
- fn,
867
- timeout ?? getDefaultHookTimeout(),
868
- true,
869
- new Error("STACK_TRACE_ERROR")
870
- )
871
- );
872
- }
977
+ assertTypes(fn, "\"afterAll\" callback", ["function"]);
978
+ return getCurrentSuite().on("afterAll", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true, new Error("STACK_TRACE_ERROR")));
979
+ }
980
+ /**
981
+ * Registers a callback function to be executed before each test within the current suite.
982
+ * This hook is useful for scenarios where you need to reset or reinitialize the test environment before each test runs, such as resetting database states, clearing caches, or reinitializing variables.
983
+ *
984
+ * **Note:** The `beforeEach` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
985
+ *
986
+ * @param {Function} fn - The callback function to be executed before each test. This function receives an `TestContext` parameter if additional test context is needed.
987
+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
988
+ * @returns {void}
989
+ * @example
990
+ * ```ts
991
+ * // Example of using beforeEach to reset a database state
992
+ * beforeEach(async () => {
993
+ * await database.reset();
994
+ * });
995
+ * ```
996
+ */
873
997
  function beforeEach(fn, timeout = getDefaultHookTimeout()) {
874
- assertTypes(fn, '"beforeEach" callback', ["function"]);
875
- const stackTraceError = new Error("STACK_TRACE_ERROR");
876
- return getCurrentSuite().on(
877
- "beforeEach",
878
- Object.assign(
879
- withTimeout(
880
- withFixtures(fn),
881
- timeout ?? getDefaultHookTimeout(),
882
- true,
883
- stackTraceError
884
- ),
885
- {
886
- [CLEANUP_TIMEOUT_KEY]: timeout,
887
- [CLEANUP_STACK_TRACE_KEY]: stackTraceError
888
- }
889
- )
890
- );
891
- }
998
+ assertTypes(fn, "\"beforeEach\" callback", ["function"]);
999
+ const stackTraceError = new Error("STACK_TRACE_ERROR");
1000
+ return getCurrentSuite().on("beforeEach", Object.assign(withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true, stackTraceError), {
1001
+ [CLEANUP_TIMEOUT_KEY]: timeout,
1002
+ [CLEANUP_STACK_TRACE_KEY]: stackTraceError
1003
+ }));
1004
+ }
1005
+ /**
1006
+ * Registers a callback function to be executed after each test within the current suite has completed.
1007
+ * This hook is useful for scenarios where you need to clean up or reset the test environment after each test runs, such as deleting temporary files, clearing test-specific database entries, or resetting mocked functions.
1008
+ *
1009
+ * **Note:** The `afterEach` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
1010
+ *
1011
+ * @param {Function} fn - The callback function to be executed after each test. This function receives an `TestContext` parameter if additional test context is needed.
1012
+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
1013
+ * @returns {void}
1014
+ * @example
1015
+ * ```ts
1016
+ * // Example of using afterEach to delete temporary files created during a test
1017
+ * afterEach(async () => {
1018
+ * await fileSystem.deleteTempFiles();
1019
+ * });
1020
+ * ```
1021
+ */
892
1022
  function afterEach(fn, timeout) {
893
- assertTypes(fn, '"afterEach" callback', ["function"]);
894
- return getCurrentSuite().on(
895
- "afterEach",
896
- withTimeout(
897
- withFixtures(fn),
898
- timeout ?? getDefaultHookTimeout(),
899
- true,
900
- new Error("STACK_TRACE_ERROR")
901
- )
902
- );
903
- }
904
- const onTestFailed = createTestHook(
905
- "onTestFailed",
906
- (test, handler, timeout) => {
907
- test.onFailed || (test.onFailed = []);
908
- test.onFailed.push(
909
- withTimeout(
910
- handler,
911
- timeout ?? getDefaultHookTimeout(),
912
- true,
913
- new Error("STACK_TRACE_ERROR")
914
- )
915
- );
916
- }
917
- );
918
- const onTestFinished = createTestHook(
919
- "onTestFinished",
920
- (test, handler, timeout) => {
921
- test.onFinished || (test.onFinished = []);
922
- test.onFinished.push(
923
- withTimeout(
924
- handler,
925
- timeout ?? getDefaultHookTimeout(),
926
- true,
927
- new Error("STACK_TRACE_ERROR")
928
- )
929
- );
930
- }
931
- );
1023
+ assertTypes(fn, "\"afterEach\" callback", ["function"]);
1024
+ return getCurrentSuite().on("afterEach", withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true, new Error("STACK_TRACE_ERROR")));
1025
+ }
1026
+ /**
1027
+ * Registers a callback function to be executed when a test fails within the current suite.
1028
+ * This function allows for custom actions to be performed in response to test failures, such as logging, cleanup, or additional diagnostics.
1029
+ *
1030
+ * **Note:** The `onTestFailed` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
1031
+ *
1032
+ * @param {Function} fn - The callback function to be executed upon a test failure. The function receives the test result (including errors).
1033
+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
1034
+ * @throws {Error} Throws an error if the function is not called within a test.
1035
+ * @returns {void}
1036
+ * @example
1037
+ * ```ts
1038
+ * // Example of using onTestFailed to log failure details
1039
+ * onTestFailed(({ errors }) => {
1040
+ * console.log(`Test failed: ${test.name}`, errors);
1041
+ * });
1042
+ * ```
1043
+ */
1044
+ const onTestFailed = createTestHook("onTestFailed", (test, handler, timeout) => {
1045
+ test.onFailed || (test.onFailed = []);
1046
+ test.onFailed.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, new Error("STACK_TRACE_ERROR")));
1047
+ });
1048
+ /**
1049
+ * Registers a callback function to be executed when the current test finishes, regardless of the outcome (pass or fail).
1050
+ * This function is ideal for performing actions that should occur after every test execution, such as cleanup, logging, or resetting shared resources.
1051
+ *
1052
+ * This hook is useful if you have access to a resource in the test itself and you want to clean it up after the test finishes. It is a more compact way to clean up resources than using the combination of `beforeEach` and `afterEach`.
1053
+ *
1054
+ * **Note:** The `onTestFinished` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
1055
+ *
1056
+ * **Note:** The `onTestFinished` hook is not called if the test is canceled with a dynamic `ctx.skip()` call.
1057
+ *
1058
+ * @param {Function} fn - The callback function to be executed after a test finishes. The function can receive parameters providing details about the completed test, including its success or failure status.
1059
+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
1060
+ * @throws {Error} Throws an error if the function is not called within a test.
1061
+ * @returns {void}
1062
+ * @example
1063
+ * ```ts
1064
+ * // Example of using onTestFinished for cleanup
1065
+ * const db = await connectToDatabase();
1066
+ * onTestFinished(async () => {
1067
+ * await db.disconnect();
1068
+ * });
1069
+ * ```
1070
+ */
1071
+ const onTestFinished = createTestHook("onTestFinished", (test, handler, timeout) => {
1072
+ test.onFinished || (test.onFinished = []);
1073
+ test.onFinished.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, new Error("STACK_TRACE_ERROR")));
1074
+ });
932
1075
  function createTestHook(name, handler) {
933
- return (fn, timeout) => {
934
- assertTypes(fn, `"${name}" callback`, ["function"]);
935
- const current = getCurrentTest();
936
- if (!current) {
937
- throw new Error(`Hook ${name}() can only be called inside a test`);
938
- }
939
- return handler(current, fn, timeout);
940
- };
1076
+ return (fn, timeout) => {
1077
+ assertTypes(fn, `"${name}" callback`, ["function"]);
1078
+ const current = getCurrentTest();
1079
+ if (!current) {
1080
+ throw new Error(`Hook ${name}() can only be called inside a test`);
1081
+ }
1082
+ return handler(current, fn, timeout);
1083
+ };
941
1084
  }
942
1085
 
943
1086
  async function runSetupFiles(config, files, runner) {
944
- if (config.sequence.setupFiles === "parallel") {
945
- await Promise.all(
946
- files.map(async (fsPath) => {
947
- await runner.importFile(fsPath, "setup");
948
- })
949
- );
950
- } else {
951
- for (const fsPath of files) {
952
- await runner.importFile(fsPath, "setup");
953
- }
954
- }
1087
+ if (config.sequence.setupFiles === "parallel") {
1088
+ await Promise.all(files.map(async (fsPath) => {
1089
+ await runner.importFile(fsPath, "setup");
1090
+ }));
1091
+ } else {
1092
+ for (const fsPath of files) {
1093
+ await runner.importFile(fsPath, "setup");
1094
+ }
1095
+ }
955
1096
  }
956
1097
 
957
1098
  const now$1 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
958
1099
  async function collectTests(specs, runner) {
959
- var _a;
960
- const files = [];
961
- const config = runner.config;
962
- for (const spec of specs) {
963
- const filepath = typeof spec === "string" ? spec : spec.filepath;
964
- const testLocations = typeof spec === "string" ? void 0 : spec.testLocations;
965
- const file = createFileTask(filepath, config.root, config.name, runner.pool);
966
- file.shuffle = config.sequence.shuffle;
967
- (_a = runner.onCollectStart) == null ? void 0 : _a.call(runner, file);
968
- clearCollectorContext(filepath, runner);
969
- try {
970
- const setupFiles = toArray(config.setupFiles);
971
- if (setupFiles.length) {
972
- const setupStart = now$1();
973
- await runSetupFiles(config, setupFiles, runner);
974
- const setupEnd = now$1();
975
- file.setupDuration = setupEnd - setupStart;
976
- } else {
977
- file.setupDuration = 0;
978
- }
979
- const collectStart = now$1();
980
- await runner.importFile(filepath, "collect");
981
- const defaultTasks = await getDefaultSuite().collect(file);
982
- const fileHooks = createSuiteHooks();
983
- mergeHooks(fileHooks, getHooks(defaultTasks));
984
- for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) {
985
- if (c.type === "test" || c.type === "suite") {
986
- file.tasks.push(c);
987
- } else if (c.type === "collector") {
988
- const suite = await c.collect(file);
989
- if (suite.name || suite.tasks.length) {
990
- mergeHooks(fileHooks, getHooks(suite));
991
- file.tasks.push(suite);
992
- }
993
- } else {
994
- c;
995
- }
996
- }
997
- setHooks(file, fileHooks);
998
- file.collectDuration = now$1() - collectStart;
999
- } catch (e) {
1000
- const error = processError(e);
1001
- file.result = {
1002
- state: "fail",
1003
- errors: [error]
1004
- };
1005
- }
1006
- calculateSuiteHash(file);
1007
- const hasOnlyTasks = someTasksAreOnly(file);
1008
- interpretTaskModes(
1009
- file,
1010
- config.testNamePattern,
1011
- testLocations,
1012
- hasOnlyTasks,
1013
- false,
1014
- config.allowOnly
1015
- );
1016
- if (file.mode === "queued") {
1017
- file.mode = "run";
1018
- }
1019
- files.push(file);
1020
- }
1021
- return files;
1100
+ const files = [];
1101
+ const config = runner.config;
1102
+ for (const spec of specs) {
1103
+ var _runner$onCollectStar;
1104
+ const filepath = typeof spec === "string" ? spec : spec.filepath;
1105
+ const testLocations = typeof spec === "string" ? undefined : spec.testLocations;
1106
+ const file = createFileTask(filepath, config.root, config.name, runner.pool);
1107
+ file.shuffle = config.sequence.shuffle;
1108
+ (_runner$onCollectStar = runner.onCollectStart) === null || _runner$onCollectStar === void 0 ? void 0 : _runner$onCollectStar.call(runner, file);
1109
+ clearCollectorContext(filepath, runner);
1110
+ try {
1111
+ const setupFiles = toArray(config.setupFiles);
1112
+ if (setupFiles.length) {
1113
+ const setupStart = now$1();
1114
+ await runSetupFiles(config, setupFiles, runner);
1115
+ const setupEnd = now$1();
1116
+ file.setupDuration = setupEnd - setupStart;
1117
+ } else {
1118
+ file.setupDuration = 0;
1119
+ }
1120
+ const collectStart = now$1();
1121
+ await runner.importFile(filepath, "collect");
1122
+ const defaultTasks = await getDefaultSuite().collect(file);
1123
+ const fileHooks = createSuiteHooks();
1124
+ mergeHooks(fileHooks, getHooks(defaultTasks));
1125
+ for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) {
1126
+ if (c.type === "test" || c.type === "suite") {
1127
+ file.tasks.push(c);
1128
+ } else if (c.type === "collector") {
1129
+ const suite = await c.collect(file);
1130
+ if (suite.name || suite.tasks.length) {
1131
+ mergeHooks(fileHooks, getHooks(suite));
1132
+ file.tasks.push(suite);
1133
+ }
1134
+ } else {
1135
+ c;
1136
+ }
1137
+ }
1138
+ setHooks(file, fileHooks);
1139
+ file.collectDuration = now$1() - collectStart;
1140
+ } catch (e) {
1141
+ const error = processError(e);
1142
+ file.result = {
1143
+ state: "fail",
1144
+ errors: [error]
1145
+ };
1146
+ }
1147
+ calculateSuiteHash(file);
1148
+ const hasOnlyTasks = someTasksAreOnly(file);
1149
+ interpretTaskModes(file, config.testNamePattern, testLocations, hasOnlyTasks, false, config.allowOnly);
1150
+ if (file.mode === "queued") {
1151
+ file.mode = "run";
1152
+ }
1153
+ files.push(file);
1154
+ }
1155
+ return files;
1022
1156
  }
1023
1157
  function mergeHooks(baseHooks, hooks) {
1024
- for (const _key in hooks) {
1025
- const key = _key;
1026
- baseHooks[key].push(...hooks[key]);
1027
- }
1028
- return baseHooks;
1158
+ for (const _key in hooks) {
1159
+ const key = _key;
1160
+ baseHooks[key].push(...hooks[key]);
1161
+ }
1162
+ return baseHooks;
1029
1163
  }
1030
1164
 
1031
1165
  const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
1032
1166
  const unixNow = Date.now;
1033
1167
  function updateSuiteHookState(task, name, state, runner) {
1034
- if (!task.result) {
1035
- task.result = { state: "run" };
1036
- }
1037
- if (!task.result.hooks) {
1038
- task.result.hooks = {};
1039
- }
1040
- const suiteHooks = task.result.hooks;
1041
- if (suiteHooks) {
1042
- suiteHooks[name] = state;
1043
- let event = state === "run" ? "before-hook-start" : "before-hook-end";
1044
- if (name === "afterAll" || name === "afterEach") {
1045
- event = state === "run" ? "after-hook-start" : "after-hook-end";
1046
- }
1047
- updateTask(
1048
- event,
1049
- task,
1050
- runner
1051
- );
1052
- }
1168
+ if (!task.result) {
1169
+ task.result = { state: "run" };
1170
+ }
1171
+ if (!task.result.hooks) {
1172
+ task.result.hooks = {};
1173
+ }
1174
+ const suiteHooks = task.result.hooks;
1175
+ if (suiteHooks) {
1176
+ suiteHooks[name] = state;
1177
+ let event = state === "run" ? "before-hook-start" : "before-hook-end";
1178
+ if (name === "afterAll" || name === "afterEach") {
1179
+ event = state === "run" ? "after-hook-start" : "after-hook-end";
1180
+ }
1181
+ updateTask(event, task, runner);
1182
+ }
1053
1183
  }
1054
1184
  function getSuiteHooks(suite, name, sequence) {
1055
- const hooks = getHooks(suite)[name];
1056
- if (sequence === "stack" && (name === "afterAll" || name === "afterEach")) {
1057
- return hooks.slice().reverse();
1058
- }
1059
- return hooks;
1185
+ const hooks = getHooks(suite)[name];
1186
+ if (sequence === "stack" && (name === "afterAll" || name === "afterEach")) {
1187
+ return hooks.slice().reverse();
1188
+ }
1189
+ return hooks;
1060
1190
  }
1061
1191
  async function callTestHooks(runner, test, hooks, sequence) {
1062
- if (sequence === "stack") {
1063
- hooks = hooks.slice().reverse();
1064
- }
1065
- if (!hooks.length) {
1066
- return;
1067
- }
1068
- const onTestFailed = test.context.onTestFailed;
1069
- const onTestFinished = test.context.onTestFinished;
1070
- test.context.onTestFailed = () => {
1071
- throw new Error(`Cannot call "onTestFailed" inside a test hook.`);
1072
- };
1073
- test.context.onTestFinished = () => {
1074
- throw new Error(`Cannot call "onTestFinished" inside a test hook.`);
1075
- };
1076
- if (sequence === "parallel") {
1077
- try {
1078
- await Promise.all(hooks.map((fn) => fn(test.context)));
1079
- } catch (e) {
1080
- failTask(test.result, e, runner.config.diffOptions);
1081
- }
1082
- } else {
1083
- for (const fn of hooks) {
1084
- try {
1085
- await fn(test.context);
1086
- } catch (e) {
1087
- failTask(test.result, e, runner.config.diffOptions);
1088
- }
1089
- }
1090
- }
1091
- test.context.onTestFailed = onTestFailed;
1092
- test.context.onTestFinished = onTestFinished;
1192
+ if (sequence === "stack") {
1193
+ hooks = hooks.slice().reverse();
1194
+ }
1195
+ if (!hooks.length) {
1196
+ return;
1197
+ }
1198
+ const onTestFailed = test.context.onTestFailed;
1199
+ const onTestFinished = test.context.onTestFinished;
1200
+ test.context.onTestFailed = () => {
1201
+ throw new Error(`Cannot call "onTestFailed" inside a test hook.`);
1202
+ };
1203
+ test.context.onTestFinished = () => {
1204
+ throw new Error(`Cannot call "onTestFinished" inside a test hook.`);
1205
+ };
1206
+ if (sequence === "parallel") {
1207
+ try {
1208
+ await Promise.all(hooks.map((fn) => fn(test.context)));
1209
+ } catch (e) {
1210
+ failTask(test.result, e, runner.config.diffOptions);
1211
+ }
1212
+ } else {
1213
+ for (const fn of hooks) {
1214
+ try {
1215
+ await fn(test.context);
1216
+ } catch (e) {
1217
+ failTask(test.result, e, runner.config.diffOptions);
1218
+ }
1219
+ }
1220
+ }
1221
+ test.context.onTestFailed = onTestFailed;
1222
+ test.context.onTestFinished = onTestFinished;
1093
1223
  }
1094
1224
  async function callSuiteHook(suite, currentTask, name, runner, args) {
1095
- const sequence = runner.config.sequence.hooks;
1096
- const callbacks = [];
1097
- const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
1098
- if (name === "beforeEach" && parentSuite) {
1099
- callbacks.push(
1100
- ...await callSuiteHook(parentSuite, currentTask, name, runner, args)
1101
- );
1102
- }
1103
- const hooks = getSuiteHooks(suite, name, sequence);
1104
- if (hooks.length > 0) {
1105
- updateSuiteHookState(currentTask, name, "run", runner);
1106
- }
1107
- async function runHook(hook) {
1108
- return getBeforeHookCleanupCallback(hook, await hook(...args));
1109
- }
1110
- if (sequence === "parallel") {
1111
- callbacks.push(
1112
- ...await Promise.all(hooks.map((hook) => runHook(hook)))
1113
- );
1114
- } else {
1115
- for (const hook of hooks) {
1116
- callbacks.push(await runHook(hook));
1117
- }
1118
- }
1119
- if (hooks.length > 0) {
1120
- updateSuiteHookState(currentTask, name, "pass", runner);
1121
- }
1122
- if (name === "afterEach" && parentSuite) {
1123
- callbacks.push(
1124
- ...await callSuiteHook(parentSuite, currentTask, name, runner, args)
1125
- );
1126
- }
1127
- return callbacks;
1128
- }
1129
- const packs = /* @__PURE__ */ new Map();
1225
+ const sequence = runner.config.sequence.hooks;
1226
+ const callbacks = [];
1227
+ const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
1228
+ if (name === "beforeEach" && parentSuite) {
1229
+ callbacks.push(...await callSuiteHook(parentSuite, currentTask, name, runner, args));
1230
+ }
1231
+ const hooks = getSuiteHooks(suite, name, sequence);
1232
+ if (hooks.length > 0) {
1233
+ updateSuiteHookState(currentTask, name, "run", runner);
1234
+ }
1235
+ async function runHook(hook) {
1236
+ return getBeforeHookCleanupCallback(hook, await hook(...args));
1237
+ }
1238
+ if (sequence === "parallel") {
1239
+ callbacks.push(...await Promise.all(hooks.map((hook) => runHook(hook))));
1240
+ } else {
1241
+ for (const hook of hooks) {
1242
+ callbacks.push(await runHook(hook));
1243
+ }
1244
+ }
1245
+ if (hooks.length > 0) {
1246
+ updateSuiteHookState(currentTask, name, "pass", runner);
1247
+ }
1248
+ if (name === "afterEach" && parentSuite) {
1249
+ callbacks.push(...await callSuiteHook(parentSuite, currentTask, name, runner, args));
1250
+ }
1251
+ return callbacks;
1252
+ }
1253
+ const packs = new Map();
1130
1254
  const eventsPacks = [];
1131
- let updateTimer;
1132
- let previousUpdate;
1255
+ const pendingTasksUpdates = [];
1256
+ function sendTasksUpdate(runner) {
1257
+ if (packs.size) {
1258
+ var _runner$onTaskUpdate;
1259
+ const taskPacks = Array.from(packs).map(([id, task]) => {
1260
+ return [
1261
+ id,
1262
+ task[0],
1263
+ task[1]
1264
+ ];
1265
+ });
1266
+ const p = (_runner$onTaskUpdate = runner.onTaskUpdate) === null || _runner$onTaskUpdate === void 0 ? void 0 : _runner$onTaskUpdate.call(runner, taskPacks, eventsPacks);
1267
+ if (p) {
1268
+ pendingTasksUpdates.push(p);
1269
+ p.then(() => pendingTasksUpdates.splice(pendingTasksUpdates.indexOf(p), 1), () => {});
1270
+ }
1271
+ eventsPacks.length = 0;
1272
+ packs.clear();
1273
+ }
1274
+ }
1275
+ async function finishSendTasksUpdate(runner) {
1276
+ sendTasksUpdate(runner);
1277
+ await Promise.all(pendingTasksUpdates);
1278
+ }
1279
+ function throttle(fn, ms) {
1280
+ let last = 0;
1281
+ return function(...args) {
1282
+ const now = unixNow();
1283
+ if (now - last > ms) {
1284
+ last = now;
1285
+ return fn.apply(this, args);
1286
+ }
1287
+ };
1288
+ }
1289
+ const sendTasksUpdateThrottled = throttle(sendTasksUpdate, 100);
1133
1290
  function updateTask(event, task, runner) {
1134
- eventsPacks.push([task.id, event]);
1135
- packs.set(task.id, [task.result, task.meta]);
1136
- const { clearTimeout, setTimeout } = getSafeTimers();
1137
- clearTimeout(updateTimer);
1138
- updateTimer = setTimeout(() => {
1139
- previousUpdate = sendTasksUpdate(runner);
1140
- }, 10);
1141
- }
1142
- async function sendTasksUpdate(runner) {
1143
- var _a;
1144
- const { clearTimeout } = getSafeTimers();
1145
- clearTimeout(updateTimer);
1146
- await previousUpdate;
1147
- if (packs.size) {
1148
- const taskPacks = Array.from(packs).map(([id, task]) => {
1149
- return [id, task[0], task[1]];
1150
- });
1151
- const p = (_a = runner.onTaskUpdate) == null ? void 0 : _a.call(runner, taskPacks, eventsPacks);
1152
- eventsPacks.length = 0;
1153
- packs.clear();
1154
- return p;
1155
- }
1291
+ eventsPacks.push([task.id, event]);
1292
+ packs.set(task.id, [task.result, task.meta]);
1293
+ sendTasksUpdateThrottled(runner);
1156
1294
  }
1157
1295
  async function callCleanupHooks(cleanups) {
1158
- await Promise.all(
1159
- cleanups.map(async (fn) => {
1160
- if (typeof fn !== "function") {
1161
- return;
1162
- }
1163
- await fn();
1164
- })
1165
- );
1296
+ await Promise.all(cleanups.map(async (fn) => {
1297
+ if (typeof fn !== "function") {
1298
+ return;
1299
+ }
1300
+ await fn();
1301
+ }));
1166
1302
  }
1167
1303
  async function runTest(test, runner) {
1168
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1169
- await ((_a = runner.onBeforeRunTask) == null ? void 0 : _a.call(runner, test));
1170
- if (test.mode !== "run" && test.mode !== "queued") {
1171
- return;
1172
- }
1173
- if (((_b = test.result) == null ? void 0 : _b.state) === "fail") {
1174
- updateTask("test-failed-early", test, runner);
1175
- return;
1176
- }
1177
- const start = now();
1178
- test.result = {
1179
- state: "run",
1180
- startTime: unixNow(),
1181
- retryCount: 0
1182
- };
1183
- updateTask("test-prepare", test, runner);
1184
- setCurrentTest(test);
1185
- const suite = test.suite || test.file;
1186
- const repeats = test.repeats ?? 0;
1187
- for (let repeatCount = 0; repeatCount <= repeats; repeatCount++) {
1188
- const retry = test.retry ?? 0;
1189
- for (let retryCount = 0; retryCount <= retry; retryCount++) {
1190
- let beforeEachCleanups = [];
1191
- try {
1192
- await ((_c = runner.onBeforeTryTask) == null ? void 0 : _c.call(runner, test, {
1193
- retry: retryCount,
1194
- repeats: repeatCount
1195
- }));
1196
- test.result.repeatCount = repeatCount;
1197
- beforeEachCleanups = await callSuiteHook(
1198
- suite,
1199
- test,
1200
- "beforeEach",
1201
- runner,
1202
- [test.context, suite]
1203
- );
1204
- if (runner.runTask) {
1205
- await runner.runTask(test);
1206
- } else {
1207
- const fn = getFn(test);
1208
- if (!fn) {
1209
- throw new Error(
1210
- "Test function is not found. Did you add it using `setFn`?"
1211
- );
1212
- }
1213
- await fn();
1214
- }
1215
- await ((_d = runner.onAfterTryTask) == null ? void 0 : _d.call(runner, test, {
1216
- retry: retryCount,
1217
- repeats: repeatCount
1218
- }));
1219
- if (test.result.state !== "fail") {
1220
- if (!test.repeats) {
1221
- test.result.state = "pass";
1222
- } else if (test.repeats && retry === retryCount) {
1223
- test.result.state = "pass";
1224
- }
1225
- }
1226
- } catch (e) {
1227
- failTask(test.result, e, runner.config.diffOptions);
1228
- }
1229
- if (((_e = test.result) == null ? void 0 : _e.pending) || ((_f = test.result) == null ? void 0 : _f.state) === "skip") {
1230
- test.mode = "skip";
1231
- test.result = { state: "skip", note: (_g = test.result) == null ? void 0 : _g.note, pending: true };
1232
- updateTask("test-finished", test, runner);
1233
- setCurrentTest(void 0);
1234
- return;
1235
- }
1236
- try {
1237
- await ((_h = runner.onTaskFinished) == null ? void 0 : _h.call(runner, test));
1238
- } catch (e) {
1239
- failTask(test.result, e, runner.config.diffOptions);
1240
- }
1241
- try {
1242
- await callSuiteHook(suite, test, "afterEach", runner, [
1243
- test.context,
1244
- suite
1245
- ]);
1246
- await callCleanupHooks(beforeEachCleanups);
1247
- await callFixtureCleanup(test.context);
1248
- } catch (e) {
1249
- failTask(test.result, e, runner.config.diffOptions);
1250
- }
1251
- await callTestHooks(runner, test, test.onFinished || [], "stack");
1252
- if (test.result.state === "fail") {
1253
- await callTestHooks(
1254
- runner,
1255
- test,
1256
- test.onFailed || [],
1257
- runner.config.sequence.hooks
1258
- );
1259
- }
1260
- test.onFailed = void 0;
1261
- test.onFinished = void 0;
1262
- if (test.result.state === "pass") {
1263
- break;
1264
- }
1265
- if (retryCount < retry) {
1266
- test.result.state = "run";
1267
- test.result.retryCount = (test.result.retryCount ?? 0) + 1;
1268
- }
1269
- updateTask("test-retried", test, runner);
1270
- }
1271
- }
1272
- if (test.fails) {
1273
- if (test.result.state === "pass") {
1274
- const error = processError(new Error("Expect test to fail"));
1275
- test.result.state = "fail";
1276
- test.result.errors = [error];
1277
- } else {
1278
- test.result.state = "pass";
1279
- test.result.errors = void 0;
1280
- }
1281
- }
1282
- setCurrentTest(void 0);
1283
- test.result.duration = now() - start;
1284
- await ((_i = runner.onAfterRunTask) == null ? void 0 : _i.call(runner, test));
1285
- updateTask("test-finished", test, runner);
1304
+ var _runner$onBeforeRunTa, _test$result, _runner$onAfterRunTas;
1305
+ await ((_runner$onBeforeRunTa = runner.onBeforeRunTask) === null || _runner$onBeforeRunTa === void 0 ? void 0 : _runner$onBeforeRunTa.call(runner, test));
1306
+ if (test.mode !== "run" && test.mode !== "queued") {
1307
+ updateTask("test-prepare", test, runner);
1308
+ updateTask("test-finished", test, runner);
1309
+ return;
1310
+ }
1311
+ if (((_test$result = test.result) === null || _test$result === void 0 ? void 0 : _test$result.state) === "fail") {
1312
+ updateTask("test-failed-early", test, runner);
1313
+ return;
1314
+ }
1315
+ const start = now();
1316
+ test.result = {
1317
+ state: "run",
1318
+ startTime: unixNow(),
1319
+ retryCount: 0
1320
+ };
1321
+ updateTask("test-prepare", test, runner);
1322
+ setCurrentTest(test);
1323
+ const suite = test.suite || test.file;
1324
+ const repeats = test.repeats ?? 0;
1325
+ for (let repeatCount = 0; repeatCount <= repeats; repeatCount++) {
1326
+ const retry = test.retry ?? 0;
1327
+ for (let retryCount = 0; retryCount <= retry; retryCount++) {
1328
+ var _test$result2, _test$result3;
1329
+ let beforeEachCleanups = [];
1330
+ try {
1331
+ var _runner$onBeforeTryTa, _runner$onAfterTryTas;
1332
+ await ((_runner$onBeforeTryTa = runner.onBeforeTryTask) === null || _runner$onBeforeTryTa === void 0 ? void 0 : _runner$onBeforeTryTa.call(runner, test, {
1333
+ retry: retryCount,
1334
+ repeats: repeatCount
1335
+ }));
1336
+ test.result.repeatCount = repeatCount;
1337
+ beforeEachCleanups = await callSuiteHook(suite, test, "beforeEach", runner, [test.context, suite]);
1338
+ if (runner.runTask) {
1339
+ await runner.runTask(test);
1340
+ } else {
1341
+ const fn = getFn(test);
1342
+ if (!fn) {
1343
+ throw new Error("Test function is not found. Did you add it using `setFn`?");
1344
+ }
1345
+ await fn();
1346
+ }
1347
+ await ((_runner$onAfterTryTas = runner.onAfterTryTask) === null || _runner$onAfterTryTas === void 0 ? void 0 : _runner$onAfterTryTas.call(runner, test, {
1348
+ retry: retryCount,
1349
+ repeats: repeatCount
1350
+ }));
1351
+ if (test.result.state !== "fail") {
1352
+ if (!test.repeats) {
1353
+ test.result.state = "pass";
1354
+ } else if (test.repeats && retry === retryCount) {
1355
+ test.result.state = "pass";
1356
+ }
1357
+ }
1358
+ } catch (e) {
1359
+ failTask(test.result, e, runner.config.diffOptions);
1360
+ }
1361
+ if (((_test$result2 = test.result) === null || _test$result2 === void 0 ? void 0 : _test$result2.pending) || ((_test$result3 = test.result) === null || _test$result3 === void 0 ? void 0 : _test$result3.state) === "skip") {
1362
+ var _test$result4;
1363
+ test.mode = "skip";
1364
+ test.result = {
1365
+ state: "skip",
1366
+ note: (_test$result4 = test.result) === null || _test$result4 === void 0 ? void 0 : _test$result4.note,
1367
+ pending: true
1368
+ };
1369
+ updateTask("test-finished", test, runner);
1370
+ setCurrentTest(undefined);
1371
+ return;
1372
+ }
1373
+ try {
1374
+ var _runner$onTaskFinishe;
1375
+ await ((_runner$onTaskFinishe = runner.onTaskFinished) === null || _runner$onTaskFinishe === void 0 ? void 0 : _runner$onTaskFinishe.call(runner, test));
1376
+ } catch (e) {
1377
+ failTask(test.result, e, runner.config.diffOptions);
1378
+ }
1379
+ try {
1380
+ await callSuiteHook(suite, test, "afterEach", runner, [test.context, suite]);
1381
+ await callCleanupHooks(beforeEachCleanups);
1382
+ await callFixtureCleanup(test.context);
1383
+ } catch (e) {
1384
+ failTask(test.result, e, runner.config.diffOptions);
1385
+ }
1386
+ await callTestHooks(runner, test, test.onFinished || [], "stack");
1387
+ if (test.result.state === "fail") {
1388
+ await callTestHooks(runner, test, test.onFailed || [], runner.config.sequence.hooks);
1389
+ }
1390
+ test.onFailed = undefined;
1391
+ test.onFinished = undefined;
1392
+ if (test.result.state === "pass") {
1393
+ break;
1394
+ }
1395
+ if (retryCount < retry) {
1396
+ test.result.state = "run";
1397
+ test.result.retryCount = (test.result.retryCount ?? 0) + 1;
1398
+ }
1399
+ updateTask("test-retried", test, runner);
1400
+ }
1401
+ }
1402
+ if (test.fails) {
1403
+ if (test.result.state === "pass") {
1404
+ const error = processError(new Error("Expect test to fail"));
1405
+ test.result.state = "fail";
1406
+ test.result.errors = [error];
1407
+ } else {
1408
+ test.result.state = "pass";
1409
+ test.result.errors = undefined;
1410
+ }
1411
+ }
1412
+ setCurrentTest(undefined);
1413
+ test.result.duration = now() - start;
1414
+ await ((_runner$onAfterRunTas = runner.onAfterRunTask) === null || _runner$onAfterRunTas === void 0 ? void 0 : _runner$onAfterRunTas.call(runner, test));
1415
+ updateTask("test-finished", test, runner);
1286
1416
  }
1287
1417
  function failTask(result, err, diffOptions) {
1288
- if (err instanceof PendingError) {
1289
- result.state = "skip";
1290
- result.note = err.note;
1291
- result.pending = true;
1292
- return;
1293
- }
1294
- result.state = "fail";
1295
- const errors = Array.isArray(err) ? err : [err];
1296
- for (const e of errors) {
1297
- const error = processError(e, diffOptions);
1298
- result.errors ?? (result.errors = []);
1299
- result.errors.push(error);
1300
- }
1418
+ if (err instanceof PendingError) {
1419
+ result.state = "skip";
1420
+ result.note = err.note;
1421
+ result.pending = true;
1422
+ return;
1423
+ }
1424
+ result.state = "fail";
1425
+ const errors = Array.isArray(err) ? err : [err];
1426
+ for (const e of errors) {
1427
+ const error = processError(e, diffOptions);
1428
+ result.errors ?? (result.errors = []);
1429
+ result.errors.push(error);
1430
+ }
1301
1431
  }
1302
1432
  function markTasksAsSkipped(suite, runner) {
1303
- suite.tasks.forEach((t) => {
1304
- t.mode = "skip";
1305
- t.result = { ...t.result, state: "skip" };
1306
- updateTask("test-finished", t, runner);
1307
- if (t.type === "suite") {
1308
- markTasksAsSkipped(t, runner);
1309
- }
1310
- });
1433
+ suite.tasks.forEach((t) => {
1434
+ t.mode = "skip";
1435
+ t.result = {
1436
+ ...t.result,
1437
+ state: "skip"
1438
+ };
1439
+ updateTask("test-finished", t, runner);
1440
+ if (t.type === "suite") {
1441
+ markTasksAsSkipped(t, runner);
1442
+ }
1443
+ });
1311
1444
  }
1312
1445
  async function runSuite(suite, runner) {
1313
- var _a, _b, _c, _d;
1314
- await ((_a = runner.onBeforeRunSuite) == null ? void 0 : _a.call(runner, suite));
1315
- if (((_b = suite.result) == null ? void 0 : _b.state) === "fail") {
1316
- markTasksAsSkipped(suite, runner);
1317
- updateTask("suite-failed-early", suite, runner);
1318
- return;
1319
- }
1320
- const start = now();
1321
- const mode = suite.mode;
1322
- suite.result = {
1323
- state: mode === "skip" || mode === "todo" ? mode : "run",
1324
- startTime: unixNow()
1325
- };
1326
- updateTask("suite-prepare", suite, runner);
1327
- let beforeAllCleanups = [];
1328
- if (suite.mode === "skip") {
1329
- suite.result.state = "skip";
1330
- updateTask("suite-finished", suite, runner);
1331
- } else if (suite.mode === "todo") {
1332
- suite.result.state = "todo";
1333
- updateTask("suite-finished", suite, runner);
1334
- } else {
1335
- try {
1336
- try {
1337
- beforeAllCleanups = await callSuiteHook(
1338
- suite,
1339
- suite,
1340
- "beforeAll",
1341
- runner,
1342
- [suite]
1343
- );
1344
- } catch (e) {
1345
- markTasksAsSkipped(suite, runner);
1346
- throw e;
1347
- }
1348
- if (runner.runSuite) {
1349
- await runner.runSuite(suite);
1350
- } else {
1351
- for (let tasksGroup of partitionSuiteChildren(suite)) {
1352
- if (tasksGroup[0].concurrent === true) {
1353
- await Promise.all(tasksGroup.map((c) => runSuiteChild(c, runner)));
1354
- } else {
1355
- const { sequence } = runner.config;
1356
- if (suite.shuffle) {
1357
- const suites = tasksGroup.filter(
1358
- (group) => group.type === "suite"
1359
- );
1360
- const tests = tasksGroup.filter((group) => group.type === "test");
1361
- const groups = shuffle([suites, tests], sequence.seed);
1362
- tasksGroup = groups.flatMap(
1363
- (group) => shuffle(group, sequence.seed)
1364
- );
1365
- }
1366
- for (const c of tasksGroup) {
1367
- await runSuiteChild(c, runner);
1368
- }
1369
- }
1370
- }
1371
- }
1372
- } catch (e) {
1373
- failTask(suite.result, e, runner.config.diffOptions);
1374
- }
1375
- try {
1376
- await callSuiteHook(suite, suite, "afterAll", runner, [suite]);
1377
- await callCleanupHooks(beforeAllCleanups);
1378
- } catch (e) {
1379
- failTask(suite.result, e, runner.config.diffOptions);
1380
- }
1381
- if (suite.mode === "run" || suite.mode === "queued") {
1382
- if (!runner.config.passWithNoTests && !hasTests(suite)) {
1383
- suite.result.state = "fail";
1384
- if (!((_c = suite.result.errors) == null ? void 0 : _c.length)) {
1385
- const error = processError(
1386
- new Error(`No test found in suite ${suite.name}`)
1387
- );
1388
- suite.result.errors = [error];
1389
- }
1390
- } else if (hasFailed(suite)) {
1391
- suite.result.state = "fail";
1392
- } else {
1393
- suite.result.state = "pass";
1394
- }
1395
- }
1396
- suite.result.duration = now() - start;
1397
- updateTask("suite-finished", suite, runner);
1398
- await ((_d = runner.onAfterRunSuite) == null ? void 0 : _d.call(runner, suite));
1399
- }
1446
+ var _runner$onBeforeRunSu, _suite$result;
1447
+ await ((_runner$onBeforeRunSu = runner.onBeforeRunSuite) === null || _runner$onBeforeRunSu === void 0 ? void 0 : _runner$onBeforeRunSu.call(runner, suite));
1448
+ if (((_suite$result = suite.result) === null || _suite$result === void 0 ? void 0 : _suite$result.state) === "fail") {
1449
+ markTasksAsSkipped(suite, runner);
1450
+ updateTask("suite-failed-early", suite, runner);
1451
+ return;
1452
+ }
1453
+ const start = now();
1454
+ const mode = suite.mode;
1455
+ suite.result = {
1456
+ state: mode === "skip" || mode === "todo" ? mode : "run",
1457
+ startTime: unixNow()
1458
+ };
1459
+ updateTask("suite-prepare", suite, runner);
1460
+ let beforeAllCleanups = [];
1461
+ if (suite.mode === "skip") {
1462
+ suite.result.state = "skip";
1463
+ updateTask("suite-finished", suite, runner);
1464
+ } else if (suite.mode === "todo") {
1465
+ suite.result.state = "todo";
1466
+ updateTask("suite-finished", suite, runner);
1467
+ } else {
1468
+ var _runner$onAfterRunSui;
1469
+ try {
1470
+ try {
1471
+ beforeAllCleanups = await callSuiteHook(suite, suite, "beforeAll", runner, [suite]);
1472
+ } catch (e) {
1473
+ markTasksAsSkipped(suite, runner);
1474
+ throw e;
1475
+ }
1476
+ if (runner.runSuite) {
1477
+ await runner.runSuite(suite);
1478
+ } else {
1479
+ for (let tasksGroup of partitionSuiteChildren(suite)) {
1480
+ if (tasksGroup[0].concurrent === true) {
1481
+ await Promise.all(tasksGroup.map((c) => runSuiteChild(c, runner)));
1482
+ } else {
1483
+ const { sequence } = runner.config;
1484
+ if (suite.shuffle) {
1485
+ const suites = tasksGroup.filter((group) => group.type === "suite");
1486
+ const tests = tasksGroup.filter((group) => group.type === "test");
1487
+ const groups = shuffle([suites, tests], sequence.seed);
1488
+ tasksGroup = groups.flatMap((group) => shuffle(group, sequence.seed));
1489
+ }
1490
+ for (const c of tasksGroup) {
1491
+ await runSuiteChild(c, runner);
1492
+ }
1493
+ }
1494
+ }
1495
+ }
1496
+ } catch (e) {
1497
+ failTask(suite.result, e, runner.config.diffOptions);
1498
+ }
1499
+ try {
1500
+ await callSuiteHook(suite, suite, "afterAll", runner, [suite]);
1501
+ await callCleanupHooks(beforeAllCleanups);
1502
+ } catch (e) {
1503
+ failTask(suite.result, e, runner.config.diffOptions);
1504
+ }
1505
+ if (suite.mode === "run" || suite.mode === "queued") {
1506
+ if (!runner.config.passWithNoTests && !hasTests(suite)) {
1507
+ var _suite$result$errors;
1508
+ suite.result.state = "fail";
1509
+ if (!((_suite$result$errors = suite.result.errors) === null || _suite$result$errors === void 0 ? void 0 : _suite$result$errors.length)) {
1510
+ const error = processError(new Error(`No test found in suite ${suite.name}`));
1511
+ suite.result.errors = [error];
1512
+ }
1513
+ } else if (hasFailed(suite)) {
1514
+ suite.result.state = "fail";
1515
+ } else {
1516
+ suite.result.state = "pass";
1517
+ }
1518
+ }
1519
+ suite.result.duration = now() - start;
1520
+ updateTask("suite-finished", suite, runner);
1521
+ await ((_runner$onAfterRunSui = runner.onAfterRunSuite) === null || _runner$onAfterRunSui === void 0 ? void 0 : _runner$onAfterRunSui.call(runner, suite));
1522
+ }
1400
1523
  }
1401
1524
  let limitMaxConcurrency;
1402
1525
  async function runSuiteChild(c, runner) {
1403
- if (c.type === "test") {
1404
- return limitMaxConcurrency(() => runTest(c, runner));
1405
- } else if (c.type === "suite") {
1406
- return runSuite(c, runner);
1407
- }
1526
+ if (c.type === "test") {
1527
+ return limitMaxConcurrency(() => runTest(c, runner));
1528
+ } else if (c.type === "suite") {
1529
+ return runSuite(c, runner);
1530
+ }
1408
1531
  }
1409
1532
  async function runFiles(files, runner) {
1410
- var _a, _b;
1411
- limitMaxConcurrency ?? (limitMaxConcurrency = limitConcurrency(runner.config.maxConcurrency));
1412
- for (const file of files) {
1413
- if (!file.tasks.length && !runner.config.passWithNoTests) {
1414
- if (!((_b = (_a = file.result) == null ? void 0 : _a.errors) == null ? void 0 : _b.length)) {
1415
- const error = processError(
1416
- new Error(`No test suite found in file ${file.filepath}`)
1417
- );
1418
- file.result = {
1419
- state: "fail",
1420
- errors: [error]
1421
- };
1422
- }
1423
- }
1424
- await runSuite(file, runner);
1425
- }
1533
+ limitMaxConcurrency ?? (limitMaxConcurrency = limitConcurrency(runner.config.maxConcurrency));
1534
+ for (const file of files) {
1535
+ if (!file.tasks.length && !runner.config.passWithNoTests) {
1536
+ var _file$result;
1537
+ if (!((_file$result = file.result) === null || _file$result === void 0 || (_file$result = _file$result.errors) === null || _file$result === void 0 ? void 0 : _file$result.length)) {
1538
+ const error = processError(new Error(`No test suite found in file ${file.filepath}`));
1539
+ file.result = {
1540
+ state: "fail",
1541
+ errors: [error]
1542
+ };
1543
+ }
1544
+ }
1545
+ await runSuite(file, runner);
1546
+ }
1426
1547
  }
1427
1548
  async function startTests(specs, runner) {
1428
- var _a, _b, _c, _d;
1429
- const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1430
- await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
1431
- const files = await collectTests(specs, runner);
1432
- await ((_b = runner.onCollected) == null ? void 0 : _b.call(runner, files));
1433
- await ((_c = runner.onBeforeRunFiles) == null ? void 0 : _c.call(runner, files));
1434
- await runFiles(files, runner);
1435
- await ((_d = runner.onAfterRunFiles) == null ? void 0 : _d.call(runner, files));
1436
- await sendTasksUpdate(runner);
1437
- return files;
1549
+ var _runner$onBeforeColle, _runner$onCollected, _runner$onBeforeRunFi, _runner$onAfterRunFil;
1550
+ const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1551
+ await ((_runner$onBeforeColle = runner.onBeforeCollect) === null || _runner$onBeforeColle === void 0 ? void 0 : _runner$onBeforeColle.call(runner, paths));
1552
+ const files = await collectTests(specs, runner);
1553
+ await ((_runner$onCollected = runner.onCollected) === null || _runner$onCollected === void 0 ? void 0 : _runner$onCollected.call(runner, files));
1554
+ await ((_runner$onBeforeRunFi = runner.onBeforeRunFiles) === null || _runner$onBeforeRunFi === void 0 ? void 0 : _runner$onBeforeRunFi.call(runner, files));
1555
+ await runFiles(files, runner);
1556
+ await ((_runner$onAfterRunFil = runner.onAfterRunFiles) === null || _runner$onAfterRunFil === void 0 ? void 0 : _runner$onAfterRunFil.call(runner, files));
1557
+ await finishSendTasksUpdate(runner);
1558
+ return files;
1438
1559
  }
1439
1560
  async function publicCollect(specs, runner) {
1440
- var _a, _b;
1441
- const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1442
- await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
1443
- const files = await collectTests(specs, runner);
1444
- await ((_b = runner.onCollected) == null ? void 0 : _b.call(runner, files));
1445
- return files;
1561
+ var _runner$onBeforeColle2, _runner$onCollected2;
1562
+ const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1563
+ await ((_runner$onBeforeColle2 = runner.onBeforeCollect) === null || _runner$onBeforeColle2 === void 0 ? void 0 : _runner$onBeforeColle2.call(runner, paths));
1564
+ const files = await collectTests(specs, runner);
1565
+ await ((_runner$onCollected2 = runner.onCollected) === null || _runner$onCollected2 === void 0 ? void 0 : _runner$onCollected2.call(runner, files));
1566
+ return files;
1446
1567
  }
1447
1568
 
1448
1569
  export { afterAll, afterEach, beforeAll, beforeEach, publicCollect as collectTests, createTaskCollector, describe, getCurrentSuite, getCurrentTest, getFn, getHooks, it, onTestFailed, onTestFinished, setFn, setHooks, startTests, suite, test, updateTask };