@vitest/runner 2.0.0-beta.10 → 2.0.0-beta.11
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 +47 -22
- package/dist/index.d.ts +4 -4
- package/dist/index.js +306 -149
- package/dist/{tasks-CcHkacEF.d.ts → tasks-BP89OzIP.d.ts} +14 -4
- package/dist/types.d.ts +3 -3
- package/dist/utils.d.ts +4 -3
- package/dist/utils.js +1 -1
- package/package.json +2 -2
package/dist/chunk-tasks.js
CHANGED
@@ -13,8 +13,9 @@ function partitionSuiteChildren(suite) {
|
|
13
13
|
tasksGroup = [c];
|
14
14
|
}
|
15
15
|
}
|
16
|
-
if (tasksGroup.length > 0)
|
16
|
+
if (tasksGroup.length > 0) {
|
17
17
|
tasksGroups.push(tasksGroup);
|
18
|
+
}
|
18
19
|
return tasksGroups;
|
19
20
|
}
|
20
21
|
|
@@ -36,39 +37,50 @@ function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnl
|
|
36
37
|
}
|
37
38
|
}
|
38
39
|
if (t.type === "test") {
|
39
|
-
if (namePattern && !getTaskFullName(t).match(namePattern))
|
40
|
+
if (namePattern && !getTaskFullName(t).match(namePattern)) {
|
40
41
|
t.mode = "skip";
|
42
|
+
}
|
41
43
|
} else if (t.type === "suite") {
|
42
|
-
if (t.mode === "skip")
|
44
|
+
if (t.mode === "skip") {
|
43
45
|
skipAllTasks(t);
|
44
|
-
else
|
46
|
+
} else {
|
45
47
|
interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
|
48
|
+
}
|
46
49
|
}
|
47
50
|
});
|
48
51
|
if (suite.mode === "run") {
|
49
|
-
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run"))
|
52
|
+
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run")) {
|
50
53
|
suite.mode = "skip";
|
54
|
+
}
|
51
55
|
}
|
52
56
|
}
|
53
57
|
function getTaskFullName(task) {
|
54
58
|
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
55
59
|
}
|
56
60
|
function someTasksAreOnly(suite) {
|
57
|
-
return suite.tasks.some(
|
61
|
+
return suite.tasks.some(
|
62
|
+
(t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t)
|
63
|
+
);
|
58
64
|
}
|
59
65
|
function skipAllTasks(suite) {
|
60
66
|
suite.tasks.forEach((t) => {
|
61
67
|
if (t.mode === "run") {
|
62
68
|
t.mode = "skip";
|
63
|
-
if (t.type === "suite")
|
69
|
+
if (t.type === "suite") {
|
64
70
|
skipAllTasks(t);
|
71
|
+
}
|
65
72
|
}
|
66
73
|
});
|
67
74
|
}
|
68
75
|
function checkAllowOnly(task, allowOnly) {
|
69
|
-
if (allowOnly)
|
76
|
+
if (allowOnly) {
|
70
77
|
return;
|
71
|
-
|
78
|
+
}
|
79
|
+
const error = processError(
|
80
|
+
new Error(
|
81
|
+
"[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"
|
82
|
+
)
|
83
|
+
);
|
72
84
|
task.result = {
|
73
85
|
state: "fail",
|
74
86
|
errors: [error]
|
@@ -76,8 +88,9 @@ function checkAllowOnly(task, allowOnly) {
|
|
76
88
|
}
|
77
89
|
function generateHash(str) {
|
78
90
|
let hash = 0;
|
79
|
-
if (str.length === 0)
|
91
|
+
if (str.length === 0) {
|
80
92
|
return `${hash}`;
|
93
|
+
}
|
81
94
|
for (let i = 0; i < str.length; i++) {
|
82
95
|
const char = str.charCodeAt(i);
|
83
96
|
hash = (hash << 5) - hash + char;
|
@@ -88,8 +101,9 @@ function generateHash(str) {
|
|
88
101
|
function calculateSuiteHash(parent) {
|
89
102
|
parent.tasks.forEach((t, idx) => {
|
90
103
|
t.id = `${parent.id}_${idx}`;
|
91
|
-
if (t.type === "suite")
|
104
|
+
if (t.type === "suite") {
|
92
105
|
calculateSuiteHash(t);
|
106
|
+
}
|
93
107
|
});
|
94
108
|
}
|
95
109
|
function createFileTask(filepath, root, projectName) {
|
@@ -151,8 +165,9 @@ function getTests(suite) {
|
|
151
165
|
tests.push(task);
|
152
166
|
} else {
|
153
167
|
const taskTests = getTests(task);
|
154
|
-
for (const test of taskTests)
|
168
|
+
for (const test of taskTests) {
|
155
169
|
tests.push(test);
|
170
|
+
}
|
156
171
|
}
|
157
172
|
}
|
158
173
|
}
|
@@ -160,31 +175,41 @@ function getTests(suite) {
|
|
160
175
|
return tests;
|
161
176
|
}
|
162
177
|
function getTasks(tasks = []) {
|
163
|
-
return toArray(tasks).flatMap(
|
178
|
+
return toArray(tasks).flatMap(
|
179
|
+
(s) => isAtomTest(s) ? [s] : [s, ...getTasks(s.tasks)]
|
180
|
+
);
|
164
181
|
}
|
165
182
|
function getSuites(suite) {
|
166
|
-
return toArray(suite).flatMap(
|
183
|
+
return toArray(suite).flatMap(
|
184
|
+
(s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []
|
185
|
+
);
|
167
186
|
}
|
168
187
|
function hasTests(suite) {
|
169
|
-
return toArray(suite).some(
|
188
|
+
return toArray(suite).some(
|
189
|
+
(s) => s.tasks.some((c) => isAtomTest(c) || hasTests(c))
|
190
|
+
);
|
170
191
|
}
|
171
192
|
function hasFailed(suite) {
|
172
|
-
return toArray(suite).some(
|
173
|
-
|
174
|
-
|
175
|
-
|
193
|
+
return toArray(suite).some(
|
194
|
+
(s) => {
|
195
|
+
var _a;
|
196
|
+
return ((_a = s.result) == null ? void 0 : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
197
|
+
}
|
198
|
+
);
|
176
199
|
}
|
177
200
|
function getNames(task) {
|
178
201
|
const names = [task.name];
|
179
202
|
let current = task;
|
180
203
|
while (current == null ? void 0 : current.suite) {
|
181
204
|
current = current.suite;
|
182
|
-
if (current == null ? void 0 : current.name)
|
205
|
+
if (current == null ? void 0 : current.name) {
|
183
206
|
names.unshift(current.name);
|
207
|
+
}
|
184
208
|
}
|
185
|
-
if (current !== task.file)
|
209
|
+
if (current !== task.file) {
|
186
210
|
names.unshift(task.file.name);
|
211
|
+
}
|
187
212
|
return names;
|
188
213
|
}
|
189
214
|
|
190
|
-
export { createFileTask as a,
|
215
|
+
export { createFileTask as a, isAtomTest as b, calculateSuiteHash as c, getTests as d, getTasks as e, getSuites as f, generateHash as g, hasTests as h, interpretTaskModes as i, hasFailed as j, getNames as k, createChainable as l, partitionSuiteChildren as p, someTasksAreOnly as s };
|
package/dist/index.d.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { VitestRunner } from './types.js';
|
2
2
|
export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
|
3
|
-
import { T as Task, F as File, d as SuiteAPI, e as TestAPI, f as SuiteCollector, g as CustomAPI, h as SuiteHooks, O as OnTestFailedHandler, i as OnTestFinishedHandler, a as Test, C as Custom, S as Suite } from './tasks-
|
4
|
-
export { D as DoneCallback, E as ExtendedContext, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, R as RunMode, y as RuntimeContext, B as SequenceHooks, G as SequenceSetupFiles, x as SuiteFactory, k as TaskBase, A as TaskContext, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, o as TaskResultPack, j as TaskState, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-
|
3
|
+
import { T as Task, F as File, d as SuiteAPI, e as TestAPI, f as SuiteCollector, g as CustomAPI, h as SuiteHooks, O as OnTestFailedHandler, i as OnTestFinishedHandler, a as Test, C as Custom, S as Suite } from './tasks-BP89OzIP.js';
|
4
|
+
export { D as DoneCallback, E as ExtendedContext, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, R as RunMode, y as RuntimeContext, B as SequenceHooks, G as SequenceSetupFiles, x as SuiteFactory, k as TaskBase, A as TaskContext, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, o as TaskResultPack, j as TaskState, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-BP89OzIP.js';
|
5
5
|
import { Awaitable } from '@vitest/utils';
|
6
6
|
export { processError } from '@vitest/utils/error';
|
7
7
|
import '@vitest/utils/diff';
|
@@ -23,8 +23,8 @@ declare function afterEach<ExtraContext = {}>(fn: SuiteHooks<ExtraContext>['afte
|
|
23
23
|
declare const onTestFailed: (fn: OnTestFailedHandler) => void;
|
24
24
|
declare const onTestFinished: (fn: OnTestFinishedHandler) => void;
|
25
25
|
|
26
|
-
declare function setFn(key: Test | Custom, fn: (
|
27
|
-
declare function getFn<Task = Test | Custom>(key: Task): (
|
26
|
+
declare function setFn(key: Test | Custom, fn: () => Awaitable<void>): void;
|
27
|
+
declare function getFn<Task = Test | Custom>(key: Task): () => Awaitable<void>;
|
28
28
|
declare function setHooks(key: Suite, hooks: SuiteHooks): void;
|
29
29
|
declare function getHooks(key: Suite): SuiteHooks;
|
30
30
|
|
package/dist/index.js
CHANGED
@@ -2,7 +2,7 @@ import limit from 'p-limit';
|
|
2
2
|
import { getSafeTimers, isObject, createDefer, isNegativeNaN, format, objDisplay, objectAttr, toArray, shuffle } from '@vitest/utils';
|
3
3
|
import { processError } from '@vitest/utils/error';
|
4
4
|
export { processError } from '@vitest/utils/error';
|
5
|
-
import {
|
5
|
+
import { l as createChainable, a as createFileTask, c as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, p as partitionSuiteChildren, h as hasTests, j as hasFailed } from './chunk-tasks.js';
|
6
6
|
import { parseSingleStack } from '@vitest/utils/source-map';
|
7
7
|
import 'pathe';
|
8
8
|
|
@@ -53,18 +53,22 @@ async function runWithSuite(suite, fn) {
|
|
53
53
|
collectorContext.currentSuite = prev;
|
54
54
|
}
|
55
55
|
function withTimeout(fn, timeout, isHook = false) {
|
56
|
-
if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY)
|
56
|
+
if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY) {
|
57
57
|
return fn;
|
58
|
+
}
|
58
59
|
const { setTimeout, clearTimeout } = getSafeTimers();
|
59
60
|
return (...args) => {
|
60
|
-
return Promise.race([
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
return Promise.race([
|
62
|
+
fn(...args),
|
63
|
+
new Promise((resolve, reject) => {
|
64
|
+
var _a;
|
65
|
+
const timer = setTimeout(() => {
|
66
|
+
clearTimeout(timer);
|
67
|
+
reject(new Error(makeTimeoutMsg(isHook, timeout)));
|
68
|
+
}, timeout);
|
69
|
+
(_a = timer.unref) == null ? void 0 : _a.call(timer);
|
70
|
+
})
|
71
|
+
]);
|
68
72
|
};
|
69
73
|
}
|
70
74
|
function createTestContext(test, runner) {
|
@@ -94,25 +98,31 @@ If this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as t
|
|
94
98
|
|
95
99
|
function mergeContextFixtures(fixtures, context = {}) {
|
96
100
|
const fixtureOptionKeys = ["auto"];
|
97
|
-
const fixtureArray = Object.entries(fixtures).map(
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
101
|
+
const fixtureArray = Object.entries(fixtures).map(
|
102
|
+
([prop, value]) => {
|
103
|
+
const fixtureItem = { value };
|
104
|
+
if (Array.isArray(value) && value.length >= 2 && isObject(value[1]) && Object.keys(value[1]).some((key) => fixtureOptionKeys.includes(key))) {
|
105
|
+
Object.assign(fixtureItem, value[1]);
|
106
|
+
fixtureItem.value = value[0];
|
107
|
+
}
|
108
|
+
fixtureItem.prop = prop;
|
109
|
+
fixtureItem.isFn = typeof fixtureItem.value === "function";
|
110
|
+
return fixtureItem;
|
102
111
|
}
|
103
|
-
|
104
|
-
|
105
|
-
return fixtureItem;
|
106
|
-
});
|
107
|
-
if (Array.isArray(context.fixtures))
|
112
|
+
);
|
113
|
+
if (Array.isArray(context.fixtures)) {
|
108
114
|
context.fixtures = context.fixtures.concat(fixtureArray);
|
109
|
-
else
|
115
|
+
} else {
|
110
116
|
context.fixtures = fixtureArray;
|
117
|
+
}
|
111
118
|
fixtureArray.forEach((fixture) => {
|
112
119
|
if (fixture.isFn) {
|
113
120
|
const usedProps = getUsedProps(fixture.value);
|
114
|
-
if (usedProps.length)
|
115
|
-
fixture.deps = context.fixtures.filter(
|
121
|
+
if (usedProps.length) {
|
122
|
+
fixture.deps = context.fixtures.filter(
|
123
|
+
({ prop }) => prop !== fixture.prop && usedProps.includes(prop)
|
124
|
+
);
|
125
|
+
}
|
116
126
|
}
|
117
127
|
});
|
118
128
|
return context;
|
@@ -121,36 +131,46 @@ const fixtureValueMaps = /* @__PURE__ */ new Map();
|
|
121
131
|
const cleanupFnArrayMap = /* @__PURE__ */ new Map();
|
122
132
|
async function callFixtureCleanup(context) {
|
123
133
|
const cleanupFnArray = cleanupFnArrayMap.get(context) ?? [];
|
124
|
-
for (const cleanup of cleanupFnArray.reverse())
|
134
|
+
for (const cleanup of cleanupFnArray.reverse()) {
|
125
135
|
await cleanup();
|
136
|
+
}
|
126
137
|
cleanupFnArrayMap.delete(context);
|
127
138
|
}
|
128
139
|
function withFixtures(fn, testContext) {
|
129
140
|
return (hookContext) => {
|
130
141
|
const context = hookContext || testContext;
|
131
|
-
if (!context)
|
142
|
+
if (!context) {
|
132
143
|
return fn({});
|
144
|
+
}
|
133
145
|
const fixtures = getFixture(context);
|
134
|
-
if (!(fixtures == null ? void 0 : fixtures.length))
|
146
|
+
if (!(fixtures == null ? void 0 : fixtures.length)) {
|
135
147
|
return fn(context);
|
148
|
+
}
|
136
149
|
const usedProps = getUsedProps(fn);
|
137
150
|
const hasAutoFixture = fixtures.some(({ auto }) => auto);
|
138
|
-
if (!usedProps.length && !hasAutoFixture)
|
151
|
+
if (!usedProps.length && !hasAutoFixture) {
|
139
152
|
return fn(context);
|
140
|
-
|
153
|
+
}
|
154
|
+
if (!fixtureValueMaps.get(context)) {
|
141
155
|
fixtureValueMaps.set(context, /* @__PURE__ */ new Map());
|
156
|
+
}
|
142
157
|
const fixtureValueMap = fixtureValueMaps.get(context);
|
143
|
-
if (!cleanupFnArrayMap.has(context))
|
158
|
+
if (!cleanupFnArrayMap.has(context)) {
|
144
159
|
cleanupFnArrayMap.set(context, []);
|
160
|
+
}
|
145
161
|
const cleanupFnArray = cleanupFnArrayMap.get(context);
|
146
|
-
const usedFixtures = fixtures.filter(
|
162
|
+
const usedFixtures = fixtures.filter(
|
163
|
+
({ prop, auto }) => auto || usedProps.includes(prop)
|
164
|
+
);
|
147
165
|
const pendingFixtures = resolveDeps(usedFixtures);
|
148
|
-
if (!pendingFixtures.length)
|
166
|
+
if (!pendingFixtures.length) {
|
149
167
|
return fn(context);
|
168
|
+
}
|
150
169
|
async function resolveFixtures() {
|
151
170
|
for (const fixture of pendingFixtures) {
|
152
|
-
if (fixtureValueMap.has(fixture))
|
171
|
+
if (fixtureValueMap.has(fixture)) {
|
153
172
|
continue;
|
173
|
+
}
|
154
174
|
const resolvedValue = fixture.isFn ? await resolveFixtureFunction(fixture.value, context, cleanupFnArray) : fixture.value;
|
155
175
|
context[fixture.prop] = resolvedValue;
|
156
176
|
fixtureValueMap.set(fixture, resolvedValue);
|
@@ -185,14 +205,18 @@ async function resolveFixtureFunction(fixtureFn, context, cleanupFnArray) {
|
|
185
205
|
}
|
186
206
|
function resolveDeps(fixtures, depSet = /* @__PURE__ */ new Set(), pendingFixtures = []) {
|
187
207
|
fixtures.forEach((fixture) => {
|
188
|
-
if (pendingFixtures.includes(fixture))
|
208
|
+
if (pendingFixtures.includes(fixture)) {
|
189
209
|
return;
|
210
|
+
}
|
190
211
|
if (!fixture.isFn || !fixture.deps) {
|
191
212
|
pendingFixtures.push(fixture);
|
192
213
|
return;
|
193
214
|
}
|
194
|
-
if (depSet.has(fixture))
|
195
|
-
throw new Error(
|
215
|
+
if (depSet.has(fixture)) {
|
216
|
+
throw new Error(
|
217
|
+
`Circular fixture dependency detected: ${fixture.prop} <- ${[...depSet].reverse().map((d) => d.prop).join(" <- ")}`
|
218
|
+
);
|
219
|
+
}
|
196
220
|
depSet.add(fixture);
|
197
221
|
resolveDeps(fixture.deps, depSet, pendingFixtures);
|
198
222
|
pendingFixtures.push(fixture);
|
@@ -202,26 +226,35 @@ function resolveDeps(fixtures, depSet = /* @__PURE__ */ new Set(), pendingFixtur
|
|
202
226
|
}
|
203
227
|
function getUsedProps(fn) {
|
204
228
|
const match = fn.toString().match(/[^(]*\(([^)]*)/);
|
205
|
-
if (!match)
|
229
|
+
if (!match) {
|
206
230
|
return [];
|
231
|
+
}
|
207
232
|
const args = splitByComma(match[1]);
|
208
|
-
if (!args.length)
|
233
|
+
if (!args.length) {
|
209
234
|
return [];
|
235
|
+
}
|
210
236
|
let first = args[0];
|
211
237
|
if ("__VITEST_FIXTURE_INDEX__" in fn) {
|
212
238
|
first = args[fn.__VITEST_FIXTURE_INDEX__];
|
213
|
-
if (!first)
|
239
|
+
if (!first) {
|
214
240
|
return [];
|
241
|
+
}
|
242
|
+
}
|
243
|
+
if (!(first.startsWith("{") && first.endsWith("}"))) {
|
244
|
+
throw new Error(
|
245
|
+
`The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "${first}".`
|
246
|
+
);
|
215
247
|
}
|
216
|
-
if (!(first.startsWith("{") && first.endsWith("}")))
|
217
|
-
throw new Error(`The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "${first}".`);
|
218
248
|
const _first = first.slice(1, -1).replace(/\s/g, "");
|
219
249
|
const props = splitByComma(_first).map((prop) => {
|
220
250
|
return prop.replace(/:.*|=.*/g, "");
|
221
251
|
});
|
222
252
|
const last = props.at(-1);
|
223
|
-
if (last && last.startsWith("..."))
|
224
|
-
throw new Error(
|
253
|
+
if (last && last.startsWith("...")) {
|
254
|
+
throw new Error(
|
255
|
+
`Rest parameters are not supported in fixtures, received "${last}".`
|
256
|
+
);
|
257
|
+
}
|
225
258
|
return props;
|
226
259
|
}
|
227
260
|
function splitByComma(s) {
|
@@ -235,14 +268,16 @@ function splitByComma(s) {
|
|
235
268
|
stack.pop();
|
236
269
|
} else if (!stack.length && s[i] === ",") {
|
237
270
|
const token = s.substring(start, i).trim();
|
238
|
-
if (token)
|
271
|
+
if (token) {
|
239
272
|
result.push(token);
|
273
|
+
}
|
240
274
|
start = i + 1;
|
241
275
|
}
|
242
276
|
}
|
243
277
|
const lastToken = s.substring(start).trim();
|
244
|
-
if (lastToken)
|
278
|
+
if (lastToken) {
|
245
279
|
result.push(lastToken);
|
280
|
+
}
|
246
281
|
return result;
|
247
282
|
}
|
248
283
|
|
@@ -255,13 +290,19 @@ function getCurrentTest() {
|
|
255
290
|
}
|
256
291
|
|
257
292
|
const suite = createSuite();
|
258
|
-
const test = createTest(
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
293
|
+
const test = createTest(function(name, optionsOrFn, optionsOrTest) {
|
294
|
+
if (getCurrentTest()) {
|
295
|
+
throw new Error(
|
296
|
+
'Calling the test function inside another test function is not allowed. Please put it inside "describe" or "suite" so it can be properly collected.'
|
297
|
+
);
|
263
298
|
}
|
264
|
-
)
|
299
|
+
getCurrentSuite().test.fn.call(
|
300
|
+
this,
|
301
|
+
formatName(name),
|
302
|
+
optionsOrFn,
|
303
|
+
optionsOrTest
|
304
|
+
);
|
305
|
+
});
|
265
306
|
const describe = suite;
|
266
307
|
const it = test;
|
267
308
|
let runner;
|
@@ -283,8 +324,9 @@ function createDefaultSuite(runner2) {
|
|
283
324
|
});
|
284
325
|
}
|
285
326
|
function clearCollectorContext(filepath, currentRunner) {
|
286
|
-
if (!defaultSuite)
|
327
|
+
if (!defaultSuite) {
|
287
328
|
defaultSuite = createDefaultSuite(currentRunner);
|
329
|
+
}
|
288
330
|
runner = currentRunner;
|
289
331
|
currentTestFilepath = filepath;
|
290
332
|
collectorContext.tasks.length = 0;
|
@@ -307,8 +349,11 @@ function parseArguments(optionsOrFn, optionsOrTest) {
|
|
307
349
|
let fn = () => {
|
308
350
|
};
|
309
351
|
if (typeof optionsOrTest === "object") {
|
310
|
-
if (typeof optionsOrFn === "object")
|
311
|
-
throw new TypeError(
|
352
|
+
if (typeof optionsOrFn === "object") {
|
353
|
+
throw new TypeError(
|
354
|
+
"Cannot use two objects as arguments. Please provide options and a function callback in that order."
|
355
|
+
);
|
356
|
+
}
|
312
357
|
options = optionsOrTest;
|
313
358
|
} else if (typeof optionsOrTest === "number") {
|
314
359
|
options = { timeout: optionsOrTest };
|
@@ -316,8 +361,11 @@ function parseArguments(optionsOrFn, optionsOrTest) {
|
|
316
361
|
options = optionsOrFn;
|
317
362
|
}
|
318
363
|
if (typeof optionsOrFn === "function") {
|
319
|
-
if (typeof optionsOrTest === "function")
|
320
|
-
throw new TypeError(
|
364
|
+
if (typeof optionsOrTest === "function") {
|
365
|
+
throw new TypeError(
|
366
|
+
"Cannot use two functions as arguments. Please use the second argument for options."
|
367
|
+
);
|
368
|
+
}
|
321
369
|
fn = optionsOrFn;
|
322
370
|
} else if (typeof optionsOrTest === "function") {
|
323
371
|
fn = optionsOrTest;
|
@@ -349,10 +397,12 @@ function createSuiteCollector(name, factory = () => {
|
|
349
397
|
meta: options.meta ?? /* @__PURE__ */ Object.create(null)
|
350
398
|
};
|
351
399
|
const handler = options.handler;
|
352
|
-
if (options.concurrent || !options.sequential && runner.config.sequence.concurrent)
|
400
|
+
if (options.concurrent || !options.sequential && runner.config.sequence.concurrent) {
|
353
401
|
task2.concurrent = true;
|
354
|
-
|
402
|
+
}
|
403
|
+
if (shuffle) {
|
355
404
|
task2.shuffle = true;
|
405
|
+
}
|
356
406
|
const context = createTestContext(task2, runner);
|
357
407
|
Object.defineProperty(task2, "context", {
|
358
408
|
value: context,
|
@@ -360,10 +410,13 @@ function createSuiteCollector(name, factory = () => {
|
|
360
410
|
});
|
361
411
|
setFixture(context, options.fixtures);
|
362
412
|
if (handler) {
|
363
|
-
setFn(
|
364
|
-
|
365
|
-
(
|
366
|
-
|
413
|
+
setFn(
|
414
|
+
task2,
|
415
|
+
withTimeout(
|
416
|
+
withFixtures(handler, context),
|
417
|
+
(options == null ? void 0 : options.timeout) ?? runner.config.testTimeout
|
418
|
+
)
|
419
|
+
);
|
367
420
|
}
|
368
421
|
if (runner.config.includeTaskLocation) {
|
369
422
|
const limit = Error.stackTraceLimit;
|
@@ -371,25 +424,25 @@ function createSuiteCollector(name, factory = () => {
|
|
371
424
|
const error = new Error("stacktrace").stack;
|
372
425
|
Error.stackTraceLimit = limit;
|
373
426
|
const stack = findTestFileStackTrace(error, task2.each ?? false);
|
374
|
-
if (stack)
|
427
|
+
if (stack) {
|
375
428
|
task2.location = stack;
|
429
|
+
}
|
376
430
|
}
|
377
431
|
tasks.push(task2);
|
378
432
|
return task2;
|
379
433
|
};
|
380
434
|
const test2 = createTest(function(name2, optionsOrFn, optionsOrTest) {
|
381
|
-
let { options, handler } = parseArguments(
|
382
|
-
|
383
|
-
optionsOrTest
|
384
|
-
);
|
385
|
-
if (typeof suiteOptions === "object")
|
435
|
+
let { options, handler } = parseArguments(optionsOrFn, optionsOrTest);
|
436
|
+
if (typeof suiteOptions === "object") {
|
386
437
|
options = Object.assign({}, suiteOptions, options);
|
438
|
+
}
|
387
439
|
options.concurrent = this.concurrent || !this.sequential && (options == null ? void 0 : options.concurrent);
|
388
440
|
options.sequential = this.sequential || !this.concurrent && (options == null ? void 0 : options.sequential);
|
389
|
-
const test3 = task(
|
390
|
-
|
391
|
-
|
392
|
-
|
441
|
+
const test3 = task(formatName(name2), {
|
442
|
+
...this,
|
443
|
+
...options,
|
444
|
+
handler
|
445
|
+
});
|
393
446
|
test3.type = "test";
|
394
447
|
});
|
395
448
|
const collector = {
|
@@ -408,8 +461,9 @@ function createSuiteCollector(name, factory = () => {
|
|
408
461
|
getHooks(suite2)[name2].push(...fn);
|
409
462
|
}
|
410
463
|
function initSuite(includeLocation) {
|
411
|
-
if (typeof suiteOptions === "number")
|
464
|
+
if (typeof suiteOptions === "number") {
|
412
465
|
suiteOptions = { timeout: suiteOptions };
|
466
|
+
}
|
413
467
|
suite2 = {
|
414
468
|
id: "",
|
415
469
|
type: "suite",
|
@@ -428,8 +482,9 @@ function createSuiteCollector(name, factory = () => {
|
|
428
482
|
const error = new Error("stacktrace").stack;
|
429
483
|
Error.stackTraceLimit = limit;
|
430
484
|
const stack = findTestFileStackTrace(error, suite2.each ?? false);
|
431
|
-
if (stack)
|
485
|
+
if (stack) {
|
432
486
|
suite2.location = stack;
|
487
|
+
}
|
433
488
|
}
|
434
489
|
setHooks(suite2, createSuiteHooks());
|
435
490
|
}
|
@@ -439,14 +494,17 @@ function createSuiteCollector(name, factory = () => {
|
|
439
494
|
initSuite(false);
|
440
495
|
}
|
441
496
|
async function collect(file) {
|
442
|
-
if (!file)
|
497
|
+
if (!file) {
|
443
498
|
throw new TypeError("File is required to collect tasks.");
|
499
|
+
}
|
444
500
|
factoryQueue.length = 0;
|
445
|
-
if (factory)
|
501
|
+
if (factory) {
|
446
502
|
await runWithSuite(collector, () => factory(test2));
|
503
|
+
}
|
447
504
|
const allChildren = [];
|
448
|
-
for (const i of [...factoryQueue, ...tasks])
|
505
|
+
for (const i of [...factoryQueue, ...tasks]) {
|
449
506
|
allChildren.push(i.type === "collector" ? await i.collect(file) : i);
|
507
|
+
}
|
450
508
|
suite2.file = file;
|
451
509
|
suite2.tasks = allChildren;
|
452
510
|
allChildren.forEach((task2) => {
|
@@ -466,31 +524,41 @@ function createSuite() {
|
|
466
524
|
factoryOrOptions,
|
467
525
|
optionsOrFactory
|
468
526
|
);
|
469
|
-
if (currentSuite == null ? void 0 : currentSuite.options)
|
527
|
+
if (currentSuite == null ? void 0 : currentSuite.options) {
|
470
528
|
options = { ...currentSuite.options, ...options };
|
529
|
+
}
|
471
530
|
const isConcurrent = options.concurrent || this.concurrent && !this.sequential;
|
472
531
|
const isSequential = options.sequential || this.sequential && !this.concurrent;
|
473
532
|
options.concurrent = isConcurrent && !isSequential;
|
474
533
|
options.sequential = isSequential && !isConcurrent;
|
475
|
-
return createSuiteCollector(
|
534
|
+
return createSuiteCollector(
|
535
|
+
formatName(name),
|
536
|
+
factory,
|
537
|
+
mode,
|
538
|
+
this.shuffle,
|
539
|
+
this.each,
|
540
|
+
options
|
541
|
+
);
|
476
542
|
}
|
477
543
|
suiteFn.each = function(cases, ...args) {
|
478
544
|
const suite2 = this.withContext();
|
479
545
|
this.setContext("each", true);
|
480
|
-
if (Array.isArray(cases) && args.length)
|
546
|
+
if (Array.isArray(cases) && args.length) {
|
481
547
|
cases = formatTemplateString(cases, args);
|
548
|
+
}
|
482
549
|
return (name, optionsOrFn, fnOrOptions) => {
|
483
550
|
const _name = formatName(name);
|
484
551
|
const arrayOnlyCases = cases.every(Array.isArray);
|
485
|
-
const { options, handler } = parseArguments(
|
486
|
-
optionsOrFn,
|
487
|
-
fnOrOptions
|
488
|
-
);
|
552
|
+
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
489
553
|
const fnFirst = typeof optionsOrFn === "function";
|
490
554
|
cases.forEach((i, idx) => {
|
491
555
|
const items = Array.isArray(i) ? i : [i];
|
492
556
|
if (fnFirst) {
|
493
|
-
arrayOnlyCases ? suite2(
|
557
|
+
arrayOnlyCases ? suite2(
|
558
|
+
formatTitle(_name, items, idx),
|
559
|
+
() => handler(...items),
|
560
|
+
options
|
561
|
+
) : suite2(formatTitle(_name, items, idx), () => handler(i), options);
|
494
562
|
} else {
|
495
563
|
arrayOnlyCases ? suite2(formatTitle(_name, items, idx), options, () => handler(...items)) : suite2(formatTitle(_name, items, idx), options, () => handler(i));
|
496
564
|
}
|
@@ -510,20 +578,22 @@ function createTaskCollector(fn, context) {
|
|
510
578
|
taskFn.each = function(cases, ...args) {
|
511
579
|
const test2 = this.withContext();
|
512
580
|
this.setContext("each", true);
|
513
|
-
if (Array.isArray(cases) && args.length)
|
581
|
+
if (Array.isArray(cases) && args.length) {
|
514
582
|
cases = formatTemplateString(cases, args);
|
583
|
+
}
|
515
584
|
return (name, optionsOrFn, fnOrOptions) => {
|
516
585
|
const _name = formatName(name);
|
517
586
|
const arrayOnlyCases = cases.every(Array.isArray);
|
518
|
-
const { options, handler } = parseArguments(
|
519
|
-
optionsOrFn,
|
520
|
-
fnOrOptions
|
521
|
-
);
|
587
|
+
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
522
588
|
const fnFirst = typeof optionsOrFn === "function";
|
523
589
|
cases.forEach((i, idx) => {
|
524
590
|
const items = Array.isArray(i) ? i : [i];
|
525
591
|
if (fnFirst) {
|
526
|
-
arrayOnlyCases ? test2(
|
592
|
+
arrayOnlyCases ? test2(
|
593
|
+
formatTitle(_name, items, idx),
|
594
|
+
() => handler(...items),
|
595
|
+
options
|
596
|
+
) : test2(formatTitle(_name, items, idx), () => handler(i), options);
|
527
597
|
} else {
|
528
598
|
arrayOnlyCases ? test2(formatTitle(_name, items, idx), options, () => handler(...items)) : test2(formatTitle(_name, items, idx), options, () => handler(i));
|
529
599
|
}
|
@@ -533,8 +603,9 @@ function createTaskCollector(fn, context) {
|
|
533
603
|
};
|
534
604
|
taskFn.for = function(cases, ...args) {
|
535
605
|
const test2 = this.withContext();
|
536
|
-
if (Array.isArray(cases) && args.length)
|
606
|
+
if (Array.isArray(cases) && args.length) {
|
537
607
|
cases = formatTemplateString(cases, args);
|
608
|
+
}
|
538
609
|
return (name, optionsOrFn, fnOrOptions) => {
|
539
610
|
const _name = formatName(name);
|
540
611
|
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
|
@@ -555,15 +626,21 @@ function createTaskCollector(fn, context) {
|
|
555
626
|
taskFn.extend = function(fixtures) {
|
556
627
|
const _context = mergeContextFixtures(fixtures, context);
|
557
628
|
return createTest(function fn2(name, optionsOrFn, optionsOrTest) {
|
558
|
-
getCurrentSuite().test.fn.call(
|
629
|
+
getCurrentSuite().test.fn.call(
|
630
|
+
this,
|
631
|
+
formatName(name),
|
632
|
+
optionsOrFn,
|
633
|
+
optionsOrTest
|
634
|
+
);
|
559
635
|
}, _context);
|
560
636
|
};
|
561
637
|
const _test = createChainable(
|
562
638
|
["concurrent", "sequential", "skip", "only", "todo", "fails"],
|
563
639
|
taskFn
|
564
640
|
);
|
565
|
-
if (context)
|
641
|
+
if (context) {
|
566
642
|
_test.mergeContext(context);
|
643
|
+
}
|
567
644
|
return _test;
|
568
645
|
}
|
569
646
|
function createTest(fn, context) {
|
@@ -596,7 +673,9 @@ function formatTitle(template, items, idx) {
|
|
596
673
|
// https://github.com/chaijs/chai/pull/1490
|
597
674
|
(_, key) => {
|
598
675
|
var _a, _b;
|
599
|
-
return objDisplay(objectAttr(items[0], key), {
|
676
|
+
return objDisplay(objectAttr(items[0], key), {
|
677
|
+
truncate: (_b = (_a = runner == null ? void 0 : runner.config) == null ? void 0 : _a.chaiConfig) == null ? void 0 : _b.truncateThreshold
|
678
|
+
});
|
600
679
|
}
|
601
680
|
);
|
602
681
|
}
|
@@ -607,8 +686,9 @@ function formatTemplateString(cases, args) {
|
|
607
686
|
const res = [];
|
608
687
|
for (let i = 0; i < Math.floor(args.length / header.length); i++) {
|
609
688
|
const oneCase = {};
|
610
|
-
for (let j = 0; j < header.length; j++)
|
689
|
+
for (let j = 0; j < header.length; j++) {
|
611
690
|
oneCase[header[j]] = args[i * header.length + j];
|
691
|
+
}
|
612
692
|
res.push(oneCase);
|
613
693
|
}
|
614
694
|
return res;
|
@@ -641,8 +721,9 @@ async function runSetupFiles(config, runner) {
|
|
641
721
|
})
|
642
722
|
);
|
643
723
|
} else {
|
644
|
-
for (const fsPath of files)
|
724
|
+
for (const fsPath of files) {
|
645
725
|
await runner.importFile(fsPath, "setup");
|
726
|
+
}
|
646
727
|
}
|
647
728
|
}
|
648
729
|
|
@@ -688,11 +769,18 @@ async function collectTests(paths, runner) {
|
|
688
769
|
}
|
689
770
|
calculateSuiteHash(file);
|
690
771
|
const hasOnlyTasks = someTasksAreOnly(file);
|
691
|
-
interpretTaskModes(
|
772
|
+
interpretTaskModes(
|
773
|
+
file,
|
774
|
+
config.testNamePattern,
|
775
|
+
hasOnlyTasks,
|
776
|
+
false,
|
777
|
+
config.allowOnly
|
778
|
+
);
|
692
779
|
file.tasks.forEach((task) => {
|
693
780
|
var _a2;
|
694
|
-
if (((_a2 = task.suite) == null ? void 0 : _a2.id) === "")
|
781
|
+
if (((_a2 = task.suite) == null ? void 0 : _a2.id) === "") {
|
695
782
|
delete task.suite;
|
783
|
+
}
|
696
784
|
});
|
697
785
|
files.push(file);
|
698
786
|
}
|
@@ -709,10 +797,12 @@ function mergeHooks(baseHooks, hooks) {
|
|
709
797
|
const now = Date.now;
|
710
798
|
function updateSuiteHookState(suite, name, state, runner) {
|
711
799
|
var _a;
|
712
|
-
if (!suite.result)
|
800
|
+
if (!suite.result) {
|
713
801
|
suite.result = { state: "run" };
|
714
|
-
|
802
|
+
}
|
803
|
+
if (!((_a = suite.result) == null ? void 0 : _a.hooks)) {
|
715
804
|
suite.result.hooks = {};
|
805
|
+
}
|
716
806
|
const suiteHooks = suite.result.hooks;
|
717
807
|
if (suiteHooks) {
|
718
808
|
suiteHooks[name] = state;
|
@@ -721,18 +811,21 @@ function updateSuiteHookState(suite, name, state, runner) {
|
|
721
811
|
}
|
722
812
|
function getSuiteHooks(suite, name, sequence) {
|
723
813
|
const hooks = getHooks(suite)[name];
|
724
|
-
if (sequence === "stack" && (name === "afterAll" || name === "afterEach"))
|
814
|
+
if (sequence === "stack" && (name === "afterAll" || name === "afterEach")) {
|
725
815
|
return hooks.slice().reverse();
|
816
|
+
}
|
726
817
|
return hooks;
|
727
818
|
}
|
728
819
|
async function callTaskHooks(task, hooks, sequence) {
|
729
|
-
if (sequence === "stack")
|
820
|
+
if (sequence === "stack") {
|
730
821
|
hooks = hooks.slice().reverse();
|
822
|
+
}
|
731
823
|
if (sequence === "parallel") {
|
732
824
|
await Promise.all(hooks.map((fn) => fn(task.result)));
|
733
825
|
} else {
|
734
|
-
for (const fn of hooks)
|
826
|
+
for (const fn of hooks) {
|
735
827
|
await fn(task.result);
|
828
|
+
}
|
736
829
|
}
|
737
830
|
}
|
738
831
|
async function callSuiteHook(suite, currentTask, name, runner, args) {
|
@@ -747,10 +840,13 @@ async function callSuiteHook(suite, currentTask, name, runner, args) {
|
|
747
840
|
updateSuiteHookState(currentTask, name, "run", runner);
|
748
841
|
const hooks = getSuiteHooks(suite, name, sequence);
|
749
842
|
if (sequence === "parallel") {
|
750
|
-
callbacks.push(
|
843
|
+
callbacks.push(
|
844
|
+
...await Promise.all(hooks.map((fn) => fn(...args)))
|
845
|
+
);
|
751
846
|
} else {
|
752
|
-
for (const hook of hooks)
|
847
|
+
for (const hook of hooks) {
|
753
848
|
callbacks.push(await hook(...args));
|
849
|
+
}
|
754
850
|
}
|
755
851
|
updateSuiteHookState(currentTask, name, "pass", runner);
|
756
852
|
if (name === "afterEach" && parentSuite) {
|
@@ -778,11 +874,7 @@ async function sendTasksUpdate(runner) {
|
|
778
874
|
await previousUpdate;
|
779
875
|
if (packs.size) {
|
780
876
|
const taskPacks = Array.from(packs).map(([id, task]) => {
|
781
|
-
return [
|
782
|
-
id,
|
783
|
-
task[0],
|
784
|
-
task[1]
|
785
|
-
];
|
877
|
+
return [id, task[0], task[1]];
|
786
878
|
});
|
787
879
|
const p = (_a = runner.onTaskUpdate) == null ? void 0 : _a.call(runner, taskPacks);
|
788
880
|
packs.clear();
|
@@ -790,17 +882,21 @@ async function sendTasksUpdate(runner) {
|
|
790
882
|
}
|
791
883
|
}
|
792
884
|
async function callCleanupHooks(cleanups) {
|
793
|
-
await Promise.all(
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
885
|
+
await Promise.all(
|
886
|
+
cleanups.map(async (fn) => {
|
887
|
+
if (typeof fn !== "function") {
|
888
|
+
return;
|
889
|
+
}
|
890
|
+
await fn();
|
891
|
+
})
|
892
|
+
);
|
798
893
|
}
|
799
894
|
async function runTest(test, runner) {
|
800
895
|
var _a, _b, _c, _d, _e, _f;
|
801
896
|
await ((_a = runner.onBeforeRunTask) == null ? void 0 : _a.call(runner, test));
|
802
|
-
if (test.mode !== "run")
|
897
|
+
if (test.mode !== "run") {
|
803
898
|
return;
|
899
|
+
}
|
804
900
|
if (((_b = test.result) == null ? void 0 : _b.state) === "fail") {
|
805
901
|
updateTask(test, runner);
|
806
902
|
return;
|
@@ -820,29 +916,46 @@ async function runTest(test, runner) {
|
|
820
916
|
for (let retryCount = 0; retryCount <= retry; retryCount++) {
|
821
917
|
let beforeEachCleanups = [];
|
822
918
|
try {
|
823
|
-
await ((_c = runner.onBeforeTryTask) == null ? void 0 : _c.call(runner, test, {
|
919
|
+
await ((_c = runner.onBeforeTryTask) == null ? void 0 : _c.call(runner, test, {
|
920
|
+
retry: retryCount,
|
921
|
+
repeats: repeatCount
|
922
|
+
}));
|
824
923
|
test.result.repeatCount = repeatCount;
|
825
|
-
beforeEachCleanups = await callSuiteHook(
|
924
|
+
beforeEachCleanups = await callSuiteHook(
|
925
|
+
suite,
|
926
|
+
test,
|
927
|
+
"beforeEach",
|
928
|
+
runner,
|
929
|
+
[test.context, suite]
|
930
|
+
);
|
826
931
|
if (runner.runTask) {
|
827
932
|
await runner.runTask(test);
|
828
933
|
} else {
|
829
934
|
const fn = getFn(test);
|
830
|
-
if (!fn)
|
831
|
-
throw new Error(
|
935
|
+
if (!fn) {
|
936
|
+
throw new Error(
|
937
|
+
"Test function is not found. Did you add it using `setFn`?"
|
938
|
+
);
|
939
|
+
}
|
832
940
|
await fn();
|
833
941
|
}
|
834
942
|
if (test.promises) {
|
835
943
|
const result = await Promise.allSettled(test.promises);
|
836
944
|
const errors = result.map((r) => r.status === "rejected" ? r.reason : void 0).filter(Boolean);
|
837
|
-
if (errors.length)
|
945
|
+
if (errors.length) {
|
838
946
|
throw errors;
|
947
|
+
}
|
839
948
|
}
|
840
|
-
await ((_d = runner.onAfterTryTask) == null ? void 0 : _d.call(runner, test, {
|
949
|
+
await ((_d = runner.onAfterTryTask) == null ? void 0 : _d.call(runner, test, {
|
950
|
+
retry: retryCount,
|
951
|
+
repeats: repeatCount
|
952
|
+
}));
|
841
953
|
if (test.result.state !== "fail") {
|
842
|
-
if (!test.repeats)
|
954
|
+
if (!test.repeats) {
|
843
955
|
test.result.state = "pass";
|
844
|
-
else if (test.repeats && retry === retryCount)
|
956
|
+
} else if (test.repeats && retry === retryCount) {
|
845
957
|
test.result.state = "pass";
|
958
|
+
}
|
846
959
|
}
|
847
960
|
} catch (e) {
|
848
961
|
failTask(test.result, e, runner.config.diffOptions);
|
@@ -855,14 +968,18 @@ async function runTest(test, runner) {
|
|
855
968
|
return;
|
856
969
|
}
|
857
970
|
try {
|
858
|
-
await callSuiteHook(suite, test, "afterEach", runner, [
|
971
|
+
await callSuiteHook(suite, test, "afterEach", runner, [
|
972
|
+
test.context,
|
973
|
+
suite
|
974
|
+
]);
|
859
975
|
await callCleanupHooks(beforeEachCleanups);
|
860
976
|
await callFixtureCleanup(test.context);
|
861
977
|
} catch (e) {
|
862
978
|
failTask(test.result, e, runner.config.diffOptions);
|
863
979
|
}
|
864
|
-
if (test.result.state === "pass")
|
980
|
+
if (test.result.state === "pass") {
|
865
981
|
break;
|
982
|
+
}
|
866
983
|
if (retryCount < retry) {
|
867
984
|
test.result.state = "run";
|
868
985
|
test.result.retryCount = (test.result.retryCount ?? 0) + 1;
|
@@ -877,7 +994,11 @@ async function runTest(test, runner) {
|
|
877
994
|
}
|
878
995
|
if (test.result.state === "fail") {
|
879
996
|
try {
|
880
|
-
await callTaskHooks(
|
997
|
+
await callTaskHooks(
|
998
|
+
test,
|
999
|
+
test.onFailed || [],
|
1000
|
+
runner.config.sequence.hooks
|
1001
|
+
);
|
881
1002
|
} catch (e) {
|
882
1003
|
failTask(test.result, e, runner.config.diffOptions);
|
883
1004
|
}
|
@@ -915,8 +1036,9 @@ function markTasksAsSkipped(suite, runner) {
|
|
915
1036
|
t.mode = "skip";
|
916
1037
|
t.result = { ...t.result, state: "skip" };
|
917
1038
|
updateTask(t, runner);
|
918
|
-
if (t.type === "suite")
|
1039
|
+
if (t.type === "suite") {
|
919
1040
|
markTasksAsSkipped(t, runner);
|
1041
|
+
}
|
920
1042
|
});
|
921
1043
|
}
|
922
1044
|
async function runSuite(suite, runner) {
|
@@ -940,7 +1062,13 @@ async function runSuite(suite, runner) {
|
|
940
1062
|
suite.result.state = "todo";
|
941
1063
|
} else {
|
942
1064
|
try {
|
943
|
-
beforeAllCleanups = await callSuiteHook(
|
1065
|
+
beforeAllCleanups = await callSuiteHook(
|
1066
|
+
suite,
|
1067
|
+
suite,
|
1068
|
+
"beforeAll",
|
1069
|
+
runner,
|
1070
|
+
[suite]
|
1071
|
+
);
|
944
1072
|
if (runner.runSuite) {
|
945
1073
|
await runner.runSuite(suite);
|
946
1074
|
} else {
|
@@ -950,13 +1078,18 @@ async function runSuite(suite, runner) {
|
|
950
1078
|
} else {
|
951
1079
|
const { sequence } = runner.config;
|
952
1080
|
if (sequence.shuffle || suite.shuffle) {
|
953
|
-
const suites = tasksGroup.filter(
|
1081
|
+
const suites = tasksGroup.filter(
|
1082
|
+
(group) => group.type === "suite"
|
1083
|
+
);
|
954
1084
|
const tests = tasksGroup.filter((group) => group.type === "test");
|
955
1085
|
const groups = shuffle([suites, tests], sequence.seed);
|
956
|
-
tasksGroup = groups.flatMap(
|
1086
|
+
tasksGroup = groups.flatMap(
|
1087
|
+
(group) => shuffle(group, sequence.seed)
|
1088
|
+
);
|
957
1089
|
}
|
958
|
-
for (const c of tasksGroup)
|
1090
|
+
for (const c of tasksGroup) {
|
959
1091
|
await runSuiteChild(c, runner);
|
1092
|
+
}
|
960
1093
|
}
|
961
1094
|
}
|
962
1095
|
}
|
@@ -973,7 +1106,9 @@ async function runSuite(suite, runner) {
|
|
973
1106
|
if (!runner.config.passWithNoTests && !hasTests(suite)) {
|
974
1107
|
suite.result.state = "fail";
|
975
1108
|
if (!((_c = suite.result.errors) == null ? void 0 : _c.length)) {
|
976
|
-
const error = processError(
|
1109
|
+
const error = processError(
|
1110
|
+
new Error(`No test found in suite ${suite.name}`)
|
1111
|
+
);
|
977
1112
|
suite.result.errors = [error];
|
978
1113
|
}
|
979
1114
|
} else if (hasFailed(suite)) {
|
@@ -989,10 +1124,11 @@ async function runSuite(suite, runner) {
|
|
989
1124
|
}
|
990
1125
|
let limitMaxConcurrency;
|
991
1126
|
async function runSuiteChild(c, runner) {
|
992
|
-
if (c.type === "test" || c.type === "custom")
|
1127
|
+
if (c.type === "test" || c.type === "custom") {
|
993
1128
|
return limitMaxConcurrency(() => runTest(c, runner));
|
994
|
-
else if (c.type === "suite")
|
1129
|
+
} else if (c.type === "suite") {
|
995
1130
|
return runSuite(c, runner);
|
1131
|
+
}
|
996
1132
|
}
|
997
1133
|
async function runFiles(files, runner) {
|
998
1134
|
var _a, _b;
|
@@ -1000,7 +1136,9 @@ async function runFiles(files, runner) {
|
|
1000
1136
|
for (const file of files) {
|
1001
1137
|
if (!file.tasks.length && !runner.config.passWithNoTests) {
|
1002
1138
|
if (!((_b = (_a = file.result) == null ? void 0 : _a.errors) == null ? void 0 : _b.length)) {
|
1003
|
-
const error = processError(
|
1139
|
+
const error = processError(
|
1140
|
+
new Error(`No test suite found in file ${file.filepath}`)
|
1141
|
+
);
|
1004
1142
|
file.result = {
|
1005
1143
|
state: "fail",
|
1006
1144
|
errors: [error]
|
@@ -1026,30 +1164,49 @@ function getDefaultHookTimeout() {
|
|
1026
1164
|
return getRunner().config.hookTimeout;
|
1027
1165
|
}
|
1028
1166
|
function beforeAll(fn, timeout) {
|
1029
|
-
return getCurrentSuite().on(
|
1167
|
+
return getCurrentSuite().on(
|
1168
|
+
"beforeAll",
|
1169
|
+
withTimeout(fn, timeout ?? getDefaultHookTimeout(), true)
|
1170
|
+
);
|
1030
1171
|
}
|
1031
1172
|
function afterAll(fn, timeout) {
|
1032
|
-
return getCurrentSuite().on(
|
1173
|
+
return getCurrentSuite().on(
|
1174
|
+
"afterAll",
|
1175
|
+
withTimeout(fn, timeout ?? getDefaultHookTimeout(), true)
|
1176
|
+
);
|
1033
1177
|
}
|
1034
1178
|
function beforeEach(fn, timeout) {
|
1035
|
-
return getCurrentSuite().on(
|
1179
|
+
return getCurrentSuite().on(
|
1180
|
+
"beforeEach",
|
1181
|
+
withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true)
|
1182
|
+
);
|
1036
1183
|
}
|
1037
1184
|
function afterEach(fn, timeout) {
|
1038
|
-
return getCurrentSuite().on(
|
1185
|
+
return getCurrentSuite().on(
|
1186
|
+
"afterEach",
|
1187
|
+
withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true)
|
1188
|
+
);
|
1039
1189
|
}
|
1040
|
-
const onTestFailed = createTestHook(
|
1041
|
-
|
1042
|
-
test
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1190
|
+
const onTestFailed = createTestHook(
|
1191
|
+
"onTestFailed",
|
1192
|
+
(test, handler) => {
|
1193
|
+
test.onFailed || (test.onFailed = []);
|
1194
|
+
test.onFailed.push(handler);
|
1195
|
+
}
|
1196
|
+
);
|
1197
|
+
const onTestFinished = createTestHook(
|
1198
|
+
"onTestFinished",
|
1199
|
+
(test, handler) => {
|
1200
|
+
test.onFinished || (test.onFinished = []);
|
1201
|
+
test.onFinished.push(handler);
|
1202
|
+
}
|
1203
|
+
);
|
1048
1204
|
function createTestHook(name, handler) {
|
1049
1205
|
return (fn) => {
|
1050
1206
|
const current = getCurrentTest();
|
1051
|
-
if (!current)
|
1207
|
+
if (!current) {
|
1052
1208
|
throw new Error(`Hook ${name}() can only be called inside a test`);
|
1209
|
+
}
|
1053
1210
|
return handler(current, fn);
|
1054
1211
|
};
|
1055
1212
|
}
|
@@ -64,7 +64,11 @@ interface TaskResult {
|
|
64
64
|
retryCount?: number;
|
65
65
|
repeatCount?: number;
|
66
66
|
}
|
67
|
-
type TaskResultPack = [
|
67
|
+
type TaskResultPack = [
|
68
|
+
id: string,
|
69
|
+
result: TaskResult | undefined,
|
70
|
+
meta: TaskMeta
|
71
|
+
];
|
68
72
|
interface Suite extends TaskBase {
|
69
73
|
file: File;
|
70
74
|
type: 'suite';
|
@@ -202,7 +206,7 @@ interface FixtureOptions {
|
|
202
206
|
}
|
203
207
|
type Use<T> = (value: T) => Promise<void>;
|
204
208
|
type FixtureFn<T, K extends keyof T, ExtraContext> = (context: Omit<T, K> & ExtraContext, use: Use<T[K]>) => Promise<void>;
|
205
|
-
type Fixture<T, K extends keyof T, ExtraContext = {}> = ((...args: any) => any) extends T[K] ?
|
209
|
+
type Fixture<T, K extends keyof T, ExtraContext = {}> = ((...args: any) => any) extends T[K] ? T[K] extends any ? FixtureFn<T, K, Omit<ExtraContext, Exclude<keyof T, K>>> : never : T[K] | (T[K] extends any ? FixtureFn<T, K, Omit<ExtraContext, Exclude<keyof T, K>>> : never);
|
206
210
|
type Fixtures<T extends Record<string, any>, ExtraContext = {}> = {
|
207
211
|
[K in keyof T]: Fixture<T, K, ExtraContext & ExtendedContext<Test>> | [Fixture<T, K, ExtraContext & ExtendedContext<Test>>, FixtureOptions?];
|
208
212
|
};
|
@@ -227,8 +231,14 @@ type HookCleanupCallback = (() => Awaitable<unknown>) | void;
|
|
227
231
|
interface SuiteHooks<ExtraContext = {}> {
|
228
232
|
beforeAll: HookListener<[Readonly<Suite | File>], HookCleanupCallback>[];
|
229
233
|
afterAll: HookListener<[Readonly<Suite | File>]>[];
|
230
|
-
beforeEach: HookListener<[
|
231
|
-
|
234
|
+
beforeEach: HookListener<[
|
235
|
+
ExtendedContext<Test | Custom> & ExtraContext,
|
236
|
+
Readonly<Suite>
|
237
|
+
], HookCleanupCallback>[];
|
238
|
+
afterEach: HookListener<[
|
239
|
+
ExtendedContext<Test | Custom> & ExtraContext,
|
240
|
+
Readonly<Suite>
|
241
|
+
]>[];
|
232
242
|
}
|
233
243
|
interface TaskCustomOptions extends TestOptions {
|
234
244
|
concurrent?: boolean;
|
package/dist/types.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { B as SequenceHooks, G as SequenceSetupFiles, F as File, T as Task, S as Suite, o as TaskResultPack, a as Test, C as Custom, A as TaskContext, E as ExtendedContext } from './tasks-
|
2
|
-
export { g as CustomAPI, D as DoneCallback, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, i as OnTestFinishedHandler, R as RunMode, y as RuntimeContext, d as SuiteAPI, f as SuiteCollector, x as SuiteFactory, h as SuiteHooks, k as TaskBase, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, j as TaskState, e as TestAPI, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-
|
1
|
+
import { B as SequenceHooks, G as SequenceSetupFiles, F as File, T as Task, S as Suite, o as TaskResultPack, a as Test, C as Custom, A as TaskContext, E as ExtendedContext } from './tasks-BP89OzIP.js';
|
2
|
+
export { g as CustomAPI, D as DoneCallback, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, i as OnTestFinishedHandler, R as RunMode, y as RuntimeContext, d as SuiteAPI, f as SuiteCollector, x as SuiteFactory, h as SuiteHooks, k as TaskBase, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, j as TaskState, e as TestAPI, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-BP89OzIP.js';
|
3
3
|
import { DiffOptions } from '@vitest/utils/diff';
|
4
4
|
import '@vitest/utils';
|
5
5
|
|
@@ -31,7 +31,7 @@ type VitestRunnerImportSource = 'collect' | 'setup';
|
|
31
31
|
interface VitestRunnerConstructor {
|
32
32
|
new (config: VitestRunnerConfig): VitestRunner;
|
33
33
|
}
|
34
|
-
type CancelReason = 'keyboard-input' | 'test-failure' | string & Record<string, never
|
34
|
+
type CancelReason = 'keyboard-input' | 'test-failure' | (string & Record<string, never>);
|
35
35
|
interface VitestRunner {
|
36
36
|
/**
|
37
37
|
* First thing that's getting called before actually collecting and running tests.
|
package/dist/utils.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { S as Suite, F as File, T as Task, a as Test, C as Custom } from './tasks-
|
2
|
-
export { b as ChainableFunction, c as createChainable } from './tasks-
|
1
|
+
import { S as Suite, F as File, T as Task, a as Test, C as Custom } from './tasks-BP89OzIP.js';
|
2
|
+
export { b as ChainableFunction, c as createChainable } from './tasks-BP89OzIP.js';
|
3
3
|
import { Arrayable } from '@vitest/utils';
|
4
4
|
|
5
5
|
/**
|
@@ -16,6 +16,7 @@ declare function createFileTask(filepath: string, root: string, projectName: str
|
|
16
16
|
*/
|
17
17
|
declare function partitionSuiteChildren(suite: Suite): Task[][];
|
18
18
|
|
19
|
+
declare function isAtomTest(s: Task): s is Test | Custom;
|
19
20
|
declare function getTests(suite: Arrayable<Task>): (Test | Custom)[];
|
20
21
|
declare function getTasks(tasks?: Arrayable<Task>): Task[];
|
21
22
|
declare function getSuites(suite: Arrayable<Task>): Suite[];
|
@@ -23,4 +24,4 @@ declare function hasTests(suite: Arrayable<Suite>): boolean;
|
|
23
24
|
declare function hasFailed(suite: Arrayable<Task>): boolean;
|
24
25
|
declare function getNames(task: Task): string[];
|
25
26
|
|
26
|
-
export { calculateSuiteHash, createFileTask, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, partitionSuiteChildren, someTasksAreOnly };
|
27
|
+
export { calculateSuiteHash, createFileTask, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, isAtomTest, partitionSuiteChildren, someTasksAreOnly };
|
package/dist/utils.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
export { c as calculateSuiteHash,
|
1
|
+
export { c as calculateSuiteHash, l as createChainable, a as createFileTask, g as generateHash, k as getNames, f as getSuites, e as getTasks, d as getTests, j as hasFailed, h as hasTests, i as interpretTaskModes, b as isAtomTest, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
|
2
2
|
import '@vitest/utils/error';
|
3
3
|
import 'pathe';
|
4
4
|
import '@vitest/utils';
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitest/runner",
|
3
3
|
"type": "module",
|
4
|
-
"version": "2.0.0-beta.
|
4
|
+
"version": "2.0.0-beta.11",
|
5
5
|
"description": "Vitest test runner",
|
6
6
|
"license": "MIT",
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
@@ -40,7 +40,7 @@
|
|
40
40
|
"dependencies": {
|
41
41
|
"p-limit": "^5.0.0",
|
42
42
|
"pathe": "^1.1.2",
|
43
|
-
"@vitest/utils": "2.0.0-beta.
|
43
|
+
"@vitest/utils": "2.0.0-beta.11"
|
44
44
|
},
|
45
45
|
"scripts": {
|
46
46
|
"build": "rimraf dist && rollup -c",
|