@vitest/runner 4.0.0-beta.9 → 4.0.1
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/chunk-tasks.js +332 -0
- package/dist/{tasks.d-Bsp8b7Fx.d.ts → hooks.d-C0RE9A6t.d.ts} +128 -37
- package/dist/index.d.ts +3 -120
- package/dist/index.js +1988 -4
- package/dist/types.d.ts +10 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -3
- package/package.json +3 -4
- package/dist/chunk-hooks.js +0 -2253
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { processError } from '@vitest/utils/error';
|
|
2
|
+
import { parseSingleStack } from '@vitest/utils/source-map';
|
|
3
|
+
import { relative } from 'pathe';
|
|
4
|
+
import { toArray } from '@vitest/utils/helpers';
|
|
5
|
+
|
|
6
|
+
function createChainable(keys, fn) {
|
|
7
|
+
function create(context) {
|
|
8
|
+
const chain = function(...args) {
|
|
9
|
+
return fn.apply(context, args);
|
|
10
|
+
};
|
|
11
|
+
Object.assign(chain, fn);
|
|
12
|
+
chain.withContext = () => chain.bind(context);
|
|
13
|
+
chain.setContext = (key, value) => {
|
|
14
|
+
context[key] = value;
|
|
15
|
+
};
|
|
16
|
+
chain.mergeContext = (ctx) => {
|
|
17
|
+
Object.assign(context, ctx);
|
|
18
|
+
};
|
|
19
|
+
for (const key of keys) {
|
|
20
|
+
Object.defineProperty(chain, key, { get() {
|
|
21
|
+
return create({
|
|
22
|
+
...context,
|
|
23
|
+
[key]: true
|
|
24
|
+
});
|
|
25
|
+
} });
|
|
26
|
+
}
|
|
27
|
+
return chain;
|
|
28
|
+
}
|
|
29
|
+
const chain = create({});
|
|
30
|
+
chain.fn = fn;
|
|
31
|
+
return chain;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* If any tasks been marked as `only`, mark all other tasks as `skip`.
|
|
36
|
+
*/
|
|
37
|
+
function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIsOnly, allowOnly) {
|
|
38
|
+
const matchedLocations = [];
|
|
39
|
+
const traverseSuite = (suite, parentIsOnly, parentMatchedWithLocation) => {
|
|
40
|
+
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
|
41
|
+
suite.tasks.forEach((t) => {
|
|
42
|
+
// Check if either the parent suite or the task itself are marked as included
|
|
43
|
+
const includeTask = suiteIsOnly || t.mode === "only";
|
|
44
|
+
if (onlyMode) {
|
|
45
|
+
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
|
46
|
+
// Don't skip this suite
|
|
47
|
+
if (t.mode === "only") {
|
|
48
|
+
checkAllowOnly(t, allowOnly);
|
|
49
|
+
t.mode = "run";
|
|
50
|
+
}
|
|
51
|
+
} else if (t.mode === "run" && !includeTask) {
|
|
52
|
+
t.mode = "skip";
|
|
53
|
+
} else if (t.mode === "only") {
|
|
54
|
+
checkAllowOnly(t, allowOnly);
|
|
55
|
+
t.mode = "run";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
let hasLocationMatch = parentMatchedWithLocation;
|
|
59
|
+
// Match test location against provided locations, only run if present
|
|
60
|
+
// in `testLocations`. Note: if `includeTaskLocations` is not enabled,
|
|
61
|
+
// all test will be skipped.
|
|
62
|
+
if (testLocations !== undefined && testLocations.length !== 0) {
|
|
63
|
+
if (t.location && (testLocations === null || testLocations === void 0 ? void 0 : testLocations.includes(t.location.line))) {
|
|
64
|
+
t.mode = "run";
|
|
65
|
+
matchedLocations.push(t.location.line);
|
|
66
|
+
hasLocationMatch = true;
|
|
67
|
+
} else if (parentMatchedWithLocation) {
|
|
68
|
+
t.mode = "run";
|
|
69
|
+
} else if (t.type === "test") {
|
|
70
|
+
t.mode = "skip";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (t.type === "test") {
|
|
74
|
+
if (namePattern && !getTaskFullName(t).match(namePattern)) {
|
|
75
|
+
t.mode = "skip";
|
|
76
|
+
}
|
|
77
|
+
} else if (t.type === "suite") {
|
|
78
|
+
if (t.mode === "skip") {
|
|
79
|
+
skipAllTasks(t);
|
|
80
|
+
} else if (t.mode === "todo") {
|
|
81
|
+
todoAllTasks(t);
|
|
82
|
+
} else {
|
|
83
|
+
traverseSuite(t, includeTask, hasLocationMatch);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// if all subtasks are skipped, mark as skip
|
|
88
|
+
if (suite.mode === "run" || suite.mode === "queued") {
|
|
89
|
+
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run" && i.mode !== "queued")) {
|
|
90
|
+
suite.mode = "skip";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
traverseSuite(file, parentIsOnly, false);
|
|
95
|
+
const nonMatching = testLocations === null || testLocations === void 0 ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
|
|
96
|
+
if (nonMatching && nonMatching.length !== 0) {
|
|
97
|
+
const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
|
|
98
|
+
if (file.result === undefined) {
|
|
99
|
+
file.result = {
|
|
100
|
+
state: "fail",
|
|
101
|
+
errors: []
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (file.result.errors === undefined) {
|
|
105
|
+
file.result.errors = [];
|
|
106
|
+
}
|
|
107
|
+
file.result.errors.push(processError(new Error(`No test found in ${file.name} in ${message}`)));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function getTaskFullName(task) {
|
|
111
|
+
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
|
112
|
+
}
|
|
113
|
+
function someTasksAreOnly(suite) {
|
|
114
|
+
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
|
115
|
+
}
|
|
116
|
+
function skipAllTasks(suite) {
|
|
117
|
+
suite.tasks.forEach((t) => {
|
|
118
|
+
if (t.mode === "run" || t.mode === "queued") {
|
|
119
|
+
t.mode = "skip";
|
|
120
|
+
if (t.type === "suite") {
|
|
121
|
+
skipAllTasks(t);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function todoAllTasks(suite) {
|
|
127
|
+
suite.tasks.forEach((t) => {
|
|
128
|
+
if (t.mode === "run" || t.mode === "queued") {
|
|
129
|
+
t.mode = "todo";
|
|
130
|
+
if (t.type === "suite") {
|
|
131
|
+
todoAllTasks(t);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function checkAllowOnly(task, allowOnly) {
|
|
137
|
+
if (allowOnly) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
|
|
141
|
+
task.result = {
|
|
142
|
+
state: "fail",
|
|
143
|
+
errors: [error]
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
147
|
+
function generateHash(str) {
|
|
148
|
+
let hash = 0;
|
|
149
|
+
if (str.length === 0) {
|
|
150
|
+
return `${hash}`;
|
|
151
|
+
}
|
|
152
|
+
for (let i = 0; i < str.length; i++) {
|
|
153
|
+
const char = str.charCodeAt(i);
|
|
154
|
+
hash = (hash << 5) - hash + char;
|
|
155
|
+
hash = hash & hash;
|
|
156
|
+
}
|
|
157
|
+
return `${hash}`;
|
|
158
|
+
}
|
|
159
|
+
function calculateSuiteHash(parent) {
|
|
160
|
+
parent.tasks.forEach((t, idx) => {
|
|
161
|
+
t.id = `${parent.id}_${idx}`;
|
|
162
|
+
if (t.type === "suite") {
|
|
163
|
+
calculateSuiteHash(t);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function createFileTask(filepath, root, projectName, pool) {
|
|
168
|
+
const path = relative(root, filepath);
|
|
169
|
+
const file = {
|
|
170
|
+
id: generateFileHash(path, projectName),
|
|
171
|
+
name: path,
|
|
172
|
+
type: "suite",
|
|
173
|
+
mode: "queued",
|
|
174
|
+
filepath,
|
|
175
|
+
tasks: [],
|
|
176
|
+
meta: Object.create(null),
|
|
177
|
+
projectName,
|
|
178
|
+
file: undefined,
|
|
179
|
+
pool
|
|
180
|
+
};
|
|
181
|
+
file.file = file;
|
|
182
|
+
return file;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Generate a unique ID for a file based on its path and project name
|
|
186
|
+
* @param file File relative to the root of the project to keep ID the same between different machines
|
|
187
|
+
* @param projectName The name of the test project
|
|
188
|
+
*/
|
|
189
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
190
|
+
function generateFileHash(file, projectName) {
|
|
191
|
+
return /* @__PURE__ */ generateHash(`${file}${projectName || ""}`);
|
|
192
|
+
}
|
|
193
|
+
function findTestFileStackTrace(testFilePath, error) {
|
|
194
|
+
// first line is the error message
|
|
195
|
+
const lines = error.split("\n").slice(1);
|
|
196
|
+
for (const line of lines) {
|
|
197
|
+
const stack = parseSingleStack(line);
|
|
198
|
+
if (stack && stack.file === testFilePath) {
|
|
199
|
+
return stack;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Return a function for running multiple async operations with limited concurrency.
|
|
206
|
+
*/
|
|
207
|
+
function limitConcurrency(concurrency = Infinity) {
|
|
208
|
+
// The number of currently active + pending tasks.
|
|
209
|
+
let count = 0;
|
|
210
|
+
// The head and tail of the pending task queue, built using a singly linked list.
|
|
211
|
+
// Both head and tail are initially undefined, signifying an empty queue.
|
|
212
|
+
// They both become undefined again whenever there are no pending tasks.
|
|
213
|
+
let head;
|
|
214
|
+
let tail;
|
|
215
|
+
// A bookkeeping function executed whenever a task has been run to completion.
|
|
216
|
+
const finish = () => {
|
|
217
|
+
count--;
|
|
218
|
+
// Check if there are further pending tasks in the queue.
|
|
219
|
+
if (head) {
|
|
220
|
+
// Allow the next pending task to run and pop it from the queue.
|
|
221
|
+
head[0]();
|
|
222
|
+
head = head[1];
|
|
223
|
+
// The head may now be undefined if there are no further pending tasks.
|
|
224
|
+
// In that case, set tail to undefined as well.
|
|
225
|
+
tail = head && tail;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
return (func, ...args) => {
|
|
229
|
+
// Create a promise chain that:
|
|
230
|
+
// 1. Waits for its turn in the task queue (if necessary).
|
|
231
|
+
// 2. Runs the task.
|
|
232
|
+
// 3. Allows the next pending task (if any) to run.
|
|
233
|
+
return new Promise((resolve) => {
|
|
234
|
+
if (count++ < concurrency) {
|
|
235
|
+
// No need to queue if fewer than maxConcurrency tasks are running.
|
|
236
|
+
resolve();
|
|
237
|
+
} else if (tail) {
|
|
238
|
+
// There are pending tasks, so append to the queue.
|
|
239
|
+
tail = tail[1] = [resolve];
|
|
240
|
+
} else {
|
|
241
|
+
// No other pending tasks, initialize the queue with a new tail and head.
|
|
242
|
+
head = tail = [resolve];
|
|
243
|
+
}
|
|
244
|
+
}).then(() => {
|
|
245
|
+
// Running func here ensures that even a non-thenable result or an
|
|
246
|
+
// immediately thrown error gets wrapped into a Promise.
|
|
247
|
+
return func(...args);
|
|
248
|
+
}).finally(finish);
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Partition in tasks groups by consecutive concurrent
|
|
254
|
+
*/
|
|
255
|
+
function partitionSuiteChildren(suite) {
|
|
256
|
+
let tasksGroup = [];
|
|
257
|
+
const tasksGroups = [];
|
|
258
|
+
for (const c of suite.tasks) {
|
|
259
|
+
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
|
|
260
|
+
tasksGroup.push(c);
|
|
261
|
+
} else {
|
|
262
|
+
tasksGroups.push(tasksGroup);
|
|
263
|
+
tasksGroup = [c];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (tasksGroup.length > 0) {
|
|
267
|
+
tasksGroups.push(tasksGroup);
|
|
268
|
+
}
|
|
269
|
+
return tasksGroups;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isTestCase(s) {
|
|
273
|
+
return s.type === "test";
|
|
274
|
+
}
|
|
275
|
+
function getTests(suite) {
|
|
276
|
+
const tests = [];
|
|
277
|
+
const arraySuites = toArray(suite);
|
|
278
|
+
for (const s of arraySuites) {
|
|
279
|
+
if (isTestCase(s)) {
|
|
280
|
+
tests.push(s);
|
|
281
|
+
} else {
|
|
282
|
+
for (const task of s.tasks) {
|
|
283
|
+
if (isTestCase(task)) {
|
|
284
|
+
tests.push(task);
|
|
285
|
+
} else {
|
|
286
|
+
const taskTests = getTests(task);
|
|
287
|
+
for (const test of taskTests) {
|
|
288
|
+
tests.push(test);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return tests;
|
|
295
|
+
}
|
|
296
|
+
function getTasks(tasks = []) {
|
|
297
|
+
return toArray(tasks).flatMap((s) => isTestCase(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
|
298
|
+
}
|
|
299
|
+
function getSuites(suite) {
|
|
300
|
+
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
|
301
|
+
}
|
|
302
|
+
function hasTests(suite) {
|
|
303
|
+
return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
|
|
304
|
+
}
|
|
305
|
+
function hasFailed(suite) {
|
|
306
|
+
return toArray(suite).some((s) => {
|
|
307
|
+
var _s$result;
|
|
308
|
+
return ((_s$result = s.result) === null || _s$result === void 0 ? void 0 : _s$result.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
function getNames(task) {
|
|
312
|
+
const names = [task.name];
|
|
313
|
+
let current = task;
|
|
314
|
+
while (current === null || current === void 0 ? void 0 : current.suite) {
|
|
315
|
+
current = current.suite;
|
|
316
|
+
if (current === null || current === void 0 ? void 0 : current.name) {
|
|
317
|
+
names.unshift(current.name);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (current !== task.file) {
|
|
321
|
+
names.unshift(task.file.name);
|
|
322
|
+
}
|
|
323
|
+
return names;
|
|
324
|
+
}
|
|
325
|
+
function getFullName(task, separator = " > ") {
|
|
326
|
+
return getNames(task).join(separator);
|
|
327
|
+
}
|
|
328
|
+
function getTestName(task, separator = " > ") {
|
|
329
|
+
return getNames(task).slice(1).join(separator);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export { calculateSuiteHash as a, createFileTask as b, createChainable as c, generateHash as d, getFullName as e, findTestFileStackTrace as f, generateFileHash as g, getNames as h, interpretTaskModes as i, getSuites as j, getTasks as k, limitConcurrency as l, getTestName as m, getTests as n, hasFailed as o, partitionSuiteChildren as p, hasTests as q, isTestCase as r, someTasksAreOnly as s };
|
|
@@ -251,7 +251,6 @@ interface TestAnnotation {
|
|
|
251
251
|
}
|
|
252
252
|
type Task = Test | Suite | File;
|
|
253
253
|
type TestFunction<ExtraContext = object> = (context: TestContext & ExtraContext) => Awaitable<any> | void;
|
|
254
|
-
// jest's ExtractEachCallbackArgs
|
|
255
254
|
type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
|
|
256
255
|
1: [T[0]];
|
|
257
256
|
2: [T[0], T[1]];
|
|
@@ -266,11 +265,7 @@ type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
|
|
|
266
265
|
fallback: Array<T extends ReadonlyArray<infer U> ? U : any>;
|
|
267
266
|
}[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"];
|
|
268
267
|
interface EachFunctionReturn<T extends any[]> {
|
|
269
|
-
|
|
270
|
-
* @deprecated Use options as the second argument instead
|
|
271
|
-
*/
|
|
272
|
-
(name: string | Function, fn: (...args: T) => Awaitable<void>, options: TestCollectorOptions): void;
|
|
273
|
-
(name: string | Function, fn: (...args: T) => Awaitable<void>, options?: number | TestCollectorOptions): void;
|
|
268
|
+
(name: string | Function, fn: (...args: T) => Awaitable<void>, options?: number): void;
|
|
274
269
|
(name: string | Function, options: TestCollectorOptions, fn: (...args: T) => Awaitable<void>): void;
|
|
275
270
|
}
|
|
276
271
|
interface TestEachFunction {
|
|
@@ -287,14 +282,7 @@ interface TestForFunctionReturn<
|
|
|
287
282
|
(name: string | Function, options: TestCollectorOptions, fn: (args: Arg, context: Context) => Awaitable<void>): void;
|
|
288
283
|
}
|
|
289
284
|
interface TestForFunction<ExtraContext> {
|
|
290
|
-
// test.for([1, 2, 3])
|
|
291
|
-
// test.for([[1, 2], [3, 4, 5]])
|
|
292
285
|
<T>(cases: ReadonlyArray<T>): TestForFunctionReturn<T, TestContext & ExtraContext>;
|
|
293
|
-
// test.for`
|
|
294
|
-
// a | b
|
|
295
|
-
// {1} | {2}
|
|
296
|
-
// {3} | {4}
|
|
297
|
-
// `
|
|
298
286
|
(strings: TemplateStringsArray, ...values: any[]): TestForFunctionReturn<any, TestContext & ExtraContext>;
|
|
299
287
|
}
|
|
300
288
|
interface SuiteForFunction {
|
|
@@ -302,11 +290,7 @@ interface SuiteForFunction {
|
|
|
302
290
|
(...args: [TemplateStringsArray, ...any]): EachFunctionReturn<any[]>;
|
|
303
291
|
}
|
|
304
292
|
interface TestCollectorCallable<C = object> {
|
|
305
|
-
|
|
306
|
-
* @deprecated Use options as the second argument instead
|
|
307
|
-
*/
|
|
308
|
-
<ExtraContext extends C>(name: string | Function, fn: TestFunction<ExtraContext>, options: TestCollectorOptions): void;
|
|
309
|
-
<ExtraContext extends C>(name: string | Function, fn?: TestFunction<ExtraContext>, options?: number | TestCollectorOptions): void;
|
|
293
|
+
<ExtraContext extends C>(name: string | Function, fn?: TestFunction<ExtraContext>, options?: number): void;
|
|
310
294
|
<ExtraContext extends C>(name: string | Function, options?: TestCollectorOptions, fn?: TestFunction<ExtraContext>): void;
|
|
311
295
|
}
|
|
312
296
|
type ChainableTestAPI<ExtraContext = object> = ChainableFunction<"concurrent" | "sequential" | "only" | "skip" | "todo" | "fails", TestCollectorCallable<ExtraContext>, {
|
|
@@ -368,7 +352,13 @@ interface ExtendedAPI<ExtraContext> {
|
|
|
368
352
|
skipIf: (condition: any) => ChainableTestAPI<ExtraContext>;
|
|
369
353
|
runIf: (condition: any) => ChainableTestAPI<ExtraContext>;
|
|
370
354
|
}
|
|
371
|
-
|
|
355
|
+
interface Hooks<ExtraContext> {
|
|
356
|
+
beforeAll: typeof beforeAll;
|
|
357
|
+
afterAll: typeof afterAll;
|
|
358
|
+
beforeEach: typeof beforeEach<ExtraContext>;
|
|
359
|
+
afterEach: typeof afterEach<ExtraContext>;
|
|
360
|
+
}
|
|
361
|
+
type TestAPI<ExtraContext = object> = ChainableTestAPI<ExtraContext> & ExtendedAPI<ExtraContext> & Hooks<ExtraContext> & {
|
|
372
362
|
extend: <T extends Record<string, any> = object>(fixtures: Fixtures<T, ExtraContext>) => TestAPI<{ [K in keyof T | keyof ExtraContext] : K extends keyof T ? T[K] : K extends keyof ExtraContext ? ExtraContext[K] : never }>;
|
|
373
363
|
scoped: (fixtures: Fixtures<Partial<ExtraContext>>) => void;
|
|
374
364
|
};
|
|
@@ -410,11 +400,7 @@ type Fixtures<
|
|
|
410
400
|
> = { [K in keyof T] : Fixture<T, K, ExtraContext & TestContext> | [Fixture<T, K, ExtraContext & TestContext>, FixtureOptions?] };
|
|
411
401
|
type InferFixturesTypes<T> = T extends TestAPI<infer C> ? C : T;
|
|
412
402
|
interface SuiteCollectorCallable<ExtraContext = object> {
|
|
413
|
-
|
|
414
|
-
* @deprecated Use options as the second argument instead
|
|
415
|
-
*/
|
|
416
|
-
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, fn: SuiteFactory<OverrideExtraContext>, options: TestOptions): SuiteCollector<OverrideExtraContext>;
|
|
417
|
-
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, fn?: SuiteFactory<OverrideExtraContext>, options?: number | TestOptions): SuiteCollector<OverrideExtraContext>;
|
|
403
|
+
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, fn?: SuiteFactory<OverrideExtraContext>, options?: number): SuiteCollector<OverrideExtraContext>;
|
|
418
404
|
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, options: TestOptions, fn?: SuiteFactory<OverrideExtraContext>): SuiteCollector<OverrideExtraContext>;
|
|
419
405
|
}
|
|
420
406
|
type ChainableSuiteAPI<ExtraContext = object> = ChainableFunction<"concurrent" | "sequential" | "only" | "skip" | "todo" | "shuffle", SuiteCollectorCallable<ExtraContext>, {
|
|
@@ -425,17 +411,6 @@ type SuiteAPI<ExtraContext = object> = ChainableSuiteAPI<ExtraContext> & {
|
|
|
425
411
|
skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
|
|
426
412
|
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
|
|
427
413
|
};
|
|
428
|
-
/**
|
|
429
|
-
* @deprecated
|
|
430
|
-
*/
|
|
431
|
-
type HookListener<
|
|
432
|
-
T extends any[],
|
|
433
|
-
Return = void
|
|
434
|
-
> = (...args: T) => Awaitable<Return>;
|
|
435
|
-
/**
|
|
436
|
-
* @deprecated
|
|
437
|
-
*/
|
|
438
|
-
type HookCleanupCallback = unknown;
|
|
439
414
|
interface BeforeAllListener {
|
|
440
415
|
(suite: Readonly<Suite | File>): Awaitable<unknown>;
|
|
441
416
|
}
|
|
@@ -544,5 +519,121 @@ interface TaskHook<HookListener> {
|
|
|
544
519
|
type SequenceHooks = "stack" | "list" | "parallel";
|
|
545
520
|
type SequenceSetupFiles = "list" | "parallel";
|
|
546
521
|
|
|
547
|
-
|
|
548
|
-
|
|
522
|
+
/**
|
|
523
|
+
* Registers a callback function to be executed once before all tests within the current suite.
|
|
524
|
+
* 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.
|
|
525
|
+
*
|
|
526
|
+
* **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.
|
|
527
|
+
*
|
|
528
|
+
* @param {Function} fn - The callback function to be executed before all tests.
|
|
529
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
530
|
+
* @returns {void}
|
|
531
|
+
* @example
|
|
532
|
+
* ```ts
|
|
533
|
+
* // Example of using beforeAll to set up a database connection
|
|
534
|
+
* beforeAll(async () => {
|
|
535
|
+
* await database.connect();
|
|
536
|
+
* });
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
declare function beforeAll(fn: BeforeAllListener, timeout?: number): void;
|
|
540
|
+
/**
|
|
541
|
+
* Registers a callback function to be executed once after all tests within the current suite have completed.
|
|
542
|
+
* 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.
|
|
543
|
+
*
|
|
544
|
+
* **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.
|
|
545
|
+
*
|
|
546
|
+
* @param {Function} fn - The callback function to be executed after all tests.
|
|
547
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
548
|
+
* @returns {void}
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* // Example of using afterAll to close a database connection
|
|
552
|
+
* afterAll(async () => {
|
|
553
|
+
* await database.disconnect();
|
|
554
|
+
* });
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
declare function afterAll(fn: AfterAllListener, timeout?: number): void;
|
|
558
|
+
/**
|
|
559
|
+
* Registers a callback function to be executed before each test within the current suite.
|
|
560
|
+
* 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.
|
|
561
|
+
*
|
|
562
|
+
* **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.
|
|
563
|
+
*
|
|
564
|
+
* @param {Function} fn - The callback function to be executed before each test. This function receives an `TestContext` parameter if additional test context is needed.
|
|
565
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
566
|
+
* @returns {void}
|
|
567
|
+
* @example
|
|
568
|
+
* ```ts
|
|
569
|
+
* // Example of using beforeEach to reset a database state
|
|
570
|
+
* beforeEach(async () => {
|
|
571
|
+
* await database.reset();
|
|
572
|
+
* });
|
|
573
|
+
* ```
|
|
574
|
+
*/
|
|
575
|
+
declare function beforeEach<ExtraContext = object>(fn: BeforeEachListener<ExtraContext>, timeout?: number): void;
|
|
576
|
+
/**
|
|
577
|
+
* Registers a callback function to be executed after each test within the current suite has completed.
|
|
578
|
+
* 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.
|
|
579
|
+
*
|
|
580
|
+
* **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.
|
|
581
|
+
*
|
|
582
|
+
* @param {Function} fn - The callback function to be executed after each test. This function receives an `TestContext` parameter if additional test context is needed.
|
|
583
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
584
|
+
* @returns {void}
|
|
585
|
+
* @example
|
|
586
|
+
* ```ts
|
|
587
|
+
* // Example of using afterEach to delete temporary files created during a test
|
|
588
|
+
* afterEach(async () => {
|
|
589
|
+
* await fileSystem.deleteTempFiles();
|
|
590
|
+
* });
|
|
591
|
+
* ```
|
|
592
|
+
*/
|
|
593
|
+
declare function afterEach<ExtraContext = object>(fn: AfterEachListener<ExtraContext>, timeout?: number): void;
|
|
594
|
+
/**
|
|
595
|
+
* Registers a callback function to be executed when a test fails within the current suite.
|
|
596
|
+
* This function allows for custom actions to be performed in response to test failures, such as logging, cleanup, or additional diagnostics.
|
|
597
|
+
*
|
|
598
|
+
* **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.
|
|
599
|
+
*
|
|
600
|
+
* @param {Function} fn - The callback function to be executed upon a test failure. The function receives the test result (including errors).
|
|
601
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
602
|
+
* @throws {Error} Throws an error if the function is not called within a test.
|
|
603
|
+
* @returns {void}
|
|
604
|
+
* @example
|
|
605
|
+
* ```ts
|
|
606
|
+
* // Example of using onTestFailed to log failure details
|
|
607
|
+
* onTestFailed(({ errors }) => {
|
|
608
|
+
* console.log(`Test failed: ${test.name}`, errors);
|
|
609
|
+
* });
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
declare const onTestFailed: TaskHook<OnTestFailedHandler>;
|
|
613
|
+
/**
|
|
614
|
+
* Registers a callback function to be executed when the current test finishes, regardless of the outcome (pass or fail).
|
|
615
|
+
* This function is ideal for performing actions that should occur after every test execution, such as cleanup, logging, or resetting shared resources.
|
|
616
|
+
*
|
|
617
|
+
* 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`.
|
|
618
|
+
*
|
|
619
|
+
* **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.
|
|
620
|
+
*
|
|
621
|
+
* **Note:** The `onTestFinished` hook is not called if the test is canceled with a dynamic `ctx.skip()` call.
|
|
622
|
+
*
|
|
623
|
+
* @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.
|
|
624
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
625
|
+
* @throws {Error} Throws an error if the function is not called within a test.
|
|
626
|
+
* @returns {void}
|
|
627
|
+
* @example
|
|
628
|
+
* ```ts
|
|
629
|
+
* // Example of using onTestFinished for cleanup
|
|
630
|
+
* const db = await connectToDatabase();
|
|
631
|
+
* onTestFinished(async () => {
|
|
632
|
+
* await db.disconnect();
|
|
633
|
+
* });
|
|
634
|
+
* ```
|
|
635
|
+
*/
|
|
636
|
+
declare const onTestFinished: TaskHook<OnTestFinishedHandler>;
|
|
637
|
+
|
|
638
|
+
export { createChainable as X, afterAll as g, afterEach as h, beforeAll as i, beforeEach as j, onTestFinished as k, onTestFailed as o };
|
|
639
|
+
export type { AfterAllListener as A, BeforeAllListener as B, TaskEventPack as C, TaskHook as D, TaskMeta as E, File as F, TaskPopulated as G, TaskResult as H, ImportDuration as I, TaskResultPack as J, TaskState as K, TestAnnotation as L, TestAnnotationLocation as M, TestAttachment as N, OnTestFailedHandler as O, TestContext as P, TestFunction as Q, RunMode as R, Suite as S, Test as T, TestOptions as U, Use as V, ChainableFunction as W, SuiteHooks as a, TaskUpdateEvent as b, Task as c, TestAPI as d, SuiteAPI as e, SuiteCollector as f, AfterEachListener as l, BeforeEachListener as m, Fixture as n, FixtureFn as p, FixtureOptions as q, Fixtures as r, InferFixturesTypes as s, OnTestFinishedHandler as t, RuntimeContext as u, SequenceHooks as v, SequenceSetupFiles as w, SuiteFactory as x, TaskBase as y, TaskCustomOptions as z };
|