vitest 0.17.0 → 0.18.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/LICENSE.md +1 -1
- package/dist/{chunk-api-setup.5282c6cb.mjs → chunk-api-setup.9d3f7670.mjs} +18 -9
- package/dist/{chunk-constants.511c6e9b.mjs → chunk-constants.d4406290.mjs} +1 -1
- package/dist/{chunk-env-node.dc514f41.mjs → chunk-env-node.bbba78e5.mjs} +9 -3
- package/dist/{chunk-install-pkg.3fa50769.mjs → chunk-install-pkg.2dcb2c04.mjs} +1 -1
- package/dist/chunk-integrations-globals.00b6e1ad.mjs +23 -0
- package/dist/{chunk-runtime-chain.68f305d0.mjs → chunk-runtime-chain.b60d57da.mjs} +39 -60
- package/dist/{chunk-runtime-mocker.1c207219.mjs → chunk-runtime-mocker.1d853e3a.mjs} +77 -29
- package/dist/{chunk-runtime-rpc.5e78af38.mjs → chunk-runtime-rpc.9d1f4c48.mjs} +1 -1
- package/dist/{chunk-utils-global.79a8b1cc.mjs → chunk-utils-global.0a7416cf.mjs} +70 -6
- package/dist/{chunk-utils-source-map.f52527bc.mjs → chunk-utils-source-map.c03f8bc4.mjs} +2 -2
- package/dist/{chunk-vite-node-externalize.1efbe319.mjs → chunk-vite-node-externalize.6956d2d9.mjs} +2666 -2552
- package/dist/chunk-vite-node-utils.8077cd3c.mjs +1422 -0
- package/dist/cli.mjs +13 -13
- package/dist/config.cjs +6 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.mjs +6 -1
- package/dist/entry.mjs +638 -11
- package/dist/index.d.ts +125 -52
- package/dist/index.mjs +8 -8
- package/dist/node.d.ts +126 -54
- package/dist/node.mjs +13 -13
- package/dist/spy.mjs +102 -2
- package/dist/{vendor-index.e5dc6622.mjs → vendor-index.4bf9c627.mjs} +405 -405
- package/dist/{vendor-index.98e769c1.mjs → vendor-index.de788b6a.mjs} +7 -7
- package/dist/worker.mjs +9 -9
- package/package.json +12 -12
- package/dist/chunk-integrations-globals.6bb781c7.mjs +0 -26
- package/dist/chunk-integrations-spy.674b628e.mjs +0 -102
- package/dist/chunk-vite-node-utils.4b58ae05.mjs +0 -9192
- package/dist/vendor-entry.2edaf3e0.mjs +0 -653
package/dist/entry.mjs
CHANGED
|
@@ -1,17 +1,644 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { promises } from 'fs';
|
|
2
|
+
import { v as isNode, a as getWorkerState, R as RealDate, h as safeClearTimeout, f as safeSetTimeout, F as toArray, Q as deepClone, O as getType, u as relative, S as partitionSuiteChildren, E as shuffle, T as hasTests, y as hasFailed, e as getFullName, k as resetModules } from './chunk-utils-global.0a7416cf.mjs';
|
|
3
|
+
import { d as environments, t as takeCoverage, p as pLimit, f as envs } from './chunk-env-node.bbba78e5.mjs';
|
|
4
|
+
import { r as resetRunOnceCounter, i as index, c as clearCollectorContext, d as defaultSuite, s as setHooks, g as getHooks, a as collectorContext, b as getSnapshotClient, e as setState, G as GLOBAL_EXPECT, f as getFn, h as getState, v as vi } from './chunk-runtime-chain.b60d57da.mjs';
|
|
5
|
+
import { r as rpc } from './chunk-runtime-rpc.9d1f4c48.mjs';
|
|
6
|
+
import { format } from 'util';
|
|
7
|
+
import { util } from 'chai';
|
|
8
|
+
import { s as stringify } from './chunk-utils-source-map.c03f8bc4.mjs';
|
|
9
|
+
import 'path';
|
|
4
10
|
import 'tty';
|
|
5
11
|
import 'local-pkg';
|
|
6
|
-
import 'path';
|
|
7
|
-
import './chunk-env-node.dc514f41.mjs';
|
|
8
12
|
import 'module';
|
|
9
13
|
import 'url';
|
|
10
|
-
import './chunk-runtime-chain.68f305d0.mjs';
|
|
11
|
-
import 'chai';
|
|
12
14
|
import './vendor-_commonjsHelpers.4da45ef5.mjs';
|
|
13
|
-
import './
|
|
14
|
-
import './chunk-utils-source-map.f52527bc.mjs';
|
|
15
|
-
import './chunk-integrations-spy.674b628e.mjs';
|
|
15
|
+
import './spy.mjs';
|
|
16
16
|
import 'tinyspy';
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
let globalSetup = false;
|
|
19
|
+
async function setupGlobalEnv(config) {
|
|
20
|
+
resetRunOnceCounter();
|
|
21
|
+
Object.defineProperty(globalThis, "__vitest_index__", {
|
|
22
|
+
value: index,
|
|
23
|
+
enumerable: false
|
|
24
|
+
});
|
|
25
|
+
setupDefines(config.defines);
|
|
26
|
+
if (globalSetup)
|
|
27
|
+
return;
|
|
28
|
+
globalSetup = true;
|
|
29
|
+
if (isNode)
|
|
30
|
+
await setupConsoleLogSpy();
|
|
31
|
+
if (config.globals)
|
|
32
|
+
(await import('./chunk-integrations-globals.00b6e1ad.mjs')).registerApiGlobally();
|
|
33
|
+
}
|
|
34
|
+
function setupDefines(defines) {
|
|
35
|
+
for (const key in defines)
|
|
36
|
+
globalThis[key] = defines[key];
|
|
37
|
+
}
|
|
38
|
+
async function setupConsoleLogSpy() {
|
|
39
|
+
const stdoutBuffer = /* @__PURE__ */ new Map();
|
|
40
|
+
const stderrBuffer = /* @__PURE__ */ new Map();
|
|
41
|
+
const timers = /* @__PURE__ */ new Map();
|
|
42
|
+
const unknownTestId = "__vitest__unknown_test__";
|
|
43
|
+
const { Writable } = await import('stream');
|
|
44
|
+
const { Console } = await import('console');
|
|
45
|
+
function schedule(taskId) {
|
|
46
|
+
const timer = timers.get(taskId);
|
|
47
|
+
const { stdoutTime, stderrTime } = timer;
|
|
48
|
+
safeClearTimeout(timer.timer);
|
|
49
|
+
timer.timer = safeSetTimeout(() => {
|
|
50
|
+
if (stderrTime < stdoutTime) {
|
|
51
|
+
sendStderr(taskId);
|
|
52
|
+
sendStdout(taskId);
|
|
53
|
+
} else {
|
|
54
|
+
sendStdout(taskId);
|
|
55
|
+
sendStderr(taskId);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function sendStdout(taskId) {
|
|
60
|
+
const buffer = stdoutBuffer.get(taskId);
|
|
61
|
+
if (!buffer)
|
|
62
|
+
return;
|
|
63
|
+
const content = buffer.map((i) => String(i)).join("");
|
|
64
|
+
if (!content.trim())
|
|
65
|
+
return;
|
|
66
|
+
const timer = timers.get(taskId);
|
|
67
|
+
rpc().onUserConsoleLog({
|
|
68
|
+
type: "stdout",
|
|
69
|
+
content,
|
|
70
|
+
taskId,
|
|
71
|
+
time: timer.stdoutTime || RealDate.now(),
|
|
72
|
+
size: buffer.length
|
|
73
|
+
});
|
|
74
|
+
stdoutBuffer.set(taskId, []);
|
|
75
|
+
timer.stdoutTime = 0;
|
|
76
|
+
}
|
|
77
|
+
function sendStderr(taskId) {
|
|
78
|
+
const buffer = stderrBuffer.get(taskId);
|
|
79
|
+
if (!buffer)
|
|
80
|
+
return;
|
|
81
|
+
const content = buffer.map((i) => String(i)).join("");
|
|
82
|
+
if (!content.trim())
|
|
83
|
+
return;
|
|
84
|
+
const timer = timers.get(taskId);
|
|
85
|
+
rpc().onUserConsoleLog({
|
|
86
|
+
type: "stderr",
|
|
87
|
+
content,
|
|
88
|
+
taskId,
|
|
89
|
+
time: timer.stderrTime || RealDate.now(),
|
|
90
|
+
size: buffer.length
|
|
91
|
+
});
|
|
92
|
+
stderrBuffer.set(taskId, []);
|
|
93
|
+
timer.stderrTime = 0;
|
|
94
|
+
}
|
|
95
|
+
const stdout = new Writable({
|
|
96
|
+
write(data, encoding, callback) {
|
|
97
|
+
var _a, _b;
|
|
98
|
+
const id = ((_b = (_a = getWorkerState()) == null ? void 0 : _a.current) == null ? void 0 : _b.id) ?? unknownTestId;
|
|
99
|
+
let timer = timers.get(id);
|
|
100
|
+
if (timer) {
|
|
101
|
+
timer.stdoutTime = timer.stdoutTime || RealDate.now();
|
|
102
|
+
} else {
|
|
103
|
+
timer = { stdoutTime: RealDate.now(), stderrTime: RealDate.now(), timer: 0 };
|
|
104
|
+
timers.set(id, timer);
|
|
105
|
+
}
|
|
106
|
+
let buffer = stdoutBuffer.get(id);
|
|
107
|
+
if (!buffer) {
|
|
108
|
+
buffer = [];
|
|
109
|
+
stdoutBuffer.set(id, buffer);
|
|
110
|
+
}
|
|
111
|
+
buffer.push(data);
|
|
112
|
+
schedule(id);
|
|
113
|
+
callback();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
const stderr = new Writable({
|
|
117
|
+
write(data, encoding, callback) {
|
|
118
|
+
var _a, _b;
|
|
119
|
+
const id = ((_b = (_a = getWorkerState()) == null ? void 0 : _a.current) == null ? void 0 : _b.id) ?? unknownTestId;
|
|
120
|
+
let timer = timers.get(id);
|
|
121
|
+
if (timer) {
|
|
122
|
+
timer.stderrTime = timer.stderrTime || RealDate.now();
|
|
123
|
+
} else {
|
|
124
|
+
timer = { stderrTime: RealDate.now(), stdoutTime: RealDate.now(), timer: 0 };
|
|
125
|
+
timers.set(id, timer);
|
|
126
|
+
}
|
|
127
|
+
let buffer = stderrBuffer.get(id);
|
|
128
|
+
if (!buffer) {
|
|
129
|
+
buffer = [];
|
|
130
|
+
stderrBuffer.set(id, buffer);
|
|
131
|
+
}
|
|
132
|
+
buffer.push(data);
|
|
133
|
+
schedule(id);
|
|
134
|
+
callback();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
globalThis.console = new Console({
|
|
138
|
+
stdout,
|
|
139
|
+
stderr,
|
|
140
|
+
colorMode: true,
|
|
141
|
+
groupIndentation: 2
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async function withEnv(name, options, fn) {
|
|
145
|
+
const env = await environments[name].setup(globalThis, options);
|
|
146
|
+
try {
|
|
147
|
+
await fn();
|
|
148
|
+
} finally {
|
|
149
|
+
await env.teardown(globalThis);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function runSetupFiles(config) {
|
|
153
|
+
const files = toArray(config.setupFiles);
|
|
154
|
+
await Promise.all(files.map(async (fsPath) => {
|
|
155
|
+
getWorkerState().moduleCache.delete(fsPath);
|
|
156
|
+
await import(fsPath);
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const OBJECT_PROTO = Object.getPrototypeOf({});
|
|
161
|
+
function serializeError(val, seen = /* @__PURE__ */ new WeakMap()) {
|
|
162
|
+
if (!val || typeof val === "string")
|
|
163
|
+
return val;
|
|
164
|
+
if (typeof val === "function")
|
|
165
|
+
return `Function<${val.name}>`;
|
|
166
|
+
if (typeof val !== "object")
|
|
167
|
+
return val;
|
|
168
|
+
if (val instanceof Promise || "then" in val || val.constructor && val.constructor.prototype === "AsyncFunction")
|
|
169
|
+
return "Promise";
|
|
170
|
+
if (typeof Element !== "undefined" && val instanceof Element)
|
|
171
|
+
return val.tagName;
|
|
172
|
+
if (typeof val.asymmetricMatch === "function")
|
|
173
|
+
return `${val.toString()} ${format(val.sample)}`;
|
|
174
|
+
if (seen.has(val))
|
|
175
|
+
return seen.get(val);
|
|
176
|
+
if (Array.isArray(val)) {
|
|
177
|
+
const clone = new Array(val.length);
|
|
178
|
+
seen.set(val, clone);
|
|
179
|
+
val.forEach((e, i) => {
|
|
180
|
+
clone[i] = serializeError(e, seen);
|
|
181
|
+
});
|
|
182
|
+
return clone;
|
|
183
|
+
} else {
|
|
184
|
+
const clone = /* @__PURE__ */ Object.create(null);
|
|
185
|
+
seen.set(val, clone);
|
|
186
|
+
let obj = val;
|
|
187
|
+
while (obj && obj !== OBJECT_PROTO) {
|
|
188
|
+
Object.getOwnPropertyNames(obj).forEach((key) => {
|
|
189
|
+
if (!(key in clone))
|
|
190
|
+
clone[key] = serializeError(obj[key], seen);
|
|
191
|
+
});
|
|
192
|
+
obj = Object.getPrototypeOf(obj);
|
|
193
|
+
}
|
|
194
|
+
return clone;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function normalizeErrorMessage(message) {
|
|
198
|
+
return message.replace(/__vite_ssr_import_\d+__\./g, "");
|
|
199
|
+
}
|
|
200
|
+
function processError(err) {
|
|
201
|
+
if (!err)
|
|
202
|
+
return err;
|
|
203
|
+
if (err.stack)
|
|
204
|
+
err.stackStr = String(err.stack);
|
|
205
|
+
if (err.name)
|
|
206
|
+
err.nameStr = String(err.name);
|
|
207
|
+
const clonedActual = deepClone(err.actual);
|
|
208
|
+
const clonedExpected = deepClone(err.expected);
|
|
209
|
+
const { replacedActual, replacedExpected } = replaceAsymmetricMatcher(clonedActual, clonedExpected);
|
|
210
|
+
err.actual = replacedActual;
|
|
211
|
+
err.expected = replacedExpected;
|
|
212
|
+
if (typeof err.expected !== "string")
|
|
213
|
+
err.expected = stringify(err.expected);
|
|
214
|
+
if (typeof err.actual !== "string")
|
|
215
|
+
err.actual = stringify(err.actual);
|
|
216
|
+
try {
|
|
217
|
+
if (typeof err.message === "string")
|
|
218
|
+
err.message = normalizeErrorMessage(err.message);
|
|
219
|
+
if (typeof err.cause === "object" && err.cause.message === "string")
|
|
220
|
+
err.cause.message = normalizeErrorMessage(err.cause.message);
|
|
221
|
+
} catch {
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
return serializeError(err);
|
|
225
|
+
} catch (e) {
|
|
226
|
+
return serializeError(new Error(`Failed to fully serialize error: ${e == null ? void 0 : e.message}
|
|
227
|
+
Inner error message: ${err == null ? void 0 : err.message}`));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function isAsymmetricMatcher(data) {
|
|
231
|
+
const type = getType(data);
|
|
232
|
+
return type === "Object" && typeof data.asymmetricMatch === "function";
|
|
233
|
+
}
|
|
234
|
+
function isReplaceable(obj1, obj2) {
|
|
235
|
+
const obj1Type = getType(obj1);
|
|
236
|
+
const obj2Type = getType(obj2);
|
|
237
|
+
return obj1Type === obj2Type && obj1Type === "Object";
|
|
238
|
+
}
|
|
239
|
+
function replaceAsymmetricMatcher(actual, expected, actualReplaced = /* @__PURE__ */ new WeakMap(), expectedReplaced = /* @__PURE__ */ new WeakMap()) {
|
|
240
|
+
if (!isReplaceable(actual, expected))
|
|
241
|
+
return { replacedActual: actual, replacedExpected: expected };
|
|
242
|
+
if (actualReplaced.has(actual) || expectedReplaced.has(expected))
|
|
243
|
+
return { replacedActual: actual, replacedExpected: expected };
|
|
244
|
+
actualReplaced.set(actual, true);
|
|
245
|
+
expectedReplaced.set(expected, true);
|
|
246
|
+
util.getOwnEnumerableProperties(expected).forEach((key) => {
|
|
247
|
+
const expectedValue = expected[key];
|
|
248
|
+
const actualValue = actual[key];
|
|
249
|
+
if (isAsymmetricMatcher(expectedValue)) {
|
|
250
|
+
if (expectedValue.asymmetricMatch(actualValue))
|
|
251
|
+
actual[key] = expectedValue;
|
|
252
|
+
} else if (isAsymmetricMatcher(actualValue)) {
|
|
253
|
+
if (actualValue.asymmetricMatch(expectedValue))
|
|
254
|
+
expected[key] = actualValue;
|
|
255
|
+
} else if (isReplaceable(actualValue, expectedValue)) {
|
|
256
|
+
const replaced = replaceAsymmetricMatcher(actualValue, expectedValue, actualReplaced, expectedReplaced);
|
|
257
|
+
actual[key] = replaced.replacedActual;
|
|
258
|
+
expected[key] = replaced.replacedExpected;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
return {
|
|
262
|
+
replacedActual: actual,
|
|
263
|
+
replacedExpected: expected
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const now$1 = Date.now;
|
|
268
|
+
function hash(str) {
|
|
269
|
+
let hash2 = 0;
|
|
270
|
+
if (str.length === 0)
|
|
271
|
+
return `${hash2}`;
|
|
272
|
+
for (let i = 0; i < str.length; i++) {
|
|
273
|
+
const char = str.charCodeAt(i);
|
|
274
|
+
hash2 = (hash2 << 5) - hash2 + char;
|
|
275
|
+
hash2 = hash2 & hash2;
|
|
276
|
+
}
|
|
277
|
+
return `${hash2}`;
|
|
278
|
+
}
|
|
279
|
+
async function collectTests(paths, config) {
|
|
280
|
+
const files = [];
|
|
281
|
+
for (const filepath of paths) {
|
|
282
|
+
const path = relative(config.root, filepath);
|
|
283
|
+
const file = {
|
|
284
|
+
id: hash(path),
|
|
285
|
+
name: path,
|
|
286
|
+
type: "suite",
|
|
287
|
+
mode: "run",
|
|
288
|
+
filepath,
|
|
289
|
+
tasks: []
|
|
290
|
+
};
|
|
291
|
+
clearCollectorContext();
|
|
292
|
+
try {
|
|
293
|
+
await runSetupFiles(config);
|
|
294
|
+
await import(filepath);
|
|
295
|
+
const defaultTasks = await defaultSuite.collect(file);
|
|
296
|
+
setHooks(file, getHooks(defaultTasks));
|
|
297
|
+
for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) {
|
|
298
|
+
if (c.type === "test") {
|
|
299
|
+
file.tasks.push(c);
|
|
300
|
+
} else if (c.type === "suite") {
|
|
301
|
+
file.tasks.push(c);
|
|
302
|
+
} else {
|
|
303
|
+
const start = now$1();
|
|
304
|
+
const suite = await c.collect(file);
|
|
305
|
+
file.collectDuration = now$1() - start;
|
|
306
|
+
if (suite.name || suite.tasks.length)
|
|
307
|
+
file.tasks.push(suite);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch (e) {
|
|
311
|
+
file.result = {
|
|
312
|
+
state: "fail",
|
|
313
|
+
error: processError(e)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
calculateHash(file);
|
|
317
|
+
const hasOnlyTasks = someTasksAreOnly(file);
|
|
318
|
+
interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.allowOnly);
|
|
319
|
+
files.push(file);
|
|
320
|
+
}
|
|
321
|
+
return files;
|
|
322
|
+
}
|
|
323
|
+
function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnly) {
|
|
324
|
+
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
|
325
|
+
suite.tasks.forEach((t) => {
|
|
326
|
+
const includeTask = suiteIsOnly || t.mode === "only";
|
|
327
|
+
if (onlyMode) {
|
|
328
|
+
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
|
329
|
+
if (t.mode === "only") {
|
|
330
|
+
checkAllowOnly(t, allowOnly);
|
|
331
|
+
t.mode = "run";
|
|
332
|
+
}
|
|
333
|
+
} else if (t.mode === "run" && !includeTask) {
|
|
334
|
+
t.mode = "skip";
|
|
335
|
+
} else if (t.mode === "only") {
|
|
336
|
+
checkAllowOnly(t, allowOnly);
|
|
337
|
+
t.mode = "run";
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (t.type === "test") {
|
|
341
|
+
if (namePattern && !getTaskFullName(t).match(namePattern))
|
|
342
|
+
t.mode = "skip";
|
|
343
|
+
} else if (t.type === "suite") {
|
|
344
|
+
if (t.mode === "skip")
|
|
345
|
+
skipAllTasks(t);
|
|
346
|
+
else
|
|
347
|
+
interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
if (suite.mode === "run") {
|
|
351
|
+
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run"))
|
|
352
|
+
suite.mode = "skip";
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function getTaskFullName(task) {
|
|
356
|
+
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
|
357
|
+
}
|
|
358
|
+
function someTasksAreOnly(suite) {
|
|
359
|
+
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
|
360
|
+
}
|
|
361
|
+
function skipAllTasks(suite) {
|
|
362
|
+
suite.tasks.forEach((t) => {
|
|
363
|
+
if (t.mode === "run") {
|
|
364
|
+
t.mode = "skip";
|
|
365
|
+
if (t.type === "suite")
|
|
366
|
+
skipAllTasks(t);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
function checkAllowOnly(task, allowOnly) {
|
|
371
|
+
if (allowOnly)
|
|
372
|
+
return;
|
|
373
|
+
task.result = {
|
|
374
|
+
state: "fail",
|
|
375
|
+
error: processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"))
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function calculateHash(parent) {
|
|
379
|
+
parent.tasks.forEach((t, idx) => {
|
|
380
|
+
t.id = `${parent.id}_${idx}`;
|
|
381
|
+
if (t.type === "suite")
|
|
382
|
+
calculateHash(t);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const now = Date.now;
|
|
387
|
+
function updateSuiteHookState(suite, name, state) {
|
|
388
|
+
var _a;
|
|
389
|
+
if (!suite.result)
|
|
390
|
+
suite.result = { state: "run" };
|
|
391
|
+
if (!((_a = suite.result) == null ? void 0 : _a.hooks))
|
|
392
|
+
suite.result.hooks = {};
|
|
393
|
+
const suiteHooks = suite.result.hooks;
|
|
394
|
+
if (suiteHooks) {
|
|
395
|
+
suiteHooks[name] = state;
|
|
396
|
+
updateTask(suite);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async function callSuiteHook(suite, currentTask, name, args) {
|
|
400
|
+
const callbacks = [];
|
|
401
|
+
if (name === "beforeEach" && suite.suite) {
|
|
402
|
+
callbacks.push(...await callSuiteHook(suite.suite, currentTask, name, args));
|
|
403
|
+
}
|
|
404
|
+
updateSuiteHookState(currentTask, name, "run");
|
|
405
|
+
callbacks.push(...await Promise.all(getHooks(suite)[name].map((fn) => fn(...args))));
|
|
406
|
+
updateSuiteHookState(currentTask, name, "pass");
|
|
407
|
+
if (name === "afterEach" && suite.suite) {
|
|
408
|
+
callbacks.push(...await callSuiteHook(suite.suite, currentTask, name, args));
|
|
409
|
+
}
|
|
410
|
+
return callbacks;
|
|
411
|
+
}
|
|
412
|
+
const packs = /* @__PURE__ */ new Map();
|
|
413
|
+
let updateTimer;
|
|
414
|
+
let previousUpdate;
|
|
415
|
+
function updateTask(task) {
|
|
416
|
+
packs.set(task.id, task.result);
|
|
417
|
+
safeClearTimeout(updateTimer);
|
|
418
|
+
updateTimer = safeSetTimeout(() => {
|
|
419
|
+
previousUpdate = sendTasksUpdate();
|
|
420
|
+
}, 10);
|
|
421
|
+
}
|
|
422
|
+
async function sendTasksUpdate() {
|
|
423
|
+
safeClearTimeout(updateTimer);
|
|
424
|
+
await previousUpdate;
|
|
425
|
+
if (packs.size) {
|
|
426
|
+
const p = rpc().onTaskUpdate(Array.from(packs));
|
|
427
|
+
packs.clear();
|
|
428
|
+
return p;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async function runTest(test) {
|
|
432
|
+
var _a, _b;
|
|
433
|
+
if (test.mode !== "run") {
|
|
434
|
+
getSnapshotClient().skipTestSnapshots(test);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (((_a = test.result) == null ? void 0 : _a.state) === "fail") {
|
|
438
|
+
updateTask(test);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
const start = now();
|
|
442
|
+
test.result = {
|
|
443
|
+
state: "run",
|
|
444
|
+
startTime: start
|
|
445
|
+
};
|
|
446
|
+
updateTask(test);
|
|
447
|
+
clearModuleMocks();
|
|
448
|
+
await getSnapshotClient().setTest(test);
|
|
449
|
+
const workerState = getWorkerState();
|
|
450
|
+
workerState.current = test;
|
|
451
|
+
let beforeEachCleanups = [];
|
|
452
|
+
try {
|
|
453
|
+
beforeEachCleanups = await callSuiteHook(test.suite, test, "beforeEach", [test.context, test.suite]);
|
|
454
|
+
setState({
|
|
455
|
+
assertionCalls: 0,
|
|
456
|
+
isExpectingAssertions: false,
|
|
457
|
+
isExpectingAssertionsError: null,
|
|
458
|
+
expectedAssertionsNumber: null,
|
|
459
|
+
expectedAssertionsNumberErrorGen: null,
|
|
460
|
+
testPath: (_b = test.suite.file) == null ? void 0 : _b.filepath,
|
|
461
|
+
currentTestName: getFullName(test)
|
|
462
|
+
}, globalThis[GLOBAL_EXPECT]);
|
|
463
|
+
await getFn(test)();
|
|
464
|
+
const {
|
|
465
|
+
assertionCalls,
|
|
466
|
+
expectedAssertionsNumber,
|
|
467
|
+
expectedAssertionsNumberErrorGen,
|
|
468
|
+
isExpectingAssertions,
|
|
469
|
+
isExpectingAssertionsError
|
|
470
|
+
} = test.context._local ? test.context.expect.getState() : getState(globalThis[GLOBAL_EXPECT]);
|
|
471
|
+
if (expectedAssertionsNumber !== null && assertionCalls !== expectedAssertionsNumber)
|
|
472
|
+
throw expectedAssertionsNumberErrorGen();
|
|
473
|
+
if (isExpectingAssertions === true && assertionCalls === 0)
|
|
474
|
+
throw isExpectingAssertionsError;
|
|
475
|
+
test.result.state = "pass";
|
|
476
|
+
} catch (e) {
|
|
477
|
+
test.result.state = "fail";
|
|
478
|
+
test.result.error = processError(e);
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
await callSuiteHook(test.suite, test, "afterEach", [test.context, test.suite]);
|
|
482
|
+
await Promise.all(beforeEachCleanups.map((i) => i == null ? void 0 : i()));
|
|
483
|
+
} catch (e) {
|
|
484
|
+
test.result.state = "fail";
|
|
485
|
+
test.result.error = processError(e);
|
|
486
|
+
}
|
|
487
|
+
if (test.fails) {
|
|
488
|
+
if (test.result.state === "pass") {
|
|
489
|
+
test.result.state = "fail";
|
|
490
|
+
test.result.error = processError(new Error("Expect test to fail"));
|
|
491
|
+
} else {
|
|
492
|
+
test.result.state = "pass";
|
|
493
|
+
test.result.error = void 0;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
getSnapshotClient().clearTest();
|
|
497
|
+
test.result.duration = now() - start;
|
|
498
|
+
if (workerState.config.logHeapUsage)
|
|
499
|
+
test.result.heap = process.memoryUsage().heapUsed;
|
|
500
|
+
workerState.current = void 0;
|
|
501
|
+
updateTask(test);
|
|
502
|
+
}
|
|
503
|
+
function markTasksAsSkipped(suite) {
|
|
504
|
+
suite.tasks.forEach((t) => {
|
|
505
|
+
t.mode = "skip";
|
|
506
|
+
t.result = { ...t.result, state: "skip" };
|
|
507
|
+
updateTask(t);
|
|
508
|
+
if (t.type === "suite")
|
|
509
|
+
markTasksAsSkipped(t);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
async function runSuite(suite) {
|
|
513
|
+
var _a;
|
|
514
|
+
if (((_a = suite.result) == null ? void 0 : _a.state) === "fail") {
|
|
515
|
+
markTasksAsSkipped(suite);
|
|
516
|
+
updateTask(suite);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const start = now();
|
|
520
|
+
suite.result = {
|
|
521
|
+
state: "run",
|
|
522
|
+
startTime: start
|
|
523
|
+
};
|
|
524
|
+
updateTask(suite);
|
|
525
|
+
const workerState = getWorkerState();
|
|
526
|
+
if (suite.mode === "skip") {
|
|
527
|
+
suite.result.state = "skip";
|
|
528
|
+
} else if (suite.mode === "todo") {
|
|
529
|
+
suite.result.state = "todo";
|
|
530
|
+
} else {
|
|
531
|
+
try {
|
|
532
|
+
const beforeAllCleanups = await callSuiteHook(suite, suite, "beforeAll", [suite]);
|
|
533
|
+
for (let tasksGroup of partitionSuiteChildren(suite)) {
|
|
534
|
+
if (tasksGroup[0].concurrent === true) {
|
|
535
|
+
const mutex = pLimit(workerState.config.maxConcurrency);
|
|
536
|
+
await Promise.all(tasksGroup.map((c) => mutex(() => runSuiteChild(c))));
|
|
537
|
+
} else {
|
|
538
|
+
const { sequence } = workerState.config;
|
|
539
|
+
if (sequence.shuffle || suite.shuffle) {
|
|
540
|
+
const suites = tasksGroup.filter((group) => group.type === "suite");
|
|
541
|
+
const tests = tasksGroup.filter((group) => group.type === "test");
|
|
542
|
+
const groups = shuffle([suites, tests], sequence.seed);
|
|
543
|
+
tasksGroup = groups.flatMap((group) => shuffle(group, sequence.seed));
|
|
544
|
+
}
|
|
545
|
+
for (const c of tasksGroup)
|
|
546
|
+
await runSuiteChild(c);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
await callSuiteHook(suite, suite, "afterAll", [suite]);
|
|
550
|
+
await Promise.all(beforeAllCleanups.map((i) => i == null ? void 0 : i()));
|
|
551
|
+
} catch (e) {
|
|
552
|
+
suite.result.state = "fail";
|
|
553
|
+
suite.result.error = processError(e);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
suite.result.duration = now() - start;
|
|
557
|
+
if (workerState.config.logHeapUsage)
|
|
558
|
+
suite.result.heap = process.memoryUsage().heapUsed;
|
|
559
|
+
if (suite.mode === "run") {
|
|
560
|
+
if (!hasTests(suite)) {
|
|
561
|
+
suite.result.state = "fail";
|
|
562
|
+
if (!suite.result.error)
|
|
563
|
+
suite.result.error = new Error(`No test found in suite ${suite.name}`);
|
|
564
|
+
} else if (hasFailed(suite)) {
|
|
565
|
+
suite.result.state = "fail";
|
|
566
|
+
} else {
|
|
567
|
+
suite.result.state = "pass";
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
updateTask(suite);
|
|
571
|
+
}
|
|
572
|
+
async function runSuiteChild(c) {
|
|
573
|
+
return c.type === "test" ? runTest(c) : runSuite(c);
|
|
574
|
+
}
|
|
575
|
+
async function runFiles(files, config) {
|
|
576
|
+
var _a;
|
|
577
|
+
for (const file of files) {
|
|
578
|
+
if (!file.tasks.length && !config.passWithNoTests) {
|
|
579
|
+
if (!((_a = file.result) == null ? void 0 : _a.error)) {
|
|
580
|
+
file.result = {
|
|
581
|
+
state: "fail",
|
|
582
|
+
error: new Error(`No test suite found in file ${file.filepath}`)
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
await runSuite(file);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
async function startTests(paths, config) {
|
|
590
|
+
const files = await collectTests(paths, config);
|
|
591
|
+
rpc().onCollected(files);
|
|
592
|
+
getSnapshotClient().clear();
|
|
593
|
+
await runFiles(files, config);
|
|
594
|
+
takeCoverage();
|
|
595
|
+
await getSnapshotClient().saveCurrent();
|
|
596
|
+
await sendTasksUpdate();
|
|
597
|
+
}
|
|
598
|
+
function clearModuleMocks() {
|
|
599
|
+
const { clearMocks, mockReset, restoreMocks } = getWorkerState().config;
|
|
600
|
+
if (restoreMocks)
|
|
601
|
+
vi.restoreAllMocks();
|
|
602
|
+
else if (mockReset)
|
|
603
|
+
vi.resetAllMocks();
|
|
604
|
+
else if (clearMocks)
|
|
605
|
+
vi.clearAllMocks();
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
async function run(files, config) {
|
|
609
|
+
await setupGlobalEnv(config);
|
|
610
|
+
const workerState = getWorkerState();
|
|
611
|
+
const filesWithEnv = await Promise.all(files.map(async (file) => {
|
|
612
|
+
var _a;
|
|
613
|
+
const code = await promises.readFile(file, "utf-8");
|
|
614
|
+
const env = ((_a = code.match(/@(?:vitest|jest)-environment\s+?([\w-]+)\b/)) == null ? void 0 : _a[1]) || config.environment || "node";
|
|
615
|
+
if (!envs.includes(env))
|
|
616
|
+
throw new Error(`Unsupported environment: "${env}" in ${file}`);
|
|
617
|
+
return {
|
|
618
|
+
file,
|
|
619
|
+
env
|
|
620
|
+
};
|
|
621
|
+
}));
|
|
622
|
+
const filesByEnv = filesWithEnv.reduce((acc, { file, env }) => {
|
|
623
|
+
acc[env] || (acc[env] = []);
|
|
624
|
+
acc[env].push(file);
|
|
625
|
+
return acc;
|
|
626
|
+
}, {});
|
|
627
|
+
for (const env of envs) {
|
|
628
|
+
const environment = env;
|
|
629
|
+
const files2 = filesByEnv[environment];
|
|
630
|
+
if (!files2 || !files2.length)
|
|
631
|
+
continue;
|
|
632
|
+
await withEnv(environment, config.environmentOptions || {}, async () => {
|
|
633
|
+
for (const file of files2) {
|
|
634
|
+
workerState.mockMap.clear();
|
|
635
|
+
resetModules();
|
|
636
|
+
workerState.filepath = file;
|
|
637
|
+
await startTests([file], config);
|
|
638
|
+
workerState.filepath = void 0;
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export { run };
|