@vitest/runner 0.28.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-Present Anthony Fu <https://github.com/antfu>
4
+ Copyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # @vitest/runner
2
+
3
+ Vitest mechanism to collect and run tasks.
4
+
5
+ [GitHub](https://github.com/vitest-dev/vitest) | [Documentation](https://vitest.dev/advanced/runner)
@@ -0,0 +1,285 @@
1
+ import { format, deepClone, stringify, getOwnProperties, getType, toArray } from '@vitest/utils';
2
+
3
+ function partitionSuiteChildren(suite) {
4
+ let tasksGroup = [];
5
+ const tasksGroups = [];
6
+ for (const c of suite.tasks) {
7
+ if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
8
+ tasksGroup.push(c);
9
+ } else {
10
+ tasksGroups.push(tasksGroup);
11
+ tasksGroup = [c];
12
+ }
13
+ }
14
+ if (tasksGroup.length > 0)
15
+ tasksGroups.push(tasksGroup);
16
+ return tasksGroups;
17
+ }
18
+
19
+ function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnly) {
20
+ const suiteIsOnly = parentIsOnly || suite.mode === "only";
21
+ suite.tasks.forEach((t) => {
22
+ const includeTask = suiteIsOnly || t.mode === "only";
23
+ if (onlyMode) {
24
+ if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
25
+ if (t.mode === "only") {
26
+ checkAllowOnly(t, allowOnly);
27
+ t.mode = "run";
28
+ }
29
+ } else if (t.mode === "run" && !includeTask) {
30
+ t.mode = "skip";
31
+ } else if (t.mode === "only") {
32
+ checkAllowOnly(t, allowOnly);
33
+ t.mode = "run";
34
+ }
35
+ }
36
+ if (t.type === "test") {
37
+ if (namePattern && !getTaskFullName(t).match(namePattern))
38
+ t.mode = "skip";
39
+ } else if (t.type === "suite") {
40
+ if (t.mode === "skip")
41
+ skipAllTasks(t);
42
+ else
43
+ interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
44
+ }
45
+ });
46
+ if (suite.mode === "run") {
47
+ if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run"))
48
+ suite.mode = "skip";
49
+ }
50
+ }
51
+ function getTaskFullName(task) {
52
+ return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
53
+ }
54
+ function someTasksAreOnly(suite) {
55
+ return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
56
+ }
57
+ function skipAllTasks(suite) {
58
+ suite.tasks.forEach((t) => {
59
+ if (t.mode === "run") {
60
+ t.mode = "skip";
61
+ if (t.type === "suite")
62
+ skipAllTasks(t);
63
+ }
64
+ });
65
+ }
66
+ function checkAllowOnly(task, allowOnly) {
67
+ if (allowOnly)
68
+ return;
69
+ const error = new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error");
70
+ task.result = {
71
+ state: "fail",
72
+ error,
73
+ errors: [error]
74
+ };
75
+ }
76
+ function generateHash(str) {
77
+ let hash = 0;
78
+ if (str.length === 0)
79
+ return `${hash}`;
80
+ for (let i = 0; i < str.length; i++) {
81
+ const char = str.charCodeAt(i);
82
+ hash = (hash << 5) - hash + char;
83
+ hash = hash & hash;
84
+ }
85
+ return `${hash}`;
86
+ }
87
+ function calculateSuiteHash(parent) {
88
+ parent.tasks.forEach((t, idx) => {
89
+ t.id = `${parent.id}_${idx}`;
90
+ if (t.type === "suite")
91
+ calculateSuiteHash(t);
92
+ });
93
+ }
94
+
95
+ function createChainable(keys, fn) {
96
+ function create(context) {
97
+ const chain2 = function(...args) {
98
+ return fn.apply(context, args);
99
+ };
100
+ Object.assign(chain2, fn);
101
+ chain2.withContext = () => chain2.bind(context);
102
+ for (const key of keys) {
103
+ Object.defineProperty(chain2, key, {
104
+ get() {
105
+ return create({ ...context, [key]: true });
106
+ }
107
+ });
108
+ }
109
+ return chain2;
110
+ }
111
+ const chain = create({});
112
+ chain.fn = fn;
113
+ return chain;
114
+ }
115
+
116
+ const IS_RECORD_SYMBOL = "@@__IMMUTABLE_RECORD__@@";
117
+ const IS_COLLECTION_SYMBOL = "@@__IMMUTABLE_ITERABLE__@@";
118
+ const isImmutable = (v) => v && (v[IS_COLLECTION_SYMBOL] || v[IS_RECORD_SYMBOL]);
119
+ const OBJECT_PROTO = Object.getPrototypeOf({});
120
+ function getUnserializableMessage(err) {
121
+ if (err instanceof Error)
122
+ return `<unserializable>: ${err.message}`;
123
+ if (typeof err === "string")
124
+ return `<unserializable>: ${err}`;
125
+ return "<unserializable>";
126
+ }
127
+ function serializeError(val, seen = /* @__PURE__ */ new WeakMap()) {
128
+ if (!val || typeof val === "string")
129
+ return val;
130
+ if (typeof val === "function")
131
+ return `Function<${val.name || "anonymous"}>`;
132
+ if (typeof val === "symbol")
133
+ return val.toString();
134
+ if (typeof val !== "object")
135
+ return val;
136
+ if (isImmutable(val))
137
+ return serializeError(val.toJSON(), seen);
138
+ if (val instanceof Promise || val.constructor && val.constructor.prototype === "AsyncFunction")
139
+ return "Promise";
140
+ if (typeof Element !== "undefined" && val instanceof Element)
141
+ return val.tagName;
142
+ if (typeof val.asymmetricMatch === "function")
143
+ return `${val.toString()} ${format(val.sample)}`;
144
+ if (seen.has(val))
145
+ return seen.get(val);
146
+ if (Array.isArray(val)) {
147
+ const clone = new Array(val.length);
148
+ seen.set(val, clone);
149
+ val.forEach((e, i) => {
150
+ try {
151
+ clone[i] = serializeError(e, seen);
152
+ } catch (err) {
153
+ clone[i] = getUnserializableMessage(err);
154
+ }
155
+ });
156
+ return clone;
157
+ } else {
158
+ const clone = /* @__PURE__ */ Object.create(null);
159
+ seen.set(val, clone);
160
+ let obj = val;
161
+ while (obj && obj !== OBJECT_PROTO) {
162
+ Object.getOwnPropertyNames(obj).forEach((key) => {
163
+ if (key in clone)
164
+ return;
165
+ try {
166
+ clone[key] = serializeError(val[key], seen);
167
+ } catch (err) {
168
+ delete clone[key];
169
+ clone[key] = getUnserializableMessage(err);
170
+ }
171
+ });
172
+ obj = Object.getPrototypeOf(obj);
173
+ }
174
+ return clone;
175
+ }
176
+ }
177
+ function normalizeErrorMessage(message) {
178
+ return message.replace(/__vite_ssr_import_\d+__\./g, "");
179
+ }
180
+ function processError(err, options = {}) {
181
+ if (!err || typeof err !== "object")
182
+ return err;
183
+ if (err.stack)
184
+ err.stackStr = String(err.stack);
185
+ if (err.name)
186
+ err.nameStr = String(err.name);
187
+ const clonedActual = deepClone(err.actual);
188
+ const clonedExpected = deepClone(err.expected);
189
+ const { replacedActual, replacedExpected } = replaceAsymmetricMatcher(clonedActual, clonedExpected);
190
+ err.actual = replacedActual;
191
+ err.expected = replacedExpected;
192
+ const maxDiffSize = options.outputDiffMaxSize ?? 1e4;
193
+ if (typeof err.expected !== "string")
194
+ err.expected = stringify(err.expected, 10, { maxLength: maxDiffSize });
195
+ if (typeof err.actual !== "string")
196
+ err.actual = stringify(err.actual, 10, { maxLength: maxDiffSize });
197
+ try {
198
+ if (typeof err.message === "string")
199
+ err.message = normalizeErrorMessage(err.message);
200
+ if (typeof err.cause === "object" && typeof err.cause.message === "string")
201
+ err.cause.message = normalizeErrorMessage(err.cause.message);
202
+ } catch {
203
+ }
204
+ try {
205
+ return serializeError(err);
206
+ } catch (e) {
207
+ return serializeError(new Error(`Failed to fully serialize error: ${e == null ? void 0 : e.message}
208
+ Inner error message: ${err == null ? void 0 : err.message}`));
209
+ }
210
+ }
211
+ function isAsymmetricMatcher(data) {
212
+ const type = getType(data);
213
+ return type === "Object" && typeof data.asymmetricMatch === "function";
214
+ }
215
+ function isReplaceable(obj1, obj2) {
216
+ const obj1Type = getType(obj1);
217
+ const obj2Type = getType(obj2);
218
+ return obj1Type === obj2Type && obj1Type === "Object";
219
+ }
220
+ function replaceAsymmetricMatcher(actual, expected, actualReplaced = /* @__PURE__ */ new WeakSet(), expectedReplaced = /* @__PURE__ */ new WeakSet()) {
221
+ if (!isReplaceable(actual, expected))
222
+ return { replacedActual: actual, replacedExpected: expected };
223
+ if (actualReplaced.has(actual) || expectedReplaced.has(expected))
224
+ return { replacedActual: actual, replacedExpected: expected };
225
+ actualReplaced.add(actual);
226
+ expectedReplaced.add(expected);
227
+ getOwnProperties(expected).forEach((key) => {
228
+ const expectedValue = expected[key];
229
+ const actualValue = actual[key];
230
+ if (isAsymmetricMatcher(expectedValue)) {
231
+ if (expectedValue.asymmetricMatch(actualValue))
232
+ actual[key] = expectedValue;
233
+ } else if (isAsymmetricMatcher(actualValue)) {
234
+ if (actualValue.asymmetricMatch(expectedValue))
235
+ expected[key] = actualValue;
236
+ } else if (isReplaceable(actualValue, expectedValue)) {
237
+ const replaced = replaceAsymmetricMatcher(
238
+ actualValue,
239
+ expectedValue,
240
+ actualReplaced,
241
+ expectedReplaced
242
+ );
243
+ actual[key] = replaced.replacedActual;
244
+ expected[key] = replaced.replacedExpected;
245
+ }
246
+ });
247
+ return {
248
+ replacedActual: actual,
249
+ replacedExpected: expected
250
+ };
251
+ }
252
+
253
+ function isAtomTest(s) {
254
+ return s.type === "test" || s.type === "custom";
255
+ }
256
+ function getTests(suite) {
257
+ return toArray(suite).flatMap((s) => isAtomTest(s) ? [s] : s.tasks.flatMap((c) => isAtomTest(c) ? [c] : getTests(c)));
258
+ }
259
+ function getTasks(tasks = []) {
260
+ return toArray(tasks).flatMap((s) => isAtomTest(s) ? [s] : [s, ...getTasks(s.tasks)]);
261
+ }
262
+ function getSuites(suite) {
263
+ return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
264
+ }
265
+ function hasTests(suite) {
266
+ return toArray(suite).some((s) => s.tasks.some((c) => isAtomTest(c) || hasTests(c)));
267
+ }
268
+ function hasFailed(suite) {
269
+ return toArray(suite).some((s) => {
270
+ var _a;
271
+ return ((_a = s.result) == null ? void 0 : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
272
+ });
273
+ }
274
+ function getNames(task) {
275
+ const names = [task.name];
276
+ let current = task;
277
+ while ((current == null ? void 0 : current.suite) || (current == null ? void 0 : current.file)) {
278
+ current = current.suite || current.file;
279
+ if (current == null ? void 0 : current.name)
280
+ names.unshift(current.name);
281
+ }
282
+ return names;
283
+ }
284
+
285
+ export { calculateSuiteHash as a, partitionSuiteChildren as b, createChainable as c, hasFailed as d, getTests as e, getTasks as f, generateHash as g, hasTests as h, interpretTaskModes as i, getSuites as j, getNames as k, serializeError as l, processError as p, replaceAsymmetricMatcher as r, someTasksAreOnly as s };
@@ -0,0 +1,25 @@
1
+ import { V as VitestRunner } from './runner-93cc9c0d.js';
2
+ export { V as VitestRunner, a as VitestRunnerConfig, c as VitestRunnerConstructor, b as VitestRunnerImportSource } from './runner-93cc9c0d.js';
3
+ import { T as Task, F as File, S as SuiteAPI, a as TestAPI, b as SuiteCollector, c as SuiteHooks, H as HookListener, d as TestContext, e as Suite, f as HookCleanupCallback, O as OnTestFailedHandler, g as Test } from './tasks-e1fc71d1.js';
4
+ export { D as DoneCallback, F as File, f as HookCleanupCallback, H as HookListener, O as OnTestFailedHandler, R as RunMode, p as RuntimeContext, q as SequenceHooks, e as Suite, S as SuiteAPI, b as SuiteCollector, o as SuiteFactory, c as SuiteHooks, T as Task, i as TaskBase, j as TaskCustom, k as TaskResult, l as TaskResultPack, h as TaskState, g as Test, a as TestAPI, d as TestContext, m as TestFunction, n as TestOptions } from './tasks-e1fc71d1.js';
5
+ import { Awaitable } from '@vitest/utils';
6
+
7
+ declare function updateTask(task: Task, runner: VitestRunner): void;
8
+ declare function startTests(paths: string[], runner: VitestRunner): Promise<File[]>;
9
+
10
+ declare const suite: SuiteAPI<{}>;
11
+ declare const test: TestAPI<{}>;
12
+ declare const describe: SuiteAPI<{}>;
13
+ declare const it: TestAPI<{}>;
14
+ declare function getCurrentSuite<ExtraContext = {}>(): SuiteCollector<ExtraContext>;
15
+
16
+ declare const beforeAll: (fn: SuiteHooks['beforeAll'][0], timeout?: number) => void;
17
+ declare const afterAll: (fn: SuiteHooks['afterAll'][0], timeout?: number) => void;
18
+ declare const beforeEach: <ExtraContext = {}>(fn: HookListener<[TestContext & ExtraContext, Suite], HookCleanupCallback>, timeout?: number) => void;
19
+ declare const afterEach: <ExtraContext = {}>(fn: HookListener<[TestContext & ExtraContext, Suite], void>, timeout?: number) => void;
20
+ declare const onTestFailed: (fn: OnTestFailedHandler) => void;
21
+
22
+ declare function setFn(key: Test, fn: (() => Awaitable<void>)): void;
23
+ declare function getFn<Task = Test>(key: Task): (() => Awaitable<void>);
24
+
25
+ export { afterAll, afterEach, beforeAll, beforeEach, describe, getCurrentSuite, getFn, it, onTestFailed, setFn, startTests, suite, test, updateTask };
package/dist/index.js ADDED
@@ -0,0 +1,610 @@
1
+ import limit from 'p-limit';
2
+ import { getSafeTimers, format, isObject, objDisplay, objectAttr, noop, toArray, shuffle } from '@vitest/utils';
3
+ import { c as createChainable, g as generateHash, p as processError, a as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, b as partitionSuiteChildren, h as hasTests, d as hasFailed } from './chunk-tasks.js';
4
+ import { relative } from 'pathe';
5
+
6
+ const fnMap = /* @__PURE__ */ new WeakMap();
7
+ const hooksMap = /* @__PURE__ */ new WeakMap();
8
+ function setFn(key, fn) {
9
+ fnMap.set(key, fn);
10
+ }
11
+ function getFn(key) {
12
+ return fnMap.get(key);
13
+ }
14
+ function setHooks(key, hooks) {
15
+ hooksMap.set(key, hooks);
16
+ }
17
+ function getHooks(key) {
18
+ return hooksMap.get(key);
19
+ }
20
+
21
+ const collectorContext = {
22
+ tasks: [],
23
+ currentSuite: null
24
+ };
25
+ function collectTask(task) {
26
+ var _a;
27
+ (_a = collectorContext.currentSuite) == null ? void 0 : _a.tasks.push(task);
28
+ }
29
+ async function runWithSuite(suite, fn) {
30
+ const prev = collectorContext.currentSuite;
31
+ collectorContext.currentSuite = suite;
32
+ await fn();
33
+ collectorContext.currentSuite = prev;
34
+ }
35
+ function withTimeout(fn, timeout, isHook = false) {
36
+ if (timeout <= 0 || timeout === Infinity)
37
+ return fn;
38
+ const { setTimeout, clearTimeout } = getSafeTimers();
39
+ return (...args) => {
40
+ return Promise.race([fn(...args), new Promise((resolve, reject) => {
41
+ var _a;
42
+ const timer = setTimeout(() => {
43
+ clearTimeout(timer);
44
+ reject(new Error(makeTimeoutMsg(isHook, timeout)));
45
+ }, timeout);
46
+ (_a = timer.unref) == null ? void 0 : _a.call(timer);
47
+ })]);
48
+ };
49
+ }
50
+ function createTestContext(test, runner) {
51
+ var _a;
52
+ const context = function() {
53
+ throw new Error("done() callback is deprecated, use promise instead");
54
+ };
55
+ context.meta = test;
56
+ context.onTestFailed = (fn) => {
57
+ test.onFailed || (test.onFailed = []);
58
+ test.onFailed.push(fn);
59
+ };
60
+ return ((_a = runner.extendTestContext) == null ? void 0 : _a.call(runner, context)) || context;
61
+ }
62
+ function makeTimeoutMsg(isHook, timeout) {
63
+ return `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.
64
+ 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"}".`;
65
+ }
66
+
67
+ const suite = createSuite();
68
+ const test = createTest(
69
+ function(name, fn, options) {
70
+ getCurrentSuite().test.fn.call(this, name, fn, options);
71
+ }
72
+ );
73
+ const describe = suite;
74
+ const it = test;
75
+ let runner;
76
+ let defaultSuite;
77
+ function getDefaultSuite() {
78
+ return defaultSuite;
79
+ }
80
+ function getRunner() {
81
+ return runner;
82
+ }
83
+ function clearCollectorContext(currentRunner) {
84
+ if (!defaultSuite)
85
+ defaultSuite = currentRunner.config.sequence.shuffle ? suite.shuffle("") : suite("");
86
+ runner = currentRunner;
87
+ collectorContext.tasks.length = 0;
88
+ defaultSuite.clear();
89
+ collectorContext.currentSuite = defaultSuite;
90
+ }
91
+ function getCurrentSuite() {
92
+ return collectorContext.currentSuite || defaultSuite;
93
+ }
94
+ function createSuiteHooks() {
95
+ return {
96
+ beforeAll: [],
97
+ afterAll: [],
98
+ beforeEach: [],
99
+ afterEach: []
100
+ };
101
+ }
102
+ function createSuiteCollector(name, factory = () => {
103
+ }, mode, concurrent, shuffle, suiteOptions) {
104
+ const tasks = [];
105
+ const factoryQueue = [];
106
+ let suite2;
107
+ initSuite();
108
+ const test2 = createTest(function(name2, fn = noop, options = suiteOptions) {
109
+ const mode2 = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
110
+ if (typeof options === "number")
111
+ options = { timeout: options };
112
+ const test3 = {
113
+ id: "",
114
+ type: "test",
115
+ name: name2,
116
+ mode: mode2,
117
+ suite: void 0,
118
+ fails: this.fails,
119
+ retry: options == null ? void 0 : options.retry
120
+ };
121
+ if (this.concurrent || concurrent)
122
+ test3.concurrent = true;
123
+ if (shuffle)
124
+ test3.shuffle = true;
125
+ const context = createTestContext(test3, runner);
126
+ Object.defineProperty(test3, "context", {
127
+ value: context,
128
+ enumerable: false
129
+ });
130
+ setFn(test3, withTimeout(
131
+ () => fn(context),
132
+ (options == null ? void 0 : options.timeout) ?? runner.config.testTimeout
133
+ ));
134
+ tasks.push(test3);
135
+ });
136
+ const custom = function(name2 = "") {
137
+ const self = this || {};
138
+ const task = {
139
+ id: "",
140
+ name: name2,
141
+ type: "custom",
142
+ mode: self.only ? "only" : self.skip ? "skip" : self.todo ? "todo" : "run"
143
+ };
144
+ tasks.push(task);
145
+ return task;
146
+ };
147
+ const collector = {
148
+ type: "collector",
149
+ name,
150
+ mode,
151
+ test: test2,
152
+ tasks,
153
+ collect,
154
+ custom,
155
+ clear,
156
+ on: addHook
157
+ };
158
+ function addHook(name2, ...fn) {
159
+ getHooks(suite2)[name2].push(...fn);
160
+ }
161
+ function initSuite() {
162
+ suite2 = {
163
+ id: "",
164
+ type: "suite",
165
+ name,
166
+ mode,
167
+ shuffle,
168
+ tasks: []
169
+ };
170
+ setHooks(suite2, createSuiteHooks());
171
+ }
172
+ function clear() {
173
+ tasks.length = 0;
174
+ factoryQueue.length = 0;
175
+ initSuite();
176
+ }
177
+ async function collect(file) {
178
+ factoryQueue.length = 0;
179
+ if (factory)
180
+ await runWithSuite(collector, () => factory(test2));
181
+ const allChildren = [];
182
+ for (const i of [...factoryQueue, ...tasks])
183
+ allChildren.push(i.type === "collector" ? await i.collect(file) : i);
184
+ suite2.file = file;
185
+ suite2.tasks = allChildren;
186
+ allChildren.forEach((task) => {
187
+ task.suite = suite2;
188
+ if (file)
189
+ task.file = file;
190
+ });
191
+ return suite2;
192
+ }
193
+ collectTask(collector);
194
+ return collector;
195
+ }
196
+ function createSuite() {
197
+ function suiteFn(name, factory, options) {
198
+ const mode = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
199
+ return createSuiteCollector(name, factory, mode, this.concurrent, this.shuffle, options);
200
+ }
201
+ suiteFn.each = function(cases, ...args) {
202
+ const suite2 = this.withContext();
203
+ if (Array.isArray(cases) && args.length)
204
+ cases = formatTemplateString(cases, args);
205
+ return (name, fn, options) => {
206
+ const arrayOnlyCases = cases.every(Array.isArray);
207
+ cases.forEach((i, idx) => {
208
+ const items = Array.isArray(i) ? i : [i];
209
+ arrayOnlyCases ? suite2(formatTitle(name, items, idx), () => fn(...items), options) : suite2(formatTitle(name, items, idx), () => fn(i), options);
210
+ });
211
+ };
212
+ };
213
+ suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
214
+ suiteFn.runIf = (condition) => condition ? suite : suite.skip;
215
+ return createChainable(
216
+ ["concurrent", "shuffle", "skip", "only", "todo"],
217
+ suiteFn
218
+ );
219
+ }
220
+ function createTest(fn) {
221
+ const testFn = fn;
222
+ testFn.each = function(cases, ...args) {
223
+ const test2 = this.withContext();
224
+ if (Array.isArray(cases) && args.length)
225
+ cases = formatTemplateString(cases, args);
226
+ return (name, fn2, options) => {
227
+ const arrayOnlyCases = cases.every(Array.isArray);
228
+ cases.forEach((i, idx) => {
229
+ const items = Array.isArray(i) ? i : [i];
230
+ arrayOnlyCases ? test2(formatTitle(name, items, idx), () => fn2(...items), options) : test2(formatTitle(name, items, idx), () => fn2(i), options);
231
+ });
232
+ };
233
+ };
234
+ testFn.skipIf = (condition) => condition ? test.skip : test;
235
+ testFn.runIf = (condition) => condition ? test : test.skip;
236
+ return createChainable(
237
+ ["concurrent", "skip", "only", "todo", "fails"],
238
+ testFn
239
+ );
240
+ }
241
+ function formatTitle(template, items, idx) {
242
+ if (template.includes("%#")) {
243
+ template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/__vitest_escaped_%__/g, "%%");
244
+ }
245
+ const count = template.split("%").length - 1;
246
+ let formatted = format(template, ...items.slice(0, count));
247
+ if (isObject(items[0])) {
248
+ formatted = formatted.replace(
249
+ /\$([$\w_.]+)/g,
250
+ (_, key) => objDisplay(objectAttr(items[0], key))
251
+ );
252
+ }
253
+ return formatted;
254
+ }
255
+ function formatTemplateString(cases, args) {
256
+ const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
257
+ const res = [];
258
+ for (let i = 0; i < Math.floor(args.length / header.length); i++) {
259
+ const oneCase = {};
260
+ for (let j = 0; j < header.length; j++)
261
+ oneCase[header[j]] = args[i * header.length + j];
262
+ res.push(oneCase);
263
+ }
264
+ return res;
265
+ }
266
+
267
+ async function runSetupFiles(config, runner) {
268
+ const files = toArray(config.setupFiles);
269
+ await Promise.all(
270
+ files.map(async (fsPath) => {
271
+ await runner.importFile(fsPath, "setup");
272
+ })
273
+ );
274
+ }
275
+
276
+ const now$1 = Date.now;
277
+ async function collectTests(paths, runner) {
278
+ const files = [];
279
+ const config = runner.config;
280
+ for (const filepath of paths) {
281
+ const path = relative(config.root, filepath);
282
+ const file = {
283
+ id: generateHash(path),
284
+ name: path,
285
+ type: "suite",
286
+ mode: "run",
287
+ filepath,
288
+ tasks: [],
289
+ projectName: config.name
290
+ };
291
+ clearCollectorContext(runner);
292
+ try {
293
+ const setupStart = now$1();
294
+ await runSetupFiles(config, runner);
295
+ const collectStart = now$1();
296
+ file.setupDuration = collectStart - setupStart;
297
+ await runner.importFile(filepath, "collect");
298
+ const defaultTasks = await getDefaultSuite().collect(file);
299
+ setHooks(file, getHooks(defaultTasks));
300
+ for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) {
301
+ if (c.type === "test") {
302
+ file.tasks.push(c);
303
+ } else if (c.type === "custom") {
304
+ file.tasks.push(c);
305
+ } else if (c.type === "suite") {
306
+ file.tasks.push(c);
307
+ } else if (c.type === "collector") {
308
+ const suite = await c.collect(file);
309
+ if (suite.name || suite.tasks.length)
310
+ file.tasks.push(suite);
311
+ }
312
+ }
313
+ file.collectDuration = now$1() - collectStart;
314
+ } catch (e) {
315
+ const error = processError(e);
316
+ file.result = {
317
+ state: "fail",
318
+ error,
319
+ errors: [error]
320
+ };
321
+ }
322
+ calculateSuiteHash(file);
323
+ const hasOnlyTasks = someTasksAreOnly(file);
324
+ interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.allowOnly);
325
+ files.push(file);
326
+ }
327
+ return files;
328
+ }
329
+
330
+ let _test;
331
+ function setCurrentTest(test) {
332
+ _test = test;
333
+ }
334
+ function getCurrentTest() {
335
+ return _test;
336
+ }
337
+
338
+ const now = Date.now;
339
+ function updateSuiteHookState(suite, name, state, runner) {
340
+ var _a;
341
+ if (!suite.result)
342
+ suite.result = { state: "run" };
343
+ if (!((_a = suite.result) == null ? void 0 : _a.hooks))
344
+ suite.result.hooks = {};
345
+ const suiteHooks = suite.result.hooks;
346
+ if (suiteHooks) {
347
+ suiteHooks[name] = state;
348
+ updateTask(suite, runner);
349
+ }
350
+ }
351
+ function getSuiteHooks(suite, name, sequence) {
352
+ const hooks = getHooks(suite)[name];
353
+ if (sequence === "stack" && (name === "afterAll" || name === "afterEach"))
354
+ return hooks.slice().reverse();
355
+ return hooks;
356
+ }
357
+ async function callSuiteHook(suite, currentTask, name, runner, args) {
358
+ const sequence = runner.config.sequence.hooks;
359
+ const callbacks = [];
360
+ if (name === "beforeEach" && suite.suite) {
361
+ callbacks.push(
362
+ ...await callSuiteHook(suite.suite, currentTask, name, runner, args)
363
+ );
364
+ }
365
+ updateSuiteHookState(currentTask, name, "run", runner);
366
+ const hooks = getSuiteHooks(suite, name, sequence);
367
+ if (sequence === "parallel") {
368
+ callbacks.push(...await Promise.all(hooks.map((fn) => fn(...args))));
369
+ } else {
370
+ for (const hook of hooks)
371
+ callbacks.push(await hook(...args));
372
+ }
373
+ updateSuiteHookState(currentTask, name, "pass", runner);
374
+ if (name === "afterEach" && suite.suite) {
375
+ callbacks.push(
376
+ ...await callSuiteHook(suite.suite, currentTask, name, runner, args)
377
+ );
378
+ }
379
+ return callbacks;
380
+ }
381
+ const packs = /* @__PURE__ */ new Map();
382
+ let updateTimer;
383
+ let previousUpdate;
384
+ function updateTask(task, runner) {
385
+ packs.set(task.id, task.result);
386
+ const { clearTimeout, setTimeout } = getSafeTimers();
387
+ clearTimeout(updateTimer);
388
+ updateTimer = setTimeout(() => {
389
+ previousUpdate = sendTasksUpdate(runner);
390
+ }, 10);
391
+ }
392
+ async function sendTasksUpdate(runner) {
393
+ var _a;
394
+ const { clearTimeout } = getSafeTimers();
395
+ clearTimeout(updateTimer);
396
+ await previousUpdate;
397
+ if (packs.size) {
398
+ const p = (_a = runner.onTaskUpdate) == null ? void 0 : _a.call(runner, Array.from(packs));
399
+ packs.clear();
400
+ return p;
401
+ }
402
+ }
403
+ const callCleanupHooks = async (cleanups) => {
404
+ await Promise.all(cleanups.map(async (fn) => {
405
+ if (typeof fn !== "function")
406
+ return;
407
+ await fn();
408
+ }));
409
+ };
410
+ async function runTest(test, runner) {
411
+ var _a, _b, _c, _d, _e, _f;
412
+ await ((_a = runner.onBeforeRunTest) == null ? void 0 : _a.call(runner, test));
413
+ if (test.mode !== "run")
414
+ return;
415
+ if (((_b = test.result) == null ? void 0 : _b.state) === "fail") {
416
+ updateTask(test, runner);
417
+ return;
418
+ }
419
+ const start = now();
420
+ test.result = {
421
+ state: "run",
422
+ startTime: start
423
+ };
424
+ updateTask(test, runner);
425
+ setCurrentTest(test);
426
+ const retry = test.retry || 1;
427
+ for (let retryCount = 0; retryCount < retry; retryCount++) {
428
+ let beforeEachCleanups = [];
429
+ try {
430
+ await ((_c = runner.onBeforeTryTest) == null ? void 0 : _c.call(runner, test, retryCount));
431
+ beforeEachCleanups = await callSuiteHook(test.suite, test, "beforeEach", runner, [test.context, test.suite]);
432
+ test.result.retryCount = retryCount;
433
+ if (runner.runTest) {
434
+ await runner.runTest(test);
435
+ } else {
436
+ const fn = getFn(test);
437
+ if (!fn)
438
+ throw new Error("Test function is not found. Did you add it using `setFn`?");
439
+ await fn();
440
+ }
441
+ await ((_d = runner.onAfterTryTest) == null ? void 0 : _d.call(runner, test, retryCount));
442
+ test.result.state = "pass";
443
+ } catch (e) {
444
+ const error = processError(e);
445
+ test.result.state = "fail";
446
+ test.result.error = error;
447
+ test.result.errors = [error];
448
+ }
449
+ try {
450
+ await callSuiteHook(test.suite, test, "afterEach", runner, [test.context, test.suite]);
451
+ await callCleanupHooks(beforeEachCleanups);
452
+ } catch (e) {
453
+ const error = processError(e);
454
+ test.result.state = "fail";
455
+ test.result.error = error;
456
+ test.result.errors = [error];
457
+ }
458
+ if (test.result.state === "pass")
459
+ break;
460
+ updateTask(test, runner);
461
+ }
462
+ if (test.result.state === "fail")
463
+ await Promise.all(((_e = test.onFailed) == null ? void 0 : _e.map((fn) => fn(test.result))) || []);
464
+ if (test.fails) {
465
+ if (test.result.state === "pass") {
466
+ const error = processError(new Error("Expect test to fail"));
467
+ test.result.state = "fail";
468
+ test.result.error = error;
469
+ test.result.errors = [error];
470
+ } else {
471
+ test.result.state = "pass";
472
+ test.result.error = void 0;
473
+ test.result.errors = void 0;
474
+ }
475
+ }
476
+ setCurrentTest(void 0);
477
+ test.result.duration = now() - start;
478
+ await ((_f = runner.onAfterRunTest) == null ? void 0 : _f.call(runner, test));
479
+ updateTask(test, runner);
480
+ }
481
+ function markTasksAsSkipped(suite, runner) {
482
+ suite.tasks.forEach((t) => {
483
+ t.mode = "skip";
484
+ t.result = { ...t.result, state: "skip" };
485
+ updateTask(t, runner);
486
+ if (t.type === "suite")
487
+ markTasksAsSkipped(t, runner);
488
+ });
489
+ }
490
+ async function runSuite(suite, runner) {
491
+ var _a, _b, _c;
492
+ await ((_a = runner.onBeforeRunSuite) == null ? void 0 : _a.call(runner, suite));
493
+ if (((_b = suite.result) == null ? void 0 : _b.state) === "fail") {
494
+ markTasksAsSkipped(suite, runner);
495
+ updateTask(suite, runner);
496
+ return;
497
+ }
498
+ const start = now();
499
+ suite.result = {
500
+ state: "run",
501
+ startTime: start
502
+ };
503
+ updateTask(suite, runner);
504
+ if (suite.mode === "skip") {
505
+ suite.result.state = "skip";
506
+ } else if (suite.mode === "todo") {
507
+ suite.result.state = "todo";
508
+ } else {
509
+ try {
510
+ const beforeAllCleanups = await callSuiteHook(suite, suite, "beforeAll", runner, [suite]);
511
+ if (runner.runSuite) {
512
+ await runner.runSuite(suite);
513
+ } else {
514
+ for (let tasksGroup of partitionSuiteChildren(suite)) {
515
+ if (tasksGroup[0].concurrent === true) {
516
+ const mutex = limit(runner.config.maxConcurrency);
517
+ await Promise.all(tasksGroup.map((c) => mutex(() => runSuiteChild(c, runner))));
518
+ } else {
519
+ const { sequence } = runner.config;
520
+ if (sequence.shuffle || suite.shuffle) {
521
+ const suites = tasksGroup.filter((group) => group.type === "suite");
522
+ const tests = tasksGroup.filter((group) => group.type === "test");
523
+ const groups = shuffle([suites, tests], sequence.seed);
524
+ tasksGroup = groups.flatMap((group) => shuffle(group, sequence.seed));
525
+ }
526
+ for (const c of tasksGroup)
527
+ await runSuiteChild(c, runner);
528
+ }
529
+ }
530
+ }
531
+ await callSuiteHook(suite, suite, "afterAll", runner, [suite]);
532
+ await callCleanupHooks(beforeAllCleanups);
533
+ } catch (e) {
534
+ const error = processError(e);
535
+ suite.result.state = "fail";
536
+ suite.result.error = error;
537
+ suite.result.errors = [error];
538
+ }
539
+ }
540
+ suite.result.duration = now() - start;
541
+ if (suite.mode === "run") {
542
+ if (!hasTests(suite)) {
543
+ suite.result.state = "fail";
544
+ if (!suite.result.error) {
545
+ const error = processError(new Error(`No test found in suite ${suite.name}`));
546
+ suite.result.error = error;
547
+ suite.result.errors = [error];
548
+ }
549
+ } else if (hasFailed(suite)) {
550
+ suite.result.state = "fail";
551
+ } else {
552
+ suite.result.state = "pass";
553
+ }
554
+ }
555
+ await ((_c = runner.onAfterRunSuite) == null ? void 0 : _c.call(runner, suite));
556
+ updateTask(suite, runner);
557
+ }
558
+ async function runSuiteChild(c, runner) {
559
+ if (c.type === "test")
560
+ return runTest(c, runner);
561
+ else if (c.type === "suite")
562
+ return runSuite(c, runner);
563
+ }
564
+ async function runFiles(files, runner) {
565
+ var _a, _b;
566
+ for (const file of files) {
567
+ if (!file.tasks.length && !runner.config.passWithNoTests) {
568
+ if (!((_b = (_a = file.result) == null ? void 0 : _a.errors) == null ? void 0 : _b.length)) {
569
+ const error = processError(new Error(`No test suite found in file ${file.filepath}`));
570
+ file.result = {
571
+ state: "fail",
572
+ error,
573
+ errors: [error]
574
+ };
575
+ }
576
+ }
577
+ await runSuite(file, runner);
578
+ }
579
+ }
580
+ async function startTests(paths, runner) {
581
+ var _a, _b, _c, _d;
582
+ await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
583
+ const files = await collectTests(paths, runner);
584
+ (_b = runner.onCollected) == null ? void 0 : _b.call(runner, files);
585
+ await ((_c = runner.onBeforeRun) == null ? void 0 : _c.call(runner, files));
586
+ await runFiles(files, runner);
587
+ await ((_d = runner.onAfterRun) == null ? void 0 : _d.call(runner, files));
588
+ await sendTasksUpdate(runner);
589
+ return files;
590
+ }
591
+
592
+ const getDefaultHookTimeout = () => getRunner().config.hookTimeout;
593
+ const beforeAll = (fn, timeout) => getCurrentSuite().on("beforeAll", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
594
+ const afterAll = (fn, timeout) => getCurrentSuite().on("afterAll", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
595
+ const beforeEach = (fn, timeout) => getCurrentSuite().on("beforeEach", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
596
+ const afterEach = (fn, timeout) => getCurrentSuite().on("afterEach", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
597
+ const onTestFailed = createTestHook("onTestFailed", (test, handler) => {
598
+ test.onFailed || (test.onFailed = []);
599
+ test.onFailed.push(handler);
600
+ });
601
+ function createTestHook(name, handler) {
602
+ return (fn) => {
603
+ const current = getCurrentTest();
604
+ if (!current)
605
+ throw new Error(`Hook ${name}() can only be called inside a test`);
606
+ handler(current, fn);
607
+ };
608
+ }
609
+
610
+ export { afterAll, afterEach, beforeAll, beforeEach, describe, getCurrentSuite, getFn, it, onTestFailed, setFn, startTests, suite, test, updateTask };
@@ -0,0 +1,93 @@
1
+ import { q as SequenceHooks, F as File, g as Test, e as Suite, k as TaskResult, d as TestContext } from './tasks-e1fc71d1.js';
2
+
3
+ interface VitestRunnerConfig {
4
+ root: string;
5
+ setupFiles: string[] | string;
6
+ name: string;
7
+ passWithNoTests: boolean;
8
+ testNamePattern?: RegExp;
9
+ allowOnly?: boolean;
10
+ sequence: {
11
+ shuffle?: boolean;
12
+ seed?: number;
13
+ hooks: SequenceHooks;
14
+ };
15
+ maxConcurrency: number;
16
+ testTimeout: number;
17
+ hookTimeout: number;
18
+ }
19
+ type VitestRunnerImportSource = 'collect' | 'setup';
20
+ interface VitestRunnerConstructor {
21
+ new (config: VitestRunnerConfig): VitestRunner;
22
+ }
23
+ interface VitestRunner {
24
+ /**
25
+ * First thing that's getting called before actually collecting and running tests.
26
+ */
27
+ onBeforeCollect?(paths: string[]): unknown;
28
+ /**
29
+ * Called after collecting tests and before "onBeforeRun".
30
+ */
31
+ onCollected?(files: File[]): unknown;
32
+ /**
33
+ * Called before running a single test. Doesn't have "result" yet.
34
+ */
35
+ onBeforeRunTest?(test: Test): unknown;
36
+ /**
37
+ * Called before actually running the test function. Already has "result" with "state" and "startTime".
38
+ */
39
+ onBeforeTryTest?(test: Test, retryCount: number): unknown;
40
+ /**
41
+ * Called after result and state are set.
42
+ */
43
+ onAfterRunTest?(test: Test): unknown;
44
+ /**
45
+ * Called right after running the test function. Doesn't have new state yet. Will not be called, if the test function throws.
46
+ */
47
+ onAfterTryTest?(test: Test, retryCount: number): unknown;
48
+ /**
49
+ * Called before running a single suite. Doesn't have "result" yet.
50
+ */
51
+ onBeforeRunSuite?(suite: Suite): unknown;
52
+ /**
53
+ * Called after running a single suite. Has state and result.
54
+ */
55
+ onAfterRunSuite?(suite: Suite): unknown;
56
+ /**
57
+ * If defined, will be called instead of usual Vitest suite partition and handling.
58
+ * "before" and "after" hooks will not be ignored.
59
+ */
60
+ runSuite?(suite: Suite): Promise<void>;
61
+ /**
62
+ * If defined, will be called instead of usual Vitest handling. Useful, if you have your custom test function.
63
+ * "before" and "after" hooks will not be ignored.
64
+ */
65
+ runTest?(test: Test): Promise<void>;
66
+ /**
67
+ * Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
68
+ */
69
+ onTaskUpdate?(task: [string, TaskResult | undefined][]): Promise<void>;
70
+ /**
71
+ * Called before running all tests in collected paths.
72
+ */
73
+ onBeforeRun?(files: File[]): unknown;
74
+ /**
75
+ * Called right after running all tests in collected paths.
76
+ */
77
+ onAfterRun?(files: File[]): unknown;
78
+ /**
79
+ * Called when new context for a test is defined. Useful, if you want to add custom properties to the context.
80
+ * If you only want to define custom context, consider using "beforeAll" in "setupFiles" instead.
81
+ */
82
+ extendTestContext?(context: TestContext): TestContext;
83
+ /**
84
+ * Called, when files are imported. Can be called in two situations: when collecting tests and when importing setup files.
85
+ */
86
+ importFile(filepath: string, source: VitestRunnerImportSource): unknown;
87
+ /**
88
+ * Publically available configuration.
89
+ */
90
+ config: VitestRunnerConfig;
91
+ }
92
+
93
+ export { VitestRunner as V, VitestRunnerConfig as a, VitestRunnerImportSource as b, VitestRunnerConstructor as c };
@@ -0,0 +1,195 @@
1
+ import { Awaitable } from '@vitest/utils';
2
+
3
+ type ChainableFunction<T extends string, Args extends any[], R = any, E = {}> = {
4
+ (...args: Args): R;
5
+ } & {
6
+ [x in T]: ChainableFunction<T, Args, R, E>;
7
+ } & {
8
+ fn: (this: Record<T, boolean | undefined>, ...args: Args) => R;
9
+ } & E;
10
+ declare function createChainable<T extends string, Args extends any[], R = any, E = {}>(keys: T[], fn: (this: Record<T, boolean | undefined>, ...args: Args) => R): ChainableFunction<T, Args, R, E>;
11
+
12
+ interface ParsedStack {
13
+ method: string;
14
+ file: string;
15
+ line: number;
16
+ column: number;
17
+ }
18
+ interface ErrorWithDiff extends Error {
19
+ name: string;
20
+ nameStr?: string;
21
+ stack?: string;
22
+ stackStr?: string;
23
+ stacks?: ParsedStack[];
24
+ showDiff?: boolean;
25
+ actual?: any;
26
+ expected?: any;
27
+ operator?: string;
28
+ type?: string;
29
+ frame?: string;
30
+ }
31
+ declare function serializeError(val: any, seen?: WeakMap<object, any>): any;
32
+ interface ProcessErrorOptions {
33
+ outputDiffMaxSize?: number;
34
+ }
35
+ declare function processError(err: any, options?: ProcessErrorOptions): any;
36
+ declare function replaceAsymmetricMatcher(actual: any, expected: any, actualReplaced?: WeakSet<object>, expectedReplaced?: WeakSet<object>): {
37
+ replacedActual: any;
38
+ replacedExpected: any;
39
+ };
40
+
41
+ type RunMode = 'run' | 'skip' | 'only' | 'todo';
42
+ type TaskState = RunMode | 'pass' | 'fail';
43
+ interface TaskBase {
44
+ id: string;
45
+ name: string;
46
+ mode: RunMode;
47
+ concurrent?: boolean;
48
+ shuffle?: boolean;
49
+ suite?: Suite;
50
+ file?: File;
51
+ result?: TaskResult;
52
+ retry?: number;
53
+ meta?: any;
54
+ }
55
+ interface TaskCustom extends TaskBase {
56
+ type: 'custom';
57
+ }
58
+ interface TaskResult {
59
+ state: TaskState;
60
+ duration?: number;
61
+ startTime?: number;
62
+ heap?: number;
63
+ /**
64
+ * @deprecated Use "errors" instead
65
+ */
66
+ error?: ErrorWithDiff;
67
+ errors?: ErrorWithDiff[];
68
+ htmlError?: string;
69
+ hooks?: Partial<Record<keyof SuiteHooks, TaskState>>;
70
+ retryCount?: number;
71
+ }
72
+ type TaskResultPack = [id: string, result: TaskResult | undefined];
73
+ interface Suite extends TaskBase {
74
+ type: 'suite';
75
+ tasks: Task[];
76
+ filepath?: string;
77
+ projectName?: string;
78
+ }
79
+ interface File extends Suite {
80
+ filepath: string;
81
+ collectDuration?: number;
82
+ setupDuration?: number;
83
+ }
84
+ interface Test<ExtraContext = {}> extends TaskBase {
85
+ type: 'test';
86
+ suite: Suite;
87
+ result?: TaskResult;
88
+ fails?: boolean;
89
+ context: TestContext & ExtraContext;
90
+ onFailed?: OnTestFailedHandler[];
91
+ }
92
+ type Task = Test | Suite | TaskCustom | File;
93
+ type DoneCallback = (error?: any) => void;
94
+ type TestFunction<ExtraContext = {}> = (context: TestContext & ExtraContext) => Awaitable<any> | void;
95
+ type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
96
+ 1: [T[0]];
97
+ 2: [T[0], T[1]];
98
+ 3: [T[0], T[1], T[2]];
99
+ 4: [T[0], T[1], T[2], T[3]];
100
+ 5: [T[0], T[1], T[2], T[3], T[4]];
101
+ 6: [T[0], T[1], T[2], T[3], T[4], T[5]];
102
+ 7: [T[0], T[1], T[2], T[3], T[4], T[5], T[6]];
103
+ 8: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7]];
104
+ 9: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8]];
105
+ 10: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]];
106
+ fallback: Array<T extends ReadonlyArray<infer U> ? U : any>;
107
+ }[T extends Readonly<[any]> ? 1 : T extends Readonly<[any, any]> ? 2 : T extends Readonly<[any, any, any]> ? 3 : T extends Readonly<[any, any, any, any]> ? 4 : T extends Readonly<[any, any, any, any, any]> ? 5 : T extends Readonly<[any, any, any, any, any, any]> ? 6 : T extends Readonly<[any, any, any, any, any, any, any]> ? 7 : T extends Readonly<[any, any, any, any, any, any, any, any]> ? 8 : T extends Readonly<[any, any, any, any, any, any, any, any, any]> ? 9 : T extends Readonly<[any, any, any, any, any, any, any, any, any, any]> ? 10 : 'fallback'];
108
+ interface SuiteEachFunction {
109
+ <T extends any[] | [any]>(cases: ReadonlyArray<T>): (name: string, fn: (...args: T) => Awaitable<void>) => void;
110
+ <T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (name: string, fn: (...args: ExtractEachCallbackArgs<T>) => Awaitable<void>) => void;
111
+ <T>(cases: ReadonlyArray<T>): (name: string, fn: (...args: T[]) => Awaitable<void>) => void;
112
+ }
113
+ interface TestEachFunction {
114
+ <T extends any[] | [any]>(cases: ReadonlyArray<T>): (name: string, fn: (...args: T) => Awaitable<void>, options?: number | TestOptions) => void;
115
+ <T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (name: string, fn: (...args: ExtractEachCallbackArgs<T>) => Awaitable<void>, options?: number | TestOptions) => void;
116
+ <T>(cases: ReadonlyArray<T>): (name: string, fn: (...args: T[]) => Awaitable<void>, options?: number | TestOptions) => void;
117
+ (...args: [TemplateStringsArray, ...any]): (name: string, fn: (...args: any[]) => Awaitable<void>, options?: number | TestOptions) => void;
118
+ }
119
+ type ChainableTestAPI<ExtraContext = {}> = ChainableFunction<'concurrent' | 'only' | 'skip' | 'todo' | 'fails', [
120
+ name: string,
121
+ fn?: TestFunction<ExtraContext>,
122
+ options?: number | TestOptions
123
+ ], void, {
124
+ each: TestEachFunction;
125
+ <T extends ExtraContext>(name: string, fn?: TestFunction<T>, options?: number | TestOptions): void;
126
+ }>;
127
+ interface TestOptions {
128
+ /**
129
+ * Test timeout.
130
+ */
131
+ timeout?: number;
132
+ /**
133
+ * Times to retry the test if fails. Useful for making flaky tests more stable.
134
+ * When retries is up, the last test error will be thrown.
135
+ *
136
+ * @default 1
137
+ */
138
+ retry?: number;
139
+ }
140
+ type TestAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & {
141
+ each: TestEachFunction;
142
+ skipIf(condition: any): ChainableTestAPI<ExtraContext>;
143
+ runIf(condition: any): ChainableTestAPI<ExtraContext>;
144
+ };
145
+ type ChainableSuiteAPI<ExtraContext = {}> = ChainableFunction<'concurrent' | 'only' | 'skip' | 'todo' | 'shuffle', [
146
+ name: string,
147
+ factory?: SuiteFactory<ExtraContext>,
148
+ options?: number | TestOptions
149
+ ], SuiteCollector<ExtraContext>, {
150
+ each: TestEachFunction;
151
+ <T extends ExtraContext>(name: string, factory?: SuiteFactory<T>): SuiteCollector<T>;
152
+ }>;
153
+ type SuiteAPI<ExtraContext = {}> = ChainableSuiteAPI<ExtraContext> & {
154
+ each: SuiteEachFunction;
155
+ skipIf(condition: any): ChainableSuiteAPI<ExtraContext>;
156
+ runIf(condition: any): ChainableSuiteAPI<ExtraContext>;
157
+ };
158
+ type HookListener<T extends any[], Return = void> = (...args: T) => Awaitable<Return>;
159
+ type HookCleanupCallback = (() => Awaitable<unknown>) | void;
160
+ interface SuiteHooks<ExtraContext = {}> {
161
+ beforeAll: HookListener<[Suite | File], HookCleanupCallback>[];
162
+ afterAll: HookListener<[Suite | File]>[];
163
+ beforeEach: HookListener<[TestContext & ExtraContext, Suite], HookCleanupCallback>[];
164
+ afterEach: HookListener<[TestContext & ExtraContext, Suite]>[];
165
+ }
166
+ interface SuiteCollector<ExtraContext = {}> {
167
+ readonly name: string;
168
+ readonly mode: RunMode;
169
+ type: 'collector';
170
+ test: TestAPI<ExtraContext>;
171
+ tasks: (Suite | TaskCustom | Test | SuiteCollector<ExtraContext>)[];
172
+ custom: (name: string) => TaskCustom;
173
+ collect: (file?: File) => Promise<Suite>;
174
+ clear: () => void;
175
+ on: <T extends keyof SuiteHooks<ExtraContext>>(name: T, ...fn: SuiteHooks<ExtraContext>[T]) => void;
176
+ }
177
+ type SuiteFactory<ExtraContext = {}> = (test: (name: string, fn: TestFunction<ExtraContext>) => void) => Awaitable<void>;
178
+ interface RuntimeContext {
179
+ tasks: (SuiteCollector | Test)[];
180
+ currentSuite: SuiteCollector | null;
181
+ }
182
+ interface TestContext {
183
+ /**
184
+ * Metadata of the current test
185
+ */
186
+ meta: Readonly<Test>;
187
+ /**
188
+ * Extract hooks on test failed
189
+ */
190
+ onTestFailed: (fn: OnTestFailedHandler) => void;
191
+ }
192
+ type OnTestFailedHandler = (result: TaskResult) => Awaitable<void>;
193
+ type SequenceHooks = 'stack' | 'list' | 'parallel';
194
+
195
+ export { ChainableFunction as C, DoneCallback as D, ErrorWithDiff as E, File as F, HookListener as H, OnTestFailedHandler as O, ParsedStack as P, RunMode as R, SuiteAPI as S, Task as T, TestAPI as a, SuiteCollector as b, SuiteHooks as c, TestContext as d, Suite as e, HookCleanupCallback as f, Test as g, TaskState as h, TaskBase as i, TaskCustom as j, TaskResult as k, TaskResultPack as l, TestFunction as m, TestOptions as n, SuiteFactory as o, RuntimeContext as p, SequenceHooks as q, createChainable as r, serializeError as s, processError as t, replaceAsymmetricMatcher as u };
@@ -0,0 +1,3 @@
1
+ export { D as DoneCallback, F as File, f as HookCleanupCallback, H as HookListener, O as OnTestFailedHandler, R as RunMode, p as RuntimeContext, q as SequenceHooks, e as Suite, S as SuiteAPI, b as SuiteCollector, o as SuiteFactory, c as SuiteHooks, T as Task, i as TaskBase, j as TaskCustom, k as TaskResult, l as TaskResultPack, h as TaskState, g as Test, a as TestAPI, d as TestContext, m as TestFunction, n as TestOptions } from './tasks-e1fc71d1.js';
2
+ export { V as VitestRunner, a as VitestRunnerConfig, c as VitestRunnerConstructor, b as VitestRunnerImportSource } from './runner-93cc9c0d.js';
3
+ import '@vitest/utils';
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,25 @@
1
+ import { e as Suite, T as Task, g as Test, j as TaskCustom } from './tasks-e1fc71d1.js';
2
+ export { C as ChainableFunction, E as ErrorWithDiff, P as ParsedStack, r as createChainable, t as processError, u as replaceAsymmetricMatcher, s as serializeError } from './tasks-e1fc71d1.js';
3
+ import { Arrayable } from '@vitest/utils';
4
+
5
+ /**
6
+ * If any tasks been marked as `only`, mark all other tasks as `skip`.
7
+ */
8
+ declare function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, parentIsOnly?: boolean, allowOnly?: boolean): void;
9
+ declare function someTasksAreOnly(suite: Suite): boolean;
10
+ declare function generateHash(str: string): string;
11
+ declare function calculateSuiteHash(parent: Suite): void;
12
+
13
+ /**
14
+ * Partition in tasks groups by consecutive concurrent
15
+ */
16
+ declare function partitionSuiteChildren(suite: Suite): Task[][];
17
+
18
+ declare function getTests(suite: Arrayable<Task>): (Test | TaskCustom)[];
19
+ declare function getTasks(tasks?: Arrayable<Task>): Task[];
20
+ declare function getSuites(suite: Arrayable<Task>): Suite[];
21
+ declare function hasTests(suite: Arrayable<Suite>): boolean;
22
+ declare function hasFailed(suite: Arrayable<Task>): boolean;
23
+ declare function getNames(task: Task): string[];
24
+
25
+ export { calculateSuiteHash, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, partitionSuiteChildren, someTasksAreOnly };
package/dist/utils.js ADDED
@@ -0,0 +1,2 @@
1
+ export { a as calculateSuiteHash, c as createChainable, g as generateHash, k as getNames, j as getSuites, f as getTasks, e as getTests, d as hasFailed, h as hasTests, i as interpretTaskModes, b as partitionSuiteChildren, p as processError, r as replaceAsymmetricMatcher, l as serializeError, s as someTasksAreOnly } from './chunk-tasks.js';
2
+ import '@vitest/utils';
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@vitest/runner",
3
+ "type": "module",
4
+ "version": "0.28.0",
5
+ "description": "Vitest test runner",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/vitest-dev/vitest.git",
10
+ "directory": "packages/runner"
11
+ },
12
+ "sideEffects": true,
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ },
18
+ "./utils": {
19
+ "types": "./dist/utils.d.ts",
20
+ "import": "./dist/utils.js"
21
+ },
22
+ "./types": {
23
+ "types": "./dist/types.d.ts",
24
+ "import": "./dist/types.js"
25
+ },
26
+ "./*": "./*"
27
+ },
28
+ "main": "./dist/index.js",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "files": [
32
+ "dist",
33
+ "*.d.ts"
34
+ ],
35
+ "dependencies": {
36
+ "p-limit": "^4.0.0",
37
+ "pathe": "^1.1.0",
38
+ "@vitest/utils": "0.28.0"
39
+ },
40
+ "scripts": {
41
+ "build": "rimraf dist && rollup -c",
42
+ "dev": "rollup -c --watch"
43
+ }
44
+ }
package/types.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/types.js'
package/utils.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/utils.js'