vitest 4.0.0-beta.5 → 4.0.0-beta.7
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/browser.d.ts +3 -3
- package/dist/browser.js +2 -2
- package/dist/chunks/{base.DMfOuRWD.js → base.BXI97p6t.js} +7 -16
- package/dist/chunks/{benchmark.CtuRzf-i.js → benchmark.UW6Ezvxy.js} +4 -9
- package/dist/chunks/{browser.d.Cawq_X_N.d.ts → browser.d.DOMmqJQx.d.ts} +1 -1
- package/dist/chunks/{cac.CKnbxhn2.js → cac.Dsn7ixFt.js} +38 -113
- package/dist/chunks/{cli-api.COn58yrl.js → cli-api.DfGJyldU.js} +829 -1232
- package/dist/chunks/{config.d.CKNVOKm0.d.ts → config.d._GBBbReY.d.ts} +1 -0
- package/dist/chunks/{console.Duv2dVIC.js → console.B0quX7yH.js} +32 -68
- package/dist/chunks/{coverage.B6cReEn1.js → coverage.Dvxug1RM.js} +210 -579
- package/dist/chunks/{creator.DUVZ6rfm.js → creator.KEg6n5IC.js} +28 -74
- package/dist/chunks/{date.Bq6ZW5rf.js → date.-jtEtIeV.js} +6 -17
- package/dist/chunks/{git.BVQ8w_Sw.js → git.BFNcloKD.js} +1 -2
- package/dist/chunks/{globals.CJQ63oO0.js → globals.lgsmH00r.js} +5 -5
- package/dist/chunks/{index.QZr3S3vQ.js → index.AR8aAkCC.js} +2 -2
- package/dist/chunks/{index.DQhAfQQU.js → index.C3EbxYwt.js} +276 -607
- package/dist/chunks/{index.oWRWx-nj.js → index.CsFXYRkW.js} +17 -36
- package/dist/chunks/{index.DgN0Zk9a.js → index.D2B6d2vv.js} +14 -24
- package/dist/chunks/{index.BRtIe7r8.js → index.DfviD7lX.js} +55 -110
- package/dist/chunks/{inspector.C914Efll.js → inspector.CvQD-Nie.js} +10 -25
- package/dist/chunks/{moduleRunner.d.mmOmOGrW.d.ts → moduleRunner.d.CX4DuqOx.d.ts} +2 -2
- package/dist/chunks/{node.4JV5OXkt.js → node.BOqcT2jW.js} +1 -1
- package/dist/chunks/{plugin.d.CvOlgjxK.d.ts → plugin.d.vcD4xbMS.d.ts} +1 -1
- package/dist/chunks/{reporters.d.CYE9sT5z.d.ts → reporters.d.BC86JJdB.d.ts} +799 -758
- package/dist/chunks/{resolver.D5bG4zy5.js → resolver.Bx6lE0iq.js} +21 -64
- package/dist/chunks/{rpc.DGoW_Vl-.js → rpc.RpPylpp0.js} +7 -21
- package/dist/chunks/{runBaseTests.B3KcKqlF.js → runBaseTests.D6sfuWBM.js} +25 -54
- package/dist/chunks/{setup-common.lgPs-bYv.js → setup-common.hLGRxhC8.js} +9 -22
- package/dist/chunks/{startModuleRunner.C8FtT_BY.js → startModuleRunner.C8TW8zTN.js} +83 -205
- package/dist/chunks/{typechecker.BgoW4nTA.js → typechecker.DSo_maXz.js} +97 -209
- package/dist/chunks/{utils.CcGm2cd1.js → utils.C2YI6McM.js} +4 -13
- package/dist/chunks/{utils.B9FY3b73.js → utils.C7__0Iv5.js} +5 -14
- package/dist/chunks/{vi.DGAfBY4R.js → vi.BfdOiD4j.js} +110 -267
- package/dist/chunks/{vm.BKfKvaKl.js → vm.BHBje7cC.js} +73 -177
- package/dist/chunks/{worker.d.Db-UVmXc.d.ts → worker.d.BKu8cnnX.d.ts} +1 -1
- package/dist/chunks/{worker.d.D9QWnzAe.d.ts → worker.d.DYlqbejz.d.ts} +1 -1
- package/dist/cli.js +3 -3
- package/dist/config.d.ts +7 -7
- package/dist/coverage.d.ts +4 -4
- package/dist/coverage.js +2 -2
- package/dist/environments.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -5
- package/dist/module-evaluator.d.ts +3 -3
- package/dist/module-evaluator.js +33 -84
- package/dist/module-runner.js +2 -2
- package/dist/node.d.ts +11 -9
- package/dist/node.js +16 -27
- package/dist/reporters.d.ts +5 -5
- package/dist/reporters.js +3 -3
- package/dist/runners.d.ts +1 -1
- package/dist/runners.js +23 -51
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +18 -34
- package/dist/workers/forks.js +4 -4
- package/dist/workers/runVmTests.js +19 -37
- package/dist/workers/threads.js +4 -4
- package/dist/workers/vmForks.js +7 -7
- package/dist/workers/vmThreads.js +7 -7
- package/dist/workers.d.ts +3 -3
- package/dist/workers.js +11 -11
- package/package.json +11 -11
|
@@ -2,16 +2,17 @@ import fs, { promises, existsSync, readFileSync, mkdirSync, writeFileSync } from
|
|
|
2
2
|
import { relative, resolve, dirname, extname, normalize, join, basename, isAbsolute } from 'pathe';
|
|
3
3
|
import { C as CoverageProviderMap } from './coverage.D_JHT54q.js';
|
|
4
4
|
import path, { resolve as resolve$1 } from 'node:path';
|
|
5
|
-
import { noop,
|
|
5
|
+
import { noop, createDefer, slash, highlight, toArray, cleanUrl, deepMerge, KNOWN_ASSET_RE, nanoid, deepClone, isPrimitive, notNullish } from '@vitest/utils';
|
|
6
6
|
import { f as findUp, p as prompt } from './index.X0nbfr6-.js';
|
|
7
7
|
import * as vite from 'vite';
|
|
8
|
-
import { searchForWorkspaceRoot, version, mergeConfig, createServer } from 'vite';
|
|
8
|
+
import { parseAst, searchForWorkspaceRoot, version, mergeConfig, createServer } from 'vite';
|
|
9
9
|
import { A as API_PATH, c as configFiles, d as defaultBrowserPort, a as defaultPort } from './constants.D_Q9UYh-.js';
|
|
10
|
-
import
|
|
10
|
+
import nodeos__default, { tmpdir } from 'node:os';
|
|
11
|
+
import { generateHash as generateHash$1, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, generateFileHash, limitConcurrency, createFileTask as createFileTask$1, hasFailed, getTasks, getTests } from '@vitest/runner/utils';
|
|
11
12
|
import { SnapshotManager } from '@vitest/snapshot/manager';
|
|
12
|
-
import { v as version$1 } from './cac.
|
|
13
|
+
import { v as version$1 } from './cac.Dsn7ixFt.js';
|
|
13
14
|
import { c as createBirpc } from './index.Bgo3tNWt.js';
|
|
14
|
-
import { p as parse, s as stringify, d as printError, f as formatProjectName, w as withLabel, e as errorBanner, h as divider, i as generateCodeFrame, R as ReportersMap, B as BlobReporter, r as readBlobs, H as HangingProcessReporter } from './index.
|
|
15
|
+
import { p as parse, s as stringify, d as printError, f as formatProjectName, w as withLabel, e as errorBanner, h as divider, i as generateCodeFrame, R as ReportersMap, B as BlobReporter, r as readBlobs, H as HangingProcessReporter } from './index.C3EbxYwt.js';
|
|
15
16
|
import require$$0$3 from 'events';
|
|
16
17
|
import require$$1$1 from 'https';
|
|
17
18
|
import require$$2 from 'http';
|
|
@@ -23,11 +24,12 @@ import require$$7 from 'url';
|
|
|
23
24
|
import require$$0 from 'zlib';
|
|
24
25
|
import require$$0$1 from 'buffer';
|
|
25
26
|
import { g as getDefaultExportFromCjs } from './_commonjsHelpers.BFTU3MAI.js';
|
|
26
|
-
import { parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
27
27
|
import crypto, { createHash } from 'node:crypto';
|
|
28
28
|
import { distDir, rootDir } from '../path.js';
|
|
29
|
-
import { h as hash, d as createFetchModuleFunction, n as normalizeResolvedIdToUrl, R as RandomSequencer, i as isPackageExists, g as getFilePoolName, e as isBrowserEnabled, r as resolveConfig, f as groupBy, j as getCoverageProvider, k as createPool, w as wildcardPatternToRegExp, a as resolveApiServerConfig, s as stdout } from './coverage.
|
|
30
|
-
import { c as convertTasksToEvents } from './typechecker.
|
|
29
|
+
import { h as hash, d as createFetchModuleFunction, n as normalizeResolvedIdToUrl, R as RandomSequencer, i as isPackageExists, g as getFilePoolName, e as isBrowserEnabled, r as resolveConfig, f as groupBy, j as getCoverageProvider, k as createPool, w as wildcardPatternToRegExp, a as resolveApiServerConfig, s as stdout } from './coverage.Dvxug1RM.js';
|
|
30
|
+
import { b as ancestor, c as convertTasksToEvents } from './typechecker.DSo_maXz.js';
|
|
31
|
+
import { TraceMap, originalPositionFor, parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
32
|
+
import createDebug from 'debug';
|
|
31
33
|
import { VitestModuleEvaluator } from '#module-evaluator';
|
|
32
34
|
import { ModuleRunner } from 'vite/module-runner';
|
|
33
35
|
import { Console } from 'node:console';
|
|
@@ -36,17 +38,16 @@ import { createRequire, builtinModules, isBuiltin } from 'node:module';
|
|
|
36
38
|
import url, { pathToFileURL } from 'node:url';
|
|
37
39
|
import { i as isTTY, a as isWindows } from './env.D4Lgay0q.js';
|
|
38
40
|
import { rm, mkdir, copyFile } from 'node:fs/promises';
|
|
39
|
-
import nodeos__default, { tmpdir } from 'node:os';
|
|
40
41
|
import pm from 'picomatch';
|
|
41
42
|
import { glob, isDynamicPattern } from 'tinyglobby';
|
|
42
43
|
import MagicString from 'magic-string';
|
|
43
44
|
import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
|
|
44
45
|
import { c as configDefaults } from './defaults.CXFFjsi8.js';
|
|
45
|
-
import { f as findNearestPackageData } from './resolver.
|
|
46
|
+
import { f as findNearestPackageData } from './resolver.Bx6lE0iq.js';
|
|
46
47
|
import * as esModuleLexer from 'es-module-lexer';
|
|
47
|
-
import { a as BenchmarkReportsMap } from './index.
|
|
48
|
+
import { a as BenchmarkReportsMap } from './index.D2B6d2vv.js';
|
|
48
49
|
import assert$1 from 'node:assert';
|
|
49
|
-
import { serializeError } from '@vitest/utils/error';
|
|
50
|
+
import { serializeError as serializeError$1 } from '@vitest/utils/error';
|
|
50
51
|
import readline from 'node:readline';
|
|
51
52
|
import { stripVTControlCharacters } from 'node:util';
|
|
52
53
|
|
|
@@ -5017,26 +5018,18 @@ var websocketServerExports = requireWebsocketServer();
|
|
|
5017
5018
|
var WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExports);
|
|
5018
5019
|
|
|
5019
5020
|
async function getModuleGraph(ctx, projectName, id, browser = false) {
|
|
5020
|
-
const graph = {};
|
|
5021
|
-
const externalized = /* @__PURE__ */ new Set();
|
|
5022
|
-
const inlined = /* @__PURE__ */ new Set();
|
|
5023
|
-
const project = ctx.getProjectByName(projectName);
|
|
5021
|
+
const graph = {}, externalized = /* @__PURE__ */ new Set(), inlined = /* @__PURE__ */ new Set(), project = ctx.getProjectByName(projectName);
|
|
5024
5022
|
async function get(mod, seen = /* @__PURE__ */ new Map()) {
|
|
5025
|
-
if (!mod || !mod.id) return;
|
|
5026
|
-
if (mod.id === "\0@vitest/browser/context") return;
|
|
5023
|
+
if (!mod || !mod.id || mod.id === "\0@vitest/browser/context") return;
|
|
5027
5024
|
if (seen.has(mod)) return seen.get(mod);
|
|
5028
5025
|
let id = clearId(mod.id);
|
|
5029
5026
|
seen.set(mod, id);
|
|
5030
5027
|
// TODO: how to know if it was rewritten(?) - what is rewritten?
|
|
5031
5028
|
const rewrote = browser ? mod.file?.includes(project.browser.vite.config.cacheDir) ? mod.id : false : false;
|
|
5032
|
-
if (rewrote)
|
|
5033
|
-
|
|
5034
|
-
externalized.add(id);
|
|
5035
|
-
seen.set(mod, id);
|
|
5036
|
-
} else inlined.add(id);
|
|
5029
|
+
if (rewrote) id = rewrote, externalized.add(id), seen.set(mod, id);
|
|
5030
|
+
else inlined.add(id);
|
|
5037
5031
|
const mods = Array.from(mod.importedModules).filter((i) => i.id && !i.id.includes("/vitest/dist/"));
|
|
5038
|
-
graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean);
|
|
5039
|
-
return id;
|
|
5032
|
+
return graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean), id;
|
|
5040
5033
|
}
|
|
5041
5034
|
if (browser && project.browser) await get(project.browser.vite.moduleGraph.getModuleById(id));
|
|
5042
5035
|
else await get(project.vite.moduleGraph.getModuleById(id));
|
|
@@ -5088,21 +5081,19 @@ catch {}
|
|
|
5088
5081
|
}
|
|
5089
5082
|
|
|
5090
5083
|
function setup(ctx, _server) {
|
|
5091
|
-
const wss = new WebSocketServer({ noServer: true });
|
|
5092
|
-
const clients = /* @__PURE__ */ new Map();
|
|
5093
|
-
const server = _server || ctx.server;
|
|
5084
|
+
const wss = new WebSocketServer({ noServer: true }), clients = /* @__PURE__ */ new Map(), server = _server || ctx.server;
|
|
5094
5085
|
server.httpServer?.on("upgrade", (request, socket, head) => {
|
|
5095
5086
|
if (!request.url) return;
|
|
5096
5087
|
const { pathname } = new URL(request.url, "http://localhost");
|
|
5097
|
-
if (pathname
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5088
|
+
if (pathname === API_PATH) {
|
|
5089
|
+
if (!isValidApiRequest(ctx.config, request)) {
|
|
5090
|
+
socket.destroy();
|
|
5091
|
+
return;
|
|
5092
|
+
}
|
|
5093
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
5094
|
+
wss.emit("connection", ws, request), setupClient(ws);
|
|
5095
|
+
});
|
|
5101
5096
|
}
|
|
5102
|
-
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
5103
|
-
wss.emit("connection", ws, request);
|
|
5104
|
-
setupClient(ws);
|
|
5105
|
-
});
|
|
5106
5097
|
});
|
|
5107
5098
|
function setupClient(ws) {
|
|
5108
5099
|
const rpc = createBirpc({
|
|
@@ -5116,8 +5107,7 @@ function setup(ctx, _server) {
|
|
|
5116
5107
|
return ctx.state.getPaths();
|
|
5117
5108
|
},
|
|
5118
5109
|
async readTestFile(id) {
|
|
5119
|
-
|
|
5120
|
-
return promises.readFile(id, "utf-8");
|
|
5110
|
+
return !ctx.state.filesMap.has(id) || !existsSync(id) ? null : promises.readFile(id, "utf-8");
|
|
5121
5111
|
},
|
|
5122
5112
|
async saveTestFile(id, content) {
|
|
5123
5113
|
if (!ctx.state.filesMap.has(id) || !existsSync(id)) throw new Error(`Test file "${id}" was not registered, so it cannot be updated using the API.`);
|
|
@@ -5139,8 +5129,7 @@ function setup(ctx, _server) {
|
|
|
5139
5129
|
}));
|
|
5140
5130
|
},
|
|
5141
5131
|
async getTransformResult(projectName, id, browser = false) {
|
|
5142
|
-
const project = ctx.getProjectByName(projectName);
|
|
5143
|
-
const result = browser ? await project.browser.vite.transformRequest(id) : await project.vite.transformRequest(id);
|
|
5132
|
+
const project = ctx.getProjectByName(projectName), result = browser ? await project.browser.vite.transformRequest(id) : await project.vite.transformRequest(id);
|
|
5144
5133
|
if (result) {
|
|
5145
5134
|
try {
|
|
5146
5135
|
result.source = result.source || await promises.readFile(id, "utf-8");
|
|
@@ -5183,56 +5172,41 @@ function setup(ctx, _server) {
|
|
|
5183
5172
|
deserialize: parse,
|
|
5184
5173
|
timeout: -1
|
|
5185
5174
|
});
|
|
5186
|
-
clients.set(ws, rpc)
|
|
5187
|
-
|
|
5188
|
-
clients.delete(ws);
|
|
5189
|
-
rpc.$close(/* @__PURE__ */ new Error("[vitest-api]: Pending methods while closing rpc"));
|
|
5175
|
+
clients.set(ws, rpc), ws.on("close", () => {
|
|
5176
|
+
clients.delete(ws), rpc.$close(/* @__PURE__ */ new Error("[vitest-api]: Pending methods while closing rpc"));
|
|
5190
5177
|
});
|
|
5191
5178
|
}
|
|
5192
5179
|
ctx.reporters.push(new WebSocketReporter(ctx, wss, clients));
|
|
5193
5180
|
}
|
|
5194
5181
|
class WebSocketReporter {
|
|
5195
5182
|
constructor(ctx, wss, clients) {
|
|
5196
|
-
this.ctx = ctx;
|
|
5197
|
-
this.wss = wss;
|
|
5198
|
-
this.clients = clients;
|
|
5183
|
+
this.ctx = ctx, this.wss = wss, this.clients = clients;
|
|
5199
5184
|
}
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
client.onCollected?.(files)?.catch?.(noop);
|
|
5185
|
+
onTestModuleCollected(testModule) {
|
|
5186
|
+
this.clients.size !== 0 && this.clients.forEach((client) => {
|
|
5187
|
+
client.onCollected?.([testModule.task])?.catch?.(noop);
|
|
5204
5188
|
});
|
|
5205
5189
|
}
|
|
5206
|
-
|
|
5190
|
+
onTestRunStart(specifications) {
|
|
5207
5191
|
if (this.clients.size === 0) return;
|
|
5192
|
+
const serializedSpecs = specifications.map((spec) => spec.toJSON());
|
|
5208
5193
|
this.clients.forEach((client) => {
|
|
5209
|
-
client.onSpecsCollected?.(
|
|
5194
|
+
client.onSpecsCollected?.(serializedSpecs)?.catch?.(noop);
|
|
5210
5195
|
});
|
|
5211
5196
|
}
|
|
5212
5197
|
async onTestCaseAnnotate(testCase, annotation) {
|
|
5213
|
-
|
|
5214
|
-
this.clients.forEach((client) => {
|
|
5198
|
+
this.clients.size !== 0 && this.clients.forEach((client) => {
|
|
5215
5199
|
client.onTestAnnotate?.(testCase.id, annotation)?.catch?.(noop);
|
|
5216
5200
|
});
|
|
5217
5201
|
}
|
|
5218
5202
|
async onTaskUpdate(packs, events) {
|
|
5219
|
-
|
|
5220
|
-
packs.forEach(([taskId, result]) => {
|
|
5221
|
-
const task = this.ctx.state.idMap.get(taskId);
|
|
5222
|
-
const isBrowser = task && task.file.pool === "browser";
|
|
5223
|
-
result?.errors?.forEach((error) => {
|
|
5224
|
-
if (isPrimitive(error)) return;
|
|
5225
|
-
if (isBrowser) {
|
|
5226
|
-
const project = this.ctx.getProjectByName(task.file.projectName || "");
|
|
5227
|
-
error.stacks = project.browser?.parseErrorStacktrace(error);
|
|
5228
|
-
} else error.stacks = parseErrorStacktrace(error);
|
|
5229
|
-
});
|
|
5230
|
-
});
|
|
5231
|
-
this.clients.forEach((client) => {
|
|
5203
|
+
this.clients.size !== 0 && this.clients.forEach((client) => {
|
|
5232
5204
|
client.onTaskUpdate?.(packs, events)?.catch?.(noop);
|
|
5233
5205
|
});
|
|
5234
5206
|
}
|
|
5235
|
-
|
|
5207
|
+
onTestRunEnd(testModules, unhandledErrors) {
|
|
5208
|
+
if (!this.clients.size) return;
|
|
5209
|
+
const files = testModules.map((testModule) => testModule.task), errors = [...unhandledErrors];
|
|
5236
5210
|
this.clients.forEach((client) => {
|
|
5237
5211
|
client.onFinished?.(files, errors)?.catch?.(noop);
|
|
5238
5212
|
});
|
|
@@ -5255,6 +5229,265 @@ var setup$1 = /*#__PURE__*/Object.freeze({
|
|
|
5255
5229
|
setup: setup
|
|
5256
5230
|
});
|
|
5257
5231
|
|
|
5232
|
+
function createDebugger(namespace) {
|
|
5233
|
+
const debug = createDebug(namespace);
|
|
5234
|
+
if (debug.enabled) return debug;
|
|
5235
|
+
}
|
|
5236
|
+
|
|
5237
|
+
const debug = createDebugger("vitest:ast-collect-info"), verbose = createDebugger("vitest:ast-collect-verbose");
|
|
5238
|
+
function astParseFile(filepath, code) {
|
|
5239
|
+
const ast = parseAst(code);
|
|
5240
|
+
if (verbose) verbose("Collecting", filepath, code);
|
|
5241
|
+
else debug?.("Collecting", filepath);
|
|
5242
|
+
const definitions = [], getName = (callee) => {
|
|
5243
|
+
if (!callee) return null;
|
|
5244
|
+
if (callee.type === "Identifier") return callee.name;
|
|
5245
|
+
if (callee.type === "CallExpression") return getName(callee.callee);
|
|
5246
|
+
if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
|
|
5247
|
+
if (callee.type === "MemberExpression")
|
|
5248
|
+
// call as `__vite_ssr__.test.skip()`
|
|
5249
|
+
return callee.object?.type === "Identifier" && [
|
|
5250
|
+
"it",
|
|
5251
|
+
"test",
|
|
5252
|
+
"describe",
|
|
5253
|
+
"suite"
|
|
5254
|
+
].includes(callee.object.name) ? callee.object?.name : callee.object?.name?.startsWith("__vite_ssr_") || callee.object?.object?.name?.startsWith("__vite_ssr_") && callee.object?.property?.name === "Vitest" ? getName(callee.property) : getName(callee.object?.property);
|
|
5255
|
+
// unwrap (0, ...)
|
|
5256
|
+
if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
|
|
5257
|
+
const [e0, e1] = callee.expressions;
|
|
5258
|
+
if (e0.type === "Literal" && e0.value === 0) return getName(e1);
|
|
5259
|
+
}
|
|
5260
|
+
return null;
|
|
5261
|
+
};
|
|
5262
|
+
return ancestor(ast, { CallExpression(node) {
|
|
5263
|
+
const { callee } = node, name = getName(callee);
|
|
5264
|
+
if (!name) return;
|
|
5265
|
+
if (![
|
|
5266
|
+
"it",
|
|
5267
|
+
"test",
|
|
5268
|
+
"describe",
|
|
5269
|
+
"suite"
|
|
5270
|
+
].includes(name)) {
|
|
5271
|
+
verbose?.(`Skipping ${name} (unknown call)`);
|
|
5272
|
+
return;
|
|
5273
|
+
}
|
|
5274
|
+
const property = callee?.property?.name;
|
|
5275
|
+
let mode = !property || property === name ? "run" : property;
|
|
5276
|
+
// they will be picked up in the next iteration
|
|
5277
|
+
if ([
|
|
5278
|
+
"each",
|
|
5279
|
+
"for",
|
|
5280
|
+
"skipIf",
|
|
5281
|
+
"runIf"
|
|
5282
|
+
].includes(mode)) return;
|
|
5283
|
+
let start;
|
|
5284
|
+
const end = node.end;
|
|
5285
|
+
// .each or (0, __vite_ssr_exports_0__.test)()
|
|
5286
|
+
if (callee.type === "CallExpression" || callee.type === "SequenceExpression" || callee.type === "TaggedTemplateExpression") start = callee.end;
|
|
5287
|
+
else start = node.start;
|
|
5288
|
+
const messageNode = node.arguments?.[0];
|
|
5289
|
+
if (messageNode == null) {
|
|
5290
|
+
verbose?.(`Skipping node at ${node.start} because it doesn't have a name`);
|
|
5291
|
+
return;
|
|
5292
|
+
}
|
|
5293
|
+
let message;
|
|
5294
|
+
if (messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral") message = code.slice(messageNode.start + 1, messageNode.end - 1);
|
|
5295
|
+
else message = code.slice(messageNode.start, messageNode.end);
|
|
5296
|
+
if (message.startsWith("0,")) message = message.slice(2);
|
|
5297
|
+
// cannot statically analyze, so we always skip it
|
|
5298
|
+
if (message = message.replace(/__vite_ssr_import_\d+__\./g, "").replace(/__vi_import_\d+__\./g, ""), mode === "skipIf" || mode === "runIf") mode = "skip";
|
|
5299
|
+
const parentCalleeName = typeof callee?.callee === "object" && callee?.callee.type === "MemberExpression" && callee?.callee.property?.name;
|
|
5300
|
+
let isDynamicEach = parentCalleeName === "each" || parentCalleeName === "for";
|
|
5301
|
+
if (!isDynamicEach && callee.type === "TaggedTemplateExpression") {
|
|
5302
|
+
const property = callee.tag?.property?.name;
|
|
5303
|
+
isDynamicEach = property === "each" || property === "for";
|
|
5304
|
+
}
|
|
5305
|
+
debug?.("Found", name, message, `(${mode})`), definitions.push({
|
|
5306
|
+
start,
|
|
5307
|
+
end,
|
|
5308
|
+
name: message,
|
|
5309
|
+
type: name === "it" || name === "test" ? "test" : "suite",
|
|
5310
|
+
mode,
|
|
5311
|
+
task: null,
|
|
5312
|
+
dynamic: isDynamicEach
|
|
5313
|
+
});
|
|
5314
|
+
} }), {
|
|
5315
|
+
ast,
|
|
5316
|
+
definitions
|
|
5317
|
+
};
|
|
5318
|
+
}
|
|
5319
|
+
function createFailedFileTask(project, filepath, error) {
|
|
5320
|
+
const testFilepath = relative(project.config.root, filepath), file = {
|
|
5321
|
+
filepath,
|
|
5322
|
+
type: "suite",
|
|
5323
|
+
id: /* @__PURE__ */ generateHash$1(`${testFilepath}${project.config.name || ""}`),
|
|
5324
|
+
name: testFilepath,
|
|
5325
|
+
mode: "run",
|
|
5326
|
+
tasks: [],
|
|
5327
|
+
start: 0,
|
|
5328
|
+
end: 0,
|
|
5329
|
+
projectName: project.getName(),
|
|
5330
|
+
meta: {},
|
|
5331
|
+
pool: project.browser ? "browser" : project.config.pool,
|
|
5332
|
+
file: null,
|
|
5333
|
+
result: {
|
|
5334
|
+
state: "fail",
|
|
5335
|
+
errors: serializeError(project, error)
|
|
5336
|
+
}
|
|
5337
|
+
};
|
|
5338
|
+
return file.file = file, file;
|
|
5339
|
+
}
|
|
5340
|
+
function serializeError(ctx, error) {
|
|
5341
|
+
if ("errors" in error && "pluginCode" in error) {
|
|
5342
|
+
const errors = error.errors.map((e) => {
|
|
5343
|
+
return {
|
|
5344
|
+
name: error.name,
|
|
5345
|
+
message: e.text,
|
|
5346
|
+
stack: e.location ? `${error.name}: ${e.text}\n at ${relative(ctx.config.root, e.location.file)}:${e.location.line}:${e.location.column}` : ""
|
|
5347
|
+
};
|
|
5348
|
+
});
|
|
5349
|
+
return errors;
|
|
5350
|
+
}
|
|
5351
|
+
return [{
|
|
5352
|
+
name: error.name,
|
|
5353
|
+
stack: error.stack,
|
|
5354
|
+
message: error.message
|
|
5355
|
+
}];
|
|
5356
|
+
}
|
|
5357
|
+
function createFileTask(testFilepath, code, requestMap, options) {
|
|
5358
|
+
const { definitions, ast } = astParseFile(testFilepath, code), file = {
|
|
5359
|
+
filepath: options.filepath,
|
|
5360
|
+
type: "suite",
|
|
5361
|
+
id: /* @__PURE__ */ generateHash$1(`${testFilepath}${options.name || ""}`),
|
|
5362
|
+
name: testFilepath,
|
|
5363
|
+
mode: "run",
|
|
5364
|
+
tasks: [],
|
|
5365
|
+
start: ast.start,
|
|
5366
|
+
end: ast.end,
|
|
5367
|
+
projectName: options.name,
|
|
5368
|
+
meta: {},
|
|
5369
|
+
pool: "browser",
|
|
5370
|
+
file: null
|
|
5371
|
+
};
|
|
5372
|
+
file.file = file;
|
|
5373
|
+
const indexMap = createIndexMap(code), map = requestMap && new TraceMap(requestMap);
|
|
5374
|
+
let lastSuite = file;
|
|
5375
|
+
const updateLatestSuite = (index) => {
|
|
5376
|
+
while (lastSuite.suite && lastSuite.end < index) lastSuite = lastSuite.suite;
|
|
5377
|
+
return lastSuite;
|
|
5378
|
+
};
|
|
5379
|
+
definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
|
|
5380
|
+
const latestSuite = updateLatestSuite(definition.start);
|
|
5381
|
+
let mode = definition.mode;
|
|
5382
|
+
if (latestSuite.mode !== "run")
|
|
5383
|
+
// inherit suite mode, if it's set
|
|
5384
|
+
mode = latestSuite.mode;
|
|
5385
|
+
const processedLocation = indexMap.get(definition.start);
|
|
5386
|
+
let location;
|
|
5387
|
+
if (map && processedLocation) {
|
|
5388
|
+
const originalLocation = originalPositionFor(map, {
|
|
5389
|
+
line: processedLocation.line,
|
|
5390
|
+
column: processedLocation.column
|
|
5391
|
+
});
|
|
5392
|
+
if (originalLocation.column != null) verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column}`, "->", `${originalLocation.line}:${originalLocation.column}`), location = originalLocation;
|
|
5393
|
+
else debug?.("Cannot find original location for", definition.type, definition.name, `${processedLocation.column}:${processedLocation.line}`);
|
|
5394
|
+
} else debug?.("Cannot find original location for", definition.type, definition.name, `${definition.start}`);
|
|
5395
|
+
if (definition.type === "suite") {
|
|
5396
|
+
const task = {
|
|
5397
|
+
type: definition.type,
|
|
5398
|
+
id: "",
|
|
5399
|
+
suite: latestSuite,
|
|
5400
|
+
file,
|
|
5401
|
+
tasks: [],
|
|
5402
|
+
mode,
|
|
5403
|
+
name: definition.name,
|
|
5404
|
+
end: definition.end,
|
|
5405
|
+
start: definition.start,
|
|
5406
|
+
location,
|
|
5407
|
+
dynamic: definition.dynamic,
|
|
5408
|
+
meta: {}
|
|
5409
|
+
};
|
|
5410
|
+
definition.task = task, latestSuite.tasks.push(task), lastSuite = task;
|
|
5411
|
+
return;
|
|
5412
|
+
}
|
|
5413
|
+
const task = {
|
|
5414
|
+
type: definition.type,
|
|
5415
|
+
id: "",
|
|
5416
|
+
suite: latestSuite,
|
|
5417
|
+
file,
|
|
5418
|
+
mode,
|
|
5419
|
+
context: {},
|
|
5420
|
+
name: definition.name,
|
|
5421
|
+
end: definition.end,
|
|
5422
|
+
start: definition.start,
|
|
5423
|
+
location,
|
|
5424
|
+
dynamic: definition.dynamic,
|
|
5425
|
+
meta: {},
|
|
5426
|
+
timeout: 0,
|
|
5427
|
+
annotations: []
|
|
5428
|
+
};
|
|
5429
|
+
definition.task = task, latestSuite.tasks.push(task);
|
|
5430
|
+
}), calculateSuiteHash(file);
|
|
5431
|
+
const hasOnly = someTasksAreOnly(file);
|
|
5432
|
+
if (interpretTaskModes(file, options.testNamePattern, void 0, hasOnly, false, options.allowOnly), markDynamicTests(file.tasks), !file.tasks.length) file.result = {
|
|
5433
|
+
state: "fail",
|
|
5434
|
+
errors: [{
|
|
5435
|
+
name: "Error",
|
|
5436
|
+
message: `No test suite found in file ${options.filepath}`
|
|
5437
|
+
}]
|
|
5438
|
+
};
|
|
5439
|
+
return file;
|
|
5440
|
+
}
|
|
5441
|
+
async function astCollectTests(project, filepath) {
|
|
5442
|
+
const request = await transformSSR(project, filepath), testFilepath = relative(project.config.root, filepath);
|
|
5443
|
+
return request ? createFileTask(testFilepath, request.code, request.map, {
|
|
5444
|
+
name: project.config.name,
|
|
5445
|
+
filepath,
|
|
5446
|
+
allowOnly: project.config.allowOnly,
|
|
5447
|
+
testNamePattern: project.config.testNamePattern,
|
|
5448
|
+
pool: project.browser ? "browser" : project.config.pool
|
|
5449
|
+
}) : (debug?.("Cannot parse", testFilepath, "(vite didn't return anything)"), createFailedFileTask(project, filepath, /* @__PURE__ */ new Error(`Failed to parse ${testFilepath}. Vite didn't return anything.`)));
|
|
5450
|
+
}
|
|
5451
|
+
async function transformSSR(project, filepath) {
|
|
5452
|
+
const request = await project.vite.transformRequest(filepath, { ssr: false });
|
|
5453
|
+
return request ? await project.vite.ssrTransform(request.code, request.map, filepath) : null;
|
|
5454
|
+
}
|
|
5455
|
+
function createIndexMap(source) {
|
|
5456
|
+
const map = /* @__PURE__ */ new Map();
|
|
5457
|
+
let index = 0, line = 1, column = 1;
|
|
5458
|
+
for (const char of source) if (map.set(index++, {
|
|
5459
|
+
line,
|
|
5460
|
+
column
|
|
5461
|
+
}), char === "\n" || char === "\r\n") line++, column = 0;
|
|
5462
|
+
else column++;
|
|
5463
|
+
return map;
|
|
5464
|
+
}
|
|
5465
|
+
function markDynamicTests(tasks) {
|
|
5466
|
+
for (const task of tasks) {
|
|
5467
|
+
if (task.dynamic) task.id += "-dynamic";
|
|
5468
|
+
if ("tasks" in task) markDynamicTests(task.tasks);
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
function escapeRegex(str) {
|
|
5472
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5473
|
+
}
|
|
5474
|
+
const kReplacers = new Map([
|
|
5475
|
+
["%i", "\\d+?"],
|
|
5476
|
+
["%#", "\\d+?"],
|
|
5477
|
+
["%d", "[\\d.eE+-]+?"],
|
|
5478
|
+
["%f", "[\\d.eE+-]+?"],
|
|
5479
|
+
["%s", ".+?"],
|
|
5480
|
+
["%j", ".+?"],
|
|
5481
|
+
["%o", ".+?"],
|
|
5482
|
+
["%%", "%"]
|
|
5483
|
+
]);
|
|
5484
|
+
function escapeTestName(label, dynamic) {
|
|
5485
|
+
if (!dynamic) return escapeRegex(label);
|
|
5486
|
+
// Replace object access patterns ($value, $obj.a) with %s first
|
|
5487
|
+
let pattern = label.replace(/\$[a-z_.]+/gi, "%s");
|
|
5488
|
+
return pattern = escapeRegex(pattern), pattern = pattern.replace(/%[i#dfsjo%]/g, (m) => kReplacers.get(m) || m), pattern;
|
|
5489
|
+
}
|
|
5490
|
+
|
|
5258
5491
|
class BrowserSessions {
|
|
5259
5492
|
sessions = /* @__PURE__ */ new Map();
|
|
5260
5493
|
sessionIds = /* @__PURE__ */ new Set();
|
|
@@ -5266,23 +5499,18 @@ class BrowserSessions {
|
|
|
5266
5499
|
}
|
|
5267
5500
|
createSession(sessionId, project, pool) {
|
|
5268
5501
|
// this promise only waits for the WS connection with the orhcestrator to be established
|
|
5269
|
-
const defer = createDefer()
|
|
5270
|
-
const timeout = setTimeout(() => {
|
|
5502
|
+
const defer = createDefer(), timeout = setTimeout(() => {
|
|
5271
5503
|
defer.reject(/* @__PURE__ */ new Error(`Failed to connect to the browser session "${sessionId}" [${project.name}] within the timeout.`));
|
|
5272
5504
|
}, project.vitest.config.browser.connectTimeout ?? 6e4).unref();
|
|
5273
|
-
this.sessions.set(sessionId, {
|
|
5505
|
+
return this.sessions.set(sessionId, {
|
|
5274
5506
|
project,
|
|
5275
5507
|
connected: () => {
|
|
5276
|
-
defer.resolve();
|
|
5277
|
-
clearTimeout(timeout);
|
|
5508
|
+
defer.resolve(), clearTimeout(timeout);
|
|
5278
5509
|
},
|
|
5279
5510
|
fail: (error) => {
|
|
5280
|
-
defer.resolve();
|
|
5281
|
-
clearTimeout(timeout);
|
|
5282
|
-
pool.reject(error);
|
|
5511
|
+
defer.resolve(), clearTimeout(timeout), pool.reject(error);
|
|
5283
5512
|
}
|
|
5284
|
-
});
|
|
5285
|
-
return defer;
|
|
5513
|
+
}), defer;
|
|
5286
5514
|
}
|
|
5287
5515
|
}
|
|
5288
5516
|
|
|
@@ -5323,37 +5551,25 @@ class ResultsCache {
|
|
|
5323
5551
|
return this.cachePath;
|
|
5324
5552
|
}
|
|
5325
5553
|
setConfig(root, config) {
|
|
5326
|
-
this.root = root;
|
|
5327
|
-
if (config) this.cachePath = resolve(config.dir, "results.json");
|
|
5554
|
+
if (this.root = root, config) this.cachePath = resolve(config.dir, "results.json");
|
|
5328
5555
|
}
|
|
5329
5556
|
getResults(key) {
|
|
5330
5557
|
return this.cache.get(key);
|
|
5331
5558
|
}
|
|
5332
5559
|
async readFromCache() {
|
|
5333
|
-
if (!this.cachePath) return;
|
|
5334
|
-
|
|
5335
|
-
const resultsCache = await fs.promises.readFile(this.cachePath, "utf8");
|
|
5336
|
-
const { results, version } = JSON.parse(resultsCache || "[]");
|
|
5337
|
-
const [major, minor] = version.split(".");
|
|
5560
|
+
if (!this.cachePath || !fs.existsSync(this.cachePath)) return;
|
|
5561
|
+
const resultsCache = await fs.promises.readFile(this.cachePath, "utf8"), { results, version } = JSON.parse(resultsCache || "[]"), [major, minor] = version.split(".");
|
|
5338
5562
|
// handling changed in 0.30.0
|
|
5339
|
-
if (major > 0 || Number(minor) >= 30) {
|
|
5340
|
-
|
|
5341
|
-
this.
|
|
5342
|
-
|
|
5343
|
-
const [projectName, relativePath] = spec.split(":");
|
|
5344
|
-
const keyMap = this.workspacesKeyMap.get(relativePath) || [];
|
|
5345
|
-
keyMap.push(projectName);
|
|
5346
|
-
this.workspacesKeyMap.set(relativePath, keyMap);
|
|
5347
|
-
});
|
|
5348
|
-
}
|
|
5563
|
+
if (major > 0 || Number(minor) >= 30) this.cache = new Map(results), this.version = version, results.forEach(([spec]) => {
|
|
5564
|
+
const [projectName, relativePath] = spec.split(":"), keyMap = this.workspacesKeyMap.get(relativePath) || [];
|
|
5565
|
+
keyMap.push(projectName), this.workspacesKeyMap.set(relativePath, keyMap);
|
|
5566
|
+
});
|
|
5349
5567
|
}
|
|
5350
5568
|
updateResults(files) {
|
|
5351
5569
|
files.forEach((file) => {
|
|
5352
5570
|
const result = file.result;
|
|
5353
5571
|
if (!result) return;
|
|
5354
|
-
const duration = result.duration || 0;
|
|
5355
|
-
// store as relative, so cache would be the same in CI and locally
|
|
5356
|
-
const relativePath = relative(this.root, file.filepath);
|
|
5572
|
+
const duration = result.duration || 0, relativePath = relative(this.root, file.filepath);
|
|
5357
5573
|
this.cache.set(`${file.projectName || ""}:${relativePath}`, {
|
|
5358
5574
|
duration: duration >= 0 ? duration : 0,
|
|
5359
5575
|
failed: result.state === "fail"
|
|
@@ -5367,8 +5583,7 @@ class ResultsCache {
|
|
|
5367
5583
|
}
|
|
5368
5584
|
async writeToCache() {
|
|
5369
5585
|
if (!this.cachePath) return;
|
|
5370
|
-
const results = Array.from(this.cache.entries());
|
|
5371
|
-
const cacheDirname = dirname(this.cachePath);
|
|
5586
|
+
const results = Array.from(this.cache.entries()), cacheDirname = dirname(this.cachePath);
|
|
5372
5587
|
if (!fs.existsSync(cacheDirname)) await fs.promises.mkdir(cacheDirname, { recursive: true });
|
|
5373
5588
|
const cache = JSON.stringify({
|
|
5374
5589
|
version: this.version,
|
|
@@ -5412,9 +5627,7 @@ class ServerModuleRunner extends ModuleRunner {
|
|
|
5412
5627
|
return { error };
|
|
5413
5628
|
}
|
|
5414
5629
|
} }
|
|
5415
|
-
}, new VitestModuleEvaluator());
|
|
5416
|
-
this.environment = environment;
|
|
5417
|
-
this.config = config;
|
|
5630
|
+
}, new VitestModuleEvaluator()), this.environment = environment, this.config = config;
|
|
5418
5631
|
}
|
|
5419
5632
|
async import(rawId) {
|
|
5420
5633
|
const resolved = await this.environment.pluginContainer.resolveId(rawId, this.config.root);
|
|
@@ -5481,43 +5694,26 @@ function highlightCode(id, source, colors) {
|
|
|
5481
5694
|
});
|
|
5482
5695
|
}
|
|
5483
5696
|
|
|
5484
|
-
const PAD = " ";
|
|
5485
|
-
const ESC$1 = "\x1B[";
|
|
5486
|
-
const ERASE_DOWN = `${ESC$1}J`;
|
|
5487
|
-
const ERASE_SCROLLBACK = `${ESC$1}3J`;
|
|
5488
|
-
const CURSOR_TO_START = `${ESC$1}1;1H`;
|
|
5489
|
-
const HIDE_CURSOR = `${ESC$1}?25l`;
|
|
5490
|
-
const SHOW_CURSOR = `${ESC$1}?25h`;
|
|
5491
|
-
const CLEAR_SCREEN = "\x1Bc";
|
|
5697
|
+
const PAD = " ", ESC$1 = "\x1B[", ERASE_DOWN = `${ESC$1}J`, ERASE_SCROLLBACK = `${ESC$1}3J`, CURSOR_TO_START = `${ESC$1}1;1H`, HIDE_CURSOR = `${ESC$1}?25l`, SHOW_CURSOR = `${ESC$1}?25h`, CLEAR_SCREEN = "\x1Bc";
|
|
5492
5698
|
class Logger {
|
|
5493
5699
|
_clearScreenPending;
|
|
5494
5700
|
_highlights = /* @__PURE__ */ new Map();
|
|
5495
5701
|
cleanupListeners = [];
|
|
5496
5702
|
console;
|
|
5497
5703
|
constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
|
|
5498
|
-
this.ctx = ctx
|
|
5499
|
-
this.outputStream = outputStream;
|
|
5500
|
-
this.errorStream = errorStream;
|
|
5501
|
-
this.console = new Console({
|
|
5704
|
+
if (this.ctx = ctx, this.outputStream = outputStream, this.errorStream = errorStream, this.console = new Console({
|
|
5502
5705
|
stdout: outputStream,
|
|
5503
5706
|
stderr: errorStream
|
|
5504
|
-
});
|
|
5505
|
-
this._highlights.clear();
|
|
5506
|
-
this.addCleanupListeners();
|
|
5507
|
-
this.registerUnhandledRejection();
|
|
5508
|
-
if (this.outputStream.isTTY) this.outputStream.write(HIDE_CURSOR);
|
|
5707
|
+
}), this._highlights.clear(), this.addCleanupListeners(), this.registerUnhandledRejection(), this.outputStream.isTTY) this.outputStream.write(HIDE_CURSOR);
|
|
5509
5708
|
}
|
|
5510
5709
|
log(...args) {
|
|
5511
|
-
this._clearScreen();
|
|
5512
|
-
this.console.log(...args);
|
|
5710
|
+
this._clearScreen(), this.console.log(...args);
|
|
5513
5711
|
}
|
|
5514
5712
|
error(...args) {
|
|
5515
|
-
this._clearScreen();
|
|
5516
|
-
this.console.error(...args);
|
|
5713
|
+
this._clearScreen(), this.console.error(...args);
|
|
5517
5714
|
}
|
|
5518
5715
|
warn(...args) {
|
|
5519
|
-
this._clearScreen();
|
|
5520
|
-
this.console.warn(...args);
|
|
5716
|
+
this._clearScreen(), this.console.warn(...args);
|
|
5521
5717
|
}
|
|
5522
5718
|
clearFullScreen(message = "") {
|
|
5523
5719
|
if (!this.ctx.config.clearScreen) {
|
|
@@ -5532,14 +5728,12 @@ class Logger {
|
|
|
5532
5728
|
this.console.log(message);
|
|
5533
5729
|
return;
|
|
5534
5730
|
}
|
|
5535
|
-
this._clearScreenPending = message;
|
|
5536
|
-
if (force) this._clearScreen();
|
|
5731
|
+
if (this._clearScreenPending = message, force) this._clearScreen();
|
|
5537
5732
|
}
|
|
5538
5733
|
_clearScreen() {
|
|
5539
5734
|
if (this._clearScreenPending == null) return;
|
|
5540
5735
|
const log = this._clearScreenPending;
|
|
5541
|
-
this._clearScreenPending = void 0;
|
|
5542
|
-
this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
|
|
5736
|
+
this._clearScreenPending = void 0, this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
|
|
5543
5737
|
}
|
|
5544
5738
|
printError(err, options = {}) {
|
|
5545
5739
|
printError(err, this.ctx, this, options);
|
|
@@ -5554,8 +5748,7 @@ class Logger {
|
|
|
5554
5748
|
highlight(filename, source) {
|
|
5555
5749
|
if (this._highlights.has(filename)) return this._highlights.get(filename);
|
|
5556
5750
|
const code = highlightCode(filename, source);
|
|
5557
|
-
this._highlights.set(filename, code);
|
|
5558
|
-
return code;
|
|
5751
|
+
return this._highlights.set(filename, code), code;
|
|
5559
5752
|
}
|
|
5560
5753
|
printNoTestFound(filters) {
|
|
5561
5754
|
const config = this.ctx.config;
|
|
@@ -5568,34 +5761,22 @@ class Logger {
|
|
|
5568
5761
|
const projectsFilter = toArray(config.project);
|
|
5569
5762
|
if (projectsFilter.length) this.console.error(c.dim("projects: ") + c.yellow(projectsFilter.join(comma)));
|
|
5570
5763
|
this.ctx.projects.forEach((project) => {
|
|
5571
|
-
const config = project.config;
|
|
5572
|
-
const printConfig = !project.isRootProject() && project.name;
|
|
5764
|
+
const config = project.config, printConfig = !project.isRootProject() && project.name;
|
|
5573
5765
|
if (printConfig) this.console.error(`\n${formatProjectName(project)}\n`);
|
|
5574
5766
|
if (config.include) this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
|
|
5575
5767
|
if (config.exclude) this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
|
|
5576
|
-
if (config.typecheck.enabled)
|
|
5577
|
-
|
|
5578
|
-
this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
|
|
5579
|
-
}
|
|
5580
|
-
});
|
|
5581
|
-
this.console.error();
|
|
5768
|
+
if (config.typecheck.enabled) this.console.error(c.dim("typecheck include: ") + c.yellow(config.typecheck.include.join(comma))), this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
|
|
5769
|
+
}), this.console.error();
|
|
5582
5770
|
}
|
|
5583
5771
|
printBanner() {
|
|
5584
5772
|
this.log();
|
|
5585
|
-
const color = this.ctx.config.watch ? "blue" : "cyan";
|
|
5586
|
-
|
|
5587
|
-
this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root));
|
|
5588
|
-
if (this.ctx.config.sequence.sequencer === RandomSequencer) this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
|
|
5773
|
+
const color = this.ctx.config.watch ? "blue" : "cyan", mode = this.ctx.config.watch ? "DEV" : "RUN";
|
|
5774
|
+
if (this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root)), this.ctx.config.sequence.sequencer === RandomSequencer) this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
|
|
5589
5775
|
if (this.ctx.config.ui) {
|
|
5590
|
-
const host = this.ctx.config.api?.host || "localhost";
|
|
5591
|
-
const port = this.ctx.server.config.server.port;
|
|
5592
|
-
const base = this.ctx.config.uiBase;
|
|
5776
|
+
const host = this.ctx.config.api?.host || "localhost", port = this.ctx.server.config.server.port, base = this.ctx.config.uiBase;
|
|
5593
5777
|
this.log(PAD + c.dim(c.green(`UI started at http://${host}:${c.bold(port)}${base}`)));
|
|
5594
5778
|
} else if (this.ctx.config.api?.port) {
|
|
5595
|
-
const resolvedUrls = this.ctx.server.resolvedUrls;
|
|
5596
|
-
// workaround for https://github.com/vitejs/vite/issues/15438, it was fixed in vite 5.1
|
|
5597
|
-
const fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`;
|
|
5598
|
-
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
|
|
5779
|
+
const resolvedUrls = this.ctx.server.resolvedUrls, fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
|
|
5599
5780
|
this.log(PAD + c.dim(c.green(`API started at ${new URL("/", origin)}`)));
|
|
5600
5781
|
}
|
|
5601
5782
|
if (this.ctx.coverageProvider) this.log(PAD + c.dim("Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
|
|
@@ -5604,35 +5785,26 @@ class Logger {
|
|
|
5604
5785
|
}
|
|
5605
5786
|
printBrowserBanner(project) {
|
|
5606
5787
|
if (!project.browser) return;
|
|
5607
|
-
const resolvedUrls = project.browser.vite.resolvedUrls;
|
|
5608
|
-
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
|
|
5788
|
+
const resolvedUrls = project.browser.vite.resolvedUrls, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
|
|
5609
5789
|
if (!origin) return;
|
|
5610
|
-
const output = project.isRootProject() ? "" : formatProjectName(project)
|
|
5611
|
-
const provider = project.browser.provider.name;
|
|
5612
|
-
const providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
|
|
5790
|
+
const output = project.isRootProject() ? "" : formatProjectName(project), provider = project.browser.provider.name, providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
|
|
5613
5791
|
this.log(c.dim(`${output}Browser runner started${providerString} ${c.dim("at")} ${c.blue(new URL("/__vitest_test__/", origin))}\n`));
|
|
5614
5792
|
}
|
|
5615
5793
|
printUnhandledErrors(errors) {
|
|
5616
5794
|
const errorMessage = c.red(c.bold(`\nVitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
|
|
5617
5795
|
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`));
|
|
5618
|
-
this.error(errorBanner("Unhandled Errors"))
|
|
5619
|
-
this.error(errorMessage);
|
|
5620
|
-
errors.forEach((err) => {
|
|
5796
|
+
this.error(errorBanner("Unhandled Errors")), this.error(errorMessage), errors.forEach((err) => {
|
|
5621
5797
|
this.printError(err, {
|
|
5622
5798
|
fullStack: true,
|
|
5623
5799
|
type: err.type || "Unhandled Error"
|
|
5624
5800
|
});
|
|
5625
|
-
});
|
|
5626
|
-
this.error(c.red(divider()));
|
|
5801
|
+
}), this.error(c.red(divider()));
|
|
5627
5802
|
}
|
|
5628
5803
|
printSourceTypeErrors(errors) {
|
|
5629
5804
|
const errorMessage = c.red(c.bold(`\nVitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related to your test files.`));
|
|
5630
|
-
this.log(errorBanner("Source Errors"))
|
|
5631
|
-
this.log(errorMessage);
|
|
5632
|
-
errors.forEach((err) => {
|
|
5805
|
+
this.log(errorBanner("Source Errors")), this.log(errorMessage), errors.forEach((err) => {
|
|
5633
5806
|
this.printError(err, { fullStack: true });
|
|
5634
|
-
});
|
|
5635
|
-
this.log(c.red(divider()));
|
|
5807
|
+
}), this.log(c.red(divider()));
|
|
5636
5808
|
}
|
|
5637
5809
|
getColumns() {
|
|
5638
5810
|
return "columns" in this.outputStream ? this.outputStream.columns : 80;
|
|
@@ -5642,38 +5814,25 @@ This might cause false positive tests. Resolve unhandled errors to make sure you
|
|
|
5642
5814
|
}
|
|
5643
5815
|
addCleanupListeners() {
|
|
5644
5816
|
const cleanup = () => {
|
|
5645
|
-
this.cleanupListeners.forEach((fn) => fn());
|
|
5646
|
-
|
|
5647
|
-
};
|
|
5648
|
-
const onExit = (signal, exitCode) => {
|
|
5649
|
-
cleanup();
|
|
5817
|
+
if (this.cleanupListeners.forEach((fn) => fn()), this.outputStream.isTTY) this.outputStream.write(SHOW_CURSOR);
|
|
5818
|
+
}, onExit = (signal, exitCode) => {
|
|
5650
5819
|
// Interrupted signals don't set exit code automatically.
|
|
5651
5820
|
// Use same exit code as node: https://nodejs.org/api/process.html#signal-events
|
|
5652
|
-
if (process.exitCode === void 0) process.exitCode = exitCode !== void 0 ? 128 + exitCode : Number(signal);
|
|
5821
|
+
if (cleanup(), process.exitCode === void 0) process.exitCode = exitCode !== void 0 ? 128 + exitCode : Number(signal);
|
|
5653
5822
|
process.exit();
|
|
5654
5823
|
};
|
|
5655
|
-
process.once("SIGINT", onExit)
|
|
5656
|
-
|
|
5657
|
-
process.once("exit", onExit);
|
|
5658
|
-
this.ctx.onClose(() => {
|
|
5659
|
-
process.off("SIGINT", onExit);
|
|
5660
|
-
process.off("SIGTERM", onExit);
|
|
5661
|
-
process.off("exit", onExit);
|
|
5662
|
-
cleanup();
|
|
5824
|
+
process.once("SIGINT", onExit), process.once("SIGTERM", onExit), process.once("exit", onExit), this.ctx.onClose(() => {
|
|
5825
|
+
process.off("SIGINT", onExit), process.off("SIGTERM", onExit), process.off("exit", onExit), cleanup();
|
|
5663
5826
|
});
|
|
5664
5827
|
}
|
|
5665
5828
|
registerUnhandledRejection() {
|
|
5666
5829
|
const onUnhandledRejection = (err) => {
|
|
5667
|
-
process.exitCode = 1
|
|
5668
|
-
this.printError(err, {
|
|
5830
|
+
process.exitCode = 1, this.printError(err, {
|
|
5669
5831
|
fullStack: true,
|
|
5670
5832
|
type: "Unhandled Rejection"
|
|
5671
|
-
});
|
|
5672
|
-
this.error("\n\n");
|
|
5673
|
-
process.exit();
|
|
5833
|
+
}), this.error("\n\n"), process.exit();
|
|
5674
5834
|
};
|
|
5675
|
-
process.on("unhandledRejection", onUnhandledRejection)
|
|
5676
|
-
this.ctx.onClose(() => {
|
|
5835
|
+
process.on("unhandledRejection", onUnhandledRejection), this.ctx.onClose(() => {
|
|
5677
5836
|
process.off("unhandledRejection", onUnhandledRejection);
|
|
5678
5837
|
});
|
|
5679
5838
|
}
|
|
@@ -5689,36 +5848,26 @@ class VitestPackageInstaller {
|
|
|
5689
5848
|
if (process.versions.pnp) {
|
|
5690
5849
|
const targetRequire = createRequire(__dirname);
|
|
5691
5850
|
try {
|
|
5692
|
-
targetRequire.resolve(dependency, { paths: [root, __dirname] });
|
|
5693
|
-
return true;
|
|
5851
|
+
return targetRequire.resolve(dependency, { paths: [root, __dirname] }), true;
|
|
5694
5852
|
} catch {}
|
|
5695
5853
|
}
|
|
5696
5854
|
if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] })) return true;
|
|
5697
|
-
process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`));
|
|
5698
|
-
|
|
5699
|
-
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; });
|
|
5700
|
-
const { install } = await prompts.default({
|
|
5855
|
+
if (process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`)), !isTTY) return false;
|
|
5856
|
+
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; }), { install } = await prompts.default({
|
|
5701
5857
|
type: "confirm",
|
|
5702
5858
|
name: "install",
|
|
5703
5859
|
message: c.reset(`Do you want to install ${c.green(dependency)}?`)
|
|
5704
5860
|
});
|
|
5705
5861
|
if (install) {
|
|
5706
5862
|
const packageName = version ? `${dependency}@${version}` : dependency;
|
|
5707
|
-
await (await import('./index.D3XRDfWc.js')).installPackage(packageName, { dev: true });
|
|
5708
|
-
// TODO: somehow it fails to load the package after installation, remove this when it's fixed
|
|
5709
|
-
process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`));
|
|
5710
|
-
process.exit();
|
|
5711
|
-
return true;
|
|
5863
|
+
return await (await import('./index.D3XRDfWc.js')).installPackage(packageName, { dev: true }), process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`)), process.exit(), true;
|
|
5712
5864
|
}
|
|
5713
5865
|
return false;
|
|
5714
5866
|
}
|
|
5715
5867
|
}
|
|
5716
5868
|
|
|
5717
5869
|
function serializeConfig(config, coreConfig, viteConfig) {
|
|
5718
|
-
const optimizer = config.deps?.optimizer || {};
|
|
5719
|
-
const poolOptions = config.poolOptions;
|
|
5720
|
-
// Resolve from server.config to avoid comparing against default value
|
|
5721
|
-
const isolate = viteConfig?.test?.isolate;
|
|
5870
|
+
const optimizer = config.deps?.optimizer || {}, poolOptions = config.poolOptions, isolate = viteConfig?.test?.isolate;
|
|
5722
5871
|
return {
|
|
5723
5872
|
environmentOptions: config.environmentOptions,
|
|
5724
5873
|
mode: config.mode,
|
|
@@ -5752,8 +5901,7 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5752
5901
|
snapshotEnvironment: config.snapshotEnvironment,
|
|
5753
5902
|
passWithNoTests: config.passWithNoTests,
|
|
5754
5903
|
coverage: ((coverage) => {
|
|
5755
|
-
const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html");
|
|
5756
|
-
const subdir = htmlReporter && htmlReporter[1]?.subdir;
|
|
5904
|
+
const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html"), subdir = htmlReporter && htmlReporter[1]?.subdir;
|
|
5757
5905
|
return {
|
|
5758
5906
|
reportsDirectory: coverage.reportsDirectory,
|
|
5759
5907
|
provider: coverage.provider,
|
|
@@ -5778,8 +5926,7 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5778
5926
|
deps: {
|
|
5779
5927
|
web: config.deps.web || {},
|
|
5780
5928
|
optimizer: Object.entries(optimizer).reduce((acc, [name, option]) => {
|
|
5781
|
-
acc[name] = { enabled: option?.enabled ?? false };
|
|
5782
|
-
return acc;
|
|
5929
|
+
return acc[name] = { enabled: option?.enabled ?? false }, acc;
|
|
5783
5930
|
}, {}),
|
|
5784
5931
|
interopDefault: config.deps.interopDefault,
|
|
5785
5932
|
moduleDirectories: config.deps.moduleDirectories
|
|
@@ -5816,7 +5963,8 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5816
5963
|
viewport: browser.viewport,
|
|
5817
5964
|
screenshotFailures: browser.screenshotFailures,
|
|
5818
5965
|
locators: { testIdAttribute: browser.locators.testIdAttribute },
|
|
5819
|
-
providerOptions: browser.provider === "playwright" ? { actionTimeout: browser.providerOptions?.context?.actionTimeout } : {}
|
|
5966
|
+
providerOptions: browser.provider === "playwright" ? { actionTimeout: browser.providerOptions?.context?.actionTimeout } : {},
|
|
5967
|
+
trackUnhandledErrors: browser.trackUnhandledErrors ?? true
|
|
5820
5968
|
};
|
|
5821
5969
|
})(config.browser),
|
|
5822
5970
|
standalone: config.standalone,
|
|
@@ -5840,12 +5988,12 @@ async function loadGlobalSetupFile(file, runner) {
|
|
|
5840
5988
|
file,
|
|
5841
5989
|
setup: m.default
|
|
5842
5990
|
};
|
|
5843
|
-
|
|
5991
|
+
if (m.setup || m.teardown) return {
|
|
5844
5992
|
file,
|
|
5845
5993
|
setup: m.setup,
|
|
5846
5994
|
teardown: m.teardown
|
|
5847
5995
|
};
|
|
5848
|
-
|
|
5996
|
+
throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
|
|
5849
5997
|
}
|
|
5850
5998
|
|
|
5851
5999
|
function CoverageTransform(ctx) {
|
|
@@ -6350,12 +6498,10 @@ function MetaEnvReplacerPlugin() {
|
|
|
6350
6498
|
transform(code, id) {
|
|
6351
6499
|
if (!/\bimport\.meta\.env\b/.test(code)) return null;
|
|
6352
6500
|
let s = null;
|
|
6353
|
-
const cleanCode = stripLiteral(code);
|
|
6354
|
-
const envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
|
|
6501
|
+
const cleanCode = stripLiteral(code), envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
|
|
6355
6502
|
for (const env of envs) {
|
|
6356
6503
|
s ||= new MagicString(code);
|
|
6357
|
-
const startIndex = env.index;
|
|
6358
|
-
const endIndex = startIndex + env[0].length;
|
|
6504
|
+
const startIndex = env.index, endIndex = startIndex + env[0].length;
|
|
6359
6505
|
s.overwrite(startIndex, endIndex, `Object.assign(/* istanbul ignore next */ globalThis.__vitest_worker__?.metaEnv ?? import.meta.env)`);
|
|
6360
6506
|
}
|
|
6361
6507
|
if (s) return {
|
|
@@ -6373,9 +6519,7 @@ function MocksPlugins(options = {}) {
|
|
|
6373
6519
|
const normalizedDistDir = normalize(distDir);
|
|
6374
6520
|
return [hoistMocksPlugin({
|
|
6375
6521
|
filter(id) {
|
|
6376
|
-
|
|
6377
|
-
if (options.filter) return options.filter(id);
|
|
6378
|
-
return true;
|
|
6522
|
+
return id.includes(normalizedDistDir) ? false : options.filter ? options.filter(id) : true;
|
|
6379
6523
|
},
|
|
6380
6524
|
codeFrameGenerator(node, id, code) {
|
|
6381
6525
|
return generateCodeFrame(code, 4, node.start + 1);
|
|
@@ -6401,34 +6545,23 @@ const LogLevels = {
|
|
|
6401
6545
|
info: 3
|
|
6402
6546
|
};
|
|
6403
6547
|
function clearScreen(logger) {
|
|
6404
|
-
const repeatCount = process.stdout.rows - 2;
|
|
6405
|
-
const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
|
|
6548
|
+
const repeatCount = process.stdout.rows - 2, blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
|
|
6406
6549
|
logger.clearScreen(blank);
|
|
6407
6550
|
}
|
|
6408
|
-
let lastType;
|
|
6409
|
-
let lastMsg;
|
|
6410
|
-
let sameCount = 0;
|
|
6411
|
-
// Only initialize the timeFormatter when the timestamp option is used, and
|
|
6412
|
-
// reuse it across all loggers
|
|
6413
|
-
let timeFormatter;
|
|
6551
|
+
let lastType, lastMsg, sameCount = 0, timeFormatter;
|
|
6414
6552
|
function getTimeFormatter() {
|
|
6415
|
-
timeFormatter ??= new Intl.DateTimeFormat(void 0, {
|
|
6553
|
+
return timeFormatter ??= new Intl.DateTimeFormat(void 0, {
|
|
6416
6554
|
hour: "numeric",
|
|
6417
6555
|
minute: "numeric",
|
|
6418
6556
|
second: "numeric"
|
|
6419
|
-
});
|
|
6420
|
-
return timeFormatter;
|
|
6557
|
+
}), timeFormatter;
|
|
6421
6558
|
}
|
|
6422
6559
|
// This is copy-pasted and needs to be synced from time to time. Ideally, Vite's `createLogger` should accept a custom `console`
|
|
6423
6560
|
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/logger.ts?rgh-link-date=2024-10-16T23%3A29%3A19Z
|
|
6424
6561
|
// When Vitest supports only Vite 6 and above, we can use Vite's `createLogger({ console })`
|
|
6425
6562
|
// https://github.com/vitejs/vite/pull/18379
|
|
6426
6563
|
function createViteLogger(console, level = "info", options = {}) {
|
|
6427
|
-
const loggedErrors = /* @__PURE__ */ new WeakSet();
|
|
6428
|
-
const { prefix = "[vite]", allowClearScreen = true } = options;
|
|
6429
|
-
const thresh = LogLevels[level];
|
|
6430
|
-
const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
|
|
6431
|
-
const clear = canClearScreen ? clearScreen : () => {};
|
|
6564
|
+
const loggedErrors = /* @__PURE__ */ new WeakSet(), { prefix = "[vite]", allowClearScreen = true } = options, thresh = LogLevels[level], canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI, clear = canClearScreen ? clearScreen : () => {};
|
|
6432
6565
|
function format(type, msg, options = {}) {
|
|
6433
6566
|
if (options.timestamp) {
|
|
6434
6567
|
let tag = "";
|
|
@@ -6443,39 +6576,27 @@ function createViteLogger(console, level = "info", options = {}) {
|
|
|
6443
6576
|
if (thresh >= LogLevels[type]) {
|
|
6444
6577
|
const method = type === "info" ? "log" : type;
|
|
6445
6578
|
if (options.error) loggedErrors.add(options.error);
|
|
6446
|
-
if (canClearScreen) if (type === lastType && msg === lastMsg) {
|
|
6447
|
-
|
|
6448
|
-
clear(console);
|
|
6449
|
-
console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
|
|
6450
|
-
} else {
|
|
6451
|
-
sameCount = 0;
|
|
6452
|
-
lastMsg = msg;
|
|
6453
|
-
lastType = type;
|
|
6454
|
-
if (options.clear) clear(console);
|
|
6579
|
+
if (canClearScreen) if (type === lastType && msg === lastMsg) sameCount++, clear(console), console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
|
|
6580
|
+
else {
|
|
6581
|
+
if (sameCount = 0, lastMsg = msg, lastType = type, options.clear) clear(console);
|
|
6455
6582
|
console[method](format(type, msg, options));
|
|
6456
6583
|
}
|
|
6457
6584
|
else console[method](format(type, msg, options));
|
|
6458
6585
|
}
|
|
6459
6586
|
}
|
|
6460
|
-
const warnedMessages = /* @__PURE__ */ new Set()
|
|
6461
|
-
const logger = {
|
|
6587
|
+
const warnedMessages = /* @__PURE__ */ new Set(), logger = {
|
|
6462
6588
|
hasWarned: false,
|
|
6463
6589
|
info(msg, opts) {
|
|
6464
6590
|
output("info", msg, opts);
|
|
6465
6591
|
},
|
|
6466
6592
|
warn(msg, opts) {
|
|
6467
|
-
logger.hasWarned = true;
|
|
6468
|
-
output("warn", msg, opts);
|
|
6593
|
+
logger.hasWarned = true, output("warn", msg, opts);
|
|
6469
6594
|
},
|
|
6470
6595
|
warnOnce(msg, opts) {
|
|
6471
|
-
|
|
6472
|
-
logger.hasWarned = true;
|
|
6473
|
-
output("warn", msg, opts);
|
|
6474
|
-
warnedMessages.add(msg);
|
|
6596
|
+
warnedMessages.has(msg) || (logger.hasWarned = true, output("warn", msg, opts), warnedMessages.add(msg));
|
|
6475
6597
|
},
|
|
6476
6598
|
error(msg, opts) {
|
|
6477
|
-
logger.hasWarned = true;
|
|
6478
|
-
output("error", msg, opts);
|
|
6599
|
+
logger.hasWarned = true, output("error", msg, opts);
|
|
6479
6600
|
},
|
|
6480
6601
|
clearScreen(type) {
|
|
6481
6602
|
if (thresh >= LogLevels[type]) clear(console);
|
|
@@ -6491,16 +6612,12 @@ function silenceImportViteIgnoreWarning(logger) {
|
|
|
6491
6612
|
return {
|
|
6492
6613
|
...logger,
|
|
6493
6614
|
warn(msg, options) {
|
|
6494
|
-
|
|
6495
|
-
logger.warn(msg, options);
|
|
6615
|
+
msg.includes("The above dynamic import cannot be analyzed by Vite") || logger.warn(msg, options);
|
|
6496
6616
|
}
|
|
6497
6617
|
};
|
|
6498
6618
|
}
|
|
6499
6619
|
|
|
6500
|
-
const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)"
|
|
6501
|
-
const cssLangRE = new RegExp(cssLangs);
|
|
6502
|
-
const cssModuleRE = /* @__PURE__ */ new RegExp(`\\.module${cssLangs}`);
|
|
6503
|
-
const cssInlineRE = /[?&]inline(?:&|$)/;
|
|
6620
|
+
const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)", cssLangRE = new RegExp(cssLangs), cssModuleRE = /* @__PURE__ */ new RegExp(`\\.module${cssLangs}`), cssInlineRE = /[?&]inline(?:&|$)/;
|
|
6504
6621
|
function isCSS(id) {
|
|
6505
6622
|
return cssLangRE.test(id);
|
|
6506
6623
|
}
|
|
@@ -6520,45 +6637,37 @@ function getCSSModuleProxyReturn(strategy, filename) {
|
|
|
6520
6637
|
function CSSEnablerPlugin(ctx) {
|
|
6521
6638
|
const shouldProcessCSS = (id) => {
|
|
6522
6639
|
const { css } = ctx.config;
|
|
6523
|
-
|
|
6524
|
-
if (toArray(css.exclude).some((re) => re.test(id))) return false;
|
|
6525
|
-
if (toArray(css.include).some((re) => re.test(id))) return true;
|
|
6526
|
-
return false;
|
|
6640
|
+
return typeof css === "boolean" ? css : toArray(css.exclude).some((re) => re.test(id)) ? false : !!toArray(css.include).some((re) => re.test(id));
|
|
6527
6641
|
};
|
|
6528
6642
|
return [{
|
|
6529
6643
|
name: "vitest:css-disable",
|
|
6530
6644
|
enforce: "pre",
|
|
6531
6645
|
transform(code, id) {
|
|
6532
|
-
if (
|
|
6533
|
-
// css plugin inside Vite won't do anything if the code is empty
|
|
6534
|
-
// but it will put __vite__updateStyle anyway
|
|
6535
|
-
if (!shouldProcessCSS(id)) return { code: "" };
|
|
6646
|
+
if (isCSS(id) && !shouldProcessCSS(id)) return { code: "" };
|
|
6536
6647
|
}
|
|
6537
6648
|
}, {
|
|
6538
6649
|
name: "vitest:css-empty-post",
|
|
6539
6650
|
enforce: "post",
|
|
6540
6651
|
transform(_, id) {
|
|
6541
|
-
if (!isCSS(id) || shouldProcessCSS(id))
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
const proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id));
|
|
6548
|
-
const code = `export default new Proxy(Object.create(null), {
|
|
6652
|
+
if (!(!isCSS(id) || shouldProcessCSS(id))) {
|
|
6653
|
+
if (isCSSModule(id) && !isInline(id)) {
|
|
6654
|
+
// return proxy for css modules, so that imported module has names:
|
|
6655
|
+
// styles.foo returns a "foo" instead of "undefined"
|
|
6656
|
+
// we don't use code content to generate hash for "scoped", because it's empty
|
|
6657
|
+
const scopeStrategy = typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable", proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id)), code = `export default new Proxy(Object.create(null), {
|
|
6549
6658
|
get(_, style) {
|
|
6550
6659
|
return ${proxyReturn};
|
|
6551
6660
|
},
|
|
6552
6661
|
})`;
|
|
6553
|
-
|
|
6662
|
+
return { code };
|
|
6663
|
+
}
|
|
6664
|
+
return { code: "export default \"\"" };
|
|
6554
6665
|
}
|
|
6555
|
-
return { code: "export default \"\"" };
|
|
6556
6666
|
}
|
|
6557
6667
|
}];
|
|
6558
6668
|
}
|
|
6559
6669
|
|
|
6560
|
-
const metaUrlLength = 15;
|
|
6561
|
-
const locationString = "self.location".padEnd(metaUrlLength, " ");
|
|
6670
|
+
const metaUrlLength = 15, locationString = "self.location".padEnd(metaUrlLength, " ");
|
|
6562
6671
|
// Vite transforms new URL('./path', import.meta.url) to new URL('/path.js', import.meta.url)
|
|
6563
6672
|
// This makes "href" equal to "http://localhost:3000/path.js" in the browser, but if we keep it like this,
|
|
6564
6673
|
// then in tests the URL will become "file:///path.js".
|
|
@@ -6569,14 +6678,11 @@ function NormalizeURLPlugin() {
|
|
|
6569
6678
|
enforce: "post",
|
|
6570
6679
|
transform(code) {
|
|
6571
6680
|
if (this.environment.name !== "client" || !code.includes("new URL") || !code.includes("import.meta.url")) return;
|
|
6572
|
-
const cleanString = stripLiteral(code);
|
|
6573
|
-
|
|
6574
|
-
let updatedCode = code;
|
|
6575
|
-
let match;
|
|
6681
|
+
const cleanString = stripLiteral(code), assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*(?:'' \+ )?import\.meta\.url\s*(?:,\s*)?\)/g;
|
|
6682
|
+
let updatedCode = code, match;
|
|
6576
6683
|
// eslint-disable-next-line no-cond-assign
|
|
6577
6684
|
while (match = assetImportMetaUrlRE.exec(cleanString)) {
|
|
6578
|
-
const { 0: exp, index } = match;
|
|
6579
|
-
const metaUrlIndex = index + exp.indexOf("import.meta.url");
|
|
6685
|
+
const { 0: exp, index } = match, metaUrlIndex = index + exp.indexOf("import.meta.url");
|
|
6580
6686
|
updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength);
|
|
6581
6687
|
}
|
|
6582
6688
|
return {
|
|
@@ -6593,10 +6699,7 @@ function VitestOptimizer() {
|
|
|
6593
6699
|
config: {
|
|
6594
6700
|
order: "post",
|
|
6595
6701
|
handler(viteConfig) {
|
|
6596
|
-
const testConfig = viteConfig.test || {};
|
|
6597
|
-
const root = resolve(viteConfig.root || process.cwd());
|
|
6598
|
-
const name = viteConfig.test?.name;
|
|
6599
|
-
const label = typeof name === "string" ? name : name?.label || "";
|
|
6702
|
+
const testConfig = viteConfig.test || {}, root = resolve(viteConfig.root || process.cwd()), name = viteConfig.test?.name, label = typeof name === "string" ? name : name?.label || "";
|
|
6600
6703
|
viteConfig.cacheDir = VitestCache.resolveCacheDir(resolve(root || process.cwd()), testConfig.cache != null && testConfig.cache !== false ? testConfig.cache.dir : viteConfig.cacheDir, label);
|
|
6601
6704
|
}
|
|
6602
6705
|
}
|
|
@@ -6606,21 +6709,17 @@ function VitestOptimizer() {
|
|
|
6606
6709
|
function resolveOptimizerConfig(_testOptions, viteOptions) {
|
|
6607
6710
|
const testOptions = _testOptions || {};
|
|
6608
6711
|
let optimizeDeps;
|
|
6609
|
-
if (testOptions.enabled !== true) {
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
} else {
|
|
6616
|
-
const currentInclude = testOptions.include || viteOptions?.include || [];
|
|
6617
|
-
const exclude = [
|
|
6712
|
+
if (testOptions.enabled !== true) testOptions.enabled ??= false, optimizeDeps = {
|
|
6713
|
+
disabled: true,
|
|
6714
|
+
entries: []
|
|
6715
|
+
};
|
|
6716
|
+
else {
|
|
6717
|
+
const currentInclude = testOptions.include || viteOptions?.include || [], exclude = [
|
|
6618
6718
|
"vitest",
|
|
6619
6719
|
"react",
|
|
6620
6720
|
"vue",
|
|
6621
6721
|
...testOptions.exclude || viteOptions?.exclude || []
|
|
6622
|
-
];
|
|
6623
|
-
const runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
|
|
6722
|
+
], runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
|
|
6624
6723
|
exclude.push(...runtime);
|
|
6625
6724
|
const include = (testOptions.include || viteOptions?.include || []).filter((n) => !exclude.includes(n));
|
|
6626
6725
|
optimizeDeps = {
|
|
@@ -6635,21 +6734,12 @@ function resolveOptimizerConfig(_testOptions, viteOptions) {
|
|
|
6635
6734
|
}
|
|
6636
6735
|
// `optimizeDeps.disabled` is deprecated since v5.1.0-beta.1
|
|
6637
6736
|
// https://github.com/vitejs/vite/pull/15184
|
|
6638
|
-
if (optimizeDeps.disabled)
|
|
6639
|
-
|
|
6640
|
-
optimizeDeps.include = [];
|
|
6641
|
-
}
|
|
6642
|
-
delete optimizeDeps.disabled;
|
|
6643
|
-
return optimizeDeps;
|
|
6737
|
+
if (optimizeDeps.disabled) optimizeDeps.noDiscovery = true, optimizeDeps.include = [];
|
|
6738
|
+
return delete optimizeDeps.disabled, optimizeDeps;
|
|
6644
6739
|
}
|
|
6645
6740
|
function deleteDefineConfig(viteConfig) {
|
|
6646
6741
|
const defines = {};
|
|
6647
|
-
if (viteConfig.define)
|
|
6648
|
-
delete viteConfig.define["import.meta.vitest"];
|
|
6649
|
-
delete viteConfig.define["process.env"];
|
|
6650
|
-
delete viteConfig.define.process;
|
|
6651
|
-
delete viteConfig.define.global;
|
|
6652
|
-
}
|
|
6742
|
+
if (viteConfig.define) delete viteConfig.define["import.meta.vitest"], delete viteConfig.define["process.env"], delete viteConfig.define.process, delete viteConfig.define.global;
|
|
6653
6743
|
for (const key in viteConfig.define) {
|
|
6654
6744
|
const val = viteConfig.define[key];
|
|
6655
6745
|
let replacement;
|
|
@@ -6662,26 +6752,20 @@ function deleteDefineConfig(viteConfig) {
|
|
|
6662
6752
|
}
|
|
6663
6753
|
if (key.startsWith("import.meta.env.")) {
|
|
6664
6754
|
const envKey = key.slice(16);
|
|
6665
|
-
process.env[envKey] = replacement;
|
|
6666
|
-
delete viteConfig.define[key];
|
|
6755
|
+
process.env[envKey] = replacement, delete viteConfig.define[key];
|
|
6667
6756
|
} else if (key.startsWith("process.env.")) {
|
|
6668
6757
|
const envKey = key.slice(12);
|
|
6669
|
-
process.env[envKey] = replacement;
|
|
6670
|
-
|
|
6671
|
-
} else if (!key.includes(".")) {
|
|
6672
|
-
defines[key] = replacement;
|
|
6673
|
-
delete viteConfig.define[key];
|
|
6674
|
-
}
|
|
6758
|
+
process.env[envKey] = replacement, delete viteConfig.define[key];
|
|
6759
|
+
} else if (!key.includes(".")) defines[key] = replacement, delete viteConfig.define[key];
|
|
6675
6760
|
}
|
|
6676
6761
|
return defines;
|
|
6677
6762
|
}
|
|
6678
6763
|
function resolveFsAllow(projectRoot, rootConfigFile) {
|
|
6679
|
-
|
|
6680
|
-
return [
|
|
6764
|
+
return rootConfigFile ? [
|
|
6681
6765
|
dirname(rootConfigFile),
|
|
6682
6766
|
searchForWorkspaceRoot(projectRoot),
|
|
6683
6767
|
rootDir
|
|
6684
|
-
];
|
|
6768
|
+
] : [searchForWorkspaceRoot(projectRoot), rootDir];
|
|
6685
6769
|
}
|
|
6686
6770
|
function getDefaultResolveOptions() {
|
|
6687
6771
|
return {
|
|
@@ -6708,78 +6792,44 @@ function ModuleRunnerTransform() {
|
|
|
6708
6792
|
const testConfig = config.test || {};
|
|
6709
6793
|
config.environments ??= {};
|
|
6710
6794
|
const names = new Set(Object.keys(config.environments));
|
|
6711
|
-
names.add("client");
|
|
6712
|
-
names.add("ssr");
|
|
6795
|
+
names.add("client"), names.add("ssr");
|
|
6713
6796
|
const pool = config.test?.pool;
|
|
6714
6797
|
if (pool === "vmForks" || pool === "vmThreads") names.add("__vitest_vm__");
|
|
6715
|
-
const external = [];
|
|
6716
|
-
const noExternal = [];
|
|
6798
|
+
const external = [], noExternal = [];
|
|
6717
6799
|
let noExternalAll;
|
|
6718
6800
|
for (const name of names) {
|
|
6719
6801
|
config.environments[name] ??= {};
|
|
6720
6802
|
const environment = config.environments[name];
|
|
6721
|
-
environment.dev ??= {};
|
|
6722
6803
|
// vm tests run using the native import mechanism
|
|
6723
|
-
if (name === "__vitest_vm__")
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
environment.dev.preTransformRequests = false;
|
|
6728
|
-
environment.keepProcessEnv = true;
|
|
6729
|
-
const resolveExternal = name === "client" ? config.resolve?.external : [];
|
|
6730
|
-
const resolveNoExternal = name === "client" ? config.resolve?.noExternal : [];
|
|
6731
|
-
const topLevelResolveOptions = {};
|
|
6804
|
+
if (environment.dev ??= {}, name === "__vitest_vm__") environment.dev.moduleRunnerTransform = false, environment.consumer = "client";
|
|
6805
|
+
else environment.dev.moduleRunnerTransform = true;
|
|
6806
|
+
environment.dev.preTransformRequests = false, environment.keepProcessEnv = true;
|
|
6807
|
+
const resolveExternal = name === "client" ? config.resolve?.external : [], resolveNoExternal = name === "client" ? config.resolve?.noExternal : [], topLevelResolveOptions = {};
|
|
6732
6808
|
if (resolveExternal != null) topLevelResolveOptions.external = resolveExternal;
|
|
6733
6809
|
if (resolveNoExternal != null) topLevelResolveOptions.noExternal = resolveNoExternal;
|
|
6734
|
-
const currentResolveOptions = mergeConfig(topLevelResolveOptions, environment.resolve || {});
|
|
6735
|
-
const envNoExternal = resolveViteResolveOptions("noExternal", currentResolveOptions);
|
|
6810
|
+
const currentResolveOptions = mergeConfig(topLevelResolveOptions, environment.resolve || {}), envNoExternal = resolveViteResolveOptions("noExternal", currentResolveOptions);
|
|
6736
6811
|
if (envNoExternal === true) noExternalAll = true;
|
|
6737
6812
|
else noExternal.push(...envNoExternal);
|
|
6738
6813
|
const envExternal = resolveViteResolveOptions("external", currentResolveOptions);
|
|
6739
6814
|
if (envExternal !== true) external.push(...envExternal);
|
|
6740
|
-
|
|
6741
|
-
environment.
|
|
6742
|
-
environment.resolve.external = [...builtinModules, ...builtinModules.map((m) => `node:${m}`)];
|
|
6743
|
-
// by setting `noExternal` to `true`, we make sure that
|
|
6744
|
-
// Vite will never use its own externalization mechanism
|
|
6745
|
-
// to externalize modules and always resolve static imports
|
|
6746
|
-
// in both SSR and Client environments
|
|
6747
|
-
environment.resolve.noExternal = true;
|
|
6748
|
-
if (name === "__vitest_vm__" || name === "__vitest__") continue;
|
|
6749
|
-
const currentOptimizeDeps = environment.optimizeDeps || (name === "client" ? config.optimizeDeps : name === "ssr" ? config.ssr?.optimizeDeps : void 0);
|
|
6750
|
-
const optimizeDeps = resolveOptimizerConfig(testConfig.deps?.optimizer?.[name], currentOptimizeDeps);
|
|
6815
|
+
if (environment.resolve ??= {}, environment.resolve.external = [...builtinModules, ...builtinModules.map((m) => `node:${m}`)], environment.resolve.noExternal = true, name === "__vitest_vm__" || name === "__vitest__") continue;
|
|
6816
|
+
const currentOptimizeDeps = environment.optimizeDeps || (name === "client" ? config.optimizeDeps : name === "ssr" ? config.ssr?.optimizeDeps : void 0), optimizeDeps = resolveOptimizerConfig(testConfig.deps?.optimizer?.[name], currentOptimizeDeps);
|
|
6751
6817
|
// Vite respects the root level optimize deps, so we override it instead
|
|
6752
|
-
if (name === "client")
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
} else if (name === "ssr") {
|
|
6756
|
-
config.ssr ??= {};
|
|
6757
|
-
config.ssr.optimizeDeps = optimizeDeps;
|
|
6758
|
-
environment.optimizeDeps = void 0;
|
|
6759
|
-
} else environment.optimizeDeps = optimizeDeps;
|
|
6818
|
+
if (name === "client") config.optimizeDeps = optimizeDeps, environment.optimizeDeps = void 0;
|
|
6819
|
+
else if (name === "ssr") config.ssr ??= {}, config.ssr.optimizeDeps = optimizeDeps, environment.optimizeDeps = void 0;
|
|
6820
|
+
else environment.optimizeDeps = optimizeDeps;
|
|
6760
6821
|
}
|
|
6761
|
-
testConfig.server ??= {}
|
|
6762
|
-
testConfig.server.deps ??= {};
|
|
6763
|
-
if (testConfig.server.deps.inline !== true) {
|
|
6822
|
+
if (testConfig.server ??= {}, testConfig.server.deps ??= {}, testConfig.server.deps.inline !== true) {
|
|
6764
6823
|
if (noExternalAll) testConfig.server.deps.inline = true;
|
|
6765
|
-
else if (noExternal.length)
|
|
6766
|
-
testConfig.server.deps.inline ??= [];
|
|
6767
|
-
testConfig.server.deps.inline.push(...noExternal);
|
|
6768
|
-
}
|
|
6769
|
-
}
|
|
6770
|
-
if (external.length) {
|
|
6771
|
-
testConfig.server.deps.external ??= [];
|
|
6772
|
-
testConfig.server.deps.external.push(...external);
|
|
6824
|
+
else if (noExternal.length) testConfig.server.deps.inline ??= [], testConfig.server.deps.inline.push(...noExternal);
|
|
6773
6825
|
}
|
|
6826
|
+
if (external.length) testConfig.server.deps.external ??= [], testConfig.server.deps.external.push(...external);
|
|
6774
6827
|
}
|
|
6775
6828
|
}
|
|
6776
6829
|
};
|
|
6777
6830
|
}
|
|
6778
6831
|
function resolveViteResolveOptions(key, options) {
|
|
6779
|
-
|
|
6780
|
-
else if (typeof options[key] === "string" || options[key] instanceof RegExp) return [options[key]];
|
|
6781
|
-
else if (typeof options[key] === "boolean") return true;
|
|
6782
|
-
return [];
|
|
6832
|
+
return Array.isArray(options[key]) ? options[key] : typeof options[key] === "string" || options[key] instanceof RegExp ? [options[key]] : typeof options[key] === "boolean" ? true : [];
|
|
6783
6833
|
}
|
|
6784
6834
|
|
|
6785
6835
|
function VitestProjectResolver(ctx) {
|
|
@@ -6826,23 +6876,16 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6826
6876
|
};
|
|
6827
6877
|
if (!name) if (typeof options.workspacePath === "string") {
|
|
6828
6878
|
// if there is a package.json, read the name from it
|
|
6829
|
-
const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath);
|
|
6830
|
-
const pkgJsonPath = resolve(dir, "package.json");
|
|
6879
|
+
const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath), pkgJsonPath = resolve(dir, "package.json");
|
|
6831
6880
|
if (existsSync(pkgJsonPath)) name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name;
|
|
6832
6881
|
if (typeof name !== "string" || !name) name = basename(dir);
|
|
6833
6882
|
} else name = options.workspacePath.toString();
|
|
6834
|
-
const isUserBrowserEnabled = viteConfig.test?.browser?.enabled;
|
|
6835
|
-
const isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled);
|
|
6836
|
-
// keep project names to potentially filter it out
|
|
6837
|
-
const workspaceNames = [name];
|
|
6838
|
-
const browser = viteConfig.test.browser || {};
|
|
6883
|
+
const isUserBrowserEnabled = viteConfig.test?.browser?.enabled, isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled), workspaceNames = [name], browser = viteConfig.test.browser || {};
|
|
6839
6884
|
if (isBrowserEnabled && browser.name && !browser.instances?.length)
|
|
6840
6885
|
// vitest injects `instances` in this case later on
|
|
6841
6886
|
workspaceNames.push(name ? `${name} (${browser.name})` : browser.name);
|
|
6842
6887
|
viteConfig.test?.browser?.instances?.forEach((instance) => {
|
|
6843
|
-
|
|
6844
|
-
instance.name ??= name ? `${name} (${instance.browser})` : instance.browser;
|
|
6845
|
-
if (isBrowserEnabled) workspaceNames.push(instance.name);
|
|
6888
|
+
if (instance.name ??= name ? `${name} (${instance.browser})` : instance.browser, isBrowserEnabled) workspaceNames.push(instance.name);
|
|
6846
6889
|
});
|
|
6847
6890
|
const filters = project.vitest.config.project;
|
|
6848
6891
|
// if there is `--project=...` filter, check if any of the potential projects match
|
|
@@ -6870,22 +6913,14 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6870
6913
|
this.meta.watchMode = false;
|
|
6871
6914
|
},
|
|
6872
6915
|
config(viteConfig) {
|
|
6873
|
-
const defines = deleteDefineConfig(viteConfig);
|
|
6874
|
-
|
|
6875
|
-
const root = testConfig.root || viteConfig.root || options.root;
|
|
6876
|
-
const resolveOptions = getDefaultResolveOptions();
|
|
6877
|
-
const config = {
|
|
6916
|
+
const defines = deleteDefineConfig(viteConfig), testConfig = viteConfig.test || {}, root = testConfig.root || viteConfig.root || options.root, resolveOptions = getDefaultResolveOptions();
|
|
6917
|
+
let config = {
|
|
6878
6918
|
root,
|
|
6879
6919
|
define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
|
|
6880
6920
|
resolve: {
|
|
6881
6921
|
...resolveOptions,
|
|
6882
6922
|
alias: testConfig.alias
|
|
6883
6923
|
},
|
|
6884
|
-
esbuild: viteConfig.esbuild === false ? false : {
|
|
6885
|
-
target: viteConfig.esbuild?.target || "node18",
|
|
6886
|
-
sourcemap: "external",
|
|
6887
|
-
legalComments: "inline"
|
|
6888
|
-
},
|
|
6889
6924
|
server: {
|
|
6890
6925
|
watch: null,
|
|
6891
6926
|
open: false,
|
|
@@ -6898,19 +6933,27 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6898
6933
|
environments: { ssr: { resolve: resolveOptions } },
|
|
6899
6934
|
test: {}
|
|
6900
6935
|
};
|
|
6936
|
+
if ("rolldownVersion" in vite) config = {
|
|
6937
|
+
...config,
|
|
6938
|
+
oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
|
|
6939
|
+
};
|
|
6940
|
+
else config = {
|
|
6941
|
+
...config,
|
|
6942
|
+
esbuild: viteConfig.esbuild === false ? false : {
|
|
6943
|
+
target: viteConfig.esbuild?.target || "node18",
|
|
6944
|
+
sourcemap: "external",
|
|
6945
|
+
legalComments: "inline"
|
|
6946
|
+
}
|
|
6947
|
+
};
|
|
6901
6948
|
config.test.defines = defines;
|
|
6902
6949
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
6903
6950
|
if (classNameStrategy !== "scoped") {
|
|
6904
|
-
config.css ??= {}
|
|
6905
|
-
config.css.modules ??= {};
|
|
6906
|
-
if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
6951
|
+
if (config.css ??= {}, config.css.modules ??= {}, config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
6907
6952
|
const root = project.config.root;
|
|
6908
6953
|
return generateScopedClassName(classNameStrategy, name, relative(root, filename));
|
|
6909
6954
|
};
|
|
6910
6955
|
}
|
|
6911
|
-
config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
|
|
6912
|
-
config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
|
|
6913
|
-
return config;
|
|
6956
|
+
return config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false }), config.customLogger = silenceImportViteIgnoreWarning(config.customLogger), config;
|
|
6914
6957
|
}
|
|
6915
6958
|
},
|
|
6916
6959
|
{
|
|
@@ -6918,8 +6961,7 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6918
6961
|
enforce: "post",
|
|
6919
6962
|
async configureServer(server) {
|
|
6920
6963
|
const options = deepMerge({}, configDefaults, server.config.test || {});
|
|
6921
|
-
await project._configureServer(options, server);
|
|
6922
|
-
await server.watcher.close();
|
|
6964
|
+
await project._configureServer(options, server), await server.watcher.close();
|
|
6923
6965
|
}
|
|
6924
6966
|
},
|
|
6925
6967
|
MetaEnvReplacerPlugin(),
|
|
@@ -6962,10 +7004,7 @@ const BUILTIN_EXTENSIONS = new Set([
|
|
|
6962
7004
|
".cjs",
|
|
6963
7005
|
".node",
|
|
6964
7006
|
".wasm"
|
|
6965
|
-
])
|
|
6966
|
-
const ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/;
|
|
6967
|
-
const ESM_FOLDER_RE = /\/(es|esm)\/(.*\.js)$/;
|
|
6968
|
-
const defaultInline = [
|
|
7007
|
+
]), ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/, ESM_FOLDER_RE = /\/(es|esm)\/(.*\.js)$/, defaultInline = [
|
|
6969
7008
|
/virtual:/,
|
|
6970
7009
|
/\.[mc]?ts$/,
|
|
6971
7010
|
/[?&](init|raw|url|inline)\b/,
|
|
@@ -6973,8 +7012,7 @@ const defaultInline = [
|
|
|
6973
7012
|
/^(?!.*node_modules).*\.mjs$/,
|
|
6974
7013
|
/^(?!.*node_modules).*\.cjs\.js$/,
|
|
6975
7014
|
/vite\w*\/dist\/client\/env.mjs/
|
|
6976
|
-
];
|
|
6977
|
-
const depsExternal = [/\/node_modules\/.*\.cjs\.js$/, /\/node_modules\/.*\.mjs$/];
|
|
7015
|
+
], depsExternal = [/\/node_modules\/.*\.cjs\.js$/, /\/node_modules\/.*\.mjs$/];
|
|
6978
7016
|
function guessCJSversion(id) {
|
|
6979
7017
|
if (id.match(ESM_EXT_RE)) {
|
|
6980
7018
|
for (const i of [
|
|
@@ -7004,8 +7042,7 @@ async function isValidNodeImport(id) {
|
|
|
7004
7042
|
if (/\.(?:\w+-)?esm?(?:-\w+)?\.js$|\/esm?\//.test(id)) return false;
|
|
7005
7043
|
try {
|
|
7006
7044
|
await esModuleLexer.init;
|
|
7007
|
-
const code = await promises.readFile(id, "utf8");
|
|
7008
|
-
const [, , , hasModuleSyntax] = esModuleLexer.parse(code);
|
|
7045
|
+
const code = await promises.readFile(id, "utf8"), [, , , hasModuleSyntax] = esModuleLexer.parse(code);
|
|
7009
7046
|
return !hasModuleSyntax;
|
|
7010
7047
|
} catch {
|
|
7011
7048
|
return false;
|
|
@@ -7016,25 +7053,17 @@ async function shouldExternalize(id, options, cache) {
|
|
|
7016
7053
|
return cache.get(id);
|
|
7017
7054
|
}
|
|
7018
7055
|
async function _shouldExternalize(id, options) {
|
|
7019
|
-
if (isBuiltin(id)) return id;
|
|
7020
7056
|
// data: should be processed by native import,
|
|
7021
7057
|
// since it is a feature of ESM.
|
|
7022
7058
|
// also externalize network imports since nodejs allows it when --experimental-network-imports
|
|
7023
|
-
if (id.startsWith("data:") || /^(?:https?:)?\/\//.test(id)) return id;
|
|
7059
|
+
if (isBuiltin(id) || id.startsWith("data:") || /^(?:https?:)?\/\//.test(id)) return id;
|
|
7024
7060
|
const moduleDirectories = options?.moduleDirectories || ["/node_modules/"];
|
|
7025
|
-
if (matchExternalizePattern(id, moduleDirectories, options?.inline)) return false;
|
|
7026
|
-
if (options?.inlineFiles && options?.inlineFiles.includes(id)) return false;
|
|
7027
|
-
if (matchExternalizePattern(id, moduleDirectories, options?.external)) return id;
|
|
7061
|
+
if (matchExternalizePattern(id, moduleDirectories, options?.inline) || options?.inlineFiles && options?.inlineFiles.includes(id)) return false;
|
|
7028
7062
|
// Unless the user explicitly opted to inline them, externalize Vite deps.
|
|
7029
7063
|
// They are too big to inline by default.
|
|
7030
|
-
if (options?.cacheDir && id.includes(options.cacheDir)) return id;
|
|
7031
|
-
const isLibraryModule = moduleDirectories.some((dir) => id.includes(dir));
|
|
7032
|
-
|
|
7033
|
-
id = guessCJS ? guessCJSversion(id) || id : id;
|
|
7034
|
-
if (matchExternalizePattern(id, moduleDirectories, defaultInline)) return false;
|
|
7035
|
-
if (matchExternalizePattern(id, moduleDirectories, depsExternal)) return id;
|
|
7036
|
-
if (isLibraryModule && await isValidNodeImport(id)) return id;
|
|
7037
|
-
return false;
|
|
7064
|
+
if (matchExternalizePattern(id, moduleDirectories, options?.external) || options?.cacheDir && id.includes(options.cacheDir)) return id;
|
|
7065
|
+
const isLibraryModule = moduleDirectories.some((dir) => id.includes(dir)), guessCJS = isLibraryModule && options?.fallbackCJS;
|
|
7066
|
+
return id = guessCJS ? guessCJSversion(id) || id : id, matchExternalizePattern(id, moduleDirectories, defaultInline) ? false : matchExternalizePattern(id, moduleDirectories, depsExternal) || isLibraryModule && await isValidNodeImport(id) ? id : false;
|
|
7038
7067
|
}
|
|
7039
7068
|
function matchExternalizePattern(id, moduleDirectories, patterns) {
|
|
7040
7069
|
if (patterns == null) return false;
|
|
@@ -7080,24 +7109,16 @@ class TestSpecification {
|
|
|
7080
7109
|
*/
|
|
7081
7110
|
testLines;
|
|
7082
7111
|
constructor(project, moduleId, pool, testLines) {
|
|
7083
|
-
this[0] = project;
|
|
7084
|
-
|
|
7085
|
-
this
|
|
7086
|
-
const name = project.config.name;
|
|
7087
|
-
const hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
|
|
7088
|
-
this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName);
|
|
7089
|
-
this.project = project;
|
|
7090
|
-
this.moduleId = moduleId;
|
|
7091
|
-
this.pool = pool;
|
|
7092
|
-
this.testLines = testLines;
|
|
7112
|
+
this[0] = project, this[1] = moduleId, this[2] = { pool };
|
|
7113
|
+
const name = project.config.name, hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
|
|
7114
|
+
this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName), this.project = project, this.moduleId = moduleId, this.pool = pool, this.testLines = testLines;
|
|
7093
7115
|
}
|
|
7094
7116
|
/**
|
|
7095
7117
|
* Test module associated with the specification.
|
|
7096
7118
|
*/
|
|
7097
7119
|
get testModule() {
|
|
7098
7120
|
const task = this.project.vitest.state.idMap.get(this.taskId);
|
|
7099
|
-
|
|
7100
|
-
return this.project.vitest.state.getReportedEntity(task);
|
|
7121
|
+
return task ? this.project.vitest.state.getReportedEntity(task) : void 0;
|
|
7101
7122
|
}
|
|
7102
7123
|
toJSON() {
|
|
7103
7124
|
return [
|
|
@@ -7117,9 +7138,7 @@ class TestSpecification {
|
|
|
7117
7138
|
* @deprecated
|
|
7118
7139
|
*/
|
|
7119
7140
|
*[Symbol.iterator]() {
|
|
7120
|
-
yield this.project;
|
|
7121
|
-
yield this.moduleId;
|
|
7122
|
-
yield this.pool;
|
|
7141
|
+
yield this.project, yield this.moduleId, yield this.pool;
|
|
7123
7142
|
}
|
|
7124
7143
|
}
|
|
7125
7144
|
|
|
@@ -7128,12 +7147,10 @@ async function createViteServer(inlineConfig) {
|
|
|
7128
7147
|
// But Vitest works correctly either way
|
|
7129
7148
|
const error = console.error;
|
|
7130
7149
|
console.error = (...args) => {
|
|
7131
|
-
|
|
7132
|
-
error(...args);
|
|
7150
|
+
typeof args[0] === "string" && args[0].includes("WebSocket server error:") || error(...args);
|
|
7133
7151
|
};
|
|
7134
7152
|
const server = await createServer(inlineConfig);
|
|
7135
|
-
console.error = error;
|
|
7136
|
-
return server;
|
|
7153
|
+
return console.error = error, server;
|
|
7137
7154
|
}
|
|
7138
7155
|
|
|
7139
7156
|
class TestProject {
|
|
@@ -7161,18 +7178,14 @@ class TestProject {
|
|
|
7161
7178
|
/** @internal */ _vite;
|
|
7162
7179
|
/** @internal */ _hash;
|
|
7163
7180
|
/** @internal */ _resolver;
|
|
7181
|
+
/** @inetrnal */ testFilesList = null;
|
|
7164
7182
|
runner;
|
|
7165
7183
|
closingPromise;
|
|
7166
|
-
testFilesList = null;
|
|
7167
7184
|
typecheckFilesList = null;
|
|
7168
7185
|
_globalSetups;
|
|
7169
7186
|
_provided = {};
|
|
7170
7187
|
constructor(path, vitest, options) {
|
|
7171
|
-
this.path = path;
|
|
7172
|
-
this.options = options;
|
|
7173
|
-
this.vitest = vitest;
|
|
7174
|
-
this.ctx = vitest;
|
|
7175
|
-
this.globalConfig = vitest.config;
|
|
7188
|
+
this.path = path, this.options = options, this.vitest = vitest, this.ctx = vitest, this.globalConfig = vitest.config;
|
|
7176
7189
|
}
|
|
7177
7190
|
/**
|
|
7178
7191
|
* The unique hash of this project. This value is consistent between the reruns.
|
|
@@ -7201,10 +7214,9 @@ class TestProject {
|
|
|
7201
7214
|
* Get the provided context. The project context is merged with the global context.
|
|
7202
7215
|
*/
|
|
7203
7216
|
getProvidedContext() {
|
|
7204
|
-
if (this.isRootProject()) return this._provided;
|
|
7205
7217
|
// globalSetup can run even if core workspace is not part of the test run
|
|
7206
7218
|
// so we need to inherit its provided context
|
|
7207
|
-
return {
|
|
7219
|
+
return this.isRootProject() ? this._provided : {
|
|
7208
7220
|
...this.vitest.getRootProject().getProvidedContext(),
|
|
7209
7221
|
...this._provided
|
|
7210
7222
|
};
|
|
@@ -7228,13 +7240,11 @@ class TestProject {
|
|
|
7228
7240
|
*/
|
|
7229
7241
|
get vite() {
|
|
7230
7242
|
if (!this._vite) throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
|
|
7231
|
-
|
|
7232
|
-
Object.defineProperty(this, "vite", {
|
|
7243
|
+
return Object.defineProperty(this, "vite", {
|
|
7233
7244
|
configurable: true,
|
|
7234
7245
|
writable: true,
|
|
7235
7246
|
value: this._vite
|
|
7236
|
-
});
|
|
7237
|
-
return this._vite;
|
|
7247
|
+
}), this._vite;
|
|
7238
7248
|
}
|
|
7239
7249
|
/**
|
|
7240
7250
|
* Resolved project configuration.
|
|
@@ -7291,13 +7301,14 @@ class TestProject {
|
|
|
7291
7301
|
}
|
|
7292
7302
|
/** @internal */
|
|
7293
7303
|
async _initializeGlobalSetup() {
|
|
7294
|
-
if (this._globalSetups)
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7304
|
+
if (!this._globalSetups) {
|
|
7305
|
+
this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
|
|
7306
|
+
for (const globalSetupFile of this._globalSetups) {
|
|
7307
|
+
const teardown = await globalSetupFile.setup?.(this);
|
|
7308
|
+
if (teardown == null || !!globalSetupFile.teardown) continue;
|
|
7309
|
+
if (typeof teardown !== "function") throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
|
|
7310
|
+
globalSetupFile.teardown = teardown;
|
|
7311
|
+
}
|
|
7301
7312
|
}
|
|
7302
7313
|
}
|
|
7303
7314
|
onTestsRerun(cb) {
|
|
@@ -7309,8 +7320,7 @@ class TestProject {
|
|
|
7309
7320
|
}
|
|
7310
7321
|
/** @internal */
|
|
7311
7322
|
async _teardownGlobalSetup() {
|
|
7312
|
-
if (
|
|
7313
|
-
for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
|
|
7323
|
+
if (this._globalSetups) for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
|
|
7314
7324
|
}
|
|
7315
7325
|
/** @deprecated use `vitest.logger` instead */
|
|
7316
7326
|
get logger() {
|
|
@@ -7340,12 +7350,8 @@ class TestProject {
|
|
|
7340
7350
|
* @param filters String filters to match the test files.
|
|
7341
7351
|
*/
|
|
7342
7352
|
async globTestFiles(filters = []) {
|
|
7343
|
-
const dir = this.config.dir || this.config.root;
|
|
7344
|
-
|
|
7345
|
-
const typecheck = this.config.typecheck;
|
|
7346
|
-
const [testFiles, typecheckTestFiles] = await Promise.all([typecheck.enabled && typecheck.only ? [] : this.globAllTestFiles(include, exclude, includeSource, dir), typecheck.enabled ? this.typecheckFilesList || this.globFiles(typecheck.include, typecheck.exclude, dir) : []]);
|
|
7347
|
-
this.typecheckFilesList = typecheckTestFiles;
|
|
7348
|
-
return {
|
|
7353
|
+
const dir = this.config.dir || this.config.root, { include, exclude, includeSource } = this.config, typecheck = this.config.typecheck, [testFiles, typecheckTestFiles] = await Promise.all([typecheck.enabled && typecheck.only ? [] : this.globAllTestFiles(include, exclude, includeSource, dir), typecheck.enabled ? this.typecheckFilesList || this.globFiles(typecheck.include, typecheck.exclude, dir) : []]);
|
|
7354
|
+
return this.typecheckFilesList = typecheckTestFiles, {
|
|
7349
7355
|
testFiles: this.filterFiles(testFiles, filters, dir),
|
|
7350
7356
|
typecheckTestFiles: this.filterFiles(typecheckTestFiles, filters, dir)
|
|
7351
7357
|
};
|
|
@@ -7364,8 +7370,7 @@ class TestProject {
|
|
|
7364
7370
|
}
|
|
7365
7371
|
}));
|
|
7366
7372
|
}
|
|
7367
|
-
this.testFilesList = testFiles;
|
|
7368
|
-
return testFiles;
|
|
7373
|
+
return this.testFilesList = testFiles, testFiles;
|
|
7369
7374
|
}
|
|
7370
7375
|
isBrowserEnabled() {
|
|
7371
7376
|
return isBrowserEnabled(this.config);
|
|
@@ -7402,8 +7407,7 @@ class TestProject {
|
|
|
7402
7407
|
cwd,
|
|
7403
7408
|
ignore: exclude,
|
|
7404
7409
|
expandDirectories: false
|
|
7405
|
-
};
|
|
7406
|
-
const files = await glob(include, globOptions);
|
|
7410
|
+
}, files = await glob(include, globOptions);
|
|
7407
7411
|
// keep the slashes consistent with Vite
|
|
7408
7412
|
// we are not using the pathe here because it normalizes the drive letter on Windows
|
|
7409
7413
|
// and we want to keep it the same as working dir
|
|
@@ -7416,16 +7420,10 @@ class TestProject {
|
|
|
7416
7420
|
if (this._isCachedTestFile(moduleId)) return true;
|
|
7417
7421
|
const relativeId = relative(this.config.dir || this.config.root, moduleId);
|
|
7418
7422
|
if (pm.isMatch(relativeId, this.config.exclude)) return false;
|
|
7419
|
-
if (pm.isMatch(relativeId, this.config.include))
|
|
7420
|
-
this.markTestFile(moduleId);
|
|
7421
|
-
return true;
|
|
7422
|
-
}
|
|
7423
|
+
if (pm.isMatch(relativeId, this.config.include)) return this.markTestFile(moduleId), true;
|
|
7423
7424
|
if (this.config.includeSource?.length && pm.isMatch(relativeId, this.config.includeSource)) {
|
|
7424
7425
|
const code = source?.() || readFileSync(moduleId, "utf-8");
|
|
7425
|
-
if (this.isInSourceTestCode(code))
|
|
7426
|
-
this.markTestFile(moduleId);
|
|
7427
|
-
return true;
|
|
7428
|
-
}
|
|
7426
|
+
if (this.isInSourceTestCode(code)) return this.markTestFile(moduleId), true;
|
|
7429
7427
|
}
|
|
7430
7428
|
return false;
|
|
7431
7429
|
}
|
|
@@ -7438,7 +7436,7 @@ class TestProject {
|
|
|
7438
7436
|
}
|
|
7439
7437
|
filterFiles(testFiles, filters, dir) {
|
|
7440
7438
|
if (filters.length && process.platform === "win32") filters = filters.map((f) => slash(f));
|
|
7441
|
-
|
|
7439
|
+
return filters.length ? testFiles.filter((t) => {
|
|
7442
7440
|
const testFile = relative(dir, t).toLocaleLowerCase();
|
|
7443
7441
|
return filters.some((f) => {
|
|
7444
7442
|
// if filter is a full file path, we should include it if it's in the same folder
|
|
@@ -7446,8 +7444,7 @@ class TestProject {
|
|
|
7446
7444
|
const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f);
|
|
7447
7445
|
return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase());
|
|
7448
7446
|
});
|
|
7449
|
-
});
|
|
7450
|
-
return testFiles;
|
|
7447
|
+
}) : testFiles;
|
|
7451
7448
|
}
|
|
7452
7449
|
_parentBrowser;
|
|
7453
7450
|
/** @internal */
|
|
@@ -7466,21 +7463,15 @@ class TestProject {
|
|
|
7466
7463
|
}
|
|
7467
7464
|
},
|
|
7468
7465
|
...MocksPlugins({ filter(id) {
|
|
7469
|
-
|
|
7470
|
-
return true;
|
|
7466
|
+
return !(id.includes(distRoot) || id.includes(cacheDir));
|
|
7471
7467
|
} }),
|
|
7472
7468
|
MetaEnvReplacerPlugin()
|
|
7473
7469
|
], [CoverageTransform(this.vitest)]);
|
|
7474
|
-
this._parentBrowser = browser;
|
|
7475
|
-
if (this.config.browser.ui) setup(this.vitest, browser.vite);
|
|
7470
|
+
if (this._parentBrowser = browser, this.config.browser.ui) setup(this.vitest, browser.vite);
|
|
7476
7471
|
});
|
|
7477
7472
|
/** @internal */
|
|
7478
7473
|
_initBrowserServer = deduped(async () => {
|
|
7479
|
-
await this._parent?._initParentBrowser();
|
|
7480
|
-
if (!this.browser && this._parent?._parentBrowser) {
|
|
7481
|
-
this.browser = this._parent._parentBrowser.spawn(this);
|
|
7482
|
-
await this.vitest.report("onBrowserInit", this);
|
|
7483
|
-
}
|
|
7474
|
+
if (await this._parent?._initParentBrowser(), !this.browser && this._parent?._parentBrowser) this.browser = this._parent._parentBrowser.spawn(this), await this.vitest.report("onBrowserInit", this);
|
|
7484
7475
|
});
|
|
7485
7476
|
/**
|
|
7486
7477
|
* Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
|
|
@@ -7493,8 +7484,7 @@ class TestProject {
|
|
|
7493
7484
|
this.browser?.close(),
|
|
7494
7485
|
this.clearTmpDir()
|
|
7495
7486
|
].filter(Boolean)).then(() => {
|
|
7496
|
-
this._provided = {};
|
|
7497
|
-
this._vite = void 0;
|
|
7487
|
+
this._provided = {}, this._vite = void 0;
|
|
7498
7488
|
});
|
|
7499
7489
|
return this.closingPromise;
|
|
7500
7490
|
}
|
|
@@ -7518,27 +7508,22 @@ class TestProject {
|
|
|
7518
7508
|
}
|
|
7519
7509
|
/** @internal */
|
|
7520
7510
|
async _configureServer(options, server) {
|
|
7521
|
-
this._config = resolveConfig(this.vitest, {
|
|
7511
|
+
for (const _providedKey in this._config = resolveConfig(this.vitest, {
|
|
7522
7512
|
...options,
|
|
7523
7513
|
coverage: this.vitest.config.coverage
|
|
7524
|
-
}, server.config)
|
|
7525
|
-
this._setHash();
|
|
7526
|
-
for (const _providedKey in this.config.provide) {
|
|
7514
|
+
}, server.config), this._setHash(), this.config.provide) {
|
|
7527
7515
|
const providedKey = _providedKey;
|
|
7528
7516
|
// type is very strict here, so we cast it to any
|
|
7529
7517
|
this.provide(providedKey, this.config.provide[providedKey]);
|
|
7530
7518
|
}
|
|
7531
|
-
this.closingPromise = void 0;
|
|
7532
|
-
this._resolver = new VitestResolver(server.config.cacheDir, this._config);
|
|
7533
|
-
this._vite = server;
|
|
7519
|
+
this.closingPromise = void 0, this._resolver = new VitestResolver(server.config.cacheDir, this._config), this._vite = server;
|
|
7534
7520
|
const environment = server.environments.__vitest__;
|
|
7535
7521
|
this.runner = new ServerModuleRunner(environment, this._resolver, this._config);
|
|
7536
7522
|
}
|
|
7537
7523
|
_serializeOverriddenConfig() {
|
|
7538
7524
|
// TODO: serialize the config _once_ or when needed
|
|
7539
7525
|
const config = serializeConfig(this.config, this.vitest.config, this.vite.config);
|
|
7540
|
-
|
|
7541
|
-
return deepMerge(config, this.vitest.configOverride);
|
|
7526
|
+
return this.vitest.configOverride ? deepMerge(config, this.vitest.configOverride) : config;
|
|
7542
7527
|
}
|
|
7543
7528
|
async clearTmpDir() {
|
|
7544
7529
|
try {
|
|
@@ -7551,9 +7536,10 @@ class TestProject {
|
|
|
7551
7536
|
}
|
|
7552
7537
|
/** @internal */
|
|
7553
7538
|
_initBrowserProvider = deduped(async () => {
|
|
7554
|
-
if (!this.isBrowserEnabled() || this.browser?.provider)
|
|
7555
|
-
|
|
7556
|
-
|
|
7539
|
+
if (!(!this.isBrowserEnabled() || this.browser?.provider)) {
|
|
7540
|
+
if (!this.browser) await this._initBrowserServer();
|
|
7541
|
+
await this.browser?.initBrowserProvider(this);
|
|
7542
|
+
}
|
|
7557
7543
|
});
|
|
7558
7544
|
/** @internal */
|
|
7559
7545
|
_provideObject(context) {
|
|
@@ -7566,40 +7552,25 @@ class TestProject {
|
|
|
7566
7552
|
/** @internal */
|
|
7567
7553
|
static _createBasicProject(vitest) {
|
|
7568
7554
|
const project = new TestProject(vitest.config.name || vitest.config.root, vitest);
|
|
7569
|
-
project.runner = vitest.runner;
|
|
7570
|
-
project._vite = vitest.server;
|
|
7571
|
-
project._config = vitest.config;
|
|
7572
|
-
project._resolver = vitest._resolver;
|
|
7573
|
-
project._setHash();
|
|
7574
|
-
project._provideObject(vitest.config.provide);
|
|
7575
|
-
return project;
|
|
7555
|
+
return project.runner = vitest.runner, project._vite = vitest.server, project._config = vitest.config, project._resolver = vitest._resolver, project._setHash(), project._provideObject(vitest.config.provide), project;
|
|
7576
7556
|
}
|
|
7577
7557
|
/** @internal */
|
|
7578
7558
|
static _cloneBrowserProject(parent, config) {
|
|
7579
7559
|
const clone = new TestProject(parent.path, parent.vitest);
|
|
7580
|
-
clone.runner = parent.runner;
|
|
7581
|
-
clone._vite = parent._vite;
|
|
7582
|
-
clone._resolver = parent._resolver;
|
|
7583
|
-
clone._config = config;
|
|
7584
|
-
clone._setHash();
|
|
7585
|
-
clone._parent = parent;
|
|
7586
|
-
clone._provideObject(config.provide);
|
|
7587
|
-
return clone;
|
|
7560
|
+
return clone.runner = parent.runner, clone._vite = parent._vite, clone._resolver = parent._resolver, clone._config = config, clone._setHash(), clone._parent = parent, clone._provideObject(config.provide), clone;
|
|
7588
7561
|
}
|
|
7589
7562
|
}
|
|
7590
7563
|
function deduped(cb) {
|
|
7591
7564
|
let _promise;
|
|
7592
|
-
return (...args) => {
|
|
7565
|
+
return ((...args) => {
|
|
7593
7566
|
if (!_promise) _promise = cb(...args).finally(() => {
|
|
7594
7567
|
_promise = void 0;
|
|
7595
7568
|
});
|
|
7596
7569
|
return _promise;
|
|
7597
|
-
};
|
|
7570
|
+
});
|
|
7598
7571
|
}
|
|
7599
7572
|
async function initializeProject(workspacePath, ctx, options) {
|
|
7600
|
-
const project = new TestProject(workspacePath, ctx, options)
|
|
7601
|
-
const { configFile,...restOptions } = options;
|
|
7602
|
-
const config = {
|
|
7573
|
+
const project = new TestProject(workspacePath, ctx, options), { configFile,...restOptions } = options, config = {
|
|
7603
7574
|
...restOptions,
|
|
7604
7575
|
configFile,
|
|
7605
7576
|
configLoader: ctx.vite.config.inlineConfig.configLoader,
|
|
@@ -7609,25 +7580,20 @@ async function initializeProject(workspacePath, ctx, options) {
|
|
|
7609
7580
|
workspacePath
|
|
7610
7581
|
})]
|
|
7611
7582
|
};
|
|
7612
|
-
await createViteServer(config);
|
|
7613
|
-
return project;
|
|
7583
|
+
return await createViteServer(config), project;
|
|
7614
7584
|
}
|
|
7615
7585
|
function generateHash(str) {
|
|
7616
7586
|
let hash = 0;
|
|
7617
7587
|
if (str.length === 0) return `${hash}`;
|
|
7618
7588
|
for (let i = 0; i < str.length; i++) {
|
|
7619
7589
|
const char = str.charCodeAt(i);
|
|
7620
|
-
hash = (hash << 5) - hash + char;
|
|
7621
|
-
hash = hash & hash;
|
|
7590
|
+
hash = (hash << 5) - hash + char, hash = hash & hash;
|
|
7622
7591
|
}
|
|
7623
7592
|
return `${hash}`;
|
|
7624
7593
|
}
|
|
7625
7594
|
|
|
7626
7595
|
async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projectsDefinition, names) {
|
|
7627
|
-
const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition)
|
|
7628
|
-
// cli options that affect the project config,
|
|
7629
|
-
// not all options are allowed to be overridden
|
|
7630
|
-
const overridesOptions = [
|
|
7596
|
+
const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition), overridesOptions = [
|
|
7631
7597
|
"logHeapUsage",
|
|
7632
7598
|
"allowOnly",
|
|
7633
7599
|
"sequence",
|
|
@@ -7646,21 +7612,12 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7646
7612
|
"inspect",
|
|
7647
7613
|
"inspectBrk",
|
|
7648
7614
|
"fileParallelism"
|
|
7649
|
-
]
|
|
7650
|
-
const cliOverrides = overridesOptions.reduce((acc, name) => {
|
|
7615
|
+
], cliOverrides = overridesOptions.reduce((acc, name) => {
|
|
7651
7616
|
if (name in cliOptions) acc[name] = cliOptions[name];
|
|
7652
7617
|
return acc;
|
|
7653
|
-
}, {});
|
|
7654
|
-
const projectPromises = [];
|
|
7655
|
-
const fileProjects = [...configFiles, ...nonConfigDirectories];
|
|
7656
|
-
const concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
|
|
7618
|
+
}, {}), projectPromises = [], fileProjects = [...configFiles, ...nonConfigDirectories], concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
|
|
7657
7619
|
projectConfigs.forEach((options, index) => {
|
|
7658
|
-
const configRoot = vitest.config.root;
|
|
7659
|
-
// if extends a config file, resolve the file path
|
|
7660
|
-
const configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false;
|
|
7661
|
-
// if `root` is configured, resolve it relative to the workspace file or vite root (like other options)
|
|
7662
|
-
// if `root` is not specified, inline configs use the same root as the root project
|
|
7663
|
-
const root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
|
|
7620
|
+
const configRoot = vitest.config.root, configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false, root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
|
|
7664
7621
|
projectPromises.push(concurrent(() => initializeProject(index, vitest, {
|
|
7665
7622
|
...options,
|
|
7666
7623
|
root,
|
|
@@ -7678,8 +7635,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7678
7635
|
if (project) projectPromises.push(Promise.resolve(project));
|
|
7679
7636
|
continue;
|
|
7680
7637
|
}
|
|
7681
|
-
const configFile = path.endsWith("/") ? false : path;
|
|
7682
|
-
const root = path.endsWith("/") ? path : dirname(path);
|
|
7638
|
+
const configFile = path.endsWith("/") ? false : path, root = path.endsWith("/") ? path : dirname(path);
|
|
7683
7639
|
projectPromises.push(concurrent(() => initializeProject(path, vitest, {
|
|
7684
7640
|
root,
|
|
7685
7641
|
configFile,
|
|
@@ -7692,9 +7648,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7692
7648
|
vitest.config.project.length ? `The filter matched no projects: ${vitest.config.project.join(", ")}. ` : "",
|
|
7693
7649
|
`The projects definition: ${JSON.stringify(projectsDefinition, null, 4)}.`
|
|
7694
7650
|
].join(""));
|
|
7695
|
-
const resolvedProjectsPromises = await Promise.allSettled(projectPromises);
|
|
7696
|
-
const errors = [];
|
|
7697
|
-
const resolvedProjects = [];
|
|
7651
|
+
const resolvedProjectsPromises = await Promise.allSettled(projectPromises), errors = [], resolvedProjects = [];
|
|
7698
7652
|
for (const result of resolvedProjectsPromises) if (result.status === "rejected") {
|
|
7699
7653
|
if (result.reason instanceof VitestFilteredOutProjectError)
|
|
7700
7654
|
// filter out filtered out projects
|
|
@@ -7706,8 +7660,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7706
7660
|
for (const project of resolvedProjects) {
|
|
7707
7661
|
const name = project.name;
|
|
7708
7662
|
if (names.has(name)) {
|
|
7709
|
-
const duplicate = resolvedProjects.find((p) => p.name === name && p !== project)
|
|
7710
|
-
const filesError = fileProjects.length ? [
|
|
7663
|
+
const duplicate = resolvedProjects.find((p) => p.name === name && p !== project), filesError = fileProjects.length ? [
|
|
7711
7664
|
"\n\nYour config matched these files:\n",
|
|
7712
7665
|
fileProjects.map((p) => ` - ${relative(vitest.config.root, p)}`).join("\n"),
|
|
7713
7666
|
"\n\n"
|
|
@@ -7729,24 +7682,18 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7729
7682
|
const removeProjects = /* @__PURE__ */ new Set();
|
|
7730
7683
|
resolvedProjects.forEach((project) => {
|
|
7731
7684
|
if (!project.config.browser.enabled) return;
|
|
7732
|
-
const instances = project.config.browser.instances || [];
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
}
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
"Read more: https://vitest.dev/guide/browser/config#browser-instances"
|
|
7745
|
-
].filter(Boolean).join("")));
|
|
7746
|
-
}
|
|
7747
|
-
const originalName = project.config.name;
|
|
7748
|
-
// if original name is in the --project=name filter, keep all instances
|
|
7749
|
-
const filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
|
|
7685
|
+
const instances = project.config.browser.instances || [], browser = project.config.browser.name;
|
|
7686
|
+
if (instances.length === 0 && browser) instances.push({
|
|
7687
|
+
browser,
|
|
7688
|
+
name: project.name ? `${project.name} (${browser})` : browser
|
|
7689
|
+
}), vitest.logger.warn(withLabel("yellow", "Vitest", [
|
|
7690
|
+
`No browser "instances" were defined`,
|
|
7691
|
+
project.name ? ` for the "${project.name}" project. ` : ". ",
|
|
7692
|
+
`Running tests in "${project.config.browser.name}" browser. `,
|
|
7693
|
+
"The \"browser.name\" field is deprecated since Vitest 3. ",
|
|
7694
|
+
"Read more: https://vitest.dev/guide/browser/config#browser-instances"
|
|
7695
|
+
].filter(Boolean).join("")));
|
|
7696
|
+
const originalName = project.config.name, filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
|
|
7750
7697
|
const newName = instance.name;
|
|
7751
7698
|
return vitest.matchesProjectFilter(newName);
|
|
7752
7699
|
});
|
|
@@ -7759,8 +7706,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7759
7706
|
filteredInstances.forEach((config, index) => {
|
|
7760
7707
|
const browser = config.browser;
|
|
7761
7708
|
if (!browser) {
|
|
7762
|
-
const nth = index + 1;
|
|
7763
|
-
const ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
|
|
7709
|
+
const nth = index + 1, ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
|
|
7764
7710
|
throw new Error(`The browser configuration must have a "browser" property. The ${nth}${ending} item in "browser.instances" doesn't have it. Make sure your${originalName ? ` "${originalName}"` : ""} configuration is correct.`);
|
|
7765
7711
|
}
|
|
7766
7712
|
const name = config.name;
|
|
@@ -7775,18 +7721,15 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7775
7721
|
clonedConfig.name = name;
|
|
7776
7722
|
const clone = TestProject._cloneBrowserProject(project, clonedConfig);
|
|
7777
7723
|
resolvedProjects.push(clone);
|
|
7778
|
-
});
|
|
7779
|
-
|
|
7780
|
-
});
|
|
7781
|
-
resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
|
|
7724
|
+
}), removeProjects.add(project);
|
|
7725
|
+
}), resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
|
|
7782
7726
|
const headedBrowserProjects = resolvedProjects.filter((project) => {
|
|
7783
7727
|
return project.config.browser.enabled && !project.config.browser.headless;
|
|
7784
7728
|
});
|
|
7785
7729
|
if (headedBrowserProjects.length > 1) {
|
|
7786
7730
|
const message = [`Found multiple projects that run browser tests in headed mode: "${headedBrowserProjects.map((p) => p.name).join("\", \"")}".`, ` Vitest cannot run multiple headed browsers at the same time.`].join("");
|
|
7787
7731
|
if (!isTTY) throw new Error(`${message} Please, filter projects with --browser=name or --project=name flag or run tests with "headless: true" option.`);
|
|
7788
|
-
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; })
|
|
7789
|
-
const { projectName } = await prompts.default({
|
|
7732
|
+
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; }), { projectName } = await prompts.default({
|
|
7790
7733
|
type: "select",
|
|
7791
7734
|
name: "projectName",
|
|
7792
7735
|
choices: headedBrowserProjects.map((project) => ({
|
|
@@ -7801,10 +7744,9 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7801
7744
|
return resolvedProjects;
|
|
7802
7745
|
}
|
|
7803
7746
|
function cloneConfig(project, { browser,...config }) {
|
|
7804
|
-
const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name,...overrideConfig } = config;
|
|
7805
|
-
const currentConfig = project.config.browser;
|
|
7747
|
+
const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name,...overrideConfig } = config, currentConfig = project.config.browser, clonedConfig = deepClone(project.config);
|
|
7806
7748
|
return mergeConfig({
|
|
7807
|
-
...
|
|
7749
|
+
...clonedConfig,
|
|
7808
7750
|
browser: {
|
|
7809
7751
|
...project.config.browser,
|
|
7810
7752
|
locators: locators ? { testIdAttribute: locators.testIdAttribute ?? currentConfig.locators.testIdAttribute } : project.config.browser.locators,
|
|
@@ -7816,18 +7758,15 @@ function cloneConfig(project, { browser,...config }) {
|
|
|
7816
7758
|
name: browser,
|
|
7817
7759
|
providerOptions: config,
|
|
7818
7760
|
instances: void 0
|
|
7819
|
-
}
|
|
7761
|
+
},
|
|
7762
|
+
include: overrideConfig.include && overrideConfig.include.length > 0 ? [] : clonedConfig.include,
|
|
7763
|
+
exclude: overrideConfig.exclude && overrideConfig.exclude.length > 0 ? [] : clonedConfig.exclude,
|
|
7764
|
+
includeSource: overrideConfig.includeSource && overrideConfig.includeSource.length > 0 ? [] : clonedConfig.includeSource
|
|
7820
7765
|
}, overrideConfig);
|
|
7821
7766
|
}
|
|
7822
7767
|
async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition) {
|
|
7823
7768
|
// project configurations that were specified directly
|
|
7824
|
-
const projectsOptions = [];
|
|
7825
|
-
// custom config files that were specified directly or resolved from a directory
|
|
7826
|
-
const projectsConfigFiles = [];
|
|
7827
|
-
// custom glob matches that should be resolved as directories or config files
|
|
7828
|
-
const projectsGlobMatches = [];
|
|
7829
|
-
// directories that don't have a config file inside, but should be treated as projects
|
|
7830
|
-
const nonConfigProjectDirectories = [];
|
|
7769
|
+
const projectsOptions = [], projectsConfigFiles = [], projectsGlobMatches = [], nonConfigProjectDirectories = [];
|
|
7831
7770
|
for (const definition of projectsDefinition) if (typeof definition === "string") {
|
|
7832
7771
|
const stringOption = definition.replace("<rootDir>", vitest.config.root);
|
|
7833
7772
|
// if the string doesn't contain a glob, we can resolve it directly
|
|
@@ -7871,8 +7810,7 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7871
7810
|
"**/*.timestamp-*",
|
|
7872
7811
|
"**/.DS_Store"
|
|
7873
7812
|
]
|
|
7874
|
-
};
|
|
7875
|
-
const projectsFs = await glob(projectsGlobMatches, globOptions);
|
|
7813
|
+
}, projectsFs = await glob(projectsGlobMatches, globOptions);
|
|
7876
7814
|
await Promise.all(projectsFs.map(async (path) => {
|
|
7877
7815
|
// directories are allowed with a glob like `packages/*`
|
|
7878
7816
|
// in this case every directory is treated as a project
|
|
@@ -7891,21 +7829,15 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7891
7829
|
};
|
|
7892
7830
|
}
|
|
7893
7831
|
async function resolveDirectoryConfig(directory) {
|
|
7894
|
-
const files = new Set(await promises.readdir(directory));
|
|
7895
|
-
|
|
7896
|
-
// this simulates how `findUp` works in packages/vitest/src/node/create.ts:29
|
|
7897
|
-
const configFile = configFiles.find((file) => files.has(file));
|
|
7898
|
-
if (configFile) return resolve(directory, configFile);
|
|
7899
|
-
return null;
|
|
7832
|
+
const files = new Set(await promises.readdir(directory)), configFile = configFiles.find((file) => files.has(file));
|
|
7833
|
+
return configFile ? resolve(directory, configFile) : null;
|
|
7900
7834
|
}
|
|
7901
7835
|
function getDefaultTestProject(vitest) {
|
|
7902
|
-
const filter = vitest.config.project;
|
|
7903
|
-
const project = vitest._ensureRootProject();
|
|
7836
|
+
const filter = vitest.config.project, project = vitest._ensureRootProject();
|
|
7904
7837
|
if (!filter.length) return project;
|
|
7905
7838
|
// check for the project name and browser names
|
|
7906
7839
|
const hasProjects = getPotentialProjectNames(project).some((p) => vitest.matchesProjectFilter(p));
|
|
7907
|
-
|
|
7908
|
-
return null;
|
|
7840
|
+
return hasProjects ? project : null;
|
|
7909
7841
|
}
|
|
7910
7842
|
function getPotentialProjectNames(project) {
|
|
7911
7843
|
const names = [project.name];
|
|
@@ -7925,8 +7857,7 @@ async function loadCustomReporterModule(path, runner) {
|
|
|
7925
7857
|
return customReporterModule.default;
|
|
7926
7858
|
}
|
|
7927
7859
|
function createReporters(reporterReferences, ctx) {
|
|
7928
|
-
const runner = ctx.runner
|
|
7929
|
-
const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
|
|
7860
|
+
const runner = ctx.runner, promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
|
|
7930
7861
|
if (Array.isArray(referenceOrInstance)) {
|
|
7931
7862
|
const [reporterName, reporterOptions] = referenceOrInstance;
|
|
7932
7863
|
if (reporterName === "html") {
|
|
@@ -7967,14 +7898,12 @@ function parseFilter(filter) {
|
|
|
7967
7898
|
filename: parsedFilename,
|
|
7968
7899
|
lineNumber: Number.parseInt(lineNumber)
|
|
7969
7900
|
};
|
|
7970
|
-
|
|
7971
|
-
|
|
7901
|
+
if (lineNumber.match(/^\d+-\d+$/)) throw new RangeLocationFilterProvidedError(filter);
|
|
7902
|
+
return { filename: filter };
|
|
7972
7903
|
}
|
|
7973
7904
|
function groupFilters(filters) {
|
|
7974
|
-
const groupedFilters_ = groupBy(filters, (f) => f.filename)
|
|
7975
|
-
|
|
7976
|
-
const [filename, filters] = entry;
|
|
7977
|
-
const testLocations = filters.map((f) => f.lineNumber);
|
|
7905
|
+
const groupedFilters_ = groupBy(filters, (f) => f.filename), groupedFilters = Object.fromEntries(Object.entries(groupedFilters_).map((entry) => {
|
|
7906
|
+
const [filename, filters] = entry, testLocations = filters.map((f) => f.lineNumber);
|
|
7978
7907
|
return [filename, testLocations.filter((l) => l !== void 0)];
|
|
7979
7908
|
}));
|
|
7980
7909
|
return groupedFilters;
|
|
@@ -7993,45 +7922,35 @@ class VitestSpecifications {
|
|
|
7993
7922
|
if (project._isCachedTestFile(moduleId)) specs.push(project.createSpecification(moduleId));
|
|
7994
7923
|
if (project._isCachedTypecheckFile(moduleId)) specs.push(project.createSpecification(moduleId, [], "typescript"));
|
|
7995
7924
|
}
|
|
7996
|
-
specs.forEach((spec) => this.ensureSpecificationCached(spec));
|
|
7997
|
-
return specs;
|
|
7925
|
+
return specs.forEach((spec) => this.ensureSpecificationCached(spec)), specs;
|
|
7998
7926
|
}
|
|
7999
7927
|
async getRelevantTestSpecifications(filters = []) {
|
|
8000
7928
|
return this.filterTestsBySource(await this.globTestSpecifications(filters));
|
|
8001
7929
|
}
|
|
8002
7930
|
async globTestSpecifications(filters = []) {
|
|
8003
|
-
const files = [];
|
|
8004
|
-
const dir = process.cwd();
|
|
8005
|
-
const parsedFilters = filters.map((f) => parseFilter(f));
|
|
7931
|
+
const files = [], dir = process.cwd(), parsedFilters = filters.map((f) => parseFilter(f));
|
|
8006
7932
|
// Require includeTaskLocation when a location filter is passed
|
|
8007
7933
|
if (!this.vitest.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) throw new IncludeTaskLocationDisabledError();
|
|
8008
7934
|
const testLines = groupFilters(parsedFilters.map((f) => ({
|
|
8009
7935
|
...f,
|
|
8010
7936
|
filename: resolve(dir, f.filename)
|
|
8011
|
-
})));
|
|
8012
|
-
|
|
8013
|
-
const testLocHasMatch = {};
|
|
8014
|
-
await Promise.all(this.vitest.projects.map(async (project) => {
|
|
7937
|
+
}))), testLocHasMatch = {};
|
|
7938
|
+
return await Promise.all(this.vitest.projects.map(async (project) => {
|
|
8015
7939
|
const { testFiles, typecheckTestFiles } = await project.globTestFiles(parsedFilters.map((f) => f.filename));
|
|
8016
7940
|
testFiles.forEach((file) => {
|
|
8017
7941
|
const lines = testLines[file];
|
|
8018
7942
|
testLocHasMatch[file] = true;
|
|
8019
7943
|
const spec = project.createSpecification(file, lines);
|
|
8020
|
-
this.ensureSpecificationCached(spec);
|
|
8021
|
-
|
|
8022
|
-
});
|
|
8023
|
-
typecheckTestFiles.forEach((file) => {
|
|
7944
|
+
this.ensureSpecificationCached(spec), files.push(spec);
|
|
7945
|
+
}), typecheckTestFiles.forEach((file) => {
|
|
8024
7946
|
const lines = testLines[file];
|
|
8025
7947
|
testLocHasMatch[file] = true;
|
|
8026
7948
|
const spec = project.createSpecification(file, lines, "typescript");
|
|
8027
|
-
this.ensureSpecificationCached(spec);
|
|
8028
|
-
files.push(spec);
|
|
7949
|
+
this.ensureSpecificationCached(spec), files.push(spec);
|
|
8029
7950
|
});
|
|
8030
|
-
}))
|
|
8031
|
-
Object.entries(testLines).forEach(([filepath, loc]) => {
|
|
7951
|
+
})), Object.entries(testLines).forEach(([filepath, loc]) => {
|
|
8032
7952
|
if (loc.length !== 0 && !testLocHasMatch[filepath]) throw new LocationFilterFileNotFoundError(relative(dir, filepath));
|
|
8033
|
-
});
|
|
8034
|
-
return files;
|
|
7953
|
+
}), files;
|
|
8035
7954
|
}
|
|
8036
7955
|
clearCache(moduleId) {
|
|
8037
7956
|
if (moduleId) this._cachedSpecs.delete(moduleId);
|
|
@@ -8041,30 +7960,20 @@ class VitestSpecifications {
|
|
|
8041
7960
|
return this._cachedSpecs.get(moduleId);
|
|
8042
7961
|
}
|
|
8043
7962
|
ensureSpecificationCached(spec) {
|
|
8044
|
-
const file = spec.moduleId;
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
if (index === -1) {
|
|
8048
|
-
specs.push(spec);
|
|
8049
|
-
this._cachedSpecs.set(file, specs);
|
|
8050
|
-
} else specs.splice(index, 1, spec);
|
|
7963
|
+
const file = spec.moduleId, specs = this._cachedSpecs.get(file) || [], index = specs.findIndex((_s) => _s.project === spec.project && _s.pool === spec.pool);
|
|
7964
|
+
if (index === -1) specs.push(spec), this._cachedSpecs.set(file, specs);
|
|
7965
|
+
else specs.splice(index, 1, spec);
|
|
8051
7966
|
return specs;
|
|
8052
7967
|
}
|
|
8053
7968
|
async filterTestsBySource(specs) {
|
|
8054
7969
|
if (this.vitest.config.changed && !this.vitest.config.related) {
|
|
8055
|
-
const { VitestGit } = await import('./git.
|
|
8056
|
-
|
|
8057
|
-
const related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
|
|
8058
|
-
if (!related) {
|
|
8059
|
-
process.exitCode = 1;
|
|
8060
|
-
throw new GitNotFoundError();
|
|
8061
|
-
}
|
|
7970
|
+
const { VitestGit } = await import('./git.BFNcloKD.js'), vitestGit = new VitestGit(this.vitest.config.root), related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
|
|
7971
|
+
if (!related) throw process.exitCode = 1, new GitNotFoundError();
|
|
8062
7972
|
this.vitest.config.related = Array.from(new Set(related));
|
|
8063
7973
|
}
|
|
8064
7974
|
const related = this.vitest.config.related;
|
|
8065
7975
|
if (!related) return specs;
|
|
8066
|
-
const forceRerunTriggers = this.vitest.config.forceRerunTriggers;
|
|
8067
|
-
const matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
|
|
7976
|
+
const forceRerunTriggers = this.vitest.config.forceRerunTriggers, matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
|
|
8068
7977
|
if (matcher && related.some((file) => matcher(file))) return specs;
|
|
8069
7978
|
// don't run anything if no related sources are found
|
|
8070
7979
|
// if we are in watch mode, we want to process all tests
|
|
@@ -8072,8 +7981,7 @@ class VitestSpecifications {
|
|
|
8072
7981
|
const testGraphs = await Promise.all(specs.map(async (spec) => {
|
|
8073
7982
|
const deps = await this.getTestDependencies(spec);
|
|
8074
7983
|
return [spec, deps];
|
|
8075
|
-
}));
|
|
8076
|
-
const runningTests = [];
|
|
7984
|
+
})), runningTests = [];
|
|
8077
7985
|
for (const [specification, deps] of testGraphs)
|
|
8078
7986
|
// if deps or the test itself were changed
|
|
8079
7987
|
if (related.some((path) => path === specification.moduleId || deps.has(path))) runningTests.push(specification);
|
|
@@ -8083,8 +7991,7 @@ class VitestSpecifications {
|
|
|
8083
7991
|
const addImports = async (project, filepath) => {
|
|
8084
7992
|
if (deps.has(filepath)) return;
|
|
8085
7993
|
deps.add(filepath);
|
|
8086
|
-
const mod = project.vite.environments.ssr.moduleGraph.getModuleById(filepath);
|
|
8087
|
-
const transformed = mod?.transformResult || await project.vite.environments.ssr.transformRequest(filepath);
|
|
7994
|
+
const mod = project.vite.environments.ssr.moduleGraph.getModuleById(filepath), transformed = mod?.transformResult || await project.vite.environments.ssr.transformRequest(filepath);
|
|
8088
7995
|
if (!transformed) return;
|
|
8089
7996
|
const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
|
|
8090
7997
|
await Promise.all(dependencies.map(async (dep) => {
|
|
@@ -8092,9 +7999,7 @@ class VitestSpecifications {
|
|
|
8092
7999
|
if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) await addImports(project, fsPath);
|
|
8093
8000
|
}));
|
|
8094
8001
|
};
|
|
8095
|
-
await addImports(spec.project, spec.moduleId);
|
|
8096
|
-
deps.delete(spec.moduleId);
|
|
8097
|
-
return deps;
|
|
8002
|
+
return await addImports(spec.project, spec.moduleId), deps.delete(spec.moduleId), deps;
|
|
8098
8003
|
}
|
|
8099
8004
|
}
|
|
8100
8005
|
|
|
@@ -8120,10 +8025,7 @@ class ReportedTaskImplementation {
|
|
|
8120
8025
|
location;
|
|
8121
8026
|
/** @internal */
|
|
8122
8027
|
constructor(task, project) {
|
|
8123
|
-
this.task = task;
|
|
8124
|
-
this.project = project;
|
|
8125
|
-
this.id = task.id;
|
|
8126
|
-
this.location = task.location;
|
|
8028
|
+
this.task = task, this.project = project, this.id = task.id, this.location = task.location;
|
|
8127
8029
|
}
|
|
8128
8030
|
/**
|
|
8129
8031
|
* Checks if the test did not fail the suite.
|
|
@@ -8145,8 +8047,7 @@ class ReportedTaskImplementation {
|
|
|
8145
8047
|
*/
|
|
8146
8048
|
static register(task, project) {
|
|
8147
8049
|
const state = new this(task, project);
|
|
8148
|
-
storeTask(project, task, state);
|
|
8149
|
-
return state;
|
|
8050
|
+
return storeTask(project, task, state), state;
|
|
8150
8051
|
}
|
|
8151
8052
|
}
|
|
8152
8053
|
class TestCase extends ReportedTaskImplementation {
|
|
@@ -8170,9 +8071,7 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8170
8071
|
parent;
|
|
8171
8072
|
/** @internal */
|
|
8172
8073
|
constructor(task, project) {
|
|
8173
|
-
super(task, project);
|
|
8174
|
-
this.name = task.name;
|
|
8175
|
-
this.module = getReportedTask(project, task.file);
|
|
8074
|
+
super(task, project), this.name = task.name, this.module = getReportedTask(project, task.file);
|
|
8176
8075
|
const suite = this.task.suite;
|
|
8177
8076
|
if (suite) this.parent = getReportedTask(project, suite);
|
|
8178
8077
|
else this.parent = this.module;
|
|
@@ -8194,8 +8093,7 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8194
8093
|
* - **skipped**: Test was skipped during collection or dynamically with `ctx.skip()`.
|
|
8195
8094
|
*/
|
|
8196
8095
|
result() {
|
|
8197
|
-
const result = this.task.result;
|
|
8198
|
-
const mode = result?.state || this.task.mode;
|
|
8096
|
+
const result = this.task.result, mode = result?.state || this.task.mode;
|
|
8199
8097
|
if (!result && (mode === "skip" || mode === "todo")) return {
|
|
8200
8098
|
state: "skipped",
|
|
8201
8099
|
note: void 0,
|
|
@@ -8206,16 +8104,14 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8206
8104
|
errors: void 0
|
|
8207
8105
|
};
|
|
8208
8106
|
const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
|
|
8209
|
-
|
|
8107
|
+
return state === "skipped" ? {
|
|
8210
8108
|
state,
|
|
8211
8109
|
note: result.note,
|
|
8212
8110
|
errors: void 0
|
|
8213
|
-
}
|
|
8214
|
-
if (state === "passed") return {
|
|
8111
|
+
} : state === "passed" ? {
|
|
8215
8112
|
state,
|
|
8216
8113
|
errors: result.errors
|
|
8217
|
-
}
|
|
8218
|
-
return {
|
|
8114
|
+
} : {
|
|
8219
8115
|
state,
|
|
8220
8116
|
errors: result.errors || []
|
|
8221
8117
|
};
|
|
@@ -8234,8 +8130,7 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8234
8130
|
const result = this.task.result;
|
|
8235
8131
|
// startTime should always be available if the test has properly finished
|
|
8236
8132
|
if (!result || !result.startTime) return void 0;
|
|
8237
|
-
const duration = result.duration || 0;
|
|
8238
|
-
const slow = duration > this.project.globalConfig.slowTestThreshold;
|
|
8133
|
+
const duration = result.duration || 0, slow = duration > this.project.globalConfig.slowTestThreshold;
|
|
8239
8134
|
return {
|
|
8240
8135
|
slow,
|
|
8241
8136
|
heap: result.heap,
|
|
@@ -8251,8 +8146,7 @@ class TestCollection {
|
|
|
8251
8146
|
#task;
|
|
8252
8147
|
#project;
|
|
8253
8148
|
constructor(task, project) {
|
|
8254
|
-
this.#task = task;
|
|
8255
|
-
this.#project = project;
|
|
8149
|
+
this.#task = task, this.#project = project;
|
|
8256
8150
|
}
|
|
8257
8151
|
/**
|
|
8258
8152
|
* Returns the test or suite at a specific index.
|
|
@@ -8305,10 +8199,7 @@ class TestCollection {
|
|
|
8305
8199
|
* Filters all suites that are part of this collection and its children.
|
|
8306
8200
|
*/
|
|
8307
8201
|
*allSuites() {
|
|
8308
|
-
for (const child of this) if (child.type === "suite")
|
|
8309
|
-
yield child;
|
|
8310
|
-
yield* child.children.allSuites();
|
|
8311
|
-
}
|
|
8202
|
+
for (const child of this) if (child.type === "suite") yield child, yield* child.children.allSuites();
|
|
8312
8203
|
}
|
|
8313
8204
|
*[Symbol.iterator]() {
|
|
8314
8205
|
for (const task of this.#task.tasks) yield getReportedTask(this.#project, task);
|
|
@@ -8321,8 +8212,7 @@ class SuiteImplementation extends ReportedTaskImplementation {
|
|
|
8321
8212
|
children;
|
|
8322
8213
|
/** @internal */
|
|
8323
8214
|
constructor(task, project) {
|
|
8324
|
-
super(task, project);
|
|
8325
|
-
this.children = new TestCollection(task, project);
|
|
8215
|
+
super(task, project), this.children = new TestCollection(task, project);
|
|
8326
8216
|
}
|
|
8327
8217
|
/**
|
|
8328
8218
|
* Errors that happened outside of the test run during collection, like syntax errors.
|
|
@@ -8352,9 +8242,7 @@ class TestSuite extends SuiteImplementation {
|
|
|
8352
8242
|
options;
|
|
8353
8243
|
/** @internal */
|
|
8354
8244
|
constructor(task, project) {
|
|
8355
|
-
super(task, project);
|
|
8356
|
-
this.name = task.name;
|
|
8357
|
-
this.module = getReportedTask(project, task.file);
|
|
8245
|
+
super(task, project), this.name = task.name, this.module = getReportedTask(project, task.file);
|
|
8358
8246
|
const suite = this.task.suite;
|
|
8359
8247
|
if (suite) this.parent = getReportedTask(project, suite);
|
|
8360
8248
|
else this.parent = this.module;
|
|
@@ -8385,29 +8273,21 @@ class TestModule extends SuiteImplementation {
|
|
|
8385
8273
|
moduleId;
|
|
8386
8274
|
/** @internal */
|
|
8387
8275
|
constructor(task, project) {
|
|
8388
|
-
super(task, project);
|
|
8389
|
-
this.moduleId = task.filepath;
|
|
8276
|
+
super(task, project), this.moduleId = task.filepath;
|
|
8390
8277
|
}
|
|
8391
8278
|
/**
|
|
8392
8279
|
* Checks the running state of the test file.
|
|
8393
8280
|
*/
|
|
8394
8281
|
state() {
|
|
8395
8282
|
const state = this.task.result?.state;
|
|
8396
|
-
|
|
8397
|
-
return getSuiteState(this.task);
|
|
8283
|
+
return state === "queued" ? "queued" : getSuiteState(this.task);
|
|
8398
8284
|
}
|
|
8399
8285
|
/**
|
|
8400
8286
|
* Useful information about the module like duration, memory usage, etc.
|
|
8401
8287
|
* If the module was not executed yet, all diagnostic values will return `0`.
|
|
8402
8288
|
*/
|
|
8403
8289
|
diagnostic() {
|
|
8404
|
-
const setupDuration = this.task.setupDuration || 0;
|
|
8405
|
-
const collectDuration = this.task.collectDuration || 0;
|
|
8406
|
-
const prepareDuration = this.task.prepareDuration || 0;
|
|
8407
|
-
const environmentSetupDuration = this.task.environmentLoad || 0;
|
|
8408
|
-
const duration = this.task.result?.duration || 0;
|
|
8409
|
-
const heap = this.task.result?.heap;
|
|
8410
|
-
const importDurations = this.task.importDurations ?? {};
|
|
8290
|
+
const setupDuration = this.task.setupDuration || 0, collectDuration = this.task.collectDuration || 0, prepareDuration = this.task.prepareDuration || 0, environmentSetupDuration = this.task.environmentLoad || 0, duration = this.task.result?.duration || 0, heap = this.task.result?.heap, importDurations = this.task.importDurations ?? {};
|
|
8411
8291
|
return {
|
|
8412
8292
|
environmentSetupDuration,
|
|
8413
8293
|
prepareDuration,
|
|
@@ -8439,18 +8319,19 @@ function getReportedTask(project, runnerTask) {
|
|
|
8439
8319
|
return reportedTask;
|
|
8440
8320
|
}
|
|
8441
8321
|
function getSuiteState(task) {
|
|
8442
|
-
const mode = task.mode;
|
|
8443
|
-
const state = task.result?.state;
|
|
8322
|
+
const mode = task.mode, state = task.result?.state;
|
|
8444
8323
|
if (mode === "skip" || mode === "todo" || state === "skip" || state === "todo") return "skipped";
|
|
8445
8324
|
if (state == null || state === "run" || state === "only") return "pending";
|
|
8446
8325
|
if (state === "fail") return "failed";
|
|
8447
8326
|
if (state === "pass") return "passed";
|
|
8448
8327
|
throw new Error(`Unknown suite state: ${state}`);
|
|
8449
8328
|
}
|
|
8329
|
+
function experimental_getRunnerTask(entity) {
|
|
8330
|
+
return entity.task;
|
|
8331
|
+
}
|
|
8450
8332
|
|
|
8451
8333
|
function isAggregateError(err) {
|
|
8452
|
-
|
|
8453
|
-
return err instanceof Error && "errors" in err;
|
|
8334
|
+
return typeof AggregateError !== "undefined" && err instanceof AggregateError ? true : err instanceof Error && "errors" in err;
|
|
8454
8335
|
}
|
|
8455
8336
|
class StateManager {
|
|
8456
8337
|
filesMap = /* @__PURE__ */ new Map();
|
|
@@ -8481,12 +8362,7 @@ class StateManager {
|
|
|
8481
8362
|
const _error = error;
|
|
8482
8363
|
if (_error && typeof _error === "object" && _error.code === "VITEST_PENDING") {
|
|
8483
8364
|
const task = this.idMap.get(_error.taskId);
|
|
8484
|
-
if (task) {
|
|
8485
|
-
task.mode = "skip";
|
|
8486
|
-
task.result ??= { state: "skip" };
|
|
8487
|
-
task.result.state = "skip";
|
|
8488
|
-
task.result.note = _error.note;
|
|
8489
|
-
}
|
|
8365
|
+
if (task) task.mode = "skip", task.result ??= { state: "skip" }, task.result.state = "skip", task.result.note = _error.note;
|
|
8490
8366
|
return;
|
|
8491
8367
|
}
|
|
8492
8368
|
if (!this.onUnhandledError || this.onUnhandledError(error) !== false) this.errorsSet.add(error);
|
|
@@ -8510,12 +8386,8 @@ class StateManager {
|
|
|
8510
8386
|
* Return files that were running or collected.
|
|
8511
8387
|
*/
|
|
8512
8388
|
getFiles(keys) {
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
// print typecheck files first
|
|
8516
|
-
if (f1.meta?.typecheck && f2.meta?.typecheck) return 0;
|
|
8517
|
-
if (f1.meta?.typecheck) return -1;
|
|
8518
|
-
return 1;
|
|
8389
|
+
return keys ? keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local) : Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
|
|
8390
|
+
return f1.meta?.typecheck && f2.meta?.typecheck ? 0 : f1.meta?.typecheck ? -1 : 1;
|
|
8519
8391
|
});
|
|
8520
8392
|
}
|
|
8521
8393
|
getTestModules(keys) {
|
|
@@ -8534,25 +8406,17 @@ class StateManager {
|
|
|
8534
8406
|
}
|
|
8535
8407
|
collectFiles(project, files = []) {
|
|
8536
8408
|
files.forEach((file) => {
|
|
8537
|
-
const existing = this.filesMap.get(file.filepath) || [];
|
|
8538
|
-
const otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck);
|
|
8539
|
-
const currentFile = existing.find((i) => i.projectName === file.projectName);
|
|
8409
|
+
const existing = this.filesMap.get(file.filepath) || [], otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck), currentFile = existing.find((i) => i.projectName === file.projectName);
|
|
8540
8410
|
// keep logs for the previous file because it should always be initiated before the collections phase
|
|
8541
8411
|
// which means that all logs are collected during the collection and not inside tests
|
|
8542
8412
|
if (currentFile) file.logs = currentFile.logs;
|
|
8543
|
-
otherFiles.push(file);
|
|
8544
|
-
this.filesMap.set(file.filepath, otherFiles);
|
|
8545
|
-
this.updateId(file, project);
|
|
8413
|
+
otherFiles.push(file), this.filesMap.set(file.filepath, otherFiles), this.updateId(file, project);
|
|
8546
8414
|
});
|
|
8547
8415
|
}
|
|
8548
8416
|
clearFiles(project, paths = []) {
|
|
8549
8417
|
paths.forEach((path) => {
|
|
8550
|
-
const files = this.filesMap.get(path);
|
|
8551
|
-
|
|
8552
|
-
fileTask.local = true;
|
|
8553
|
-
TestModule.register(fileTask, project);
|
|
8554
|
-
this.idMap.set(fileTask.id, fileTask);
|
|
8555
|
-
if (!files) {
|
|
8418
|
+
const files = this.filesMap.get(path), fileTask = createFileTask$1(path, project.config.root, project.config.name);
|
|
8419
|
+
if (fileTask.local = true, TestModule.register(fileTask, project), this.idMap.set(fileTask.id, fileTask), !files) {
|
|
8556
8420
|
this.filesMap.set(path, [fileTask]);
|
|
8557
8421
|
return;
|
|
8558
8422
|
}
|
|
@@ -8563,14 +8427,14 @@ class StateManager {
|
|
|
8563
8427
|
});
|
|
8564
8428
|
}
|
|
8565
8429
|
updateId(task, project) {
|
|
8566
|
-
if (this.idMap.get(task.id)
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
}
|
|
8430
|
+
if (this.idMap.get(task.id) !== task) {
|
|
8431
|
+
if (task.type === "suite" && "filepath" in task) TestModule.register(task, project);
|
|
8432
|
+
else if (task.type === "suite") TestSuite.register(task, project);
|
|
8433
|
+
else TestCase.register(task, project);
|
|
8434
|
+
if (this.idMap.set(task.id, task), task.type === "suite") task.tasks.forEach((task) => {
|
|
8435
|
+
this.updateId(task, project);
|
|
8436
|
+
});
|
|
8437
|
+
}
|
|
8574
8438
|
}
|
|
8575
8439
|
getReportedEntity(task) {
|
|
8576
8440
|
return this.reportedTasksMap.get(task);
|
|
@@ -8579,10 +8443,8 @@ class StateManager {
|
|
|
8579
8443
|
for (const [id, result, meta] of packs) {
|
|
8580
8444
|
const task = this.idMap.get(id);
|
|
8581
8445
|
if (task) {
|
|
8582
|
-
task.result = result;
|
|
8583
|
-
task.meta = meta;
|
|
8584
8446
|
// skipped with new PendingError
|
|
8585
|
-
if (result?.state === "skip") task.mode = "skip";
|
|
8447
|
+
if (task.result = result, task.meta = meta, result?.state === "skip") task.mode = "skip";
|
|
8586
8448
|
}
|
|
8587
8449
|
}
|
|
8588
8450
|
}
|
|
@@ -8597,7 +8459,7 @@ class StateManager {
|
|
|
8597
8459
|
return Array.from(this.idMap.values()).filter((t) => t.result?.state === "fail").length;
|
|
8598
8460
|
}
|
|
8599
8461
|
cancelFiles(files, project) {
|
|
8600
|
-
this.collectFiles(project, files.map((filepath) => createFileTask(filepath, project.config.root, project.config.name)));
|
|
8462
|
+
this.collectFiles(project, files.map((filepath) => createFileTask$1(filepath, project.config.root, project.config.name)));
|
|
8601
8463
|
}
|
|
8602
8464
|
}
|
|
8603
8465
|
|
|
@@ -9059,10 +8921,7 @@ class TestRun {
|
|
|
9059
8921
|
}
|
|
9060
8922
|
async start(specifications) {
|
|
9061
8923
|
const filepaths = specifications.map((spec) => spec.moduleId);
|
|
9062
|
-
this.vitest.state.collectPaths(filepaths);
|
|
9063
|
-
await this.vitest.report("onPathsCollected", Array.from(new Set(filepaths)));
|
|
9064
|
-
await this.vitest.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
|
|
9065
|
-
await this.vitest.report("onTestRunStart", [...specifications]);
|
|
8924
|
+
this.vitest.state.collectPaths(filepaths), await this.vitest.report("onTestRunStart", [...specifications]);
|
|
9066
8925
|
}
|
|
9067
8926
|
async enqueued(project, file) {
|
|
9068
8927
|
this.vitest.state.collectFiles(project, [file]);
|
|
@@ -9070,30 +8929,22 @@ class TestRun {
|
|
|
9070
8929
|
await this.vitest.report("onTestModuleQueued", testModule);
|
|
9071
8930
|
}
|
|
9072
8931
|
async collected(project, files) {
|
|
9073
|
-
this.vitest.state.collectFiles(project, files)
|
|
9074
|
-
await Promise.all([this.vitest.report("onCollected", files), ...files.map((file) => {
|
|
8932
|
+
this.vitest.state.collectFiles(project, files), await Promise.all(files.map((file) => {
|
|
9075
8933
|
const testModule = this.vitest.state.getReportedEntity(file);
|
|
9076
8934
|
return this.vitest.report("onTestModuleCollected", testModule);
|
|
9077
|
-
})
|
|
8935
|
+
}));
|
|
9078
8936
|
}
|
|
9079
8937
|
async log(log) {
|
|
9080
|
-
this.vitest.state.updateUserLog(log);
|
|
9081
|
-
await this.vitest.report("onUserConsoleLog", log);
|
|
8938
|
+
this.vitest.state.updateUserLog(log), await this.vitest.report("onUserConsoleLog", log);
|
|
9082
8939
|
}
|
|
9083
8940
|
async annotate(testId, annotation) {
|
|
9084
|
-
const task = this.vitest.state.idMap.get(testId);
|
|
9085
|
-
|
|
9086
|
-
assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
|
|
9087
|
-
assert$1(entity.type === "test", `Annotation can only be added to a test, instead got ${entity.type}`);
|
|
9088
|
-
await this.resolveTestAttachment(entity, annotation);
|
|
9089
|
-
entity.task.annotations.push(annotation);
|
|
9090
|
-
await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
9091
|
-
return annotation;
|
|
8941
|
+
const task = this.vitest.state.idMap.get(testId), entity = task && this.vitest.state.getReportedEntity(task);
|
|
8942
|
+
return assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`), assert$1(entity.type === "test", `Annotation can only be added to a test, instead got ${entity.type}`), await this.resolveTestAttachment(entity, annotation), entity.task.annotations.push(annotation), await this.vitest.report("onTestCaseAnnotate", entity, annotation), annotation;
|
|
9092
8943
|
}
|
|
9093
8944
|
async updated(update, events) {
|
|
9094
|
-
this.vitest.state.updateTasks(update);
|
|
8945
|
+
this.syncUpdateStacks(update), this.vitest.state.updateTasks(update);
|
|
9095
8946
|
for (const [id, event, data] of events) await this.reportEvent(id, event, data).catch((error) => {
|
|
9096
|
-
this.vitest.state.catchError(serializeError(error), "Unhandled Reporter Error");
|
|
8947
|
+
this.vitest.state.catchError(serializeError$1(error), "Unhandled Reporter Error");
|
|
9097
8948
|
});
|
|
9098
8949
|
// TODO: what is the order or reports here?
|
|
9099
8950
|
// "onTaskUpdate" in parallel with others or before all or after all?
|
|
@@ -9101,30 +8952,32 @@ class TestRun {
|
|
|
9101
8952
|
await this.vitest.report("onTaskUpdate", update, events);
|
|
9102
8953
|
}
|
|
9103
8954
|
async end(specifications, errors, coverage) {
|
|
8955
|
+
if (coverage) await this.vitest.report("onCoverage", coverage);
|
|
9104
8956
|
// specification won't have the File task if they were filtered by the --shard command
|
|
9105
|
-
const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null);
|
|
9106
|
-
const files = modules.map((m) => m.task);
|
|
9107
|
-
const state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
|
|
8957
|
+
const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null), state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
|
|
9108
8958
|
if (state !== "passed") process.exitCode = 1;
|
|
9109
|
-
|
|
9110
|
-
await Promise.all([this.vitest.report("onTestRunEnd", modules, [...errors], state), this.vitest.report("onFinished", files, errors, coverage)]);
|
|
9111
|
-
} finally {
|
|
9112
|
-
if (coverage) await this.vitest.report("onCoverage", coverage);
|
|
9113
|
-
}
|
|
8959
|
+
this.vitest.report("onTestRunEnd", modules, [...errors], state);
|
|
9114
8960
|
}
|
|
9115
8961
|
hasFailed(modules) {
|
|
9116
|
-
|
|
9117
|
-
|
|
8962
|
+
return modules.length ? modules.some((m) => !m.ok()) : !this.vitest.config.passWithNoTests;
|
|
8963
|
+
}
|
|
8964
|
+
syncUpdateStacks(update) {
|
|
8965
|
+
update.forEach(([taskId, result]) => {
|
|
8966
|
+
const task = this.vitest.state.idMap.get(taskId), isBrowser = task && task.file.pool === "browser";
|
|
8967
|
+
result?.errors?.forEach((error) => {
|
|
8968
|
+
if (isPrimitive(error)) return;
|
|
8969
|
+
const project = this.vitest.getProjectByName(task.file.projectName || "");
|
|
8970
|
+
if (isBrowser) error.stacks = project.browser?.parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace }) || [];
|
|
8971
|
+
else error.stacks = parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace });
|
|
8972
|
+
});
|
|
8973
|
+
});
|
|
9118
8974
|
}
|
|
9119
8975
|
async reportEvent(id, event, data) {
|
|
9120
|
-
const task = this.vitest.state.idMap.get(id);
|
|
9121
|
-
|
|
9122
|
-
assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
|
|
9123
|
-
if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
|
|
8976
|
+
const task = this.vitest.state.idMap.get(id), entity = task && this.vitest.state.getReportedEntity(task);
|
|
8977
|
+
if (assert$1(task && entity, `Entity must be found for task ${task?.name || id}`), event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
|
|
9124
8978
|
if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
|
|
9125
8979
|
if (event === "suite-finished") {
|
|
9126
|
-
assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module")
|
|
9127
|
-
if (entity.state() === "skipped")
|
|
8980
|
+
if (assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module"), entity.state() === "skipped")
|
|
9128
8981
|
// everything inside suite or a module is skipped,
|
|
9129
8982
|
// so we won't get any children events
|
|
9130
8983
|
// we need to report everything manually
|
|
@@ -9136,8 +8989,7 @@ class TestRun {
|
|
|
9136
8989
|
if (event === "test-prepare" && entity.type === "test") return await this.vitest.report("onTestCaseReady", entity);
|
|
9137
8990
|
if (event === "test-finished" && entity.type === "test") return await this.vitest.report("onTestCaseResult", entity);
|
|
9138
8991
|
if (event.startsWith("before-hook") || event.startsWith("after-hook")) {
|
|
9139
|
-
const isBefore = event.startsWith("before-hook")
|
|
9140
|
-
const hook = entity.type === "test" ? {
|
|
8992
|
+
const isBefore = event.startsWith("before-hook"), hook = entity.type === "test" ? {
|
|
9141
8993
|
name: isBefore ? "beforeEach" : "afterEach",
|
|
9142
8994
|
entity
|
|
9143
8995
|
} : {
|
|
@@ -9149,37 +9001,25 @@ class TestRun {
|
|
|
9149
9001
|
// this can only happen in --merge-reports, and annotation is already resolved
|
|
9150
9002
|
if (event === "test-annotation") {
|
|
9151
9003
|
const annotation = data?.annotation;
|
|
9152
|
-
assert$1(annotation && entity.type === "test");
|
|
9153
|
-
await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
9004
|
+
assert$1(annotation && entity.type === "test"), await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
9154
9005
|
}
|
|
9155
9006
|
}
|
|
9156
9007
|
}
|
|
9157
9008
|
async resolveTestAttachment(test, annotation) {
|
|
9158
|
-
const project = test.project;
|
|
9159
|
-
const attachment = annotation.attachment;
|
|
9009
|
+
const project = test.project, attachment = annotation.attachment;
|
|
9160
9010
|
if (!attachment) return attachment;
|
|
9161
9011
|
const path = attachment.path;
|
|
9162
9012
|
if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
|
|
9163
|
-
const currentPath = resolve(project.config.root, path);
|
|
9164
|
-
|
|
9165
|
-
const newPath = resolve(project.config.attachmentsDir, `${sanitizeFilePath(annotation.message)}-${hash}${extname(currentPath)}`);
|
|
9166
|
-
await mkdir(dirname(newPath), { recursive: true });
|
|
9167
|
-
await copyFile(currentPath, newPath);
|
|
9168
|
-
attachment.path = newPath;
|
|
9013
|
+
const currentPath = resolve(project.config.root, path), hash = createHash("sha1").update(currentPath).digest("hex"), newPath = resolve(project.config.attachmentsDir, `${sanitizeFilePath(annotation.message)}-${hash}${extname(currentPath)}`);
|
|
9014
|
+
await mkdir(dirname(newPath), { recursive: true }), await copyFile(currentPath, newPath), attachment.path = newPath;
|
|
9169
9015
|
const contentType = attachment.contentType ?? mime.getType(basename(currentPath));
|
|
9170
9016
|
attachment.contentType = contentType || void 0;
|
|
9171
9017
|
}
|
|
9172
9018
|
return attachment;
|
|
9173
9019
|
}
|
|
9174
9020
|
async reportChildren(children) {
|
|
9175
|
-
for (const child of children) if (child.type === "test")
|
|
9176
|
-
|
|
9177
|
-
await this.vitest.report("onTestCaseResult", child);
|
|
9178
|
-
} else {
|
|
9179
|
-
await this.vitest.report("onTestSuiteReady", child);
|
|
9180
|
-
await this.reportChildren(child.children);
|
|
9181
|
-
await this.vitest.report("onTestSuiteResult", child);
|
|
9182
|
-
}
|
|
9021
|
+
for (const child of children) if (child.type === "test") await this.vitest.report("onTestCaseReady", child), await this.vitest.report("onTestCaseResult", child);
|
|
9022
|
+
else await this.vitest.report("onTestSuiteReady", child), await this.reportChildren(child.children), await this.vitest.report("onTestSuiteResult", child);
|
|
9183
9023
|
}
|
|
9184
9024
|
}
|
|
9185
9025
|
function sanitizeFilePath(s) {
|
|
@@ -9207,23 +9047,15 @@ class VitestWatcher {
|
|
|
9207
9047
|
* @internal
|
|
9208
9048
|
*/
|
|
9209
9049
|
onWatcherRerun(cb) {
|
|
9210
|
-
this._onRerun.push(cb);
|
|
9211
|
-
return this;
|
|
9050
|
+
return this._onRerun.push(cb), this;
|
|
9212
9051
|
}
|
|
9213
9052
|
unregisterWatcher = noop;
|
|
9214
9053
|
registerWatcher() {
|
|
9215
9054
|
const watcher = this.vitest.vite.watcher;
|
|
9216
9055
|
if (this.vitest.config.forceRerunTriggers.length) watcher.add(this.vitest.config.forceRerunTriggers);
|
|
9217
|
-
watcher.on("change", this.
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
this.unregisterWatcher = () => {
|
|
9221
|
-
watcher.off("change", this.onChange);
|
|
9222
|
-
watcher.off("unlink", this.onUnlink);
|
|
9223
|
-
watcher.off("add", this.onAdd);
|
|
9224
|
-
this.unregisterWatcher = noop;
|
|
9225
|
-
};
|
|
9226
|
-
return this;
|
|
9056
|
+
return watcher.on("change", this.onFileChange), watcher.on("unlink", this.onFileDelete), watcher.on("add", this.onFileCreate), this.unregisterWatcher = () => {
|
|
9057
|
+
watcher.off("change", this.onFileChange), watcher.off("unlink", this.onFileDelete), watcher.off("add", this.onFileCreate), this.unregisterWatcher = noop;
|
|
9058
|
+
}, this;
|
|
9227
9059
|
}
|
|
9228
9060
|
scheduleRerun(file) {
|
|
9229
9061
|
this._onRerun.forEach((cb) => cb(file));
|
|
@@ -9231,25 +9063,17 @@ class VitestWatcher {
|
|
|
9231
9063
|
getTestFilesFromWatcherTrigger(id) {
|
|
9232
9064
|
if (!this.vitest.config.watchTriggerPatterns) return false;
|
|
9233
9065
|
let triggered = false;
|
|
9234
|
-
this.vitest.config.watchTriggerPatterns.forEach((definition) => {
|
|
9066
|
+
return this.vitest.config.watchTriggerPatterns.forEach((definition) => {
|
|
9235
9067
|
const exec = definition.pattern.exec(id);
|
|
9236
9068
|
if (exec) {
|
|
9237
9069
|
const files = definition.testsToRun(id, exec);
|
|
9238
|
-
if (Array.isArray(files))
|
|
9239
|
-
|
|
9240
|
-
files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
|
|
9241
|
-
} else if (typeof files === "string") {
|
|
9242
|
-
triggered = true;
|
|
9243
|
-
this.changedTests.add(resolve(this.vitest.config.root, files));
|
|
9244
|
-
}
|
|
9070
|
+
if (Array.isArray(files)) triggered = true, files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
|
|
9071
|
+
else if (typeof files === "string") triggered = true, this.changedTests.add(resolve(this.vitest.config.root, files));
|
|
9245
9072
|
}
|
|
9246
|
-
});
|
|
9247
|
-
return triggered;
|
|
9073
|
+
}), triggered;
|
|
9248
9074
|
}
|
|
9249
|
-
|
|
9250
|
-
id = slash(id);
|
|
9251
|
-
this.vitest.logger.clearHighlightCache(id);
|
|
9252
|
-
this.vitest.invalidateFile(id);
|
|
9075
|
+
onFileChange = (id) => {
|
|
9076
|
+
id = slash(id), this.vitest.logger.clearHighlightCache(id), this.vitest.invalidateFile(id);
|
|
9253
9077
|
const testFiles = this.getTestFilesFromWatcherTrigger(id);
|
|
9254
9078
|
if (testFiles) this.scheduleRerun(id);
|
|
9255
9079
|
else {
|
|
@@ -9257,22 +9081,11 @@ class VitestWatcher {
|
|
|
9257
9081
|
if (needsRerun) this.scheduleRerun(id);
|
|
9258
9082
|
}
|
|
9259
9083
|
};
|
|
9260
|
-
|
|
9261
|
-
id = slash(id);
|
|
9262
|
-
this.vitest.logger.clearHighlightCache(id);
|
|
9263
|
-
this.invalidates.add(id);
|
|
9264
|
-
if (this.vitest.state.filesMap.has(id)) {
|
|
9265
|
-
this.vitest.projects.forEach((project) => project._removeCachedTestFile(id));
|
|
9266
|
-
this.vitest.state.filesMap.delete(id);
|
|
9267
|
-
this.vitest.cache.results.removeFromCache(id);
|
|
9268
|
-
this.vitest.cache.stats.removeStats(id);
|
|
9269
|
-
this.changedTests.delete(id);
|
|
9270
|
-
this.vitest.report("onTestRemoved", id);
|
|
9271
|
-
}
|
|
9084
|
+
onFileDelete = (id) => {
|
|
9085
|
+
if (id = slash(id), this.vitest.logger.clearHighlightCache(id), this.invalidates.add(id), this.vitest.state.filesMap.has(id)) this.vitest.projects.forEach((project) => project._removeCachedTestFile(id)), this.vitest.state.filesMap.delete(id), this.vitest.cache.results.removeFromCache(id), this.vitest.cache.stats.removeStats(id), this.changedTests.delete(id), this.vitest.report("onTestRemoved", id);
|
|
9272
9086
|
};
|
|
9273
|
-
|
|
9274
|
-
id = slash(id);
|
|
9275
|
-
this.vitest.invalidateFile(id);
|
|
9087
|
+
onFileCreate = (id) => {
|
|
9088
|
+
id = slash(id), this.vitest.invalidateFile(id);
|
|
9276
9089
|
const testFiles = this.getTestFilesFromWatcherTrigger(id);
|
|
9277
9090
|
if (testFiles) {
|
|
9278
9091
|
this.scheduleRerun(id);
|
|
@@ -9280,13 +9093,10 @@ class VitestWatcher {
|
|
|
9280
9093
|
}
|
|
9281
9094
|
let fileContent;
|
|
9282
9095
|
const matchingProjects = [];
|
|
9283
|
-
this.vitest.projects.forEach((project) => {
|
|
9096
|
+
if (this.vitest.projects.forEach((project) => {
|
|
9284
9097
|
if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8"))) matchingProjects.push(project);
|
|
9285
|
-
});
|
|
9286
|
-
|
|
9287
|
-
this.changedTests.add(id);
|
|
9288
|
-
this.scheduleRerun(id);
|
|
9289
|
-
} else {
|
|
9098
|
+
}), matchingProjects.length > 0) this.changedTests.add(id), this.scheduleRerun(id);
|
|
9099
|
+
else {
|
|
9290
9100
|
// it's possible that file was already there but watcher triggered "add" event instead
|
|
9291
9101
|
const needsRerun = this.handleFileChanged(id);
|
|
9292
9102
|
if (needsRerun) this.scheduleRerun(id);
|
|
@@ -9294,51 +9104,33 @@ class VitestWatcher {
|
|
|
9294
9104
|
};
|
|
9295
9105
|
handleSetupFile(filepath) {
|
|
9296
9106
|
let isSetupFile = false;
|
|
9297
|
-
this.vitest.projects.forEach((project) => {
|
|
9298
|
-
|
|
9299
|
-
this.vitest.state.filesMap.forEach((files) => {
|
|
9107
|
+
return this.vitest.projects.forEach((project) => {
|
|
9108
|
+
project.config.setupFiles.includes(filepath) && this.vitest.state.filesMap.forEach((files) => {
|
|
9300
9109
|
files.forEach((file) => {
|
|
9301
|
-
if (file.projectName === project.name)
|
|
9302
|
-
isSetupFile = true;
|
|
9303
|
-
this.changedTests.add(file.filepath);
|
|
9304
|
-
}
|
|
9110
|
+
if (file.projectName === project.name) isSetupFile = true, this.changedTests.add(file.filepath);
|
|
9305
9111
|
});
|
|
9306
9112
|
});
|
|
9307
|
-
});
|
|
9308
|
-
return isSetupFile;
|
|
9113
|
+
}), isSetupFile;
|
|
9309
9114
|
}
|
|
9310
9115
|
/**
|
|
9311
9116
|
* @returns A value indicating whether rerun is needed (changedTests was mutated)
|
|
9312
9117
|
*/
|
|
9313
9118
|
handleFileChanged(filepath) {
|
|
9314
9119
|
if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) return false;
|
|
9315
|
-
if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers))
|
|
9316
|
-
this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file));
|
|
9317
|
-
return true;
|
|
9318
|
-
}
|
|
9120
|
+
if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) return this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file)), true;
|
|
9319
9121
|
if (this.handleSetupFile(filepath)) return true;
|
|
9320
9122
|
const projects = this.vitest.projects.filter((project) => {
|
|
9321
9123
|
const moduleGraph = project.browser?.vite.moduleGraph || project.vite.moduleGraph;
|
|
9322
9124
|
return moduleGraph.getModulesByFile(filepath)?.size;
|
|
9323
9125
|
});
|
|
9324
|
-
if (!projects.length)
|
|
9325
|
-
// if there are no modules it's possible that server was restarted
|
|
9326
|
-
// we don't have information about importers anymore, so let's check if the file is a test file at least
|
|
9327
|
-
if (this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath))) {
|
|
9328
|
-
this.changedTests.add(filepath);
|
|
9329
|
-
return true;
|
|
9330
|
-
}
|
|
9331
|
-
return false;
|
|
9332
|
-
}
|
|
9126
|
+
if (!projects.length) return this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath)) ? (this.changedTests.add(filepath), true) : false;
|
|
9333
9127
|
const files = [];
|
|
9334
9128
|
for (const project of projects) {
|
|
9335
9129
|
const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath) || project.vite.moduleGraph.getModulesByFile(filepath);
|
|
9336
9130
|
if (!mods || !mods.size) continue;
|
|
9337
|
-
this.invalidates.add(filepath);
|
|
9338
9131
|
// one of test files that we already run, or one of test files that we can run
|
|
9339
|
-
if (this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
|
|
9340
|
-
this.changedTests.add(filepath);
|
|
9341
|
-
files.push(filepath);
|
|
9132
|
+
if (this.invalidates.add(filepath), this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
|
|
9133
|
+
this.changedTests.add(filepath), files.push(filepath);
|
|
9342
9134
|
continue;
|
|
9343
9135
|
}
|
|
9344
9136
|
let rerun = false;
|
|
@@ -9385,6 +9177,14 @@ class Vitest {
|
|
|
9385
9177
|
* If projects were filtered with `--project` flag, they won't appear here.
|
|
9386
9178
|
*/
|
|
9387
9179
|
projects = [];
|
|
9180
|
+
/**
|
|
9181
|
+
* A watcher handler. This is not the file system watcher. The handler only
|
|
9182
|
+
* exposes methods to handle changed files.
|
|
9183
|
+
*
|
|
9184
|
+
* If you have your own watcher, you can use these methods to replicate
|
|
9185
|
+
* Vitest behaviour.
|
|
9186
|
+
*/
|
|
9187
|
+
watcher;
|
|
9388
9188
|
/** @internal */ configOverride = {};
|
|
9389
9189
|
/** @internal */ coverageProvider;
|
|
9390
9190
|
/** @internal */ filenamePattern;
|
|
@@ -9401,7 +9201,6 @@ class Vitest {
|
|
|
9401
9201
|
isFirstRun = true;
|
|
9402
9202
|
restartsCount = 0;
|
|
9403
9203
|
specifications;
|
|
9404
|
-
watcher;
|
|
9405
9204
|
pool;
|
|
9406
9205
|
_config;
|
|
9407
9206
|
_vite;
|
|
@@ -9409,12 +9208,7 @@ class Vitest {
|
|
|
9409
9208
|
_cache;
|
|
9410
9209
|
_snapshot;
|
|
9411
9210
|
constructor(mode, cliOptions, options = {}) {
|
|
9412
|
-
this.mode = mode;
|
|
9413
|
-
this._cliOptions = cliOptions;
|
|
9414
|
-
this.logger = new Logger(this, options.stdout, options.stderr);
|
|
9415
|
-
this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
|
|
9416
|
-
this.specifications = new VitestSpecifications(this);
|
|
9417
|
-
this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun([file]));
|
|
9211
|
+
this.mode = mode, this._cliOptions = cliOptions, this.logger = new Logger(this, options.stdout, options.stderr), this.packageInstaller = options.packageInstaller || new VitestPackageInstaller(), this.specifications = new VitestSpecifications(this), this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun(file));
|
|
9418
9212
|
}
|
|
9419
9213
|
_onRestartListeners = [];
|
|
9420
9214
|
_onClose = [];
|
|
@@ -9434,8 +9228,7 @@ class Vitest {
|
|
|
9434
9228
|
* The global config.
|
|
9435
9229
|
*/
|
|
9436
9230
|
get config() {
|
|
9437
|
-
assert(this._config, "config");
|
|
9438
|
-
return this._config;
|
|
9231
|
+
return assert(this._config, "config"), this._config;
|
|
9439
9232
|
}
|
|
9440
9233
|
/** @deprecated use `vitest.vite` instead */
|
|
9441
9234
|
get server() {
|
|
@@ -9445,30 +9238,26 @@ class Vitest {
|
|
|
9445
9238
|
* Global Vite's dev server instance.
|
|
9446
9239
|
*/
|
|
9447
9240
|
get vite() {
|
|
9448
|
-
assert(this._vite, "vite", "server");
|
|
9449
|
-
return this._vite;
|
|
9241
|
+
return assert(this._vite, "vite", "server"), this._vite;
|
|
9450
9242
|
}
|
|
9451
9243
|
/**
|
|
9452
9244
|
* The global test state manager.
|
|
9453
9245
|
* @experimental The State API is experimental and not subject to semver.
|
|
9454
9246
|
*/
|
|
9455
9247
|
get state() {
|
|
9456
|
-
assert(this._state, "state");
|
|
9457
|
-
return this._state;
|
|
9248
|
+
return assert(this._state, "state"), this._state;
|
|
9458
9249
|
}
|
|
9459
9250
|
/**
|
|
9460
9251
|
* The global snapshot manager. You can access the current state on `snapshot.summary`.
|
|
9461
9252
|
*/
|
|
9462
9253
|
get snapshot() {
|
|
9463
|
-
assert(this._snapshot, "snapshot", "snapshot manager");
|
|
9464
|
-
return this._snapshot;
|
|
9254
|
+
return assert(this._snapshot, "snapshot", "snapshot manager"), this._snapshot;
|
|
9465
9255
|
}
|
|
9466
9256
|
/**
|
|
9467
9257
|
* Test results and test file stats cache. Primarily used by the sequencer to sort tests.
|
|
9468
9258
|
*/
|
|
9469
9259
|
get cache() {
|
|
9470
|
-
assert(this._cache, "cache");
|
|
9471
|
-
return this._cache;
|
|
9260
|
+
return assert(this._cache, "cache"), this._cache;
|
|
9472
9261
|
}
|
|
9473
9262
|
/** @deprecated internal */
|
|
9474
9263
|
setServer(options, server) {
|
|
@@ -9476,48 +9265,21 @@ class Vitest {
|
|
|
9476
9265
|
}
|
|
9477
9266
|
/** @internal */
|
|
9478
9267
|
async _setServer(options, server) {
|
|
9479
|
-
this.watcher.unregisterWatcher();
|
|
9480
|
-
clearTimeout(this._rerunTimer);
|
|
9481
|
-
this.restartsCount += 1;
|
|
9482
|
-
this.pool?.close?.();
|
|
9483
|
-
this.pool = void 0;
|
|
9484
|
-
this.closingPromise = void 0;
|
|
9485
|
-
this.projects = [];
|
|
9486
|
-
this.coverageProvider = void 0;
|
|
9487
|
-
this.runningPromise = void 0;
|
|
9488
|
-
this.coreWorkspaceProject = void 0;
|
|
9489
|
-
this.specifications.clearCache();
|
|
9490
|
-
this._onUserTestsRerun = [];
|
|
9491
|
-
this._vite = server;
|
|
9268
|
+
this.watcher.unregisterWatcher(), clearTimeout(this._rerunTimer), this.restartsCount += 1, this.pool?.close?.(), this.pool = void 0, this.closingPromise = void 0, this.projects = [], this.coverageProvider = void 0, this.runningPromise = void 0, this.coreWorkspaceProject = void 0, this.specifications.clearCache(), this._onUserTestsRerun = [], this._vite = server;
|
|
9492
9269
|
const resolved = resolveConfig(this, options, server.config);
|
|
9493
|
-
this._config = resolved;
|
|
9494
|
-
this._state = new StateManager({ onUnhandledError: resolved.onUnhandledError });
|
|
9495
|
-
this._cache = new VitestCache(this.version);
|
|
9496
|
-
this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions });
|
|
9497
|
-
this._testRun = new TestRun(this);
|
|
9498
|
-
if (this.config.watch) this.watcher.registerWatcher();
|
|
9270
|
+
if (this._config = resolved, this._state = new StateManager({ onUnhandledError: resolved.onUnhandledError }), this._cache = new VitestCache(this.version), this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions }), this._testRun = new TestRun(this), this.config.watch) this.watcher.registerWatcher();
|
|
9499
9271
|
this._resolver = new VitestResolver(server.config.cacheDir, resolved);
|
|
9500
9272
|
const environment = server.environments.__vitest__;
|
|
9501
|
-
this.runner = new ServerModuleRunner(environment, this._resolver, resolved)
|
|
9502
|
-
if (this.config.watch) {
|
|
9273
|
+
if (this.runner = new ServerModuleRunner(environment, this._resolver, resolved), this.config.watch) {
|
|
9503
9274
|
// hijack server restart
|
|
9504
9275
|
const serverRestart = server.restart;
|
|
9505
|
-
server.restart = async (...args) => {
|
|
9506
|
-
await Promise.all(this._onRestartListeners.map((fn) => fn()));
|
|
9507
|
-
this.report("onServerRestart");
|
|
9508
|
-
await this.close();
|
|
9509
|
-
await serverRestart(...args);
|
|
9510
|
-
};
|
|
9511
9276
|
// since we set `server.hmr: false`, Vite does not auto restart itself
|
|
9512
|
-
server.
|
|
9277
|
+
server.restart = async (...args) => {
|
|
9278
|
+
await Promise.all(this._onRestartListeners.map((fn) => fn())), this.report("onServerRestart"), await this.close(), await serverRestart(...args);
|
|
9279
|
+
}, server.watcher.on("change", async (file) => {
|
|
9513
9280
|
file = normalize(file);
|
|
9514
9281
|
const isConfig = file === server.config.configFile || this.projects.some((p) => p.vite.config.configFile === file);
|
|
9515
|
-
if (isConfig)
|
|
9516
|
-
await Promise.all(this._onRestartListeners.map((fn) => fn("config")));
|
|
9517
|
-
this.report("onServerRestart", "config");
|
|
9518
|
-
await this.close();
|
|
9519
|
-
await serverRestart();
|
|
9520
|
-
}
|
|
9282
|
+
if (isConfig) await Promise.all(this._onRestartListeners.map((fn) => fn("config"))), this.report("onServerRestart", "config"), await this.close(), await serverRestart();
|
|
9521
9283
|
});
|
|
9522
9284
|
}
|
|
9523
9285
|
this.cache.results.setConfig(resolved.root, resolved.cache);
|
|
@@ -9525,28 +9287,24 @@ class Vitest {
|
|
|
9525
9287
|
await this.cache.results.readFromCache();
|
|
9526
9288
|
} catch {}
|
|
9527
9289
|
const projects = await this.resolveProjects(this._cliOptions);
|
|
9528
|
-
this.projects = projects
|
|
9529
|
-
await Promise.all(projects.flatMap((project) => {
|
|
9290
|
+
if (this.projects = projects, await Promise.all(projects.flatMap((project) => {
|
|
9530
9291
|
const hooks = project.vite.config.getSortedPluginHooks("configureVitest");
|
|
9531
9292
|
return hooks.map((hook) => hook({
|
|
9532
9293
|
project,
|
|
9533
9294
|
vitest: this,
|
|
9534
9295
|
injectTestProjects: this.injectTestProject
|
|
9535
9296
|
}));
|
|
9536
|
-
}))
|
|
9537
|
-
if (this._cliOptions.browser?.enabled) {
|
|
9297
|
+
})), this._cliOptions.browser?.enabled) {
|
|
9538
9298
|
const browserProjects = this.projects.filter((p) => p.config.browser.enabled);
|
|
9539
9299
|
if (!browserProjects.length) throw new Error(`Vitest received --browser flag, but no project had a browser configuration.`);
|
|
9540
9300
|
}
|
|
9541
9301
|
if (!this.projects.length) {
|
|
9542
9302
|
const filter = toArray(resolved.project).join("\", \"");
|
|
9543
|
-
|
|
9544
|
-
else throw new Error(`Vitest wasn't able to resolve any project.`);
|
|
9303
|
+
throw filter ? new Error(`No projects matched the filter "${filter}".`) : new Error(`Vitest wasn't able to resolve any project.`);
|
|
9545
9304
|
}
|
|
9546
9305
|
if (!this.coreWorkspaceProject) this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9547
9306
|
if (this.config.testNamePattern) this.configOverride.testNamePattern = this.config.testNamePattern;
|
|
9548
|
-
this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
|
|
9549
|
-
await Promise.all(this._onSetServer.map((fn) => fn()));
|
|
9307
|
+
this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this), await Promise.all(this._onSetServer.map((fn) => fn()));
|
|
9550
9308
|
}
|
|
9551
9309
|
/**
|
|
9552
9310
|
* Inject new test projects into the workspace.
|
|
@@ -9554,10 +9312,8 @@ class Vitest {
|
|
|
9554
9312
|
* @returns An array of new test projects. Can be empty if the name was filtered out.
|
|
9555
9313
|
*/
|
|
9556
9314
|
injectTestProject = async (config) => {
|
|
9557
|
-
const currentNames = new Set(this.projects.map((p) => p.name));
|
|
9558
|
-
|
|
9559
|
-
this.projects.push(...projects);
|
|
9560
|
-
return projects;
|
|
9315
|
+
const currentNames = new Set(this.projects.map((p) => p.name)), projects = await resolveProjects(this, this._cliOptions, void 0, Array.isArray(config) ? config : [config], currentNames);
|
|
9316
|
+
return this.projects.push(...projects), projects;
|
|
9561
9317
|
};
|
|
9562
9318
|
/**
|
|
9563
9319
|
* Provide a value to the test context. This value will be available to all tests with `inject`.
|
|
@@ -9573,9 +9329,7 @@ class Vitest {
|
|
|
9573
9329
|
}
|
|
9574
9330
|
/** @internal */
|
|
9575
9331
|
_ensureRootProject() {
|
|
9576
|
-
|
|
9577
|
-
this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9578
|
-
return this.coreWorkspaceProject;
|
|
9332
|
+
return this.coreWorkspaceProject ||= TestProject._createBasicProject(this), this.coreWorkspaceProject;
|
|
9579
9333
|
}
|
|
9580
9334
|
/** @deprecated use `getRootProject` instead */
|
|
9581
9335
|
getCoreWorkspaceProject() {
|
|
@@ -9592,8 +9346,7 @@ class Vitest {
|
|
|
9592
9346
|
* @deprecated use Reported Task API instead
|
|
9593
9347
|
*/
|
|
9594
9348
|
getProjectByTaskId(taskId) {
|
|
9595
|
-
const task = this.state.idMap.get(taskId);
|
|
9596
|
-
const projectName = task.projectName || task?.file?.projectName || "";
|
|
9349
|
+
const task = this.state.idMap.get(taskId), projectName = task.projectName || task?.file?.projectName || "";
|
|
9597
9350
|
return this.getProjectByName(projectName);
|
|
9598
9351
|
}
|
|
9599
9352
|
getProjectByName(name) {
|
|
@@ -9608,6 +9361,15 @@ class Vitest {
|
|
|
9608
9361
|
import(moduleId) {
|
|
9609
9362
|
return this.runner.import(moduleId);
|
|
9610
9363
|
}
|
|
9364
|
+
/**
|
|
9365
|
+
* Creates a coverage provider if `coverage` is enabled in the config.
|
|
9366
|
+
*/
|
|
9367
|
+
async createCoverageProvider() {
|
|
9368
|
+
if (this.coverageProvider) return this.coverageProvider;
|
|
9369
|
+
const coverageProvider = await this.initCoverageProvider();
|
|
9370
|
+
if (coverageProvider) await coverageProvider.clean(this.config.coverage.clean);
|
|
9371
|
+
return coverageProvider || null;
|
|
9372
|
+
}
|
|
9611
9373
|
async resolveProjects(cliOptions) {
|
|
9612
9374
|
const names = /* @__PURE__ */ new Set();
|
|
9613
9375
|
if (this.config.projects) return resolveProjects(this, cliOptions, void 0, this.config.projects, names);
|
|
@@ -9615,8 +9377,7 @@ class Vitest {
|
|
|
9615
9377
|
// user can filter projects with --project flag, `getDefaultTestProject`
|
|
9616
9378
|
// returns the project only if it matches the filter
|
|
9617
9379
|
const project = getDefaultTestProject(this);
|
|
9618
|
-
|
|
9619
|
-
return resolveBrowserProjects(this, new Set([project.name]), [project]);
|
|
9380
|
+
return project ? resolveBrowserProjects(this, new Set([project.name]), [project]) : [];
|
|
9620
9381
|
}
|
|
9621
9382
|
/**
|
|
9622
9383
|
* Glob test files in every project and create a TestSpecification for each file and pool.
|
|
@@ -9626,13 +9387,10 @@ class Vitest {
|
|
|
9626
9387
|
return this.specifications.globTestSpecifications(filters);
|
|
9627
9388
|
}
|
|
9628
9389
|
async initCoverageProvider() {
|
|
9629
|
-
if (this.coverageProvider
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
await this.coverageProvider.initialize(this);
|
|
9633
|
-
this.config.coverage = this.coverageProvider.resolveOptions();
|
|
9390
|
+
if (this.coverageProvider === void 0) {
|
|
9391
|
+
if (this.coverageProvider = await getCoverageProvider(this.config.coverage, this.runner), this.coverageProvider) await this.coverageProvider.initialize(this), this.config.coverage = this.coverageProvider.resolveOptions();
|
|
9392
|
+
return this.coverageProvider;
|
|
9634
9393
|
}
|
|
9635
|
-
return this.coverageProvider;
|
|
9636
9394
|
}
|
|
9637
9395
|
/**
|
|
9638
9396
|
* Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
|
|
@@ -9645,23 +9403,15 @@ class Vitest {
|
|
|
9645
9403
|
errors,
|
|
9646
9404
|
coverages,
|
|
9647
9405
|
executionTimes
|
|
9648
|
-
};
|
|
9649
|
-
await this.report("onInit", this);
|
|
9650
|
-
await this.report("onPathsCollected", files.flatMap((f) => f.filepath));
|
|
9406
|
+
}, await this.report("onInit", this);
|
|
9651
9407
|
const specifications = [];
|
|
9652
9408
|
for (const file of files) {
|
|
9653
|
-
const project = this.getProjectByName(file.projectName || "");
|
|
9654
|
-
const specification = project.createSpecification(file.filepath, void 0, file.pool);
|
|
9409
|
+
const project = this.getProjectByName(file.projectName || ""), specification = project.createSpecification(file.filepath, void 0, file.pool);
|
|
9655
9410
|
specifications.push(specification);
|
|
9656
9411
|
}
|
|
9657
|
-
await this.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
|
|
9658
9412
|
await this._testRun.start(specifications).catch(noop);
|
|
9659
9413
|
for (const file of files) await this._reportFileTask(file);
|
|
9660
|
-
this._checkUnhandledErrors(errors)
|
|
9661
|
-
await this._testRun.end(specifications, errors).catch(noop);
|
|
9662
|
-
await this.initCoverageProvider();
|
|
9663
|
-
await this.coverageProvider?.mergeReports?.(coverages);
|
|
9664
|
-
return {
|
|
9414
|
+
return this._checkUnhandledErrors(errors), await this._testRun.end(specifications, errors).catch(noop), await this.initCoverageProvider(), await this.coverageProvider?.mergeReports?.(coverages), {
|
|
9665
9415
|
testModules: this.state.getTestModules(),
|
|
9666
9416
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9667
9417
|
};
|
|
@@ -9669,10 +9419,8 @@ class Vitest {
|
|
|
9669
9419
|
/** @internal */
|
|
9670
9420
|
async _reportFileTask(file) {
|
|
9671
9421
|
const project = this.getProjectByName(file.projectName || "");
|
|
9672
|
-
await this._testRun.enqueued(project, file).catch(noop);
|
|
9673
|
-
|
|
9674
|
-
const logs = [];
|
|
9675
|
-
const { packs, events } = convertTasksToEvents(file, (task) => {
|
|
9422
|
+
await this._testRun.enqueued(project, file).catch(noop), await this._testRun.collected(project, [file]).catch(noop);
|
|
9423
|
+
const logs = [], { packs, events } = convertTasksToEvents(file, (task) => {
|
|
9676
9424
|
if (task.logs) logs.push(...task.logs);
|
|
9677
9425
|
});
|
|
9678
9426
|
logs.sort((log1, log2) => log1.time - log2.time);
|
|
@@ -9681,12 +9429,10 @@ class Vitest {
|
|
|
9681
9429
|
}
|
|
9682
9430
|
async collect(filters) {
|
|
9683
9431
|
const files = await this.specifications.getRelevantTestSpecifications(filters);
|
|
9684
|
-
|
|
9685
|
-
if (!files.length) return {
|
|
9432
|
+
return files.length ? this.collectTests(files) : {
|
|
9686
9433
|
testModules: [],
|
|
9687
9434
|
unhandledErrors: []
|
|
9688
9435
|
};
|
|
9689
|
-
return this.collectTests(files);
|
|
9690
9436
|
}
|
|
9691
9437
|
/** @deprecated use `getRelevantTestSpecifications` instead */
|
|
9692
9438
|
listFiles(filters) {
|
|
@@ -9709,8 +9455,7 @@ class Vitest {
|
|
|
9709
9455
|
*/
|
|
9710
9456
|
async start(filters) {
|
|
9711
9457
|
try {
|
|
9712
|
-
await this.initCoverageProvider();
|
|
9713
|
-
await this.coverageProvider?.clean(this.config.coverage.clean);
|
|
9458
|
+
await this.initCoverageProvider(), await this.coverageProvider?.clean(this.config.coverage.clean);
|
|
9714
9459
|
} finally {
|
|
9715
9460
|
await this.report("onInit", this);
|
|
9716
9461
|
}
|
|
@@ -9720,20 +9465,13 @@ class Vitest {
|
|
|
9720
9465
|
if (!files.length) {
|
|
9721
9466
|
await this._testRun.start([]);
|
|
9722
9467
|
const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
|
|
9723
|
-
await this._testRun.end([], [], coverage);
|
|
9724
|
-
// Report coverage for uncovered files
|
|
9725
|
-
await this.reportCoverage(coverage, true);
|
|
9726
|
-
if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
|
|
9468
|
+
if (await this._testRun.end([], [], coverage), await this.reportCoverage(coverage, true), !this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
|
|
9727
9469
|
}
|
|
9728
9470
|
let testModules = {
|
|
9729
9471
|
testModules: [],
|
|
9730
9472
|
unhandledErrors: []
|
|
9731
9473
|
};
|
|
9732
|
-
if (files.length)
|
|
9733
|
-
// populate once, update cache on watch
|
|
9734
|
-
await this.cache.stats.populateStats(this.config.root, files);
|
|
9735
|
-
testModules = await this.runFiles(files, true);
|
|
9736
|
-
}
|
|
9474
|
+
if (files.length) await this.cache.stats.populateStats(this.config.root, files), testModules = await this.runFiles(files, true);
|
|
9737
9475
|
if (this.config.watch) await this.report("onWatcherStart");
|
|
9738
9476
|
return testModules;
|
|
9739
9477
|
}
|
|
@@ -9743,14 +9481,11 @@ class Vitest {
|
|
|
9743
9481
|
*/
|
|
9744
9482
|
async init() {
|
|
9745
9483
|
try {
|
|
9746
|
-
await this.initCoverageProvider();
|
|
9747
|
-
await this.coverageProvider?.clean(this.config.coverage.clean);
|
|
9484
|
+
await this.initCoverageProvider(), await this.coverageProvider?.clean(this.config.coverage.clean);
|
|
9748
9485
|
} finally {
|
|
9749
9486
|
await this.report("onInit", this);
|
|
9750
9487
|
}
|
|
9751
|
-
|
|
9752
|
-
await this.globTestSpecifications();
|
|
9753
|
-
if (this.config.watch) await this.report("onWatcherStart");
|
|
9488
|
+
if (await this.globTestSpecifications(), this.config.watch) await this.report("onWatcherStart");
|
|
9754
9489
|
}
|
|
9755
9490
|
/**
|
|
9756
9491
|
* @deprecated remove when vscode extension supports "getModuleSpecifications"
|
|
@@ -9763,6 +9498,13 @@ class Vitest {
|
|
|
9763
9498
|
return this.getModuleSpecifications(file);
|
|
9764
9499
|
}
|
|
9765
9500
|
/**
|
|
9501
|
+
* If there is a test run happening, returns a promise that will
|
|
9502
|
+
* resolve when the test run is finished.
|
|
9503
|
+
*/
|
|
9504
|
+
async waitForTestRunEnd() {
|
|
9505
|
+
this.runningPromise && await this.runningPromise;
|
|
9506
|
+
}
|
|
9507
|
+
/**
|
|
9766
9508
|
* Get test specifications associated with the given module. If module is not a test file, an empty array is returned.
|
|
9767
9509
|
*
|
|
9768
9510
|
* **Note:** this method relies on a cache generated by `globTestSpecifications`. If the file was not processed yet, use `project.matchesGlobPattern` instead.
|
|
@@ -9775,7 +9517,9 @@ class Vitest {
|
|
|
9775
9517
|
* Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache altogether.
|
|
9776
9518
|
*/
|
|
9777
9519
|
clearSpecificationsCache(moduleId) {
|
|
9778
|
-
this.specifications.clearCache(moduleId)
|
|
9520
|
+
if (this.specifications.clearCache(moduleId), !moduleId) this.projects.forEach((project) => {
|
|
9521
|
+
project.testFilesList = null;
|
|
9522
|
+
});
|
|
9779
9523
|
}
|
|
9780
9524
|
/**
|
|
9781
9525
|
* Run tests for the given test specifications. This does not trigger `onWatcher*` events.
|
|
@@ -9783,8 +9527,7 @@ class Vitest {
|
|
|
9783
9527
|
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
9784
9528
|
*/
|
|
9785
9529
|
runTestSpecifications(specifications, allTestsRun = false) {
|
|
9786
|
-
specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec));
|
|
9787
|
-
return this.runFiles(specifications, allTestsRun);
|
|
9530
|
+
return specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec)), this.runFiles(specifications, allTestsRun);
|
|
9788
9531
|
}
|
|
9789
9532
|
/**
|
|
9790
9533
|
* Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
|
|
@@ -9796,24 +9539,14 @@ class Vitest {
|
|
|
9796
9539
|
const files = specifications.map((spec) => spec.moduleId);
|
|
9797
9540
|
await Promise.all([this.report("onWatcherRerun", files, "rerun test"), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
9798
9541
|
const result = await this.runTestSpecifications(specifications, allTestsRun);
|
|
9799
|
-
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
9800
|
-
return result;
|
|
9542
|
+
return await this.report("onWatcherStart", this.state.getFiles(files)), result;
|
|
9801
9543
|
}
|
|
9802
9544
|
async runFiles(specs, allTestsRun) {
|
|
9803
|
-
await this._testRun.start(specs)
|
|
9804
|
-
// previous run
|
|
9805
|
-
await this.runningPromise;
|
|
9806
|
-
this._onCancelListeners = [];
|
|
9807
|
-
this.isCancelling = false;
|
|
9808
|
-
// schedule the new run
|
|
9809
|
-
this.runningPromise = (async () => {
|
|
9545
|
+
return await this._testRun.start(specs), await this.runningPromise, this._onCancelListeners = [], this.isCancelling = false, this.runningPromise = (async () => {
|
|
9810
9546
|
try {
|
|
9811
9547
|
if (!this.pool) this.pool = createPool(this);
|
|
9812
9548
|
const invalidates = Array.from(this.watcher.invalidates);
|
|
9813
|
-
this.watcher.invalidates.clear();
|
|
9814
|
-
this.snapshot.clear();
|
|
9815
|
-
this.state.clearErrors();
|
|
9816
|
-
if (!this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
|
|
9549
|
+
if (this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), !this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
|
|
9817
9550
|
await this.initializeGlobalSetup(specs);
|
|
9818
9551
|
try {
|
|
9819
9552
|
await this.pool.runTests(specs, invalidates);
|
|
@@ -9830,21 +9563,24 @@ class Vitest {
|
|
|
9830
9563
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9831
9564
|
};
|
|
9832
9565
|
} finally {
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
const errors = this.state.getUnhandledErrors();
|
|
9836
|
-
this._checkUnhandledErrors(errors);
|
|
9837
|
-
await this._testRun.end(specs, errors, coverage);
|
|
9838
|
-
await this.reportCoverage(coverage, allTestsRun);
|
|
9566
|
+
const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun }), errors = this.state.getUnhandledErrors();
|
|
9567
|
+
this._checkUnhandledErrors(errors), await this._testRun.end(specs, errors, coverage), await this.reportCoverage(coverage, allTestsRun);
|
|
9839
9568
|
}
|
|
9840
9569
|
})().finally(() => {
|
|
9841
|
-
this.runningPromise = void 0;
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9570
|
+
this.runningPromise = void 0, this.isFirstRun = false, this.config.changed = false, this.config.related = void 0;
|
|
9571
|
+
}), await this.runningPromise;
|
|
9572
|
+
}
|
|
9573
|
+
async experimental_parseSpecifications(specifications, options) {
|
|
9574
|
+
if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecifications\` does not support "${this.mode}" mode.`);
|
|
9575
|
+
const concurrency = options?.concurrency ?? (typeof nodeos__default.availableParallelism === "function" ? nodeos__default.availableParallelism() : nodeos__default.cpus().length), limit = limitConcurrency(concurrency), promises = specifications.map((specification) => limit(() => this.experimental_parseSpecification(specification)));
|
|
9576
|
+
return Promise.all(promises);
|
|
9577
|
+
}
|
|
9578
|
+
async experimental_parseSpecification(specification) {
|
|
9579
|
+
if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecification\` does not support "${this.mode}" mode.`);
|
|
9580
|
+
const file = await astCollectTests(specification.project, specification.moduleId).catch((error) => {
|
|
9581
|
+
return createFailedFileTask(specification.project, specification.moduleId, error);
|
|
9846
9582
|
});
|
|
9847
|
-
return
|
|
9583
|
+
return this.state.collectFiles(specification.project, [file]), this.state.getReportedEntity(file);
|
|
9848
9584
|
}
|
|
9849
9585
|
/**
|
|
9850
9586
|
* Collect tests in specified modules. Vitest will run the files to collect tests.
|
|
@@ -9852,19 +9588,10 @@ class Vitest {
|
|
|
9852
9588
|
*/
|
|
9853
9589
|
async collectTests(specifications) {
|
|
9854
9590
|
const filepaths = specifications.map((spec) => spec.moduleId);
|
|
9855
|
-
this.state.collectPaths(filepaths)
|
|
9856
|
-
// previous run
|
|
9857
|
-
await this.runningPromise;
|
|
9858
|
-
this._onCancelListeners = [];
|
|
9859
|
-
this.isCancelling = false;
|
|
9860
|
-
// schedule the new run
|
|
9861
|
-
this.runningPromise = (async () => {
|
|
9591
|
+
return this.state.collectPaths(filepaths), await this.runningPromise, this._onCancelListeners = [], this.isCancelling = false, this.runningPromise = (async () => {
|
|
9862
9592
|
if (!this.pool) this.pool = createPool(this);
|
|
9863
9593
|
const invalidates = Array.from(this.watcher.invalidates);
|
|
9864
|
-
this.watcher.invalidates.clear();
|
|
9865
|
-
this.snapshot.clear();
|
|
9866
|
-
this.state.clearErrors();
|
|
9867
|
-
await this.initializeGlobalSetup(specifications);
|
|
9594
|
+
this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), await this.initializeGlobalSetup(specifications);
|
|
9868
9595
|
try {
|
|
9869
9596
|
await this.pool.collectTests(specifications, invalidates);
|
|
9870
9597
|
} catch (err) {
|
|
@@ -9879,28 +9606,21 @@ class Vitest {
|
|
|
9879
9606
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9880
9607
|
};
|
|
9881
9608
|
})().finally(() => {
|
|
9882
|
-
this.runningPromise = void 0;
|
|
9883
|
-
|
|
9884
|
-
this.config.changed = false;
|
|
9885
|
-
this.config.related = void 0;
|
|
9886
|
-
});
|
|
9887
|
-
return await this.runningPromise;
|
|
9609
|
+
this.runningPromise = void 0, this.config.changed = false, this.config.related = void 0;
|
|
9610
|
+
}), await this.runningPromise;
|
|
9888
9611
|
}
|
|
9889
9612
|
/**
|
|
9890
9613
|
* Gracefully cancel the current test run. Vitest will wait until all running tests are finished before cancelling.
|
|
9891
9614
|
*/
|
|
9892
9615
|
async cancelCurrentRun(reason) {
|
|
9893
|
-
this.isCancelling = true;
|
|
9894
|
-
await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason)));
|
|
9895
|
-
await this.runningPromise;
|
|
9616
|
+
this.isCancelling = true, await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason))), await this.runningPromise;
|
|
9896
9617
|
}
|
|
9897
9618
|
/** @internal */
|
|
9898
9619
|
async _initBrowserServers() {
|
|
9899
9620
|
await Promise.all(this.projects.map((p) => p._initBrowserServer()));
|
|
9900
9621
|
}
|
|
9901
9622
|
async initializeGlobalSetup(paths) {
|
|
9902
|
-
const projects = new Set(paths.map((spec) => spec.project));
|
|
9903
|
-
const coreProject = this.getRootProject();
|
|
9623
|
+
const projects = new Set(paths.map((spec) => spec.project)), coreProject = this.getRootProject();
|
|
9904
9624
|
if (!projects.has(coreProject)) projects.add(coreProject);
|
|
9905
9625
|
for (const project of projects) await project._initializeGlobalSetup();
|
|
9906
9626
|
}
|
|
@@ -9914,8 +9634,7 @@ class Vitest {
|
|
|
9914
9634
|
const specifications = files.flatMap((file) => this.getModuleSpecifications(file));
|
|
9915
9635
|
await Promise.all([this.report("onWatcherRerun", files, trigger), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
9916
9636
|
const testResult = await this.runFiles(specifications, allTestsRun);
|
|
9917
|
-
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
9918
|
-
return testResult;
|
|
9637
|
+
return await this.report("onWatcherStart", this.state.getFiles(files)), testResult;
|
|
9919
9638
|
}
|
|
9920
9639
|
/** @internal */
|
|
9921
9640
|
async rerunTask(id) {
|
|
@@ -9935,9 +9654,8 @@ class Vitest {
|
|
|
9935
9654
|
// Empty test name pattern should reset filename pattern as well
|
|
9936
9655
|
if (pattern === "") this.filenamePattern = void 0;
|
|
9937
9656
|
const testNamePattern = pattern ? new RegExp(pattern) : void 0;
|
|
9938
|
-
this.configOverride.testNamePattern = testNamePattern;
|
|
9939
9657
|
// filter only test files that have tests matching the pattern
|
|
9940
|
-
if (testNamePattern) files = files.filter((filepath) => {
|
|
9658
|
+
if (this.configOverride.testNamePattern = testNamePattern, testNamePattern) files = files.filter((filepath) => {
|
|
9941
9659
|
const files = this.state.getFiles([filepath]);
|
|
9942
9660
|
return !files.length || files.some((file) => {
|
|
9943
9661
|
const tasks = getTasks(file);
|
|
@@ -9961,9 +9679,7 @@ class Vitest {
|
|
|
9961
9679
|
* @param files The list of files on the file system
|
|
9962
9680
|
*/
|
|
9963
9681
|
async updateSnapshot(files) {
|
|
9964
|
-
|
|
9965
|
-
files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)];
|
|
9966
|
-
this.enableSnapshotUpdate();
|
|
9682
|
+
files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)], this.enableSnapshotUpdate();
|
|
9967
9683
|
try {
|
|
9968
9684
|
return await this.rerunFiles(files, "update snapshot", false);
|
|
9969
9685
|
} finally {
|
|
@@ -9981,15 +9697,13 @@ class Vitest {
|
|
|
9981
9697
|
this.configOverride.snapshotOptions = {
|
|
9982
9698
|
updateSnapshot: "all",
|
|
9983
9699
|
snapshotEnvironment: null
|
|
9984
|
-
};
|
|
9985
|
-
this.snapshot.options.updateSnapshot = "all";
|
|
9700
|
+
}, this.snapshot.options.updateSnapshot = "all";
|
|
9986
9701
|
}
|
|
9987
9702
|
/**
|
|
9988
9703
|
* Disable the mode that allows updating snapshots when running tests.
|
|
9989
9704
|
*/
|
|
9990
9705
|
resetSnapshotUpdate() {
|
|
9991
|
-
delete this.configOverride.snapshotOptions;
|
|
9992
|
-
this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
|
|
9706
|
+
delete this.configOverride.snapshotOptions, this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
|
|
9993
9707
|
}
|
|
9994
9708
|
/**
|
|
9995
9709
|
* Set the global test name pattern to a regexp.
|
|
@@ -10006,42 +9720,28 @@ class Vitest {
|
|
|
10006
9720
|
this.configOverride.testNamePattern = void 0;
|
|
10007
9721
|
}
|
|
10008
9722
|
_rerunTimer;
|
|
10009
|
-
// we can't use a single `triggerId` yet because vscode extension relies on this
|
|
10010
9723
|
async scheduleRerun(triggerId) {
|
|
10011
9724
|
const currentCount = this.restartsCount;
|
|
10012
|
-
clearTimeout(this._rerunTimer)
|
|
10013
|
-
await this.runningPromise;
|
|
10014
|
-
clearTimeout(this._rerunTimer);
|
|
10015
|
-
// server restarted
|
|
10016
|
-
if (this.restartsCount !== currentCount) return;
|
|
10017
|
-
this._rerunTimer = setTimeout(async () => {
|
|
9725
|
+
clearTimeout(this._rerunTimer), await this.runningPromise, clearTimeout(this._rerunTimer), this.restartsCount === currentCount && (this._rerunTimer = setTimeout(async () => {
|
|
10018
9726
|
if (this.watcher.changedTests.size === 0) {
|
|
10019
9727
|
this.watcher.invalidates.clear();
|
|
10020
9728
|
return;
|
|
10021
9729
|
}
|
|
10022
9730
|
// server restarted
|
|
10023
9731
|
if (this.restartsCount !== currentCount) return;
|
|
10024
|
-
this.isFirstRun = false;
|
|
10025
|
-
this.snapshot.clear();
|
|
9732
|
+
this.isFirstRun = false, this.snapshot.clear();
|
|
10026
9733
|
let files = Array.from(this.watcher.changedTests);
|
|
10027
9734
|
if (this.filenamePattern) {
|
|
10028
9735
|
const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
|
|
10029
|
-
files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
|
|
10030
9736
|
// A file that does not match the current filename pattern was changed
|
|
10031
|
-
if (files.length === 0) return;
|
|
9737
|
+
if (files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file)), files.length === 0) return;
|
|
10032
9738
|
}
|
|
10033
9739
|
this.watcher.changedTests.clear();
|
|
10034
|
-
const
|
|
10035
|
-
|
|
10036
|
-
// get file specifications and filter them if needed
|
|
10037
|
-
const specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
|
|
10038
|
-
if (this._onFilterWatchedSpecification.length === 0) return true;
|
|
10039
|
-
return this._onFilterWatchedSpecification.every((fn) => fn(specification));
|
|
9740
|
+
const triggerLabel = relative(this.config.root, triggerId), specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
|
|
9741
|
+
return this._onFilterWatchedSpecification.length === 0 ? true : this._onFilterWatchedSpecification.every((fn) => fn(specification));
|
|
10040
9742
|
});
|
|
10041
|
-
await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
10042
|
-
|
|
10043
|
-
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
10044
|
-
}, WATCHER_DEBOUNCE);
|
|
9743
|
+
await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]), await this.runFiles(specifications, false), await this.report("onWatcherStart", this.state.getFiles(files));
|
|
9744
|
+
}, WATCHER_DEBOUNCE));
|
|
10045
9745
|
}
|
|
10046
9746
|
/**
|
|
10047
9747
|
* Invalidate a file in all projects.
|
|
@@ -10065,8 +9765,7 @@ class Vitest {
|
|
|
10065
9765
|
}
|
|
10066
9766
|
async reportCoverage(coverage, allTestsRun) {
|
|
10067
9767
|
if (this.state.getCountOfFailedTests() > 0) {
|
|
10068
|
-
await this.coverageProvider?.onTestFailure?.();
|
|
10069
|
-
if (!this.config.coverage.reportOnFailure) return;
|
|
9768
|
+
if (await this.coverageProvider?.onTestFailure?.(), !this.config.coverage.reportOnFailure) return;
|
|
10070
9769
|
}
|
|
10071
9770
|
if (this.coverageProvider) {
|
|
10072
9771
|
await this.coverageProvider.reportCoverage(coverage, { allTestsRun });
|
|
@@ -10089,11 +9788,9 @@ class Vitest {
|
|
|
10089
9788
|
// it's possible that it's not initialized at all because it's not running any tests
|
|
10090
9789
|
if (this.coreWorkspaceProject && !this.projects.includes(this.coreWorkspaceProject)) closePromises.push(this.coreWorkspaceProject.close().then(() => this._vite = void 0));
|
|
10091
9790
|
if (this.pool) closePromises.push((async () => {
|
|
10092
|
-
await this.pool?.close?.();
|
|
10093
|
-
this.pool = void 0;
|
|
9791
|
+
await this.pool?.close?.(), this.pool = void 0;
|
|
10094
9792
|
})());
|
|
10095
|
-
closePromises.push(...this._onClose.map((fn) => fn()))
|
|
10096
|
-
return Promise.allSettled(closePromises).then((results) => {
|
|
9793
|
+
return closePromises.push(...this._onClose.map((fn) => fn())), Promise.allSettled(closePromises).then((results) => {
|
|
10097
9794
|
results.forEach((r) => {
|
|
10098
9795
|
if (r.status === "rejected") this.logger.error("error during close", r.reason);
|
|
10099
9796
|
});
|
|
@@ -10106,11 +9803,9 @@ class Vitest {
|
|
|
10106
9803
|
* @param force If true, the process will exit immediately after closing the projects.
|
|
10107
9804
|
*/
|
|
10108
9805
|
async exit(force = false) {
|
|
10109
|
-
setTimeout(() => {
|
|
9806
|
+
if (setTimeout(() => {
|
|
10110
9807
|
this.report("onProcessTimeout").then(() => {
|
|
10111
|
-
console.warn(`close timed out after ${this.config.teardownTimeout}ms`)
|
|
10112
|
-
this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause));
|
|
10113
|
-
if (!this.pool) {
|
|
9808
|
+
if (console.warn(`close timed out after ${this.config.teardownTimeout}ms`), this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause)), !this.pool) {
|
|
10114
9809
|
const runningServers = [this._vite, ...this.projects.map((p) => p._vite)].filter(Boolean).length;
|
|
10115
9810
|
if (runningServers === 1) console.warn("Tests closed successfully but something prevents Vite server from exiting");
|
|
10116
9811
|
else if (runningServers > 1) console.warn(`Tests closed successfully but something prevents ${runningServers} Vite servers from exiting`);
|
|
@@ -10119,9 +9814,7 @@ class Vitest {
|
|
|
10119
9814
|
}
|
|
10120
9815
|
process.exit();
|
|
10121
9816
|
});
|
|
10122
|
-
}, this.config.teardownTimeout).unref();
|
|
10123
|
-
await this.close();
|
|
10124
|
-
if (force) process.exit();
|
|
9817
|
+
}, this.config.teardownTimeout).unref(), await this.close(), force) process.exit();
|
|
10125
9818
|
}
|
|
10126
9819
|
/** @internal */
|
|
10127
9820
|
async report(name, ...args) {
|
|
@@ -10203,9 +9896,7 @@ class Vitest {
|
|
|
10203
9896
|
*/
|
|
10204
9897
|
matchesProjectFilter(name) {
|
|
10205
9898
|
const projects = this._config?.project || this._cliOptions?.project;
|
|
10206
|
-
|
|
10207
|
-
if (!projects || !projects.length) return true;
|
|
10208
|
-
return toArray(projects).some((project) => {
|
|
9899
|
+
return !projects || !projects.length ? true : toArray(projects).some((project) => {
|
|
10209
9900
|
const regexp = wildcardPatternToRegExp(project);
|
|
10210
9901
|
return regexp.test(name);
|
|
10211
9902
|
});
|
|
@@ -10218,8 +9909,7 @@ function assert(condition, property, name = property) {
|
|
|
10218
9909
|
async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(options))) {
|
|
10219
9910
|
const userConfig = deepMerge({}, options);
|
|
10220
9911
|
async function UIPlugin() {
|
|
10221
|
-
await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version);
|
|
10222
|
-
return (await import('@vitest/ui')).default(vitest);
|
|
9912
|
+
return await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version), (await import('@vitest/ui')).default(vitest);
|
|
10223
9913
|
}
|
|
10224
9914
|
return [
|
|
10225
9915
|
{
|
|
@@ -10245,14 +9935,9 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10245
9935
|
let open = false;
|
|
10246
9936
|
if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
|
|
10247
9937
|
const resolveOptions = getDefaultResolveOptions();
|
|
10248
|
-
|
|
9938
|
+
let config = {
|
|
10249
9939
|
root: viteConfig.test?.root || options.root,
|
|
10250
9940
|
define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
|
|
10251
|
-
esbuild: viteConfig.esbuild === false ? false : {
|
|
10252
|
-
target: viteConfig.esbuild?.target || "node18",
|
|
10253
|
-
sourcemap: "external",
|
|
10254
|
-
legalComments: "inline"
|
|
10255
|
-
},
|
|
10256
9941
|
resolve: {
|
|
10257
9942
|
...resolveOptions,
|
|
10258
9943
|
alias: testConfig.alias
|
|
@@ -10282,21 +9967,29 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10282
9967
|
deps: testConfig.deps ?? viteConfig.test?.deps
|
|
10283
9968
|
}
|
|
10284
9969
|
};
|
|
9970
|
+
if ("rolldownVersion" in vite) config = {
|
|
9971
|
+
...config,
|
|
9972
|
+
oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
|
|
9973
|
+
};
|
|
9974
|
+
else config = {
|
|
9975
|
+
...config,
|
|
9976
|
+
esbuild: viteConfig.esbuild === false ? false : {
|
|
9977
|
+
target: viteConfig.esbuild?.target || "node18",
|
|
9978
|
+
sourcemap: "external",
|
|
9979
|
+
legalComments: "inline"
|
|
9980
|
+
}
|
|
9981
|
+
};
|
|
10285
9982
|
// inherit so it's available in VitestOptimizer
|
|
10286
9983
|
// I cannot wait to rewrite all of this in Vitest 4
|
|
10287
9984
|
if (options.cache != null) config.test.cache = options.cache;
|
|
10288
9985
|
if (vitest.configOverride.project)
|
|
10289
9986
|
// project filter was set by the user, so we need to filter the project
|
|
10290
9987
|
options.project = vitest.configOverride.project;
|
|
10291
|
-
config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
|
|
10292
|
-
config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
|
|
10293
9988
|
// chokidar fsevents is unstable on macos when emitting "ready" event
|
|
10294
|
-
if (process.platform === "darwin" && false);
|
|
9989
|
+
if (config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false }), config.customLogger = silenceImportViteIgnoreWarning(config.customLogger), process.platform === "darwin" && false);
|
|
10295
9990
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
10296
9991
|
if (classNameStrategy !== "scoped") {
|
|
10297
|
-
config.css ??= {}
|
|
10298
|
-
config.css.modules ??= {};
|
|
10299
|
-
if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
9992
|
+
if (config.css ??= {}, config.css.modules ??= {}, config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
10300
9993
|
const root = vitest.config.root || options.root || process.cwd();
|
|
10301
9994
|
return generateScopedClassName(classNameStrategy, name, relative(root, filename));
|
|
10302
9995
|
};
|
|
@@ -10307,17 +10000,11 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10307
10000
|
const viteConfigTest = viteConfig.test || {};
|
|
10308
10001
|
if (viteConfigTest.watch === false) viteConfigTest.run = true;
|
|
10309
10002
|
if ("alias" in viteConfigTest) delete viteConfigTest.alias;
|
|
10310
|
-
|
|
10311
|
-
options = deepMerge({}, configDefaults, viteConfigTest, options);
|
|
10312
|
-
options.api = resolveApiServerConfig(options, defaultPort);
|
|
10003
|
+
options = deepMerge({}, configDefaults, viteConfigTest, options), options.api = resolveApiServerConfig(options, defaultPort);
|
|
10313
10004
|
// we replace every "import.meta.env" with "process.env"
|
|
10314
10005
|
// to allow reassigning, so we need to put all envs on process.env
|
|
10315
10006
|
const { PROD, DEV,...envs } = viteConfig.env;
|
|
10316
|
-
|
|
10317
|
-
// so we are making them truthy
|
|
10318
|
-
process.env.PROD ??= PROD ? "1" : "";
|
|
10319
|
-
process.env.DEV ??= DEV ? "1" : "";
|
|
10320
|
-
for (const name in envs) process.env[name] ??= envs[name];
|
|
10007
|
+
for (const name in process.env.PROD ??= PROD ? "1" : "", process.env.DEV ??= DEV ? "1" : "", envs) process.env[name] ??= envs[name];
|
|
10321
10008
|
// don't watch files in run mode
|
|
10322
10009
|
if (!options.watch) viteConfig.server.watch = null;
|
|
10323
10010
|
if (options.ui)
|
|
@@ -10337,8 +10024,7 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10337
10024
|
order: "post",
|
|
10338
10025
|
async handler(server) {
|
|
10339
10026
|
if (options.watch && false);
|
|
10340
|
-
await vitest._setServer(options, server);
|
|
10341
|
-
if (options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
|
|
10027
|
+
if (await vitest._setServer(options, server), options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
|
|
10342
10028
|
// #415, in run mode we don't need the watcher, close it would improve the performance
|
|
10343
10029
|
if (!options.watch) await server.watcher.close();
|
|
10344
10030
|
}
|
|
@@ -10360,25 +10046,19 @@ function removeUndefinedValues(obj) {
|
|
|
10360
10046
|
}
|
|
10361
10047
|
|
|
10362
10048
|
async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) {
|
|
10363
|
-
const ctx = new Vitest(mode, deepClone(options), vitestOptions);
|
|
10364
|
-
const root = slash(resolve$1(options.root || process.cwd()));
|
|
10365
|
-
const configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root });
|
|
10049
|
+
const ctx = new Vitest(mode, deepClone(options), vitestOptions), root = slash(resolve$1(options.root || process.cwd())), configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root });
|
|
10366
10050
|
options.config = configPath;
|
|
10367
|
-
const { browser: _removeBrowser,...restOptions } = options
|
|
10368
|
-
const config = {
|
|
10051
|
+
const { browser: _removeBrowser,...restOptions } = options, config = {
|
|
10369
10052
|
configFile: configPath,
|
|
10370
10053
|
configLoader: options.configLoader,
|
|
10371
10054
|
mode: options.mode || mode,
|
|
10372
10055
|
plugins: await VitestPlugin(restOptions, ctx)
|
|
10373
|
-
};
|
|
10374
|
-
const server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
|
|
10056
|
+
}, server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
|
|
10375
10057
|
if (ctx.config.api?.port) await server.listen();
|
|
10376
10058
|
return ctx;
|
|
10377
10059
|
}
|
|
10378
10060
|
|
|
10379
|
-
const MAX_RESULT_COUNT = 10;
|
|
10380
|
-
const SELECTION_MAX_INDEX = 7;
|
|
10381
|
-
const ESC = "\x1B[";
|
|
10061
|
+
const MAX_RESULT_COUNT = 10, SELECTION_MAX_INDEX = 7, ESC = "\x1B[";
|
|
10382
10062
|
class WatchFilter {
|
|
10383
10063
|
filterRL;
|
|
10384
10064
|
currentKeyword = void 0;
|
|
@@ -10389,23 +10069,17 @@ class WatchFilter {
|
|
|
10389
10069
|
stdin;
|
|
10390
10070
|
stdout;
|
|
10391
10071
|
constructor(message, stdin = process.stdin, stdout$1 = stdout()) {
|
|
10392
|
-
this.message = message
|
|
10393
|
-
this.stdin = stdin;
|
|
10394
|
-
this.stdout = stdout$1;
|
|
10395
|
-
this.filterRL = readline.createInterface({
|
|
10072
|
+
if (this.message = message, this.stdin = stdin, this.stdout = stdout$1, this.filterRL = readline.createInterface({
|
|
10396
10073
|
input: this.stdin,
|
|
10397
10074
|
escapeCodeTimeout: 50
|
|
10398
|
-
});
|
|
10399
|
-
readline.emitKeypressEvents(this.stdin, this.filterRL);
|
|
10400
|
-
if (this.stdin.isTTY) this.stdin.setRawMode(true);
|
|
10075
|
+
}), readline.emitKeypressEvents(this.stdin, this.filterRL), this.stdin.isTTY) this.stdin.setRawMode(true);
|
|
10401
10076
|
}
|
|
10402
10077
|
async filter(filterFunc) {
|
|
10403
10078
|
this.write(this.promptLine());
|
|
10404
10079
|
const resultPromise = createDefer();
|
|
10405
10080
|
this.onKeyPress = this.filterHandler(filterFunc, (result) => {
|
|
10406
10081
|
resultPromise.resolve(result);
|
|
10407
|
-
});
|
|
10408
|
-
this.stdin.on("keypress", this.onKeyPress);
|
|
10082
|
+
}), this.stdin.on("keypress", this.onKeyPress);
|
|
10409
10083
|
try {
|
|
10410
10084
|
return await resultPromise;
|
|
10411
10085
|
} finally {
|
|
@@ -10421,13 +10095,11 @@ class WatchFilter {
|
|
|
10421
10095
|
break;
|
|
10422
10096
|
case key?.ctrl && key?.name === "c":
|
|
10423
10097
|
case key?.name === "escape":
|
|
10424
|
-
this.write(`${ESC}1G${ESC}0J`);
|
|
10425
|
-
onSubmit(void 0);
|
|
10098
|
+
this.write(`${ESC}1G${ESC}0J`), onSubmit(void 0);
|
|
10426
10099
|
return;
|
|
10427
10100
|
case key?.name === "enter":
|
|
10428
10101
|
case key?.name === "return":
|
|
10429
|
-
onSubmit(this.results[this.selectionIndex] || this.currentKeyword || "");
|
|
10430
|
-
this.currentKeyword = void 0;
|
|
10102
|
+
onSubmit(this.results[this.selectionIndex] || this.currentKeyword || ""), this.currentKeyword = void 0;
|
|
10431
10103
|
break;
|
|
10432
10104
|
case key?.name === "up":
|
|
10433
10105
|
if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--;
|
|
@@ -10454,17 +10126,13 @@ class WatchFilter {
|
|
|
10454
10126
|
const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`;
|
|
10455
10127
|
let resultBody = "";
|
|
10456
10128
|
if (this.results.length > MAX_RESULT_COUNT) {
|
|
10457
|
-
const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0;
|
|
10458
|
-
|
|
10459
|
-
const remainingResultCount = this.results.length - offset - displayResults.length;
|
|
10460
|
-
resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`;
|
|
10461
|
-
if (remainingResultCount > 0) resultBody += `
|
|
10129
|
+
const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0, displayResults = this.results.slice(offset, MAX_RESULT_COUNT + offset), remainingResultCount = this.results.length - offset - displayResults.length;
|
|
10130
|
+
if (resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`, remainingResultCount > 0) resultBody += `
|
|
10462
10131
|
${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}`)}`;
|
|
10463
10132
|
} else resultBody = this.results.map((result, index) => index === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n");
|
|
10464
10133
|
printStr += `\n${resultCountLine}\n${resultBody}`;
|
|
10465
10134
|
}
|
|
10466
|
-
this.eraseAndPrint(printStr);
|
|
10467
|
-
this.restoreCursor();
|
|
10135
|
+
this.eraseAndPrint(printStr), this.restoreCursor();
|
|
10468
10136
|
}
|
|
10469
10137
|
keywordOffset() {
|
|
10470
10138
|
return `? ${this.message} › `.length + 1;
|
|
@@ -10480,14 +10148,10 @@ ${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "
|
|
|
10480
10148
|
// We have to take care of screen width in case of long lines
|
|
10481
10149
|
rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns);
|
|
10482
10150
|
}
|
|
10483
|
-
this.write(`${ESC}1G`);
|
|
10484
|
-
this.write(`${ESC}J`);
|
|
10485
|
-
this.write(str);
|
|
10486
|
-
this.write(`${ESC}${rows - 1}A`);
|
|
10151
|
+
this.write(`${ESC}1G`), this.write(`${ESC}J`), this.write(str), this.write(`${ESC}${rows - 1}A`);
|
|
10487
10152
|
}
|
|
10488
10153
|
close() {
|
|
10489
|
-
this.filterRL.close();
|
|
10490
|
-
if (this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
|
|
10154
|
+
if (this.filterRL.close(), this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
|
|
10491
10155
|
if (this.stdin.isTTY) this.stdin.setRawMode(false);
|
|
10492
10156
|
}
|
|
10493
10157
|
restoreCursor() {
|
|
@@ -10512,8 +10176,7 @@ const keys = [
|
|
|
10512
10176
|
["w", "filter by a project name"],
|
|
10513
10177
|
["b", "start the browser server if not started yet"],
|
|
10514
10178
|
["q", "quit"]
|
|
10515
|
-
]
|
|
10516
|
-
const cancelKeys = [
|
|
10179
|
+
], cancelKeys = [
|
|
10517
10180
|
"space",
|
|
10518
10181
|
"c",
|
|
10519
10182
|
"h",
|
|
@@ -10531,17 +10194,12 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10531
10194
|
// Cancel run and exit when ctrl-c or esc is pressed.
|
|
10532
10195
|
// If cancelling takes long and key is pressed multiple times, exit forcefully.
|
|
10533
10196
|
if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") {
|
|
10534
|
-
if (!ctx.isCancelling)
|
|
10535
|
-
ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n"));
|
|
10536
|
-
process.exitCode = 130;
|
|
10537
|
-
await ctx.cancelCurrentRun("keyboard-input");
|
|
10538
|
-
}
|
|
10197
|
+
if (!ctx.isCancelling) ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n")), process.exitCode = 130, await ctx.cancelCurrentRun("keyboard-input");
|
|
10539
10198
|
return ctx.exit(true);
|
|
10540
10199
|
}
|
|
10541
10200
|
// window not support suspend
|
|
10542
10201
|
if (!isWindows && key && key.ctrl && key.name === "z") {
|
|
10543
|
-
process.kill(process.ppid, "SIGTSTP");
|
|
10544
|
-
process.kill(process.pid, "SIGTSTP");
|
|
10202
|
+
process.kill(process.ppid, "SIGTSTP"), process.kill(process.pid, "SIGTSTP");
|
|
10545
10203
|
return;
|
|
10546
10204
|
}
|
|
10547
10205
|
const name = key?.name;
|
|
@@ -10570,24 +10228,17 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10570
10228
|
if (name === "t") return inputNamePattern();
|
|
10571
10229
|
// change fileNamePattern
|
|
10572
10230
|
if (name === "p") return inputFilePattern();
|
|
10573
|
-
if (name === "b") {
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
ctx.logger.log();
|
|
10577
|
-
ctx.logger.printBrowserBanner(project);
|
|
10578
|
-
});
|
|
10579
|
-
return null;
|
|
10580
|
-
}
|
|
10231
|
+
if (name === "b") return await ctx._initBrowserServers(), ctx.projects.forEach((project) => {
|
|
10232
|
+
ctx.logger.log(), ctx.logger.printBrowserBanner(project);
|
|
10233
|
+
}), null;
|
|
10581
10234
|
}
|
|
10582
10235
|
async function keypressHandler(str, key) {
|
|
10583
10236
|
await _keypressHandler(str, key);
|
|
10584
10237
|
}
|
|
10585
10238
|
async function inputNamePattern() {
|
|
10586
10239
|
off();
|
|
10587
|
-
const watchFilter = new WatchFilter("Input test name pattern (RegExp)", stdin, stdout)
|
|
10588
|
-
|
|
10589
|
-
const files = ctx.state.getFiles();
|
|
10590
|
-
const tests = getTests(files);
|
|
10240
|
+
const watchFilter = new WatchFilter("Input test name pattern (RegExp)", stdin, stdout), filter = await watchFilter.filter((str) => {
|
|
10241
|
+
const files = ctx.state.getFiles(), tests = getTests(files);
|
|
10591
10242
|
try {
|
|
10592
10243
|
const reg = new RegExp(str);
|
|
10593
10244
|
return tests.map((test) => test.name).filter((testName) => testName.match(reg));
|
|
@@ -10596,11 +10247,8 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10596
10247
|
return [];
|
|
10597
10248
|
}
|
|
10598
10249
|
});
|
|
10599
|
-
on();
|
|
10600
|
-
|
|
10601
|
-
const files = ctx.state.getFilepaths();
|
|
10602
|
-
// if running in standalone mode, Vitest instance doesn't know about any test file
|
|
10603
|
-
const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
|
|
10250
|
+
if (on(), typeof filter === "undefined") return;
|
|
10251
|
+
const files = ctx.state.getFilepaths(), cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
|
|
10604
10252
|
await ctx.changeNamePattern(filter?.trim() || "", cliFiles, "change pattern");
|
|
10605
10253
|
}
|
|
10606
10254
|
async function inputProjectName() {
|
|
@@ -10611,41 +10259,31 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10611
10259
|
message: "Input a single project name",
|
|
10612
10260
|
initial: ctx.config.project[0] || ""
|
|
10613
10261
|
}]);
|
|
10614
|
-
on();
|
|
10615
|
-
await ctx.changeProjectName(filter.trim());
|
|
10262
|
+
on(), await ctx.changeProjectName(filter.trim());
|
|
10616
10263
|
}
|
|
10617
10264
|
async function inputFilePattern() {
|
|
10618
10265
|
off();
|
|
10619
|
-
const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout)
|
|
10620
|
-
const filter = await watchFilter.filter(async (str) => {
|
|
10266
|
+
const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout), filter = await watchFilter.filter(async (str) => {
|
|
10621
10267
|
const files = await ctx.globTestFiles([str]);
|
|
10622
10268
|
return files.map((file) => relative(ctx.config.root, file[1])).filter((file, index, all) => all.indexOf(file) === index);
|
|
10623
10269
|
});
|
|
10624
|
-
on();
|
|
10625
|
-
if (typeof filter === "undefined") return;
|
|
10270
|
+
if (on(), typeof filter === "undefined") return;
|
|
10626
10271
|
latestFilename = filter?.trim() || "";
|
|
10627
10272
|
const lastResults = watchFilter.getLastResults();
|
|
10628
10273
|
await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0);
|
|
10629
10274
|
}
|
|
10630
10275
|
let rl;
|
|
10631
10276
|
function on() {
|
|
10632
|
-
off()
|
|
10633
|
-
rl = readline.createInterface({
|
|
10277
|
+
if (off(), rl = readline.createInterface({
|
|
10634
10278
|
input: stdin,
|
|
10635
10279
|
escapeCodeTimeout: 50
|
|
10636
|
-
});
|
|
10637
|
-
readline.emitKeypressEvents(stdin, rl);
|
|
10638
|
-
if (stdin.isTTY) stdin.setRawMode(true);
|
|
10280
|
+
}), readline.emitKeypressEvents(stdin, rl), stdin.isTTY) stdin.setRawMode(true);
|
|
10639
10281
|
stdin.on("keypress", keypressHandler);
|
|
10640
10282
|
}
|
|
10641
10283
|
function off() {
|
|
10642
|
-
rl?.close();
|
|
10643
|
-
rl = void 0;
|
|
10644
|
-
stdin.removeListener("keypress", keypressHandler);
|
|
10645
|
-
if (stdin.isTTY) stdin.setRawMode(false);
|
|
10284
|
+
if (rl?.close(), rl = void 0, stdin.removeListener("keypress", keypressHandler), stdin.isTTY) stdin.setRawMode(false);
|
|
10646
10285
|
}
|
|
10647
|
-
on()
|
|
10648
|
-
return function cleanup() {
|
|
10286
|
+
return on(), function cleanup() {
|
|
10649
10287
|
off();
|
|
10650
10288
|
};
|
|
10651
10289
|
}
|
|
@@ -10656,20 +10294,14 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10656
10294
|
* Returns a Vitest instance if initialized successfully.
|
|
10657
10295
|
*/
|
|
10658
10296
|
async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) {
|
|
10659
|
-
const root = resolve(options.root || process.cwd());
|
|
10660
|
-
const ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
|
|
10297
|
+
const root = resolve(options.root || process.cwd()), ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
|
|
10661
10298
|
if (mode === "test" && ctx.config.coverage.enabled) {
|
|
10662
|
-
const provider = ctx.config.coverage.provider || "v8";
|
|
10663
|
-
const requiredPackages = CoverageProviderMap[provider];
|
|
10299
|
+
const provider = ctx.config.coverage.provider || "v8", requiredPackages = CoverageProviderMap[provider];
|
|
10664
10300
|
if (requiredPackages) {
|
|
10665
|
-
if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version))
|
|
10666
|
-
process.exitCode = 1;
|
|
10667
|
-
return ctx;
|
|
10668
|
-
}
|
|
10301
|
+
if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) return process.exitCode = 1, ctx;
|
|
10669
10302
|
}
|
|
10670
10303
|
}
|
|
10671
|
-
const stdin = vitestOptions?.stdin || process.stdin;
|
|
10672
|
-
const stdout = vitestOptions?.stdout || process.stdout;
|
|
10304
|
+
const stdin = vitestOptions?.stdin || process.stdin, stdout = vitestOptions?.stdout || process.stdout;
|
|
10673
10305
|
let stdinCleanup;
|
|
10674
10306
|
if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout);
|
|
10675
10307
|
ctx.onAfterSetServer(() => {
|
|
@@ -10681,55 +10313,27 @@ async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, v
|
|
|
10681
10313
|
else if (ctx.config.standalone) await ctx.init();
|
|
10682
10314
|
else await ctx.start(cliFilters);
|
|
10683
10315
|
} catch (e) {
|
|
10684
|
-
|
|
10685
|
-
if (e instanceof GitNotFoundError) {
|
|
10686
|
-
ctx.logger.error(e.message);
|
|
10687
|
-
return ctx;
|
|
10688
|
-
}
|
|
10689
|
-
if (e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError) {
|
|
10690
|
-
ctx.logger.printError(e, { verbose: false });
|
|
10691
|
-
return ctx;
|
|
10692
|
-
}
|
|
10693
|
-
process.exitCode = 1;
|
|
10694
|
-
ctx.logger.printError(e, {
|
|
10316
|
+
return e instanceof FilesNotFoundError ? ctx : e instanceof GitNotFoundError ? (ctx.logger.error(e.message), ctx) : e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError ? (ctx.logger.printError(e, { verbose: false }), ctx) : (process.exitCode = 1, ctx.logger.printError(e, {
|
|
10695
10317
|
fullStack: true,
|
|
10696
10318
|
type: "Unhandled Error"
|
|
10697
|
-
});
|
|
10698
|
-
ctx.logger.error("\n\n");
|
|
10699
|
-
return ctx;
|
|
10319
|
+
}), ctx.logger.error("\n\n"), ctx);
|
|
10700
10320
|
}
|
|
10701
|
-
|
|
10702
|
-
stdinCleanup?.();
|
|
10703
|
-
await ctx.close();
|
|
10704
|
-
return ctx;
|
|
10321
|
+
return ctx.shouldKeepServer() ? ctx : (stdinCleanup?.(), await ctx.close(), ctx);
|
|
10705
10322
|
}
|
|
10706
10323
|
async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions, cliFilters) {
|
|
10707
|
-
process.env.TEST = "true";
|
|
10708
|
-
process.env.VITEST = "true";
|
|
10709
|
-
process.env.NODE_ENV ??= "test";
|
|
10710
|
-
if (options.run) options.watch = false;
|
|
10324
|
+
if (process.env.TEST = "true", process.env.VITEST = "true", process.env.NODE_ENV ??= "test", options.run) options.watch = false;
|
|
10711
10325
|
if (options.standalone && (cliFilters?.length || 0) > 0) options.standalone = false;
|
|
10712
10326
|
// this shouldn't affect _application root_ that can be changed inside config
|
|
10713
|
-
const root = resolve(options.root || process.cwd());
|
|
10714
|
-
|
|
10715
|
-
const environmentPackage = getEnvPackageName(ctx.config.environment);
|
|
10716
|
-
if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) {
|
|
10717
|
-
process.exitCode = 1;
|
|
10718
|
-
return ctx;
|
|
10719
|
-
}
|
|
10720
|
-
return ctx;
|
|
10327
|
+
const root = resolve(options.root || process.cwd()), ctx = await createVitest(mode, options, viteOverrides, vitestOptions), environmentPackage = getEnvPackageName(ctx.config.environment);
|
|
10328
|
+
return environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root) && (process.exitCode = 1), ctx;
|
|
10721
10329
|
}
|
|
10722
10330
|
function processCollected(ctx, files, options) {
|
|
10723
10331
|
let errorsPrinted = false;
|
|
10724
|
-
forEachSuite(files, (suite) => {
|
|
10332
|
+
if (forEachSuite(files, (suite) => {
|
|
10725
10333
|
suite.errors().forEach((error) => {
|
|
10726
|
-
errorsPrinted = true;
|
|
10727
|
-
ctx.logger.printError(error, { project: suite.project });
|
|
10334
|
+
errorsPrinted = true, ctx.logger.printError(error, { project: suite.project });
|
|
10728
10335
|
});
|
|
10729
|
-
});
|
|
10730
|
-
if (errorsPrinted) return;
|
|
10731
|
-
if (typeof options.json !== "undefined") return processJsonOutput(files, options);
|
|
10732
|
-
return formatCollectedAsString(files).forEach((test) => console.log(test));
|
|
10336
|
+
}), !errorsPrinted) return typeof options.json === "undefined" ? formatCollectedAsString(files).forEach((test) => console.log(test)) : processJsonOutput(files, options);
|
|
10733
10337
|
}
|
|
10734
10338
|
function outputFileList(files, options) {
|
|
10735
10339
|
if (typeof options.json !== "undefined") return outputJsonFileList(files, options);
|
|
@@ -10739,8 +10343,7 @@ function outputJsonFileList(files, options) {
|
|
|
10739
10343
|
if (typeof options.json === "boolean") return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10740
10344
|
if (typeof options.json === "string") {
|
|
10741
10345
|
const jsonPath = resolve(options.root || process.cwd(), options.json);
|
|
10742
|
-
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
10743
|
-
writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10346
|
+
mkdirSync(dirname(jsonPath), { recursive: true }), writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10744
10347
|
}
|
|
10745
10348
|
}
|
|
10746
10349
|
function formatFilesAsJSON(files) {
|
|
@@ -10761,8 +10364,7 @@ function processJsonOutput(files, options) {
|
|
|
10761
10364
|
if (typeof options.json === "boolean") return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10762
10365
|
if (typeof options.json === "string") {
|
|
10763
10366
|
const jsonPath = resolve(options.root || process.cwd(), options.json);
|
|
10764
|
-
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
10765
|
-
writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10367
|
+
mkdirSync(dirname(jsonPath), { recursive: true }), writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10766
10368
|
}
|
|
10767
10369
|
}
|
|
10768
10370
|
function forEachSuite(modules, callback) {
|
|
@@ -10773,7 +10375,7 @@ function forEachSuite(modules, callback) {
|
|
|
10773
10375
|
}
|
|
10774
10376
|
function formatCollectedAsJSON(files) {
|
|
10775
10377
|
const results = [];
|
|
10776
|
-
files.forEach((file) => {
|
|
10378
|
+
return files.forEach((file) => {
|
|
10777
10379
|
for (const test of file.children.allTests()) {
|
|
10778
10380
|
if (test.result().state === "skipped") continue;
|
|
10779
10381
|
const result = {
|
|
@@ -10784,19 +10386,17 @@ function formatCollectedAsJSON(files) {
|
|
|
10784
10386
|
if (test.location) result.location = test.location;
|
|
10785
10387
|
results.push(result);
|
|
10786
10388
|
}
|
|
10787
|
-
});
|
|
10788
|
-
return results;
|
|
10389
|
+
}), results;
|
|
10789
10390
|
}
|
|
10790
10391
|
function formatCollectedAsString(testModules) {
|
|
10791
10392
|
const results = [];
|
|
10792
|
-
testModules.forEach((testModule) => {
|
|
10393
|
+
return testModules.forEach((testModule) => {
|
|
10793
10394
|
for (const test of testModule.children.allTests()) {
|
|
10794
10395
|
if (test.result().state === "skipped") continue;
|
|
10795
10396
|
const fullName = `${test.module.task.name} > ${test.fullName}`;
|
|
10796
10397
|
results.push((test.project.name ? `[${test.project.name}] ` : "") + fullName);
|
|
10797
10398
|
}
|
|
10798
|
-
});
|
|
10799
|
-
return results;
|
|
10399
|
+
}), results;
|
|
10800
10400
|
}
|
|
10801
10401
|
const envPackageNames = {
|
|
10802
10402
|
"jsdom": "jsdom",
|
|
@@ -10804,10 +10404,7 @@ const envPackageNames = {
|
|
|
10804
10404
|
"edge-runtime": "@edge-runtime/vm"
|
|
10805
10405
|
};
|
|
10806
10406
|
function getEnvPackageName(env) {
|
|
10807
|
-
|
|
10808
|
-
if (env in envPackageNames) return envPackageNames[env];
|
|
10809
|
-
if (env[0] === "." || isAbsolute(env)) return null;
|
|
10810
|
-
return `vitest-environment-${env}`;
|
|
10407
|
+
return env === "node" ? null : env in envPackageNames ? envPackageNames[env] : env[0] === "." || isAbsolute(env) ? null : `vitest-environment-${env}`;
|
|
10811
10408
|
}
|
|
10812
10409
|
|
|
10813
10410
|
var cliApi = /*#__PURE__*/Object.freeze({
|
|
@@ -10820,4 +10417,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
|
|
|
10820
10417
|
startVitest: startVitest
|
|
10821
10418
|
});
|
|
10822
10419
|
|
|
10823
|
-
export { FilesNotFoundError as F, GitNotFoundError as G, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c,
|
|
10420
|
+
export { FilesNotFoundError as F, GitNotFoundError as G, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, experimental_getRunnerTask as d, escapeTestName as e, registerConsoleShortcuts as f, createViteLogger as g, createDebugger as h, isValidApiRequest as i, cliApi as j, resolveFsAllow as r, startVitest as s };
|