vitest 3.2.4 → 4.0.0-beta.10
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 +2 -2
- package/dist/browser.d.ts +13 -16
- package/dist/browser.js +6 -5
- package/dist/chunks/base.Cjha6usc.js +129 -0
- package/dist/chunks/{benchmark.CYdenmiT.js → benchmark.CJUa-Hsa.js} +6 -8
- package/dist/chunks/{benchmark.d.BwvBVTda.d.ts → benchmark.d.DAaHLpsq.d.ts} +4 -4
- package/dist/chunks/browser.d.yFAklsD1.d.ts +18 -0
- package/dist/chunks/{cac.Cb-PYCCB.js → cac.DCxo_nSu.js} +72 -163
- package/dist/chunks/{cli-api.BkDphVBG.js → cli-api.BJJXh9BV.js} +1331 -1678
- package/dist/chunks/{config.d.D2ROskhv.d.ts → config.d.B_LthbQq.d.ts} +59 -65
- package/dist/chunks/{console.CtFJOzRO.js → console.7h5kHUIf.js} +34 -70
- package/dist/chunks/{constants.DnKduX2e.js → constants.D_Q9UYh-.js} +1 -9
- package/dist/chunks/{coverage.DL5VHqXY.js → coverage.BCU-r2QL.js} +538 -765
- package/dist/chunks/{coverage.DVF1vEu8.js → coverage.D_JHT54q.js} +2 -2
- package/dist/chunks/{coverage.d.S9RMNXIe.d.ts → coverage.d.BZtK59WP.d.ts} +10 -8
- package/dist/chunks/{creator.GK6I-cL4.js → creator.08Gi-vCA.js} +93 -77
- package/dist/chunks/{date.Bq6ZW5rf.js → date.-jtEtIeV.js} +6 -17
- package/dist/chunks/{defaults.B7q_naMc.js → defaults.CXFFjsi8.js} +2 -42
- package/dist/chunks/environment.d.BsToaxti.d.ts +65 -0
- package/dist/chunks/{git.BVQ8w_Sw.js → git.BFNcloKD.js} +1 -2
- package/dist/chunks/{global.d.MAmajcmJ.d.ts → global.d.BK3X7FW1.d.ts} +7 -32
- package/dist/chunks/{globals.DEHgCU4V.js → globals.DG-S3xFe.js} +8 -8
- package/dist/chunks/{index.VByaPkjc.js → index.BIP7prJq.js} +472 -803
- package/dist/chunks/{index.B521nVV-.js → index.Bgo3tNWt.js} +23 -4
- package/dist/chunks/{index.BCWujgDG.js → index.BjKEiSn0.js} +14 -24
- package/dist/chunks/{index.CdQS2e2Q.js → index.CMfqw92x.js} +7 -8
- package/dist/chunks/{index.CmSc2RE5.js → index.DIWhzsUh.js} +72 -118
- package/dist/chunks/{inspector.C914Efll.js → inspector.CvQD-Nie.js} +10 -25
- package/dist/chunks/moduleRunner.d.D9nBoC4p.d.ts +201 -0
- package/dist/chunks/moduleTransport.I-bgQy0S.js +19 -0
- package/dist/chunks/{node.fjCdwEIl.js → node.CyipiPvJ.js} +1 -1
- package/dist/chunks/plugin.d.BMVSnsGV.d.ts +9 -0
- package/dist/chunks/{reporters.d.BFLkQcL6.d.ts → reporters.d.BUWjmRYq.d.ts} +2086 -2146
- package/dist/chunks/resolveSnapshotEnvironment.Bkht6Yor.js +81 -0
- package/dist/chunks/resolver.Bx6lE0iq.js +119 -0
- package/dist/chunks/rpc.BKr6mtxz.js +65 -0
- package/dist/chunks/{setup-common.Dd054P77.js → setup-common.uiMcU3cv.js} +17 -29
- package/dist/chunks/startModuleRunner.p67gbNo9.js +665 -0
- package/dist/chunks/{suite.d.FvehnV49.d.ts → suite.d.BJWk38HB.d.ts} +1 -1
- package/dist/chunks/test.BiqSKISg.js +214 -0
- package/dist/chunks/{typechecker.DRKU1-1g.js → typechecker.DB-fIMaH.js} +165 -234
- package/dist/chunks/{utils.CAioKnHs.js → utils.C2YI6McM.js} +5 -14
- package/dist/chunks/{utils.XdZDrNZV.js → utils.D2R2NiOH.js} +8 -27
- package/dist/chunks/{vi.bdSIJ99Y.js → vi.ZPgvtBao.js} +156 -305
- package/dist/chunks/{vm.BThCzidc.js → vm.Ca0Y0W5f.js} +116 -226
- package/dist/chunks/{worker.d.1GmBbd7G.d.ts → worker.d.BDsXGkwh.d.ts} +31 -32
- package/dist/chunks/{worker.d.CKwWzBSj.d.ts → worker.d.BNcX_2mH.d.ts} +1 -1
- package/dist/cli.js +10 -10
- package/dist/config.cjs +5 -58
- package/dist/config.d.ts +72 -71
- package/dist/config.js +3 -9
- package/dist/coverage.d.ts +31 -24
- package/dist/coverage.js +9 -9
- package/dist/environments.d.ts +9 -14
- package/dist/environments.js +1 -1
- package/dist/index.d.ts +52 -213
- package/dist/index.js +7 -9
- package/dist/module-evaluator.d.ts +13 -0
- package/dist/module-evaluator.js +276 -0
- package/dist/module-runner.js +15 -0
- package/dist/node.d.ts +62 -51
- package/dist/node.js +26 -42
- package/dist/reporters.d.ts +11 -12
- package/dist/reporters.js +12 -12
- package/dist/runners.d.ts +3 -4
- package/dist/runners.js +13 -231
- package/dist/snapshot.js +2 -2
- package/dist/suite.d.ts +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +90 -47
- package/dist/workers/forks.js +34 -10
- package/dist/workers/runVmTests.js +36 -56
- package/dist/workers/threads.js +34 -10
- package/dist/workers/vmForks.js +11 -10
- package/dist/workers/vmThreads.js +11 -10
- package/dist/workers.d.ts +5 -7
- package/dist/workers.js +35 -17
- package/globals.d.ts +17 -17
- package/package.json +32 -31
- package/dist/chunks/base.DfmxU-tU.js +0 -38
- package/dist/chunks/environment.d.cL3nLXbE.d.ts +0 -119
- package/dist/chunks/execute.B7h3T_Hc.js +0 -708
- package/dist/chunks/index.CwejwG0H.js +0 -105
- package/dist/chunks/rpc.-pEldfrD.js +0 -83
- package/dist/chunks/runBaseTests.9Ij9_de-.js +0 -129
- package/dist/chunks/vite.d.CMLlLIFP.d.ts +0 -25
- package/dist/execute.d.ts +0 -150
- package/dist/execute.js +0 -13
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import fs, { promises, existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { relative, resolve, dirname, extname, normalize, join, basename, isAbsolute } from 'pathe';
|
|
3
|
-
import { C as CoverageProviderMap } from './coverage.
|
|
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,
|
|
9
|
-
import { A as API_PATH, c as configFiles, d as defaultBrowserPort,
|
|
10
|
-
import
|
|
8
|
+
import { parseAst, searchForWorkspaceRoot, version, mergeConfig, createServer } from 'vite';
|
|
9
|
+
import { A as API_PATH, c as configFiles, d as defaultBrowserPort, a as defaultPort } from './constants.D_Q9UYh-.js';
|
|
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 {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { c as createBirpc } from './index.B521nVV-.js';
|
|
16
|
-
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, j as BlobReporter, r as readBlobs, H as HangingProcessReporter } from './index.VByaPkjc.js';
|
|
13
|
+
import { v as version$1 } from './cac.DCxo_nSu.js';
|
|
14
|
+
import { c as createBirpc } from './index.Bgo3tNWt.js';
|
|
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.BIP7prJq.js';
|
|
17
16
|
import require$$0$3 from 'events';
|
|
18
17
|
import require$$1$1 from 'https';
|
|
19
18
|
import require$$2 from 'http';
|
|
@@ -25,27 +24,30 @@ import require$$7 from 'url';
|
|
|
25
24
|
import require$$0 from 'zlib';
|
|
26
25
|
import require$$0$1 from 'buffer';
|
|
27
26
|
import { g as getDefaultExportFromCjs } from './_commonjsHelpers.BFTU3MAI.js';
|
|
28
|
-
import { parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
29
27
|
import crypto, { createHash } from 'node:crypto';
|
|
30
28
|
import { distDir, rootDir } from '../path.js';
|
|
31
|
-
import { h as hash, R as RandomSequencer, i as isPackageExists, g as getFilePoolName,
|
|
32
|
-
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.BCU-r2QL.js';
|
|
30
|
+
import { b as ancestor, c as createDefinesScript, d as convertTasksToEvents } from './typechecker.DB-fIMaH.js';
|
|
31
|
+
import { TraceMap, originalPositionFor, parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
32
|
+
import createDebug from 'debug';
|
|
33
|
+
import { VitestModuleEvaluator } from '#module-evaluator';
|
|
34
|
+
import { ModuleRunner } from 'vite/module-runner';
|
|
33
35
|
import { Console } from 'node:console';
|
|
34
36
|
import c from 'tinyrainbow';
|
|
35
|
-
import { createRequire } from 'node:module';
|
|
36
|
-
import url from 'node:url';
|
|
37
|
+
import { createRequire, builtinModules, isBuiltin } from 'node:module';
|
|
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
|
-
import { normalizeRequestId, cleanUrl } from 'vite-node/utils';
|
|
43
|
-
import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
|
|
44
|
-
import { c as configDefaults } from './defaults.B7q_naMc.js';
|
|
45
43
|
import MagicString from 'magic-string';
|
|
46
|
-
import {
|
|
44
|
+
import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
|
|
45
|
+
import { c as configDefaults } from './defaults.CXFFjsi8.js';
|
|
46
|
+
import { f as findNearestPackageData } from './resolver.Bx6lE0iq.js';
|
|
47
|
+
import * as esModuleLexer from 'es-module-lexer';
|
|
48
|
+
import { a as BenchmarkReportsMap } from './index.BjKEiSn0.js';
|
|
47
49
|
import assert$1 from 'node:assert';
|
|
48
|
-
import { serializeError } from '@vitest/utils/error';
|
|
50
|
+
import { serializeError as serializeError$1 } from '@vitest/utils/error';
|
|
49
51
|
import readline from 'node:readline';
|
|
50
52
|
import { stripVTControlCharacters } from 'node:util';
|
|
51
53
|
|
|
@@ -4717,9 +4719,11 @@ function requireWebsocketServer () {
|
|
|
4717
4719
|
return;
|
|
4718
4720
|
}
|
|
4719
4721
|
|
|
4720
|
-
if (version !==
|
|
4722
|
+
if (version !== 13 && version !== 8) {
|
|
4721
4723
|
const message = 'Missing or invalid Sec-WebSocket-Version header';
|
|
4722
|
-
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message
|
|
4724
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {
|
|
4725
|
+
'Sec-WebSocket-Version': '13, 8'
|
|
4726
|
+
});
|
|
4723
4727
|
return;
|
|
4724
4728
|
}
|
|
4725
4729
|
|
|
@@ -4987,16 +4991,24 @@ function requireWebsocketServer () {
|
|
|
4987
4991
|
* @param {Duplex} socket The socket of the upgrade request
|
|
4988
4992
|
* @param {Number} code The HTTP response status code
|
|
4989
4993
|
* @param {String} message The HTTP response body
|
|
4994
|
+
* @param {Object} [headers] The HTTP response headers
|
|
4990
4995
|
* @private
|
|
4991
4996
|
*/
|
|
4992
|
-
function abortHandshakeOrEmitwsClientError(
|
|
4997
|
+
function abortHandshakeOrEmitwsClientError(
|
|
4998
|
+
server,
|
|
4999
|
+
req,
|
|
5000
|
+
socket,
|
|
5001
|
+
code,
|
|
5002
|
+
message,
|
|
5003
|
+
headers
|
|
5004
|
+
) {
|
|
4993
5005
|
if (server.listenerCount('wsClientError')) {
|
|
4994
5006
|
const err = new Error(message);
|
|
4995
5007
|
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
|
|
4996
5008
|
|
|
4997
5009
|
server.emit('wsClientError', err, socket, req);
|
|
4998
5010
|
} else {
|
|
4999
|
-
abortHandshake(socket, code, message);
|
|
5011
|
+
abortHandshake(socket, code, message, headers);
|
|
5000
5012
|
}
|
|
5001
5013
|
}
|
|
5002
5014
|
return websocketServer;
|
|
@@ -5006,25 +5018,18 @@ var websocketServerExports = requireWebsocketServer();
|
|
|
5006
5018
|
var WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExports);
|
|
5007
5019
|
|
|
5008
5020
|
async function getModuleGraph(ctx, projectName, id, browser = false) {
|
|
5009
|
-
const graph = {};
|
|
5010
|
-
const externalized = /* @__PURE__ */ new Set();
|
|
5011
|
-
const inlined = /* @__PURE__ */ new Set();
|
|
5012
|
-
const project = ctx.getProjectByName(projectName);
|
|
5021
|
+
const graph = {}, externalized = /* @__PURE__ */ new Set(), inlined = /* @__PURE__ */ new Set(), project = ctx.getProjectByName(projectName);
|
|
5013
5022
|
async function get(mod, seen = /* @__PURE__ */ new Map()) {
|
|
5014
|
-
if (!mod || !mod.id) return;
|
|
5015
|
-
if (mod.id === "\0@vitest/browser/context") return;
|
|
5023
|
+
if (!mod || !mod.id || mod.id === "\0@vitest/browser/context") return;
|
|
5016
5024
|
if (seen.has(mod)) return seen.get(mod);
|
|
5017
5025
|
let id = clearId(mod.id);
|
|
5018
5026
|
seen.set(mod, id);
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
seen.set(mod, id);
|
|
5024
|
-
} else inlined.add(id);
|
|
5027
|
+
// TODO: how to know if it was rewritten(?) - what is rewritten?
|
|
5028
|
+
const rewrote = browser ? mod.file?.includes(project.browser.vite.config.cacheDir) ? mod.id : false : false;
|
|
5029
|
+
if (rewrote) id = rewrote, externalized.add(id), seen.set(mod, id);
|
|
5030
|
+
else inlined.add(id);
|
|
5025
5031
|
const mods = Array.from(mod.importedModules).filter((i) => i.id && !i.id.includes("/vitest/dist/"));
|
|
5026
|
-
graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean);
|
|
5027
|
-
return id;
|
|
5032
|
+
return graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean), id;
|
|
5028
5033
|
}
|
|
5029
5034
|
if (browser && project.browser) await get(project.browser.vite.moduleGraph.getModuleById(id));
|
|
5030
5035
|
else await get(project.vite.moduleGraph.getModuleById(id));
|
|
@@ -5076,21 +5081,19 @@ catch {}
|
|
|
5076
5081
|
}
|
|
5077
5082
|
|
|
5078
5083
|
function setup(ctx, _server) {
|
|
5079
|
-
const wss = new WebSocketServer({ noServer: true });
|
|
5080
|
-
const clients = /* @__PURE__ */ new Map();
|
|
5081
|
-
const server = _server || ctx.server;
|
|
5084
|
+
const wss = new WebSocketServer({ noServer: true }), clients = /* @__PURE__ */ new Map(), server = _server || ctx.vite;
|
|
5082
5085
|
server.httpServer?.on("upgrade", (request, socket, head) => {
|
|
5083
5086
|
if (!request.url) return;
|
|
5084
5087
|
const { pathname } = new URL(request.url, "http://localhost");
|
|
5085
|
-
if (pathname
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
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
|
+
});
|
|
5089
5096
|
}
|
|
5090
|
-
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
5091
|
-
wss.emit("connection", ws, request);
|
|
5092
|
-
setupClient(ws);
|
|
5093
|
-
});
|
|
5094
5097
|
});
|
|
5095
5098
|
function setupClient(ws) {
|
|
5096
5099
|
const rpc = createBirpc({
|
|
@@ -5104,8 +5107,7 @@ function setup(ctx, _server) {
|
|
|
5104
5107
|
return ctx.state.getPaths();
|
|
5105
5108
|
},
|
|
5106
5109
|
async readTestFile(id) {
|
|
5107
|
-
|
|
5108
|
-
return promises.readFile(id, "utf-8");
|
|
5110
|
+
return !ctx.state.filesMap.has(id) || !existsSync(id) ? null : promises.readFile(id, "utf-8");
|
|
5109
5111
|
},
|
|
5110
5112
|
async saveTestFile(id, content) {
|
|
5111
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.`);
|
|
@@ -5120,9 +5122,6 @@ function setup(ctx, _server) {
|
|
|
5120
5122
|
getConfig() {
|
|
5121
5123
|
return ctx.getRootProject().serializedConfig;
|
|
5122
5124
|
},
|
|
5123
|
-
getResolvedProjectNames() {
|
|
5124
|
-
return ctx.projects.map((p) => p.name);
|
|
5125
|
-
},
|
|
5126
5125
|
getResolvedProjectLabels() {
|
|
5127
5126
|
return ctx.projects.map((p) => ({
|
|
5128
5127
|
name: p.name,
|
|
@@ -5130,8 +5129,7 @@ function setup(ctx, _server) {
|
|
|
5130
5129
|
}));
|
|
5131
5130
|
},
|
|
5132
5131
|
async getTransformResult(projectName, id, browser = false) {
|
|
5133
|
-
const project = ctx.getProjectByName(projectName);
|
|
5134
|
-
const result = browser ? await project.browser.vite.transformRequest(id) : await project.vitenode.transformRequest(id);
|
|
5132
|
+
const project = ctx.getProjectByName(projectName), result = browser ? await project.browser.vite.transformRequest(id) : await project.vite.transformRequest(id);
|
|
5135
5133
|
if (result) {
|
|
5136
5134
|
try {
|
|
5137
5135
|
result.source = result.source || await promises.readFile(id, "utf-8");
|
|
@@ -5172,59 +5170,43 @@ function setup(ctx, _server) {
|
|
|
5172
5170
|
],
|
|
5173
5171
|
serialize: (data) => stringify(data, stringifyReplace),
|
|
5174
5172
|
deserialize: parse,
|
|
5175
|
-
|
|
5176
|
-
throw new Error(`[vitest-api]: Timeout calling "${functionName}"`);
|
|
5177
|
-
}
|
|
5173
|
+
timeout: -1
|
|
5178
5174
|
});
|
|
5179
|
-
clients.set(ws, rpc)
|
|
5180
|
-
|
|
5181
|
-
clients.delete(ws);
|
|
5175
|
+
clients.set(ws, rpc), ws.on("close", () => {
|
|
5176
|
+
clients.delete(ws), rpc.$close(/* @__PURE__ */ new Error("[vitest-api]: Pending methods while closing rpc"));
|
|
5182
5177
|
});
|
|
5183
5178
|
}
|
|
5184
5179
|
ctx.reporters.push(new WebSocketReporter(ctx, wss, clients));
|
|
5185
5180
|
}
|
|
5186
5181
|
class WebSocketReporter {
|
|
5187
5182
|
constructor(ctx, wss, clients) {
|
|
5188
|
-
this.ctx = ctx;
|
|
5189
|
-
this.wss = wss;
|
|
5190
|
-
this.clients = clients;
|
|
5183
|
+
this.ctx = ctx, this.wss = wss, this.clients = clients;
|
|
5191
5184
|
}
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
client.onCollected?.(files)?.catch?.(noop);
|
|
5185
|
+
onTestModuleCollected(testModule) {
|
|
5186
|
+
this.clients.size !== 0 && this.clients.forEach((client) => {
|
|
5187
|
+
client.onCollected?.([testModule.task])?.catch?.(noop);
|
|
5196
5188
|
});
|
|
5197
5189
|
}
|
|
5198
|
-
|
|
5190
|
+
onTestRunStart(specifications) {
|
|
5199
5191
|
if (this.clients.size === 0) return;
|
|
5192
|
+
const serializedSpecs = specifications.map((spec) => spec.toJSON());
|
|
5200
5193
|
this.clients.forEach((client) => {
|
|
5201
|
-
client.onSpecsCollected?.(
|
|
5194
|
+
client.onSpecsCollected?.(serializedSpecs)?.catch?.(noop);
|
|
5202
5195
|
});
|
|
5203
5196
|
}
|
|
5204
5197
|
async onTestCaseAnnotate(testCase, annotation) {
|
|
5205
|
-
|
|
5206
|
-
this.clients.forEach((client) => {
|
|
5198
|
+
this.clients.size !== 0 && this.clients.forEach((client) => {
|
|
5207
5199
|
client.onTestAnnotate?.(testCase.id, annotation)?.catch?.(noop);
|
|
5208
5200
|
});
|
|
5209
5201
|
}
|
|
5210
5202
|
async onTaskUpdate(packs, events) {
|
|
5211
|
-
|
|
5212
|
-
packs.forEach(([taskId, result]) => {
|
|
5213
|
-
const task = this.ctx.state.idMap.get(taskId);
|
|
5214
|
-
const isBrowser = task && task.file.pool === "browser";
|
|
5215
|
-
result?.errors?.forEach((error) => {
|
|
5216
|
-
if (isPrimitive(error)) return;
|
|
5217
|
-
if (isBrowser) {
|
|
5218
|
-
const project = this.ctx.getProjectByName(task.file.projectName || "");
|
|
5219
|
-
error.stacks = project.browser?.parseErrorStacktrace(error);
|
|
5220
|
-
} else error.stacks = parseErrorStacktrace(error);
|
|
5221
|
-
});
|
|
5222
|
-
});
|
|
5223
|
-
this.clients.forEach((client) => {
|
|
5203
|
+
this.clients.size !== 0 && this.clients.forEach((client) => {
|
|
5224
5204
|
client.onTaskUpdate?.(packs, events)?.catch?.(noop);
|
|
5225
5205
|
});
|
|
5226
5206
|
}
|
|
5227
|
-
|
|
5207
|
+
onTestRunEnd(testModules, unhandledErrors) {
|
|
5208
|
+
if (!this.clients.size) return;
|
|
5209
|
+
const files = testModules.map((testModule) => testModule.task), errors = [...unhandledErrors];
|
|
5228
5210
|
this.clients.forEach((client) => {
|
|
5229
5211
|
client.onFinished?.(files, errors)?.catch?.(noop);
|
|
5230
5212
|
});
|
|
@@ -5247,6 +5229,265 @@ var setup$1 = /*#__PURE__*/Object.freeze({
|
|
|
5247
5229
|
setup: setup
|
|
5248
5230
|
});
|
|
5249
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.name,
|
|
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
|
+
|
|
5250
5491
|
class BrowserSessions {
|
|
5251
5492
|
sessions = /* @__PURE__ */ new Map();
|
|
5252
5493
|
sessionIds = /* @__PURE__ */ new Set();
|
|
@@ -5258,23 +5499,18 @@ class BrowserSessions {
|
|
|
5258
5499
|
}
|
|
5259
5500
|
createSession(sessionId, project, pool) {
|
|
5260
5501
|
// this promise only waits for the WS connection with the orhcestrator to be established
|
|
5261
|
-
const defer = createDefer()
|
|
5262
|
-
|
|
5263
|
-
defer.reject(new Error(`Failed to connect to the browser session "${sessionId}" [${project.name}] within the timeout.`));
|
|
5502
|
+
const defer = createDefer(), timeout = setTimeout(() => {
|
|
5503
|
+
defer.reject(/* @__PURE__ */ new Error(`Failed to connect to the browser session "${sessionId}" [${project.name}] within the timeout.`));
|
|
5264
5504
|
}, project.vitest.config.browser.connectTimeout ?? 6e4).unref();
|
|
5265
|
-
this.sessions.set(sessionId, {
|
|
5505
|
+
return this.sessions.set(sessionId, {
|
|
5266
5506
|
project,
|
|
5267
5507
|
connected: () => {
|
|
5268
|
-
defer.resolve();
|
|
5269
|
-
clearTimeout(timeout);
|
|
5508
|
+
defer.resolve(), clearTimeout(timeout);
|
|
5270
5509
|
},
|
|
5271
5510
|
fail: (error) => {
|
|
5272
|
-
defer.resolve();
|
|
5273
|
-
clearTimeout(timeout);
|
|
5274
|
-
pool.reject(error);
|
|
5511
|
+
defer.resolve(), clearTimeout(timeout), pool.reject(error);
|
|
5275
5512
|
}
|
|
5276
|
-
});
|
|
5277
|
-
return defer;
|
|
5513
|
+
}), defer;
|
|
5278
5514
|
}
|
|
5279
5515
|
}
|
|
5280
5516
|
|
|
@@ -5285,7 +5521,7 @@ class FilesStatsCache {
|
|
|
5285
5521
|
}
|
|
5286
5522
|
async populateStats(root, specs) {
|
|
5287
5523
|
const promises = specs.map((spec) => {
|
|
5288
|
-
const key = `${spec
|
|
5524
|
+
const key = `${spec.project.name}:${relative(root, spec.moduleId)}`;
|
|
5289
5525
|
return this.updateStats(spec.moduleId, key);
|
|
5290
5526
|
});
|
|
5291
5527
|
await Promise.all(promises);
|
|
@@ -5315,37 +5551,25 @@ class ResultsCache {
|
|
|
5315
5551
|
return this.cachePath;
|
|
5316
5552
|
}
|
|
5317
5553
|
setConfig(root, config) {
|
|
5318
|
-
this.root = root;
|
|
5319
|
-
if (config) this.cachePath = resolve(config.dir, "results.json");
|
|
5554
|
+
if (this.root = root, config) this.cachePath = resolve(config.dir, "results.json");
|
|
5320
5555
|
}
|
|
5321
5556
|
getResults(key) {
|
|
5322
5557
|
return this.cache.get(key);
|
|
5323
5558
|
}
|
|
5324
5559
|
async readFromCache() {
|
|
5325
|
-
if (!this.cachePath) return;
|
|
5326
|
-
|
|
5327
|
-
const resultsCache = await fs.promises.readFile(this.cachePath, "utf8");
|
|
5328
|
-
const { results, version } = JSON.parse(resultsCache || "[]");
|
|
5329
|
-
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(".");
|
|
5330
5562
|
// handling changed in 0.30.0
|
|
5331
|
-
if (major > 0 || Number(minor) >= 30) {
|
|
5332
|
-
|
|
5333
|
-
this.
|
|
5334
|
-
|
|
5335
|
-
const [projectName, relativePath] = spec.split(":");
|
|
5336
|
-
const keyMap = this.workspacesKeyMap.get(relativePath) || [];
|
|
5337
|
-
keyMap.push(projectName);
|
|
5338
|
-
this.workspacesKeyMap.set(relativePath, keyMap);
|
|
5339
|
-
});
|
|
5340
|
-
}
|
|
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
|
+
});
|
|
5341
5567
|
}
|
|
5342
5568
|
updateResults(files) {
|
|
5343
5569
|
files.forEach((file) => {
|
|
5344
5570
|
const result = file.result;
|
|
5345
5571
|
if (!result) return;
|
|
5346
|
-
const duration = result.duration || 0;
|
|
5347
|
-
// store as relative, so cache would be the same in CI and locally
|
|
5348
|
-
const relativePath = relative(this.root, file.filepath);
|
|
5572
|
+
const duration = result.duration || 0, relativePath = relative(this.root, file.filepath);
|
|
5349
5573
|
this.cache.set(`${file.projectName || ""}:${relativePath}`, {
|
|
5350
5574
|
duration: duration >= 0 ? duration : 0,
|
|
5351
5575
|
failed: result.state === "fail"
|
|
@@ -5359,8 +5583,7 @@ class ResultsCache {
|
|
|
5359
5583
|
}
|
|
5360
5584
|
async writeToCache() {
|
|
5361
5585
|
if (!this.cachePath) return;
|
|
5362
|
-
const results = Array.from(this.cache.entries());
|
|
5363
|
-
const cacheDirname = dirname(this.cachePath);
|
|
5586
|
+
const results = Array.from(this.cache.entries()), cacheDirname = dirname(this.cachePath);
|
|
5364
5587
|
if (!fs.existsSync(cacheDirname)) await fs.promises.mkdir(cacheDirname, { recursive: true });
|
|
5365
5588
|
const cache = JSON.stringify({
|
|
5366
5589
|
version: this.version,
|
|
@@ -5388,6 +5611,34 @@ class VitestCache {
|
|
|
5388
5611
|
}
|
|
5389
5612
|
}
|
|
5390
5613
|
|
|
5614
|
+
class ServerModuleRunner extends ModuleRunner {
|
|
5615
|
+
constructor(environment, resolver, config) {
|
|
5616
|
+
const fetchModule = createFetchModuleFunction(resolver, false);
|
|
5617
|
+
super({
|
|
5618
|
+
hmr: false,
|
|
5619
|
+
sourcemapInterceptor: "node",
|
|
5620
|
+
transport: { async invoke(event) {
|
|
5621
|
+
if (event.type !== "custom") throw new Error(`Vitest Module Runner doesn't support Vite HMR events.`);
|
|
5622
|
+
const { data } = event.data;
|
|
5623
|
+
try {
|
|
5624
|
+
const result = await fetchModule(data[0], data[1], environment, data[2]);
|
|
5625
|
+
return { result };
|
|
5626
|
+
} catch (error) {
|
|
5627
|
+
return { error };
|
|
5628
|
+
}
|
|
5629
|
+
} }
|
|
5630
|
+
}, new VitestModuleEvaluator()), this.environment = environment, this.config = config;
|
|
5631
|
+
}
|
|
5632
|
+
async import(rawId) {
|
|
5633
|
+
const resolved = await this.environment.pluginContainer.resolveId(rawId, this.config.root);
|
|
5634
|
+
if (!resolved) return super.import(rawId);
|
|
5635
|
+
// Vite will make "@vitest/coverage-v8" into "@vitest/coverage-v8.js" url
|
|
5636
|
+
// instead of using an actual file path-like URL, so we resolve it here first
|
|
5637
|
+
const url = normalizeResolvedIdToUrl(this.environment, resolved.id);
|
|
5638
|
+
return super.import(url);
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
|
|
5391
5642
|
class FilesNotFoundError extends Error {
|
|
5392
5643
|
code = "VITEST_FILES_NOT_FOUND";
|
|
5393
5644
|
constructor(mode) {
|
|
@@ -5443,43 +5694,26 @@ function highlightCode(id, source, colors) {
|
|
|
5443
5694
|
});
|
|
5444
5695
|
}
|
|
5445
5696
|
|
|
5446
|
-
const PAD = " ";
|
|
5447
|
-
const ESC$1 = "\x1B[";
|
|
5448
|
-
const ERASE_DOWN = `${ESC$1}J`;
|
|
5449
|
-
const ERASE_SCROLLBACK = `${ESC$1}3J`;
|
|
5450
|
-
const CURSOR_TO_START = `${ESC$1}1;1H`;
|
|
5451
|
-
const HIDE_CURSOR = `${ESC$1}?25l`;
|
|
5452
|
-
const SHOW_CURSOR = `${ESC$1}?25h`;
|
|
5453
|
-
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";
|
|
5454
5698
|
class Logger {
|
|
5455
5699
|
_clearScreenPending;
|
|
5456
5700
|
_highlights = /* @__PURE__ */ new Map();
|
|
5457
5701
|
cleanupListeners = [];
|
|
5458
5702
|
console;
|
|
5459
5703
|
constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
|
|
5460
|
-
this.ctx = ctx
|
|
5461
|
-
this.outputStream = outputStream;
|
|
5462
|
-
this.errorStream = errorStream;
|
|
5463
|
-
this.console = new Console({
|
|
5704
|
+
if (this.ctx = ctx, this.outputStream = outputStream, this.errorStream = errorStream, this.console = new Console({
|
|
5464
5705
|
stdout: outputStream,
|
|
5465
5706
|
stderr: errorStream
|
|
5466
|
-
});
|
|
5467
|
-
this._highlights.clear();
|
|
5468
|
-
this.addCleanupListeners();
|
|
5469
|
-
this.registerUnhandledRejection();
|
|
5470
|
-
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);
|
|
5471
5708
|
}
|
|
5472
5709
|
log(...args) {
|
|
5473
|
-
this._clearScreen();
|
|
5474
|
-
this.console.log(...args);
|
|
5710
|
+
this._clearScreen(), this.console.log(...args);
|
|
5475
5711
|
}
|
|
5476
5712
|
error(...args) {
|
|
5477
|
-
this._clearScreen();
|
|
5478
|
-
this.console.error(...args);
|
|
5713
|
+
this._clearScreen(), this.console.error(...args);
|
|
5479
5714
|
}
|
|
5480
5715
|
warn(...args) {
|
|
5481
|
-
this._clearScreen();
|
|
5482
|
-
this.console.warn(...args);
|
|
5716
|
+
this._clearScreen(), this.console.warn(...args);
|
|
5483
5717
|
}
|
|
5484
5718
|
clearFullScreen(message = "") {
|
|
5485
5719
|
if (!this.ctx.config.clearScreen) {
|
|
@@ -5494,14 +5728,12 @@ class Logger {
|
|
|
5494
5728
|
this.console.log(message);
|
|
5495
5729
|
return;
|
|
5496
5730
|
}
|
|
5497
|
-
this._clearScreenPending = message;
|
|
5498
|
-
if (force) this._clearScreen();
|
|
5731
|
+
if (this._clearScreenPending = message, force) this._clearScreen();
|
|
5499
5732
|
}
|
|
5500
5733
|
_clearScreen() {
|
|
5501
5734
|
if (this._clearScreenPending == null) return;
|
|
5502
5735
|
const log = this._clearScreenPending;
|
|
5503
|
-
this._clearScreenPending = void 0;
|
|
5504
|
-
this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
|
|
5736
|
+
this._clearScreenPending = void 0, this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
|
|
5505
5737
|
}
|
|
5506
5738
|
printError(err, options = {}) {
|
|
5507
5739
|
printError(err, this.ctx, this, options);
|
|
@@ -5516,8 +5748,7 @@ class Logger {
|
|
|
5516
5748
|
highlight(filename, source) {
|
|
5517
5749
|
if (this._highlights.has(filename)) return this._highlights.get(filename);
|
|
5518
5750
|
const code = highlightCode(filename, source);
|
|
5519
|
-
this._highlights.set(filename, code);
|
|
5520
|
-
return code;
|
|
5751
|
+
return this._highlights.set(filename, code), code;
|
|
5521
5752
|
}
|
|
5522
5753
|
printNoTestFound(filters) {
|
|
5523
5754
|
const config = this.ctx.config;
|
|
@@ -5530,34 +5761,22 @@ class Logger {
|
|
|
5530
5761
|
const projectsFilter = toArray(config.project);
|
|
5531
5762
|
if (projectsFilter.length) this.console.error(c.dim("projects: ") + c.yellow(projectsFilter.join(comma)));
|
|
5532
5763
|
this.ctx.projects.forEach((project) => {
|
|
5533
|
-
const config = project.config;
|
|
5534
|
-
const printConfig = !project.isRootProject() && project.name;
|
|
5764
|
+
const config = project.config, printConfig = !project.isRootProject() && project.name;
|
|
5535
5765
|
if (printConfig) this.console.error(`\n${formatProjectName(project)}\n`);
|
|
5536
5766
|
if (config.include) this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
|
|
5537
5767
|
if (config.exclude) this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
|
|
5538
|
-
if (config.typecheck.enabled)
|
|
5539
|
-
|
|
5540
|
-
this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
|
|
5541
|
-
}
|
|
5542
|
-
});
|
|
5543
|
-
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();
|
|
5544
5770
|
}
|
|
5545
5771
|
printBanner() {
|
|
5546
5772
|
this.log();
|
|
5547
|
-
const color = this.ctx.config.watch ? "blue" : "cyan";
|
|
5548
|
-
|
|
5549
|
-
this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root));
|
|
5550
|
-
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}"`));
|
|
5551
5775
|
if (this.ctx.config.ui) {
|
|
5552
|
-
const host = this.ctx.config.api?.host || "localhost";
|
|
5553
|
-
const port = this.ctx.server.config.server.port;
|
|
5554
|
-
const base = this.ctx.config.uiBase;
|
|
5776
|
+
const host = this.ctx.config.api?.host || "localhost", port = this.ctx.vite.config.server.port, base = this.ctx.config.uiBase;
|
|
5555
5777
|
this.log(PAD + c.dim(c.green(`UI started at http://${host}:${c.bold(port)}${base}`)));
|
|
5556
5778
|
} else if (this.ctx.config.api?.port) {
|
|
5557
|
-
const resolvedUrls = this.ctx.
|
|
5558
|
-
// workaround for https://github.com/vitejs/vite/issues/15438, it was fixed in vite 5.1
|
|
5559
|
-
const fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`;
|
|
5560
|
-
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
|
|
5779
|
+
const resolvedUrls = this.ctx.vite.resolvedUrls, fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
|
|
5561
5780
|
this.log(PAD + c.dim(c.green(`API started at ${new URL("/", origin)}`)));
|
|
5562
5781
|
}
|
|
5563
5782
|
if (this.ctx.coverageProvider) this.log(PAD + c.dim("Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
|
|
@@ -5566,35 +5785,26 @@ class Logger {
|
|
|
5566
5785
|
}
|
|
5567
5786
|
printBrowserBanner(project) {
|
|
5568
5787
|
if (!project.browser) return;
|
|
5569
|
-
const resolvedUrls = project.browser.vite.resolvedUrls;
|
|
5570
|
-
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
|
|
5788
|
+
const resolvedUrls = project.browser.vite.resolvedUrls, origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
|
|
5571
5789
|
if (!origin) return;
|
|
5572
|
-
const output = project.isRootProject() ? "" : formatProjectName(project)
|
|
5573
|
-
const provider = project.browser.provider.name;
|
|
5574
|
-
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))}`;
|
|
5575
5791
|
this.log(c.dim(`${output}Browser runner started${providerString} ${c.dim("at")} ${c.blue(new URL("/__vitest_test__/", origin))}\n`));
|
|
5576
5792
|
}
|
|
5577
5793
|
printUnhandledErrors(errors) {
|
|
5578
5794
|
const errorMessage = c.red(c.bold(`\nVitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
|
|
5579
5795
|
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`));
|
|
5580
|
-
this.error(errorBanner("Unhandled Errors"))
|
|
5581
|
-
this.error(errorMessage);
|
|
5582
|
-
errors.forEach((err) => {
|
|
5796
|
+
this.error(errorBanner("Unhandled Errors")), this.error(errorMessage), errors.forEach((err) => {
|
|
5583
5797
|
this.printError(err, {
|
|
5584
5798
|
fullStack: true,
|
|
5585
5799
|
type: err.type || "Unhandled Error"
|
|
5586
5800
|
});
|
|
5587
|
-
});
|
|
5588
|
-
this.error(c.red(divider()));
|
|
5801
|
+
}), this.error(c.red(divider()));
|
|
5589
5802
|
}
|
|
5590
5803
|
printSourceTypeErrors(errors) {
|
|
5591
5804
|
const errorMessage = c.red(c.bold(`\nVitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related to your test files.`));
|
|
5592
|
-
this.log(errorBanner("Source Errors"))
|
|
5593
|
-
this.log(errorMessage);
|
|
5594
|
-
errors.forEach((err) => {
|
|
5805
|
+
this.log(errorBanner("Source Errors")), this.log(errorMessage), errors.forEach((err) => {
|
|
5595
5806
|
this.printError(err, { fullStack: true });
|
|
5596
|
-
});
|
|
5597
|
-
this.log(c.red(divider()));
|
|
5807
|
+
}), this.log(c.red(divider()));
|
|
5598
5808
|
}
|
|
5599
5809
|
getColumns() {
|
|
5600
5810
|
return "columns" in this.outputStream ? this.outputStream.columns : 80;
|
|
@@ -5604,38 +5814,25 @@ This might cause false positive tests. Resolve unhandled errors to make sure you
|
|
|
5604
5814
|
}
|
|
5605
5815
|
addCleanupListeners() {
|
|
5606
5816
|
const cleanup = () => {
|
|
5607
|
-
this.cleanupListeners.forEach((fn) => fn());
|
|
5608
|
-
|
|
5609
|
-
};
|
|
5610
|
-
const onExit = (signal, exitCode) => {
|
|
5611
|
-
cleanup();
|
|
5817
|
+
if (this.cleanupListeners.forEach((fn) => fn()), this.outputStream.isTTY) this.outputStream.write(SHOW_CURSOR);
|
|
5818
|
+
}, onExit = (signal, exitCode) => {
|
|
5612
5819
|
// Interrupted signals don't set exit code automatically.
|
|
5613
5820
|
// Use same exit code as node: https://nodejs.org/api/process.html#signal-events
|
|
5614
|
-
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);
|
|
5615
5822
|
process.exit();
|
|
5616
5823
|
};
|
|
5617
|
-
process.once("SIGINT", onExit)
|
|
5618
|
-
|
|
5619
|
-
process.once("exit", onExit);
|
|
5620
|
-
this.ctx.onClose(() => {
|
|
5621
|
-
process.off("SIGINT", onExit);
|
|
5622
|
-
process.off("SIGTERM", onExit);
|
|
5623
|
-
process.off("exit", onExit);
|
|
5624
|
-
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();
|
|
5625
5826
|
});
|
|
5626
5827
|
}
|
|
5627
5828
|
registerUnhandledRejection() {
|
|
5628
5829
|
const onUnhandledRejection = (err) => {
|
|
5629
|
-
process.exitCode = 1
|
|
5630
|
-
this.printError(err, {
|
|
5830
|
+
process.exitCode = 1, this.printError(err, {
|
|
5631
5831
|
fullStack: true,
|
|
5632
5832
|
type: "Unhandled Rejection"
|
|
5633
|
-
});
|
|
5634
|
-
this.error("\n\n");
|
|
5635
|
-
process.exit();
|
|
5833
|
+
}), this.error("\n\n"), process.exit();
|
|
5636
5834
|
};
|
|
5637
|
-
process.on("unhandledRejection", onUnhandledRejection)
|
|
5638
|
-
this.ctx.onClose(() => {
|
|
5835
|
+
process.on("unhandledRejection", onUnhandledRejection), this.ctx.onClose(() => {
|
|
5639
5836
|
process.off("unhandledRejection", onUnhandledRejection);
|
|
5640
5837
|
});
|
|
5641
5838
|
}
|
|
@@ -5651,36 +5848,26 @@ class VitestPackageInstaller {
|
|
|
5651
5848
|
if (process.versions.pnp) {
|
|
5652
5849
|
const targetRequire = createRequire(__dirname);
|
|
5653
5850
|
try {
|
|
5654
|
-
targetRequire.resolve(dependency, { paths: [root, __dirname] });
|
|
5655
|
-
return true;
|
|
5851
|
+
return targetRequire.resolve(dependency, { paths: [root, __dirname] }), true;
|
|
5656
5852
|
} catch {}
|
|
5657
5853
|
}
|
|
5658
5854
|
if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] })) return true;
|
|
5659
|
-
process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`));
|
|
5660
|
-
|
|
5661
|
-
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; });
|
|
5662
|
-
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({
|
|
5663
5857
|
type: "confirm",
|
|
5664
5858
|
name: "install",
|
|
5665
5859
|
message: c.reset(`Do you want to install ${c.green(dependency)}?`)
|
|
5666
5860
|
});
|
|
5667
5861
|
if (install) {
|
|
5668
5862
|
const packageName = version ? `${dependency}@${version}` : dependency;
|
|
5669
|
-
await (await import('./index.D3XRDfWc.js')).installPackage(packageName, { dev: true });
|
|
5670
|
-
// TODO: somehow it fails to load the package after installation, remove this when it's fixed
|
|
5671
|
-
process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`));
|
|
5672
|
-
process.exit();
|
|
5673
|
-
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;
|
|
5674
5864
|
}
|
|
5675
5865
|
return false;
|
|
5676
5866
|
}
|
|
5677
5867
|
}
|
|
5678
5868
|
|
|
5679
|
-
function serializeConfig(
|
|
5680
|
-
const optimizer = config.deps?.optimizer;
|
|
5681
|
-
const poolOptions = config.poolOptions;
|
|
5682
|
-
// Resolve from server.config to avoid comparing against default value
|
|
5683
|
-
const isolate = viteConfig?.test?.isolate;
|
|
5869
|
+
function serializeConfig(project) {
|
|
5870
|
+
const { config, globalConfig } = project, viteConfig = project._vite?.config, optimizer = config.deps?.optimizer || {}, poolOptions = config.poolOptions, isolate = viteConfig?.test?.isolate;
|
|
5684
5871
|
return {
|
|
5685
5872
|
environmentOptions: config.environmentOptions,
|
|
5686
5873
|
mode: config.mode,
|
|
@@ -5714,8 +5901,7 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5714
5901
|
snapshotEnvironment: config.snapshotEnvironment,
|
|
5715
5902
|
passWithNoTests: config.passWithNoTests,
|
|
5716
5903
|
coverage: ((coverage) => {
|
|
5717
|
-
const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html");
|
|
5718
|
-
const subdir = htmlReporter && htmlReporter[1]?.subdir;
|
|
5904
|
+
const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html"), subdir = htmlReporter && htmlReporter[1]?.subdir;
|
|
5719
5905
|
return {
|
|
5720
5906
|
reportsDirectory: coverage.reportsDirectory,
|
|
5721
5907
|
provider: coverage.provider,
|
|
@@ -5727,51 +5913,48 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5727
5913
|
fakeTimers: config.fakeTimers,
|
|
5728
5914
|
poolOptions: {
|
|
5729
5915
|
forks: {
|
|
5730
|
-
singleFork: poolOptions?.forks?.singleFork ??
|
|
5731
|
-
isolate: poolOptions?.forks?.isolate ?? isolate ??
|
|
5916
|
+
singleFork: poolOptions?.forks?.singleFork ?? globalConfig.poolOptions?.forks?.singleFork ?? false,
|
|
5917
|
+
isolate: poolOptions?.forks?.isolate ?? isolate ?? globalConfig.poolOptions?.forks?.isolate ?? true
|
|
5732
5918
|
},
|
|
5733
5919
|
threads: {
|
|
5734
|
-
singleThread: poolOptions?.threads?.singleThread ??
|
|
5735
|
-
isolate: poolOptions?.threads?.isolate ?? isolate ??
|
|
5920
|
+
singleThread: poolOptions?.threads?.singleThread ?? globalConfig.poolOptions?.threads?.singleThread ?? false,
|
|
5921
|
+
isolate: poolOptions?.threads?.isolate ?? isolate ?? globalConfig.poolOptions?.threads?.isolate ?? true
|
|
5736
5922
|
},
|
|
5737
|
-
vmThreads: { singleThread: poolOptions?.vmThreads?.singleThread ??
|
|
5738
|
-
vmForks: { singleFork: poolOptions?.vmForks?.singleFork ??
|
|
5923
|
+
vmThreads: { singleThread: poolOptions?.vmThreads?.singleThread ?? globalConfig.poolOptions?.vmThreads?.singleThread ?? false },
|
|
5924
|
+
vmForks: { singleFork: poolOptions?.vmForks?.singleFork ?? globalConfig.poolOptions?.vmForks?.singleFork ?? false }
|
|
5739
5925
|
},
|
|
5740
5926
|
deps: {
|
|
5741
5927
|
web: config.deps.web || {},
|
|
5742
|
-
optimizer: {
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
},
|
|
5928
|
+
optimizer: Object.entries(optimizer).reduce((acc, [name, option]) => {
|
|
5929
|
+
return acc[name] = { enabled: option?.enabled ?? false }, acc;
|
|
5930
|
+
}, {}),
|
|
5746
5931
|
interopDefault: config.deps.interopDefault,
|
|
5747
5932
|
moduleDirectories: config.deps.moduleDirectories
|
|
5748
5933
|
},
|
|
5749
5934
|
snapshotOptions: {
|
|
5750
5935
|
snapshotEnvironment: void 0,
|
|
5751
|
-
updateSnapshot:
|
|
5752
|
-
snapshotFormat: {
|
|
5753
|
-
|
|
5754
|
-
compareKeys: void 0
|
|
5755
|
-
},
|
|
5756
|
-
expand: config.snapshotOptions.expand ?? coreConfig.snapshotOptions.expand
|
|
5936
|
+
updateSnapshot: globalConfig.snapshotOptions.updateSnapshot,
|
|
5937
|
+
snapshotFormat: { ...globalConfig.snapshotOptions.snapshotFormat },
|
|
5938
|
+
expand: config.snapshotOptions.expand ?? globalConfig.snapshotOptions.expand
|
|
5757
5939
|
},
|
|
5758
5940
|
sequence: {
|
|
5759
|
-
shuffle:
|
|
5760
|
-
concurrent:
|
|
5761
|
-
seed:
|
|
5762
|
-
hooks:
|
|
5763
|
-
setupFiles:
|
|
5941
|
+
shuffle: globalConfig.sequence.shuffle,
|
|
5942
|
+
concurrent: globalConfig.sequence.concurrent,
|
|
5943
|
+
seed: globalConfig.sequence.seed,
|
|
5944
|
+
hooks: globalConfig.sequence.hooks,
|
|
5945
|
+
setupFiles: globalConfig.sequence.setupFiles
|
|
5764
5946
|
},
|
|
5765
|
-
inspect:
|
|
5766
|
-
inspectBrk:
|
|
5767
|
-
inspector:
|
|
5947
|
+
inspect: globalConfig.inspect,
|
|
5948
|
+
inspectBrk: globalConfig.inspectBrk,
|
|
5949
|
+
inspector: globalConfig.inspector,
|
|
5768
5950
|
watch: config.watch,
|
|
5769
|
-
includeTaskLocation: config.includeTaskLocation ??
|
|
5951
|
+
includeTaskLocation: config.includeTaskLocation ?? globalConfig.includeTaskLocation,
|
|
5770
5952
|
env: {
|
|
5771
5953
|
...viteConfig?.env,
|
|
5772
5954
|
...config.env
|
|
5773
5955
|
},
|
|
5774
5956
|
browser: ((browser) => {
|
|
5957
|
+
const provider = project.browser?.provider;
|
|
5775
5958
|
return {
|
|
5776
5959
|
name: browser.name,
|
|
5777
5960
|
headless: browser.headless,
|
|
@@ -5781,12 +5964,14 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5781
5964
|
viewport: browser.viewport,
|
|
5782
5965
|
screenshotFailures: browser.screenshotFailures,
|
|
5783
5966
|
locators: { testIdAttribute: browser.locators.testIdAttribute },
|
|
5784
|
-
providerOptions:
|
|
5967
|
+
providerOptions: provider?.name === "playwright" ? { actionTimeout: provider?.options?.actionTimeout } : {},
|
|
5968
|
+
trackUnhandledErrors: browser.trackUnhandledErrors ?? true
|
|
5785
5969
|
};
|
|
5786
5970
|
})(config.browser),
|
|
5787
5971
|
standalone: config.standalone,
|
|
5788
|
-
printConsoleTrace: config.printConsoleTrace ??
|
|
5789
|
-
benchmark: config.benchmark && { includeSamples: config.benchmark.includeSamples }
|
|
5972
|
+
printConsoleTrace: config.printConsoleTrace ?? globalConfig.printConsoleTrace,
|
|
5973
|
+
benchmark: config.benchmark && { includeSamples: config.benchmark.includeSamples },
|
|
5974
|
+
serializedDefines: config.browser.enabled ? "" : project._serializedDefines || ""
|
|
5790
5975
|
};
|
|
5791
5976
|
}
|
|
5792
5977
|
|
|
@@ -5795,7 +5980,7 @@ async function loadGlobalSetupFiles(runner, globalSetup) {
|
|
|
5795
5980
|
return Promise.all(globalSetupFiles.map((file) => loadGlobalSetupFile(file, runner)));
|
|
5796
5981
|
}
|
|
5797
5982
|
async function loadGlobalSetupFile(file, runner) {
|
|
5798
|
-
const m = await runner.
|
|
5983
|
+
const m = await runner.import(file);
|
|
5799
5984
|
for (const exp of [
|
|
5800
5985
|
"default",
|
|
5801
5986
|
"setup",
|
|
@@ -5805,211 +5990,24 @@ async function loadGlobalSetupFile(file, runner) {
|
|
|
5805
5990
|
file,
|
|
5806
5991
|
setup: m.default
|
|
5807
5992
|
};
|
|
5808
|
-
|
|
5993
|
+
if (m.setup || m.teardown) return {
|
|
5809
5994
|
file,
|
|
5810
5995
|
setup: m.setup,
|
|
5811
5996
|
teardown: m.teardown
|
|
5812
5997
|
};
|
|
5813
|
-
|
|
5998
|
+
throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
|
|
5814
5999
|
}
|
|
5815
6000
|
|
|
5816
6001
|
function CoverageTransform(ctx) {
|
|
5817
6002
|
return {
|
|
5818
6003
|
name: "vitest:coverage-transform",
|
|
6004
|
+
enforce: "post",
|
|
5819
6005
|
transform(srcCode, id) {
|
|
5820
|
-
return ctx.coverageProvider?.onFileTransform?.(srcCode,
|
|
5821
|
-
}
|
|
5822
|
-
};
|
|
5823
|
-
}
|
|
5824
|
-
|
|
5825
|
-
function MocksPlugins(options = {}) {
|
|
5826
|
-
const normalizedDistDir = normalize(distDir);
|
|
5827
|
-
return [hoistMocksPlugin({
|
|
5828
|
-
filter(id) {
|
|
5829
|
-
if (id.includes(normalizedDistDir)) return false;
|
|
5830
|
-
if (options.filter) return options.filter(id);
|
|
5831
|
-
return true;
|
|
5832
|
-
},
|
|
5833
|
-
codeFrameGenerator(node, id, code) {
|
|
5834
|
-
return generateCodeFrame(code, 4, node.start + 1);
|
|
5835
|
-
}
|
|
5836
|
-
}), automockPlugin()];
|
|
5837
|
-
}
|
|
5838
|
-
|
|
5839
|
-
function generateCssFilenameHash(filepath) {
|
|
5840
|
-
return hash("sha1", filepath, "hex").slice(0, 6);
|
|
5841
|
-
}
|
|
5842
|
-
function generateScopedClassName(strategy, name, filename) {
|
|
5843
|
-
// should be configured by Vite defaults
|
|
5844
|
-
if (strategy === "scoped") return null;
|
|
5845
|
-
if (strategy === "non-scoped") return name;
|
|
5846
|
-
const hash = generateCssFilenameHash(filename);
|
|
5847
|
-
return `_${name}_${hash}`;
|
|
5848
|
-
}
|
|
5849
|
-
|
|
5850
|
-
const LogLevels = {
|
|
5851
|
-
silent: 0,
|
|
5852
|
-
error: 1,
|
|
5853
|
-
warn: 2,
|
|
5854
|
-
info: 3
|
|
5855
|
-
};
|
|
5856
|
-
function clearScreen(logger) {
|
|
5857
|
-
const repeatCount = process.stdout.rows - 2;
|
|
5858
|
-
const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
|
|
5859
|
-
logger.clearScreen(blank);
|
|
5860
|
-
}
|
|
5861
|
-
let lastType;
|
|
5862
|
-
let lastMsg;
|
|
5863
|
-
let sameCount = 0;
|
|
5864
|
-
// Only initialize the timeFormatter when the timestamp option is used, and
|
|
5865
|
-
// reuse it across all loggers
|
|
5866
|
-
let timeFormatter;
|
|
5867
|
-
function getTimeFormatter() {
|
|
5868
|
-
timeFormatter ??= new Intl.DateTimeFormat(void 0, {
|
|
5869
|
-
hour: "numeric",
|
|
5870
|
-
minute: "numeric",
|
|
5871
|
-
second: "numeric"
|
|
5872
|
-
});
|
|
5873
|
-
return timeFormatter;
|
|
5874
|
-
}
|
|
5875
|
-
// This is copy-pasted and needs to be synced from time to time. Ideally, Vite's `createLogger` should accept a custom `console`
|
|
5876
|
-
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/logger.ts?rgh-link-date=2024-10-16T23%3A29%3A19Z
|
|
5877
|
-
// When Vitest supports only Vite 6 and above, we can use Vite's `createLogger({ console })`
|
|
5878
|
-
// https://github.com/vitejs/vite/pull/18379
|
|
5879
|
-
function createViteLogger(console, level = "info", options = {}) {
|
|
5880
|
-
const loggedErrors = /* @__PURE__ */ new WeakSet();
|
|
5881
|
-
const { prefix = "[vite]", allowClearScreen = true } = options;
|
|
5882
|
-
const thresh = LogLevels[level];
|
|
5883
|
-
const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
|
|
5884
|
-
const clear = canClearScreen ? clearScreen : () => {};
|
|
5885
|
-
function format(type, msg, options = {}) {
|
|
5886
|
-
if (options.timestamp) {
|
|
5887
|
-
let tag = "";
|
|
5888
|
-
if (type === "info") tag = c.cyan(c.bold(prefix));
|
|
5889
|
-
else if (type === "warn") tag = c.yellow(c.bold(prefix));
|
|
5890
|
-
else tag = c.red(c.bold(prefix));
|
|
5891
|
-
const environment = options.environment ? `${options.environment} ` : "";
|
|
5892
|
-
return `${c.dim(getTimeFormatter().format(/* @__PURE__ */ new Date()))} ${tag} ${environment}${msg}`;
|
|
5893
|
-
} else return msg;
|
|
5894
|
-
}
|
|
5895
|
-
function output(type, msg, options = {}) {
|
|
5896
|
-
if (thresh >= LogLevels[type]) {
|
|
5897
|
-
const method = type === "info" ? "log" : type;
|
|
5898
|
-
if (options.error) loggedErrors.add(options.error);
|
|
5899
|
-
if (canClearScreen) if (type === lastType && msg === lastMsg) {
|
|
5900
|
-
sameCount++;
|
|
5901
|
-
clear(console);
|
|
5902
|
-
console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
|
|
5903
|
-
} else {
|
|
5904
|
-
sameCount = 0;
|
|
5905
|
-
lastMsg = msg;
|
|
5906
|
-
lastType = type;
|
|
5907
|
-
if (options.clear) clear(console);
|
|
5908
|
-
console[method](format(type, msg, options));
|
|
5909
|
-
}
|
|
5910
|
-
else console[method](format(type, msg, options));
|
|
5911
|
-
}
|
|
5912
|
-
}
|
|
5913
|
-
const warnedMessages = /* @__PURE__ */ new Set();
|
|
5914
|
-
const logger = {
|
|
5915
|
-
hasWarned: false,
|
|
5916
|
-
info(msg, opts) {
|
|
5917
|
-
output("info", msg, opts);
|
|
5918
|
-
},
|
|
5919
|
-
warn(msg, opts) {
|
|
5920
|
-
logger.hasWarned = true;
|
|
5921
|
-
output("warn", msg, opts);
|
|
5922
|
-
},
|
|
5923
|
-
warnOnce(msg, opts) {
|
|
5924
|
-
if (warnedMessages.has(msg)) return;
|
|
5925
|
-
logger.hasWarned = true;
|
|
5926
|
-
output("warn", msg, opts);
|
|
5927
|
-
warnedMessages.add(msg);
|
|
5928
|
-
},
|
|
5929
|
-
error(msg, opts) {
|
|
5930
|
-
logger.hasWarned = true;
|
|
5931
|
-
output("error", msg, opts);
|
|
5932
|
-
},
|
|
5933
|
-
clearScreen(type) {
|
|
5934
|
-
if (thresh >= LogLevels[type]) clear(console);
|
|
5935
|
-
},
|
|
5936
|
-
hasErrorLogged(error) {
|
|
5937
|
-
return loggedErrors.has(error);
|
|
5938
|
-
}
|
|
5939
|
-
};
|
|
5940
|
-
return logger;
|
|
5941
|
-
}
|
|
5942
|
-
// silence warning by Vite for statically not analyzable dynamic import
|
|
5943
|
-
function silenceImportViteIgnoreWarning(logger) {
|
|
5944
|
-
return {
|
|
5945
|
-
...logger,
|
|
5946
|
-
warn(msg, options) {
|
|
5947
|
-
if (msg.includes("The above dynamic import cannot be analyzed by Vite")) return;
|
|
5948
|
-
logger.warn(msg, options);
|
|
6006
|
+
return ctx.coverageProvider?.onFileTransform?.(srcCode, id, this);
|
|
5949
6007
|
}
|
|
5950
6008
|
};
|
|
5951
6009
|
}
|
|
5952
6010
|
|
|
5953
|
-
const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)";
|
|
5954
|
-
const cssLangRE = new RegExp(cssLangs);
|
|
5955
|
-
const cssModuleRE = new RegExp(`\\.module${cssLangs}`);
|
|
5956
|
-
const cssInlineRE = /[?&]inline(?:&|$)/;
|
|
5957
|
-
function isCSS(id) {
|
|
5958
|
-
return cssLangRE.test(id);
|
|
5959
|
-
}
|
|
5960
|
-
function isCSSModule(id) {
|
|
5961
|
-
return cssModuleRE.test(id);
|
|
5962
|
-
}
|
|
5963
|
-
// inline css requests are expected to just return the
|
|
5964
|
-
// string content directly and not the proxy module
|
|
5965
|
-
function isInline(id) {
|
|
5966
|
-
return cssInlineRE.test(id);
|
|
5967
|
-
}
|
|
5968
|
-
function getCSSModuleProxyReturn(strategy, filename) {
|
|
5969
|
-
if (strategy === "non-scoped") return "style";
|
|
5970
|
-
const hash = generateCssFilenameHash(filename);
|
|
5971
|
-
return `\`_\${style}_${hash}\``;
|
|
5972
|
-
}
|
|
5973
|
-
function CSSEnablerPlugin(ctx) {
|
|
5974
|
-
const shouldProcessCSS = (id) => {
|
|
5975
|
-
const { css } = ctx.config;
|
|
5976
|
-
if (typeof css === "boolean") return css;
|
|
5977
|
-
if (toArray(css.exclude).some((re) => re.test(id))) return false;
|
|
5978
|
-
if (toArray(css.include).some((re) => re.test(id))) return true;
|
|
5979
|
-
return false;
|
|
5980
|
-
};
|
|
5981
|
-
return [{
|
|
5982
|
-
name: "vitest:css-disable",
|
|
5983
|
-
enforce: "pre",
|
|
5984
|
-
transform(code, id) {
|
|
5985
|
-
if (!isCSS(id)) return;
|
|
5986
|
-
// css plugin inside Vite won't do anything if the code is empty
|
|
5987
|
-
// but it will put __vite__updateStyle anyway
|
|
5988
|
-
if (!shouldProcessCSS(id)) return { code: "" };
|
|
5989
|
-
}
|
|
5990
|
-
}, {
|
|
5991
|
-
name: "vitest:css-empty-post",
|
|
5992
|
-
enforce: "post",
|
|
5993
|
-
transform(_, id) {
|
|
5994
|
-
if (!isCSS(id) || shouldProcessCSS(id)) return;
|
|
5995
|
-
if (isCSSModule(id) && !isInline(id)) {
|
|
5996
|
-
// return proxy for css modules, so that imported module has names:
|
|
5997
|
-
// styles.foo returns a "foo" instead of "undefined"
|
|
5998
|
-
// we don't use code content to generate hash for "scoped", because it's empty
|
|
5999
|
-
const scopeStrategy = typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable";
|
|
6000
|
-
const proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id));
|
|
6001
|
-
const code = `export default new Proxy(Object.create(null), {
|
|
6002
|
-
get(_, style) {
|
|
6003
|
-
return ${proxyReturn};
|
|
6004
|
-
},
|
|
6005
|
-
})`;
|
|
6006
|
-
return { code };
|
|
6007
|
-
}
|
|
6008
|
-
return { code: "export default \"\"" };
|
|
6009
|
-
}
|
|
6010
|
-
}];
|
|
6011
|
-
}
|
|
6012
|
-
|
|
6013
6011
|
var jsTokens_1;
|
|
6014
6012
|
var hasRequiredJsTokens;
|
|
6015
6013
|
|
|
@@ -6494,66 +6492,244 @@ function stripLiteralDetailed(code, options) {
|
|
|
6494
6492
|
return stripLiteralJsTokens(code);
|
|
6495
6493
|
}
|
|
6496
6494
|
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
// This makes "href" equal to "http://localhost:3000/path.js" in the browser, but if we keep it like this,
|
|
6501
|
-
// then in tests the URL will become "file:///path.js".
|
|
6502
|
-
// To battle this, we replace "import.meta.url" with "self.location" in the code to keep the browser behavior.
|
|
6503
|
-
function NormalizeURLPlugin() {
|
|
6495
|
+
// so people can reassign envs at runtime
|
|
6496
|
+
// import.meta.env.VITE_NAME = 'app' -> process.env.VITE_NAME = 'app'
|
|
6497
|
+
function MetaEnvReplacerPlugin() {
|
|
6504
6498
|
return {
|
|
6505
|
-
name: "vitest:
|
|
6506
|
-
enforce: "
|
|
6507
|
-
transform(code, id
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
const
|
|
6511
|
-
const
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
while (match = assetImportMetaUrlRE.exec(cleanString)) {
|
|
6516
|
-
const { 0: exp, index } = match;
|
|
6517
|
-
const metaUrlIndex = index + exp.indexOf("import.meta.url");
|
|
6518
|
-
updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength);
|
|
6499
|
+
name: "vitest:meta-env-replacer",
|
|
6500
|
+
enforce: "pre",
|
|
6501
|
+
transform(code, id) {
|
|
6502
|
+
if (!/\bimport\.meta\.env\b/.test(code)) return null;
|
|
6503
|
+
let s = null;
|
|
6504
|
+
const cleanCode = stripLiteral(code), envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
|
|
6505
|
+
for (const env of envs) {
|
|
6506
|
+
s ||= new MagicString(code);
|
|
6507
|
+
const startIndex = env.index, endIndex = startIndex + env[0].length;
|
|
6508
|
+
s.overwrite(startIndex, endIndex, `Object.assign(/* istanbul ignore next */ globalThis.__vitest_worker__?.metaEnv ?? import.meta.env)`);
|
|
6519
6509
|
}
|
|
6520
|
-
return {
|
|
6521
|
-
code:
|
|
6522
|
-
map:
|
|
6510
|
+
if (s) return {
|
|
6511
|
+
code: s.toString(),
|
|
6512
|
+
map: s.generateMap({
|
|
6513
|
+
hires: "boundary",
|
|
6514
|
+
source: cleanUrl(id)
|
|
6515
|
+
})
|
|
6523
6516
|
};
|
|
6524
6517
|
}
|
|
6525
6518
|
};
|
|
6526
6519
|
}
|
|
6527
6520
|
|
|
6528
|
-
function
|
|
6529
|
-
const
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6521
|
+
function MocksPlugins(options = {}) {
|
|
6522
|
+
const normalizedDistDir = normalize(distDir);
|
|
6523
|
+
return [hoistMocksPlugin({
|
|
6524
|
+
filter(id) {
|
|
6525
|
+
return id.includes(normalizedDistDir) ? false : options.filter ? options.filter(id) : true;
|
|
6526
|
+
},
|
|
6527
|
+
codeFrameGenerator(node, id, code) {
|
|
6528
|
+
return generateCodeFrame(code, 4, node.start + 1);
|
|
6529
|
+
}
|
|
6530
|
+
}), automockPlugin()];
|
|
6531
|
+
}
|
|
6532
|
+
|
|
6533
|
+
function generateCssFilenameHash(filepath) {
|
|
6534
|
+
return hash("sha1", filepath, "hex").slice(0, 6);
|
|
6535
|
+
}
|
|
6536
|
+
function generateScopedClassName(strategy, name, filename) {
|
|
6537
|
+
// should be configured by Vite defaults
|
|
6538
|
+
if (strategy === "scoped") return null;
|
|
6539
|
+
if (strategy === "non-scoped") return name;
|
|
6540
|
+
const hash = generateCssFilenameHash(filename);
|
|
6541
|
+
return `_${name}_${hash}`;
|
|
6542
|
+
}
|
|
6543
|
+
|
|
6544
|
+
const LogLevels = {
|
|
6545
|
+
silent: 0,
|
|
6546
|
+
error: 1,
|
|
6547
|
+
warn: 2,
|
|
6548
|
+
info: 3
|
|
6549
|
+
};
|
|
6550
|
+
function clearScreen(logger) {
|
|
6551
|
+
const repeatCount = process.stdout.rows - 2, blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
|
|
6552
|
+
logger.clearScreen(blank);
|
|
6553
|
+
}
|
|
6554
|
+
let lastType, lastMsg, sameCount = 0, timeFormatter;
|
|
6555
|
+
function getTimeFormatter() {
|
|
6556
|
+
return timeFormatter ??= new Intl.DateTimeFormat(void 0, {
|
|
6557
|
+
hour: "numeric",
|
|
6558
|
+
minute: "numeric",
|
|
6559
|
+
second: "numeric"
|
|
6560
|
+
}), timeFormatter;
|
|
6561
|
+
}
|
|
6562
|
+
// This is copy-pasted and needs to be synced from time to time. Ideally, Vite's `createLogger` should accept a custom `console`
|
|
6563
|
+
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/logger.ts?rgh-link-date=2024-10-16T23%3A29%3A19Z
|
|
6564
|
+
// When Vitest supports only Vite 6 and above, we can use Vite's `createLogger({ console })`
|
|
6565
|
+
// https://github.com/vitejs/vite/pull/18379
|
|
6566
|
+
function createViteLogger(console, level = "info", options = {}) {
|
|
6567
|
+
const loggedErrors = /* @__PURE__ */ new WeakSet(), { prefix = "[vite]", allowClearScreen = true } = options, thresh = LogLevels[level], canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI, clear = canClearScreen ? clearScreen : () => {};
|
|
6568
|
+
function format(type, msg, options = {}) {
|
|
6569
|
+
if (options.timestamp) {
|
|
6570
|
+
let tag = "";
|
|
6571
|
+
if (type === "info") tag = c.cyan(c.bold(prefix));
|
|
6572
|
+
else if (type === "warn") tag = c.yellow(c.bold(prefix));
|
|
6573
|
+
else tag = c.red(c.bold(prefix));
|
|
6574
|
+
const environment = options.environment ? `${options.environment} ` : "";
|
|
6575
|
+
return `${c.dim(getTimeFormatter().format(/* @__PURE__ */ new Date()))} ${tag} ${environment}${msg}`;
|
|
6576
|
+
} else return msg;
|
|
6577
|
+
}
|
|
6578
|
+
function output(type, msg, options = {}) {
|
|
6579
|
+
if (thresh >= LogLevels[type]) {
|
|
6580
|
+
const method = type === "info" ? "log" : type;
|
|
6581
|
+
if (options.error) loggedErrors.add(options.error);
|
|
6582
|
+
if (canClearScreen) if (type === lastType && msg === lastMsg) sameCount++, clear(console), console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
|
|
6583
|
+
else {
|
|
6584
|
+
if (sameCount = 0, lastMsg = msg, lastType = type, options.clear) clear(console);
|
|
6585
|
+
console[method](format(type, msg, options));
|
|
6586
|
+
}
|
|
6587
|
+
else console[method](format(type, msg, options));
|
|
6588
|
+
}
|
|
6589
|
+
}
|
|
6590
|
+
const warnedMessages = /* @__PURE__ */ new Set(), logger = {
|
|
6591
|
+
hasWarned: false,
|
|
6592
|
+
info(msg, opts) {
|
|
6593
|
+
output("info", msg, opts);
|
|
6594
|
+
},
|
|
6595
|
+
warn(msg, opts) {
|
|
6596
|
+
logger.hasWarned = true, output("warn", msg, opts);
|
|
6597
|
+
},
|
|
6598
|
+
warnOnce(msg, opts) {
|
|
6599
|
+
warnedMessages.has(msg) || (logger.hasWarned = true, output("warn", msg, opts), warnedMessages.add(msg));
|
|
6600
|
+
},
|
|
6601
|
+
error(msg, opts) {
|
|
6602
|
+
logger.hasWarned = true, output("error", msg, opts);
|
|
6603
|
+
},
|
|
6604
|
+
clearScreen(type) {
|
|
6605
|
+
if (thresh >= LogLevels[type]) clear(console);
|
|
6606
|
+
},
|
|
6607
|
+
hasErrorLogged(error) {
|
|
6608
|
+
return loggedErrors.has(error);
|
|
6609
|
+
}
|
|
6610
|
+
};
|
|
6611
|
+
return logger;
|
|
6612
|
+
}
|
|
6613
|
+
// silence warning by Vite for statically not analyzable dynamic import
|
|
6614
|
+
function silenceImportViteIgnoreWarning(logger) {
|
|
6615
|
+
return {
|
|
6616
|
+
...logger,
|
|
6617
|
+
warn(msg, options) {
|
|
6618
|
+
msg.includes("The above dynamic import cannot be analyzed by Vite") || logger.warn(msg, options);
|
|
6619
|
+
}
|
|
6620
|
+
};
|
|
6621
|
+
}
|
|
6622
|
+
|
|
6623
|
+
const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)", cssLangRE = new RegExp(cssLangs), cssModuleRE = /* @__PURE__ */ new RegExp(`\\.module${cssLangs}`), cssInlineRE = /[?&]inline(?:&|$)/;
|
|
6624
|
+
function isCSS(id) {
|
|
6625
|
+
return cssLangRE.test(id);
|
|
6626
|
+
}
|
|
6627
|
+
function isCSSModule(id) {
|
|
6628
|
+
return cssModuleRE.test(id);
|
|
6629
|
+
}
|
|
6630
|
+
// inline css requests are expected to just return the
|
|
6631
|
+
// string content directly and not the proxy module
|
|
6632
|
+
function isInline(id) {
|
|
6633
|
+
return cssInlineRE.test(id);
|
|
6634
|
+
}
|
|
6635
|
+
function getCSSModuleProxyReturn(strategy, filename) {
|
|
6636
|
+
if (strategy === "non-scoped") return "style";
|
|
6637
|
+
const hash = generateCssFilenameHash(filename);
|
|
6638
|
+
return `\`_\${style}_${hash}\``;
|
|
6639
|
+
}
|
|
6640
|
+
function CSSEnablerPlugin(ctx) {
|
|
6641
|
+
const shouldProcessCSS = (id) => {
|
|
6642
|
+
const { css } = ctx.config;
|
|
6643
|
+
return typeof css === "boolean" ? css : toArray(css.exclude).some((re) => re.test(id)) ? false : !!toArray(css.include).some((re) => re.test(id));
|
|
6644
|
+
};
|
|
6645
|
+
return [{
|
|
6646
|
+
name: "vitest:css-disable",
|
|
6647
|
+
enforce: "pre",
|
|
6648
|
+
transform(code, id) {
|
|
6649
|
+
if (isCSS(id) && !shouldProcessCSS(id)) return { code: "" };
|
|
6650
|
+
}
|
|
6651
|
+
}, {
|
|
6652
|
+
name: "vitest:css-empty-post",
|
|
6653
|
+
enforce: "post",
|
|
6654
|
+
transform(_, id) {
|
|
6655
|
+
if (!(!isCSS(id) || shouldProcessCSS(id))) {
|
|
6656
|
+
if (isCSSModule(id) && !isInline(id)) {
|
|
6657
|
+
// return proxy for css modules, so that imported module has names:
|
|
6658
|
+
// styles.foo returns a "foo" instead of "undefined"
|
|
6659
|
+
// we don't use code content to generate hash for "scoped", because it's empty
|
|
6660
|
+
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), {
|
|
6661
|
+
get(_, style) {
|
|
6662
|
+
return ${proxyReturn};
|
|
6663
|
+
},
|
|
6664
|
+
})`;
|
|
6665
|
+
return { code };
|
|
6666
|
+
}
|
|
6667
|
+
return { code: "export default \"\"" };
|
|
6668
|
+
}
|
|
6669
|
+
}
|
|
6670
|
+
}];
|
|
6671
|
+
}
|
|
6672
|
+
|
|
6673
|
+
const metaUrlLength = 15, locationString = "self.location".padEnd(metaUrlLength, " ");
|
|
6674
|
+
// Vite transforms new URL('./path', import.meta.url) to new URL('/path.js', import.meta.url)
|
|
6675
|
+
// This makes "href" equal to "http://localhost:3000/path.js" in the browser, but if we keep it like this,
|
|
6676
|
+
// then in tests the URL will become "file:///path.js".
|
|
6677
|
+
// To battle this, we replace "import.meta.url" with "self.location" in the code to keep the browser behavior.
|
|
6678
|
+
function NormalizeURLPlugin() {
|
|
6679
|
+
return {
|
|
6680
|
+
name: "vitest:normalize-url",
|
|
6681
|
+
enforce: "post",
|
|
6682
|
+
transform(code) {
|
|
6683
|
+
if (this.environment.name !== "client" || !code.includes("new URL") || !code.includes("import.meta.url")) return;
|
|
6684
|
+
const cleanString = stripLiteral(code), assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*(?:'' \+ )?import\.meta\.url\s*(?:,\s*)?\)/g;
|
|
6685
|
+
let updatedCode = code, match;
|
|
6686
|
+
// eslint-disable-next-line no-cond-assign
|
|
6687
|
+
while (match = assetImportMetaUrlRE.exec(cleanString)) {
|
|
6688
|
+
const { 0: exp, index } = match, metaUrlIndex = index + exp.indexOf("import.meta.url");
|
|
6689
|
+
updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength);
|
|
6690
|
+
}
|
|
6691
|
+
return {
|
|
6692
|
+
code: updatedCode,
|
|
6693
|
+
map: null
|
|
6694
|
+
};
|
|
6695
|
+
}
|
|
6696
|
+
};
|
|
6697
|
+
}
|
|
6698
|
+
|
|
6699
|
+
function VitestOptimizer() {
|
|
6700
|
+
return {
|
|
6701
|
+
name: "vitest:normalize-optimizer",
|
|
6702
|
+
config: {
|
|
6703
|
+
order: "post",
|
|
6704
|
+
handler(viteConfig) {
|
|
6705
|
+
const testConfig = viteConfig.test || {}, root = resolve(viteConfig.root || process.cwd()), name = viteConfig.test?.name, label = typeof name === "string" ? name : name?.label || "";
|
|
6706
|
+
viteConfig.cacheDir = VitestCache.resolveCacheDir(resolve(root || process.cwd()), testConfig.cache != null && testConfig.cache !== false ? testConfig.cache.dir : viteConfig.cacheDir, label);
|
|
6707
|
+
}
|
|
6708
|
+
}
|
|
6709
|
+
};
|
|
6710
|
+
}
|
|
6711
|
+
|
|
6712
|
+
function resolveOptimizerConfig(_testOptions, viteOptions) {
|
|
6713
|
+
const testOptions = _testOptions || {};
|
|
6714
|
+
let optimizeDeps;
|
|
6715
|
+
if (testOptions.enabled !== true) testOptions.enabled ??= false, optimizeDeps = {
|
|
6716
|
+
disabled: true,
|
|
6717
|
+
entries: []
|
|
6718
|
+
};
|
|
6719
|
+
else {
|
|
6720
|
+
const currentInclude = testOptions.include || viteOptions?.include || [], exclude = [
|
|
6721
|
+
"vitest",
|
|
6722
|
+
"react",
|
|
6723
|
+
"vue",
|
|
6724
|
+
...testOptions.exclude || viteOptions?.exclude || []
|
|
6725
|
+
], runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
|
|
6726
|
+
exclude.push(...runtime);
|
|
6727
|
+
const include = (testOptions.include || viteOptions?.include || []).filter((n) => !exclude.includes(n));
|
|
6728
|
+
optimizeDeps = {
|
|
6729
|
+
...viteOptions,
|
|
6730
|
+
...testOptions,
|
|
6731
|
+
noDiscovery: true,
|
|
6732
|
+
disabled: false,
|
|
6557
6733
|
entries: [],
|
|
6558
6734
|
exclude,
|
|
6559
6735
|
include
|
|
@@ -6561,23 +6737,12 @@ function resolveOptimizerConfig(_testOptions, viteOptions) {
|
|
|
6561
6737
|
}
|
|
6562
6738
|
// `optimizeDeps.disabled` is deprecated since v5.1.0-beta.1
|
|
6563
6739
|
// https://github.com/vitejs/vite/pull/15184
|
|
6564
|
-
if (
|
|
6565
|
-
|
|
6566
|
-
newConfig.optimizeDeps.noDiscovery = true;
|
|
6567
|
-
newConfig.optimizeDeps.include = [];
|
|
6568
|
-
}
|
|
6569
|
-
delete newConfig.optimizeDeps.disabled;
|
|
6570
|
-
}
|
|
6571
|
-
return newConfig;
|
|
6740
|
+
if (optimizeDeps.disabled) optimizeDeps.noDiscovery = true, optimizeDeps.include = [];
|
|
6741
|
+
return delete optimizeDeps.disabled, optimizeDeps;
|
|
6572
6742
|
}
|
|
6573
6743
|
function deleteDefineConfig(viteConfig) {
|
|
6574
6744
|
const defines = {};
|
|
6575
|
-
if (viteConfig.define)
|
|
6576
|
-
delete viteConfig.define["import.meta.vitest"];
|
|
6577
|
-
delete viteConfig.define["process.env"];
|
|
6578
|
-
delete viteConfig.define.process;
|
|
6579
|
-
delete viteConfig.define.global;
|
|
6580
|
-
}
|
|
6745
|
+
if (viteConfig.define) delete viteConfig.define["import.meta.vitest"], delete viteConfig.define["process.env"], delete viteConfig.define.process, delete viteConfig.define.global;
|
|
6581
6746
|
for (const key in viteConfig.define) {
|
|
6582
6747
|
const val = viteConfig.define[key];
|
|
6583
6748
|
let replacement;
|
|
@@ -6590,26 +6755,20 @@ function deleteDefineConfig(viteConfig) {
|
|
|
6590
6755
|
}
|
|
6591
6756
|
if (key.startsWith("import.meta.env.")) {
|
|
6592
6757
|
const envKey = key.slice(16);
|
|
6593
|
-
process.env[envKey] = replacement;
|
|
6594
|
-
delete viteConfig.define[key];
|
|
6758
|
+
process.env[envKey] = replacement, delete viteConfig.define[key];
|
|
6595
6759
|
} else if (key.startsWith("process.env.")) {
|
|
6596
6760
|
const envKey = key.slice(12);
|
|
6597
|
-
process.env[envKey] = replacement;
|
|
6598
|
-
|
|
6599
|
-
} else if (!key.includes(".")) {
|
|
6600
|
-
defines[key] = replacement;
|
|
6601
|
-
delete viteConfig.define[key];
|
|
6602
|
-
}
|
|
6761
|
+
process.env[envKey] = replacement, delete viteConfig.define[key];
|
|
6762
|
+
} else if (!key.includes(".")) defines[key] = replacement, delete viteConfig.define[key];
|
|
6603
6763
|
}
|
|
6604
6764
|
return defines;
|
|
6605
6765
|
}
|
|
6606
6766
|
function resolveFsAllow(projectRoot, rootConfigFile) {
|
|
6607
|
-
|
|
6608
|
-
return [
|
|
6767
|
+
return rootConfigFile ? [
|
|
6609
6768
|
dirname(rootConfigFile),
|
|
6610
6769
|
searchForWorkspaceRoot(projectRoot),
|
|
6611
6770
|
rootDir
|
|
6612
|
-
];
|
|
6771
|
+
] : [searchForWorkspaceRoot(projectRoot), rootDir];
|
|
6613
6772
|
}
|
|
6614
6773
|
function getDefaultResolveOptions() {
|
|
6615
6774
|
return {
|
|
@@ -6626,53 +6785,54 @@ function getDefaultServerConditions() {
|
|
|
6626
6785
|
return ["node"];
|
|
6627
6786
|
}
|
|
6628
6787
|
|
|
6629
|
-
function
|
|
6788
|
+
function ModuleRunnerTransform() {
|
|
6789
|
+
// make sure Vite always applies the module runner transform
|
|
6630
6790
|
return {
|
|
6631
|
-
name: "vitest:
|
|
6791
|
+
name: "vitest:environments-module-runner",
|
|
6632
6792
|
config: {
|
|
6633
6793
|
order: "post",
|
|
6634
|
-
handler(
|
|
6635
|
-
const testConfig =
|
|
6636
|
-
|
|
6637
|
-
const
|
|
6638
|
-
|
|
6639
|
-
const
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6794
|
+
handler(config) {
|
|
6795
|
+
const testConfig = config.test || {};
|
|
6796
|
+
config.environments ??= {};
|
|
6797
|
+
const names = new Set(Object.keys(config.environments));
|
|
6798
|
+
names.add("client"), names.add("ssr");
|
|
6799
|
+
const pool = config.test?.pool;
|
|
6800
|
+
if (pool === "vmForks" || pool === "vmThreads") names.add("__vitest_vm__");
|
|
6801
|
+
const external = [], noExternal = [];
|
|
6802
|
+
let noExternalAll;
|
|
6803
|
+
for (const name of names) {
|
|
6804
|
+
config.environments[name] ??= {};
|
|
6805
|
+
const environment = config.environments[name];
|
|
6806
|
+
// vm tests run using the native import mechanism
|
|
6807
|
+
if (environment.dev ??= {}, name === "__vitest_vm__") environment.dev.moduleRunnerTransform = false, environment.consumer = "client";
|
|
6808
|
+
else environment.dev.moduleRunnerTransform = true;
|
|
6809
|
+
environment.dev.preTransformRequests = false, environment.keepProcessEnv = true;
|
|
6810
|
+
const resolveExternal = name === "client" ? config.resolve?.external : [], resolveNoExternal = name === "client" ? config.resolve?.noExternal : [], topLevelResolveOptions = {};
|
|
6811
|
+
if (resolveExternal != null) topLevelResolveOptions.external = resolveExternal;
|
|
6812
|
+
if (resolveNoExternal != null) topLevelResolveOptions.noExternal = resolveNoExternal;
|
|
6813
|
+
const currentResolveOptions = mergeConfig(topLevelResolveOptions, environment.resolve || {}), envNoExternal = resolveViteResolveOptions("noExternal", currentResolveOptions);
|
|
6814
|
+
if (envNoExternal === true) noExternalAll = true;
|
|
6815
|
+
else noExternal.push(...envNoExternal);
|
|
6816
|
+
const envExternal = resolveViteResolveOptions("external", currentResolveOptions);
|
|
6817
|
+
if (envExternal !== true) external.push(...envExternal);
|
|
6818
|
+
if (environment.resolve ??= {}, environment.resolve.external = [...builtinModules, ...builtinModules.map((m) => `node:${m}`)], environment.resolve.noExternal = true, name === "__vitest_vm__" || name === "__vitest__") continue;
|
|
6819
|
+
const currentOptimizeDeps = environment.optimizeDeps || (name === "client" ? config.optimizeDeps : name === "ssr" ? config.ssr?.optimizeDeps : void 0), optimizeDeps = resolveOptimizerConfig(testConfig.deps?.optimizer?.[name], currentOptimizeDeps);
|
|
6820
|
+
// Vite respects the root level optimize deps, so we override it instead
|
|
6821
|
+
if (name === "client") config.optimizeDeps = optimizeDeps, environment.optimizeDeps = void 0;
|
|
6822
|
+
else if (name === "ssr") config.ssr ??= {}, config.ssr.optimizeDeps = optimizeDeps, environment.optimizeDeps = void 0;
|
|
6823
|
+
else environment.optimizeDeps = optimizeDeps;
|
|
6824
|
+
}
|
|
6825
|
+
if (testConfig.server ??= {}, testConfig.server.deps ??= {}, testConfig.server.deps.inline !== true) {
|
|
6826
|
+
if (noExternalAll) testConfig.server.deps.inline = true;
|
|
6827
|
+
else if (noExternal.length) testConfig.server.deps.inline ??= [], testConfig.server.deps.inline.push(...noExternal);
|
|
6828
|
+
}
|
|
6829
|
+
if (external.length) testConfig.server.deps.external ??= [], testConfig.server.deps.external.push(...external);
|
|
6645
6830
|
}
|
|
6646
6831
|
}
|
|
6647
6832
|
};
|
|
6648
6833
|
}
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
// import.meta.env.VITE_NAME = 'app' -> process.env.VITE_NAME = 'app'
|
|
6652
|
-
function SsrReplacerPlugin() {
|
|
6653
|
-
return {
|
|
6654
|
-
name: "vitest:ssr-replacer",
|
|
6655
|
-
enforce: "pre",
|
|
6656
|
-
transform(code, id) {
|
|
6657
|
-
if (!/\bimport\.meta\.env\b/.test(code)) return null;
|
|
6658
|
-
let s = null;
|
|
6659
|
-
const cleanCode = stripLiteral(code);
|
|
6660
|
-
const envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
|
|
6661
|
-
for (const env of envs) {
|
|
6662
|
-
s ||= new MagicString(code);
|
|
6663
|
-
const startIndex = env.index;
|
|
6664
|
-
const endIndex = startIndex + env[0].length;
|
|
6665
|
-
s.overwrite(startIndex, endIndex, "__vite_ssr_import_meta__.env");
|
|
6666
|
-
}
|
|
6667
|
-
if (s) return {
|
|
6668
|
-
code: s.toString(),
|
|
6669
|
-
map: s.generateMap({
|
|
6670
|
-
hires: "boundary",
|
|
6671
|
-
source: cleanUrl(id)
|
|
6672
|
-
})
|
|
6673
|
-
};
|
|
6674
|
-
}
|
|
6675
|
-
};
|
|
6834
|
+
function resolveViteResolveOptions(key, options) {
|
|
6835
|
+
return Array.isArray(options[key]) ? options[key] : typeof options[key] === "string" || options[key] instanceof RegExp ? [options[key]] : typeof options[key] === "boolean" ? true : [];
|
|
6676
6836
|
}
|
|
6677
6837
|
|
|
6678
6838
|
function VitestProjectResolver(ctx) {
|
|
@@ -6683,7 +6843,7 @@ function VitestProjectResolver(ctx) {
|
|
|
6683
6843
|
if (id === "vitest" || id.startsWith("@vitest/") || id.startsWith("vitest/")) {
|
|
6684
6844
|
// always redirect the request to the root vitest plugin since
|
|
6685
6845
|
// it will be the one used to run Vitest
|
|
6686
|
-
const resolved = await ctx.
|
|
6846
|
+
const resolved = await ctx.vite.pluginContainer.resolveId(id, void 0, {
|
|
6687
6847
|
skip: new Set([plugin]),
|
|
6688
6848
|
ssr
|
|
6689
6849
|
});
|
|
@@ -6719,23 +6879,16 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6719
6879
|
};
|
|
6720
6880
|
if (!name) if (typeof options.workspacePath === "string") {
|
|
6721
6881
|
// if there is a package.json, read the name from it
|
|
6722
|
-
const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath);
|
|
6723
|
-
const pkgJsonPath = resolve(dir, "package.json");
|
|
6882
|
+
const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath), pkgJsonPath = resolve(dir, "package.json");
|
|
6724
6883
|
if (existsSync(pkgJsonPath)) name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name;
|
|
6725
6884
|
if (typeof name !== "string" || !name) name = basename(dir);
|
|
6726
6885
|
} else name = options.workspacePath.toString();
|
|
6727
|
-
const isUserBrowserEnabled = viteConfig.test?.browser?.enabled;
|
|
6728
|
-
const isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled);
|
|
6729
|
-
// keep project names to potentially filter it out
|
|
6730
|
-
const workspaceNames = [name];
|
|
6731
|
-
const browser = viteConfig.test.browser || {};
|
|
6886
|
+
const isUserBrowserEnabled = viteConfig.test?.browser?.enabled, isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled), workspaceNames = [name], browser = viteConfig.test.browser || {};
|
|
6732
6887
|
if (isBrowserEnabled && browser.name && !browser.instances?.length)
|
|
6733
6888
|
// vitest injects `instances` in this case later on
|
|
6734
6889
|
workspaceNames.push(name ? `${name} (${browser.name})` : browser.name);
|
|
6735
6890
|
viteConfig.test?.browser?.instances?.forEach((instance) => {
|
|
6736
|
-
|
|
6737
|
-
instance.name ??= name ? `${name} (${instance.browser})` : instance.browser;
|
|
6738
|
-
if (isBrowserEnabled) workspaceNames.push(instance.name);
|
|
6891
|
+
if (instance.name ??= name ? `${name} (${instance.browser})` : instance.browser, isBrowserEnabled) workspaceNames.push(instance.name);
|
|
6739
6892
|
});
|
|
6740
6893
|
const filters = project.vitest.config.project;
|
|
6741
6894
|
// if there is `--project=...` filter, check if any of the potential projects match
|
|
@@ -6747,10 +6900,13 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6747
6900
|
});
|
|
6748
6901
|
if (!hasProject) throw new VitestFilteredOutProjectError();
|
|
6749
6902
|
}
|
|
6750
|
-
return {
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6903
|
+
return {
|
|
6904
|
+
environments: { __vitest__: { dev: {} } },
|
|
6905
|
+
test: { name: {
|
|
6906
|
+
label: name,
|
|
6907
|
+
color
|
|
6908
|
+
} }
|
|
6909
|
+
};
|
|
6754
6910
|
}
|
|
6755
6911
|
},
|
|
6756
6912
|
{
|
|
@@ -6760,22 +6916,14 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6760
6916
|
this.meta.watchMode = false;
|
|
6761
6917
|
},
|
|
6762
6918
|
config(viteConfig) {
|
|
6763
|
-
const defines = deleteDefineConfig(viteConfig);
|
|
6764
|
-
|
|
6765
|
-
const root = testConfig.root || viteConfig.root || options.root;
|
|
6766
|
-
const resolveOptions = getDefaultResolveOptions();
|
|
6767
|
-
const config = {
|
|
6919
|
+
const defines = deleteDefineConfig(viteConfig), testConfig = viteConfig.test || {}, root = testConfig.root || viteConfig.root || options.root, resolveOptions = getDefaultResolveOptions();
|
|
6920
|
+
let config = {
|
|
6768
6921
|
root,
|
|
6769
6922
|
define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
|
|
6770
6923
|
resolve: {
|
|
6771
6924
|
...resolveOptions,
|
|
6772
6925
|
alias: testConfig.alias
|
|
6773
6926
|
},
|
|
6774
|
-
esbuild: viteConfig.esbuild === false ? false : {
|
|
6775
|
-
target: viteConfig.esbuild?.target || "node18",
|
|
6776
|
-
sourcemap: "external",
|
|
6777
|
-
legalComments: "inline"
|
|
6778
|
-
},
|
|
6779
6927
|
server: {
|
|
6780
6928
|
watch: null,
|
|
6781
6929
|
open: false,
|
|
@@ -6788,19 +6936,27 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6788
6936
|
environments: { ssr: { resolve: resolveOptions } },
|
|
6789
6937
|
test: {}
|
|
6790
6938
|
};
|
|
6939
|
+
if ("rolldownVersion" in vite) config = {
|
|
6940
|
+
...config,
|
|
6941
|
+
oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
|
|
6942
|
+
};
|
|
6943
|
+
else config = {
|
|
6944
|
+
...config,
|
|
6945
|
+
esbuild: viteConfig.esbuild === false ? false : {
|
|
6946
|
+
target: viteConfig.esbuild?.target || "node18",
|
|
6947
|
+
sourcemap: "external",
|
|
6948
|
+
legalComments: "inline"
|
|
6949
|
+
}
|
|
6950
|
+
};
|
|
6791
6951
|
config.test.defines = defines;
|
|
6792
6952
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
6793
6953
|
if (classNameStrategy !== "scoped") {
|
|
6794
|
-
config.css ??= {}
|
|
6795
|
-
config.css.modules ??= {};
|
|
6796
|
-
if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
6954
|
+
if (config.css ??= {}, config.css.modules ??= {}, config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
6797
6955
|
const root = project.config.root;
|
|
6798
6956
|
return generateScopedClassName(classNameStrategy, name, relative(root, filename));
|
|
6799
6957
|
};
|
|
6800
6958
|
}
|
|
6801
|
-
config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
|
|
6802
|
-
config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
|
|
6803
|
-
return config;
|
|
6959
|
+
return config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false }), config.customLogger = silenceImportViteIgnoreWarning(config.customLogger), config;
|
|
6804
6960
|
}
|
|
6805
6961
|
},
|
|
6806
6962
|
{
|
|
@@ -6808,33 +6964,120 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6808
6964
|
enforce: "post",
|
|
6809
6965
|
async configureServer(server) {
|
|
6810
6966
|
const options = deepMerge({}, configDefaults, server.config.test || {});
|
|
6811
|
-
await project._configureServer(options, server);
|
|
6812
|
-
await server.watcher.close();
|
|
6967
|
+
await project._configureServer(options, server), await server.watcher.close();
|
|
6813
6968
|
}
|
|
6814
6969
|
},
|
|
6815
|
-
|
|
6970
|
+
MetaEnvReplacerPlugin(),
|
|
6816
6971
|
...CSSEnablerPlugin(project),
|
|
6817
6972
|
CoverageTransform(project.vitest),
|
|
6818
6973
|
...MocksPlugins(),
|
|
6819
6974
|
VitestProjectResolver(project.vitest),
|
|
6820
6975
|
VitestOptimizer(),
|
|
6821
|
-
NormalizeURLPlugin()
|
|
6976
|
+
NormalizeURLPlugin(),
|
|
6977
|
+
ModuleRunnerTransform()
|
|
6822
6978
|
];
|
|
6823
6979
|
}
|
|
6824
6980
|
|
|
6981
|
+
class VitestResolver {
|
|
6982
|
+
options;
|
|
6983
|
+
externalizeCache = /* @__PURE__ */ new Map();
|
|
6984
|
+
constructor(cacheDir, config) {
|
|
6985
|
+
this.options = {
|
|
6986
|
+
moduleDirectories: config.deps.moduleDirectories,
|
|
6987
|
+
inlineFiles: config.setupFiles.flatMap((file) => {
|
|
6988
|
+
if (file.startsWith("file://")) return file;
|
|
6989
|
+
const resolvedId = resolve(file);
|
|
6990
|
+
return [resolvedId, pathToFileURL(resolvedId).href];
|
|
6991
|
+
}),
|
|
6992
|
+
cacheDir,
|
|
6993
|
+
inline: config.server.deps?.inline,
|
|
6994
|
+
external: config.server.deps?.external
|
|
6995
|
+
};
|
|
6996
|
+
}
|
|
6997
|
+
shouldExternalize(file) {
|
|
6998
|
+
return shouldExternalize(normalizeId(file), this.options, this.externalizeCache);
|
|
6999
|
+
}
|
|
7000
|
+
}
|
|
7001
|
+
function normalizeId(id) {
|
|
7002
|
+
if (id.startsWith("/@fs/")) id = id.slice(isWindows ? 5 : 4);
|
|
7003
|
+
return id;
|
|
7004
|
+
}
|
|
7005
|
+
const BUILTIN_EXTENSIONS = new Set([
|
|
7006
|
+
".mjs",
|
|
7007
|
+
".cjs",
|
|
7008
|
+
".node",
|
|
7009
|
+
".wasm"
|
|
7010
|
+
]), ESM_EXT_RE = /\.(es|esm|esm-browser|esm-bundler|es6|module)\.js$/, ESM_FOLDER_RE = /\/(es|esm)\/(.*\.js)$/, defaultInline = [
|
|
7011
|
+
/virtual:/,
|
|
7012
|
+
/\.[mc]?ts$/,
|
|
7013
|
+
/[?&](init|raw|url|inline)\b/,
|
|
7014
|
+
KNOWN_ASSET_RE,
|
|
7015
|
+
/^(?!.*node_modules).*\.mjs$/,
|
|
7016
|
+
/^(?!.*node_modules).*\.cjs\.js$/,
|
|
7017
|
+
/vite\w*\/dist\/client\/env.mjs/
|
|
7018
|
+
], depsExternal = [/\/node_modules\/.*\.cjs\.js$/, /\/node_modules\/.*\.mjs$/];
|
|
7019
|
+
function guessCJSversion(id) {
|
|
7020
|
+
if (id.match(ESM_EXT_RE)) {
|
|
7021
|
+
for (const i of [
|
|
7022
|
+
id.replace(ESM_EXT_RE, ".mjs"),
|
|
7023
|
+
id.replace(ESM_EXT_RE, ".umd.js"),
|
|
7024
|
+
id.replace(ESM_EXT_RE, ".cjs.js"),
|
|
7025
|
+
id.replace(ESM_EXT_RE, ".js")
|
|
7026
|
+
]) if (existsSync(i)) return i;
|
|
7027
|
+
}
|
|
7028
|
+
if (id.match(ESM_FOLDER_RE)) {
|
|
7029
|
+
for (const i of [
|
|
7030
|
+
id.replace(ESM_FOLDER_RE, "/umd/$1"),
|
|
7031
|
+
id.replace(ESM_FOLDER_RE, "/cjs/$1"),
|
|
7032
|
+
id.replace(ESM_FOLDER_RE, "/lib/$1"),
|
|
7033
|
+
id.replace(ESM_FOLDER_RE, "/$1")
|
|
7034
|
+
]) if (existsSync(i)) return i;
|
|
7035
|
+
}
|
|
7036
|
+
}
|
|
7037
|
+
// The code from https://github.com/unjs/mlly/blob/c5bcca0cda175921344fd6de1bc0c499e73e5dac/src/syntax.ts#L51-L98
|
|
7038
|
+
async function isValidNodeImport(id) {
|
|
7039
|
+
const extension = extname(id);
|
|
7040
|
+
if (BUILTIN_EXTENSIONS.has(extension)) return true;
|
|
7041
|
+
if (extension !== ".js") return false;
|
|
7042
|
+
id = id.replace("file:///", "");
|
|
7043
|
+
const package_ = findNearestPackageData(dirname(id));
|
|
7044
|
+
if (package_.type === "module") return true;
|
|
7045
|
+
if (/\.(?:\w+-)?esm?(?:-\w+)?\.js$|\/esm?\//.test(id)) return false;
|
|
7046
|
+
try {
|
|
7047
|
+
await esModuleLexer.init;
|
|
7048
|
+
const code = await promises.readFile(id, "utf8"), [, , , hasModuleSyntax] = esModuleLexer.parse(code);
|
|
7049
|
+
return !hasModuleSyntax;
|
|
7050
|
+
} catch {
|
|
7051
|
+
return false;
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
async function shouldExternalize(id, options, cache) {
|
|
7055
|
+
if (!cache.has(id)) cache.set(id, _shouldExternalize(id, options));
|
|
7056
|
+
return cache.get(id);
|
|
7057
|
+
}
|
|
7058
|
+
async function _shouldExternalize(id, options) {
|
|
7059
|
+
// data: should be processed by native import,
|
|
7060
|
+
// since it is a feature of ESM.
|
|
7061
|
+
// also externalize network imports since nodejs allows it when --experimental-network-imports
|
|
7062
|
+
if (isBuiltin(id) || id.startsWith("data:") || /^(?:https?:)?\/\//.test(id)) return id;
|
|
7063
|
+
const moduleDirectories = options?.moduleDirectories || ["/node_modules/"];
|
|
7064
|
+
if (matchExternalizePattern(id, moduleDirectories, options?.inline) || options?.inlineFiles && options?.inlineFiles.includes(id)) return false;
|
|
7065
|
+
// Unless the user explicitly opted to inline them, externalize Vite deps.
|
|
7066
|
+
// They are too big to inline by default.
|
|
7067
|
+
if (matchExternalizePattern(id, moduleDirectories, options?.external) || options?.cacheDir && id.includes(options.cacheDir)) return id;
|
|
7068
|
+
const isLibraryModule = moduleDirectories.some((dir) => id.includes(dir)), guessCJS = isLibraryModule && options?.fallbackCJS;
|
|
7069
|
+
return id = guessCJS ? guessCJSversion(id) || id : id, matchExternalizePattern(id, moduleDirectories, defaultInline) ? false : matchExternalizePattern(id, moduleDirectories, depsExternal) || isLibraryModule && await isValidNodeImport(id) ? id : false;
|
|
7070
|
+
}
|
|
7071
|
+
function matchExternalizePattern(id, moduleDirectories, patterns) {
|
|
7072
|
+
if (patterns == null) return false;
|
|
7073
|
+
if (patterns === true) return true;
|
|
7074
|
+
for (const ex of patterns) if (typeof ex === "string") {
|
|
7075
|
+
if (moduleDirectories.some((dir) => id.includes(join(dir, ex)))) return true;
|
|
7076
|
+
} else if (ex.test(id)) return true;
|
|
7077
|
+
return false;
|
|
7078
|
+
}
|
|
7079
|
+
|
|
6825
7080
|
class TestSpecification {
|
|
6826
|
-
/**
|
|
6827
|
-
* @deprecated use `project` instead
|
|
6828
|
-
*/
|
|
6829
|
-
0;
|
|
6830
|
-
/**
|
|
6831
|
-
* @deprecated use `moduleId` instead
|
|
6832
|
-
*/
|
|
6833
|
-
1;
|
|
6834
|
-
/**
|
|
6835
|
-
* @deprecated use `pool` instead
|
|
6836
|
-
*/
|
|
6837
|
-
2;
|
|
6838
7081
|
/**
|
|
6839
7082
|
* The task ID associated with the test module.
|
|
6840
7083
|
*/
|
|
@@ -6857,24 +7100,15 @@ class TestSpecification {
|
|
|
6857
7100
|
*/
|
|
6858
7101
|
testLines;
|
|
6859
7102
|
constructor(project, moduleId, pool, testLines) {
|
|
6860
|
-
|
|
6861
|
-
this
|
|
6862
|
-
this[2] = { pool };
|
|
6863
|
-
const name = project.config.name;
|
|
6864
|
-
const hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
|
|
6865
|
-
this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName);
|
|
6866
|
-
this.project = project;
|
|
6867
|
-
this.moduleId = moduleId;
|
|
6868
|
-
this.pool = pool;
|
|
6869
|
-
this.testLines = testLines;
|
|
7103
|
+
const name = project.config.name, hashName = pool !== "typescript" ? name : name ? `${name}:__typecheck__` : "__typecheck__";
|
|
7104
|
+
this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName), this.project = project, this.moduleId = moduleId, this.pool = pool, this.testLines = testLines;
|
|
6870
7105
|
}
|
|
6871
7106
|
/**
|
|
6872
7107
|
* Test module associated with the specification.
|
|
6873
7108
|
*/
|
|
6874
7109
|
get testModule() {
|
|
6875
7110
|
const task = this.project.vitest.state.idMap.get(this.taskId);
|
|
6876
|
-
|
|
6877
|
-
return this.project.vitest.state.getReportedEntity(task);
|
|
7111
|
+
return task ? this.project.vitest.state.getReportedEntity(task) : void 0;
|
|
6878
7112
|
}
|
|
6879
7113
|
toJSON() {
|
|
6880
7114
|
return [
|
|
@@ -6889,15 +7123,6 @@ class TestSpecification {
|
|
|
6889
7123
|
}
|
|
6890
7124
|
];
|
|
6891
7125
|
}
|
|
6892
|
-
/**
|
|
6893
|
-
* for backwards compatibility
|
|
6894
|
-
* @deprecated
|
|
6895
|
-
*/
|
|
6896
|
-
*[Symbol.iterator]() {
|
|
6897
|
-
yield this.project;
|
|
6898
|
-
yield this.moduleId;
|
|
6899
|
-
yield this.pool;
|
|
6900
|
-
}
|
|
6901
7126
|
}
|
|
6902
7127
|
|
|
6903
7128
|
async function createViteServer(inlineConfig) {
|
|
@@ -6905,12 +7130,10 @@ async function createViteServer(inlineConfig) {
|
|
|
6905
7130
|
// But Vitest works correctly either way
|
|
6906
7131
|
const error = console.error;
|
|
6907
7132
|
console.error = (...args) => {
|
|
6908
|
-
|
|
6909
|
-
error(...args);
|
|
7133
|
+
typeof args[0] === "string" && args[0].includes("WebSocket server error:") || error(...args);
|
|
6910
7134
|
};
|
|
6911
7135
|
const server = await createServer(inlineConfig);
|
|
6912
|
-
console.error = error;
|
|
6913
|
-
return server;
|
|
7136
|
+
return console.error = error, server;
|
|
6914
7137
|
}
|
|
6915
7138
|
|
|
6916
7139
|
class TestProject {
|
|
@@ -6927,29 +7150,24 @@ class TestProject {
|
|
|
6927
7150
|
* Browser instance if the browser is enabled. This is initialized when the tests run for the first time.
|
|
6928
7151
|
*/
|
|
6929
7152
|
browser;
|
|
6930
|
-
/** @deprecated use `vitest` instead */
|
|
6931
|
-
ctx;
|
|
6932
7153
|
/**
|
|
6933
7154
|
* Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
|
|
6934
7155
|
*/
|
|
6935
7156
|
tmpDir = join(tmpdir(), nanoid());
|
|
6936
|
-
/** @internal */ vitenode;
|
|
6937
7157
|
/** @internal */ typechecker;
|
|
6938
7158
|
/** @internal */ _config;
|
|
6939
7159
|
/** @internal */ _vite;
|
|
6940
7160
|
/** @internal */ _hash;
|
|
7161
|
+
/** @internal */ _resolver;
|
|
7162
|
+
/** @internal */ _serializedDefines;
|
|
7163
|
+
/** @inetrnal */ testFilesList = null;
|
|
6941
7164
|
runner;
|
|
6942
7165
|
closingPromise;
|
|
6943
|
-
testFilesList = null;
|
|
6944
7166
|
typecheckFilesList = null;
|
|
6945
7167
|
_globalSetups;
|
|
6946
7168
|
_provided = {};
|
|
6947
|
-
constructor(
|
|
6948
|
-
this.
|
|
6949
|
-
this.options = options;
|
|
6950
|
-
this.vitest = vitest;
|
|
6951
|
-
this.ctx = vitest;
|
|
6952
|
-
this.globalConfig = vitest.config;
|
|
7169
|
+
constructor(vitest, options) {
|
|
7170
|
+
this.options = options, this.vitest = vitest, this.globalConfig = vitest.config;
|
|
6953
7171
|
}
|
|
6954
7172
|
/**
|
|
6955
7173
|
* The unique hash of this project. This value is consistent between the reruns.
|
|
@@ -6978,10 +7196,9 @@ class TestProject {
|
|
|
6978
7196
|
* Get the provided context. The project context is merged with the global context.
|
|
6979
7197
|
*/
|
|
6980
7198
|
getProvidedContext() {
|
|
6981
|
-
if (this.isRootProject()) return this._provided;
|
|
6982
7199
|
// globalSetup can run even if core workspace is not part of the test run
|
|
6983
7200
|
// so we need to inherit its provided context
|
|
6984
|
-
return {
|
|
7201
|
+
return this.isRootProject() ? this._provided : {
|
|
6985
7202
|
...this.vitest.getRootProject().getProvidedContext(),
|
|
6986
7203
|
...this._provided
|
|
6987
7204
|
};
|
|
@@ -6991,7 +7208,7 @@ class TestProject {
|
|
|
6991
7208
|
* @param moduleId The file path
|
|
6992
7209
|
*/
|
|
6993
7210
|
createSpecification(moduleId, locations, pool) {
|
|
6994
|
-
return new TestSpecification(this, moduleId, pool || getFilePoolName(this
|
|
7211
|
+
return new TestSpecification(this, moduleId, pool || getFilePoolName(this), locations);
|
|
6995
7212
|
}
|
|
6996
7213
|
toJSON() {
|
|
6997
7214
|
return {
|
|
@@ -7005,13 +7222,11 @@ class TestProject {
|
|
|
7005
7222
|
*/
|
|
7006
7223
|
get vite() {
|
|
7007
7224
|
if (!this._vite) throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
|
|
7008
|
-
|
|
7009
|
-
Object.defineProperty(this, "vite", {
|
|
7225
|
+
return Object.defineProperty(this, "vite", {
|
|
7010
7226
|
configurable: true,
|
|
7011
7227
|
writable: true,
|
|
7012
7228
|
value: this._vite
|
|
7013
|
-
});
|
|
7014
|
-
return this._vite;
|
|
7229
|
+
}), this._vite;
|
|
7015
7230
|
}
|
|
7016
7231
|
/**
|
|
7017
7232
|
* Resolved project configuration.
|
|
@@ -7044,85 +7259,38 @@ class TestProject {
|
|
|
7044
7259
|
get serializedConfig() {
|
|
7045
7260
|
return this._serializeOverriddenConfig();
|
|
7046
7261
|
}
|
|
7047
|
-
/** @deprecated use `vite` instead */
|
|
7048
|
-
get server() {
|
|
7049
|
-
return this._vite;
|
|
7050
|
-
}
|
|
7051
7262
|
/**
|
|
7052
7263
|
* Check if this is the root project. The root project is the one that has the root config.
|
|
7053
7264
|
*/
|
|
7054
7265
|
isRootProject() {
|
|
7055
7266
|
return this.vitest.getRootProject() === this;
|
|
7056
7267
|
}
|
|
7057
|
-
/** @deprecated use `isRootProject` instead */
|
|
7058
|
-
isCore() {
|
|
7059
|
-
return this.isRootProject();
|
|
7060
|
-
}
|
|
7061
|
-
/** @deprecated use `createSpecification` instead */
|
|
7062
|
-
createSpec(moduleId, pool) {
|
|
7063
|
-
return new TestSpecification(this, moduleId, pool);
|
|
7064
|
-
}
|
|
7065
|
-
/** @deprecated */
|
|
7066
|
-
initializeGlobalSetup() {
|
|
7067
|
-
return this._initializeGlobalSetup();
|
|
7068
|
-
}
|
|
7069
7268
|
/** @internal */
|
|
7070
7269
|
async _initializeGlobalSetup() {
|
|
7071
|
-
if (this._globalSetups)
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7270
|
+
if (!this._globalSetups) {
|
|
7271
|
+
this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
|
|
7272
|
+
for (const globalSetupFile of this._globalSetups) {
|
|
7273
|
+
const teardown = await globalSetupFile.setup?.(this);
|
|
7274
|
+
if (teardown == null || !!globalSetupFile.teardown) continue;
|
|
7275
|
+
if (typeof teardown !== "function") throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
|
|
7276
|
+
globalSetupFile.teardown = teardown;
|
|
7277
|
+
}
|
|
7078
7278
|
}
|
|
7079
7279
|
}
|
|
7080
7280
|
onTestsRerun(cb) {
|
|
7081
7281
|
this.vitest.onTestsRerun(cb);
|
|
7082
7282
|
}
|
|
7083
|
-
/** @deprecated */
|
|
7084
|
-
teardownGlobalSetup() {
|
|
7085
|
-
return this._teardownGlobalSetup();
|
|
7086
|
-
}
|
|
7087
7283
|
/** @internal */
|
|
7088
7284
|
async _teardownGlobalSetup() {
|
|
7089
|
-
if (
|
|
7090
|
-
for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
|
|
7091
|
-
}
|
|
7092
|
-
/** @deprecated use `vitest.logger` instead */
|
|
7093
|
-
get logger() {
|
|
7094
|
-
return this.vitest.logger;
|
|
7095
|
-
}
|
|
7096
|
-
// it's possible that file path was imported with different queries (?raw, ?url, etc)
|
|
7097
|
-
/** @deprecated use `.vite` or `.browser.vite` directly */
|
|
7098
|
-
getModulesByFilepath(file) {
|
|
7099
|
-
const set = this.server.moduleGraph.getModulesByFile(file) || this.browser?.vite.moduleGraph.getModulesByFile(file);
|
|
7100
|
-
return set || /* @__PURE__ */ new Set();
|
|
7101
|
-
}
|
|
7102
|
-
/** @deprecated use `.vite` or `.browser.vite` directly */
|
|
7103
|
-
getModuleById(id) {
|
|
7104
|
-
return this.server.moduleGraph.getModuleById(id) || this.browser?.vite.moduleGraph.getModuleById(id);
|
|
7105
|
-
}
|
|
7106
|
-
/** @deprecated use `.vite` or `.browser.vite` directly */
|
|
7107
|
-
getSourceMapModuleById(id) {
|
|
7108
|
-
const mod = this.server.moduleGraph.getModuleById(id);
|
|
7109
|
-
return mod?.ssrTransformResult?.map || mod?.transformResult?.map;
|
|
7110
|
-
}
|
|
7111
|
-
/** @deprecated use `vitest.reporters` instead */
|
|
7112
|
-
get reporters() {
|
|
7113
|
-
return this.ctx.reporters;
|
|
7285
|
+
if (this._globalSetups) for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
|
|
7114
7286
|
}
|
|
7115
7287
|
/**
|
|
7116
7288
|
* Get all files in the project that match the globs in the config and the filters.
|
|
7117
7289
|
* @param filters String filters to match the test files.
|
|
7118
7290
|
*/
|
|
7119
7291
|
async globTestFiles(filters = []) {
|
|
7120
|
-
const dir = this.config.dir || this.config.root;
|
|
7121
|
-
|
|
7122
|
-
const typecheck = this.config.typecheck;
|
|
7123
|
-
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) : []]);
|
|
7124
|
-
this.typecheckFilesList = typecheckTestFiles;
|
|
7125
|
-
return {
|
|
7292
|
+
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) : []]);
|
|
7293
|
+
return this.typecheckFilesList = typecheckTestFiles, {
|
|
7126
7294
|
testFiles: this.filterFiles(testFiles, filters, dir),
|
|
7127
7295
|
typecheckTestFiles: this.filterFiles(typecheckTestFiles, filters, dir)
|
|
7128
7296
|
};
|
|
@@ -7141,8 +7309,7 @@ class TestProject {
|
|
|
7141
7309
|
}
|
|
7142
7310
|
}));
|
|
7143
7311
|
}
|
|
7144
|
-
this.testFilesList = testFiles;
|
|
7145
|
-
return testFiles;
|
|
7312
|
+
return this.testFilesList = testFiles, testFiles;
|
|
7146
7313
|
}
|
|
7147
7314
|
isBrowserEnabled() {
|
|
7148
7315
|
return isBrowserEnabled(this.config);
|
|
@@ -7168,10 +7335,6 @@ class TestProject {
|
|
|
7168
7335
|
_isCachedTypecheckFile(testPath) {
|
|
7169
7336
|
return !!this.typecheckFilesList && this.typecheckFilesList.includes(testPath);
|
|
7170
7337
|
}
|
|
7171
|
-
/** @deprecated use `serializedConfig` instead */
|
|
7172
|
-
getSerializableConfig() {
|
|
7173
|
-
return this._serializeOverriddenConfig();
|
|
7174
|
-
}
|
|
7175
7338
|
/** @internal */
|
|
7176
7339
|
async globFiles(include, exclude, cwd) {
|
|
7177
7340
|
const globOptions = {
|
|
@@ -7179,8 +7342,7 @@ class TestProject {
|
|
|
7179
7342
|
cwd,
|
|
7180
7343
|
ignore: exclude,
|
|
7181
7344
|
expandDirectories: false
|
|
7182
|
-
};
|
|
7183
|
-
const files = await glob(include, globOptions);
|
|
7345
|
+
}, files = await glob(include, globOptions);
|
|
7184
7346
|
// keep the slashes consistent with Vite
|
|
7185
7347
|
// we are not using the pathe here because it normalizes the drive letter on Windows
|
|
7186
7348
|
// and we want to keep it the same as working dir
|
|
@@ -7193,29 +7355,19 @@ class TestProject {
|
|
|
7193
7355
|
if (this._isCachedTestFile(moduleId)) return true;
|
|
7194
7356
|
const relativeId = relative(this.config.dir || this.config.root, moduleId);
|
|
7195
7357
|
if (pm.isMatch(relativeId, this.config.exclude)) return false;
|
|
7196
|
-
if (pm.isMatch(relativeId, this.config.include))
|
|
7197
|
-
this.markTestFile(moduleId);
|
|
7198
|
-
return true;
|
|
7199
|
-
}
|
|
7358
|
+
if (pm.isMatch(relativeId, this.config.include)) return this.markTestFile(moduleId), true;
|
|
7200
7359
|
if (this.config.includeSource?.length && pm.isMatch(relativeId, this.config.includeSource)) {
|
|
7201
7360
|
const code = source?.() || readFileSync(moduleId, "utf-8");
|
|
7202
|
-
if (this.isInSourceTestCode(code))
|
|
7203
|
-
this.markTestFile(moduleId);
|
|
7204
|
-
return true;
|
|
7205
|
-
}
|
|
7361
|
+
if (this.isInSourceTestCode(code)) return this.markTestFile(moduleId), true;
|
|
7206
7362
|
}
|
|
7207
7363
|
return false;
|
|
7208
7364
|
}
|
|
7209
|
-
/** @deprecated use `matchesTestGlob` instead */
|
|
7210
|
-
async isTargetFile(id, source) {
|
|
7211
|
-
return this.matchesTestGlob(id, source ? () => source : void 0);
|
|
7212
|
-
}
|
|
7213
7365
|
isInSourceTestCode(code) {
|
|
7214
7366
|
return code.includes("import.meta.vitest");
|
|
7215
7367
|
}
|
|
7216
7368
|
filterFiles(testFiles, filters, dir) {
|
|
7217
7369
|
if (filters.length && process.platform === "win32") filters = filters.map((f) => slash(f));
|
|
7218
|
-
|
|
7370
|
+
return filters.length ? testFiles.filter((t) => {
|
|
7219
7371
|
const testFile = relative(dir, t).toLocaleLowerCase();
|
|
7220
7372
|
return filters.some((f) => {
|
|
7221
7373
|
// if filter is a full file path, we should include it if it's in the same folder
|
|
@@ -7223,8 +7375,7 @@ class TestProject {
|
|
|
7223
7375
|
const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f);
|
|
7224
7376
|
return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase());
|
|
7225
7377
|
});
|
|
7226
|
-
});
|
|
7227
|
-
return testFiles;
|
|
7378
|
+
}) : testFiles;
|
|
7228
7379
|
}
|
|
7229
7380
|
_parentBrowser;
|
|
7230
7381
|
/** @internal */
|
|
@@ -7235,25 +7386,23 @@ class TestProject {
|
|
|
7235
7386
|
await this.vitest.packageInstaller.ensureInstalled("@vitest/browser", this.config.root, this.vitest.version);
|
|
7236
7387
|
const { createBrowserServer, distRoot } = await import('@vitest/browser');
|
|
7237
7388
|
let cacheDir;
|
|
7238
|
-
const browser = await createBrowserServer(this, this.vite.config.configFile, [
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7389
|
+
const browser = await createBrowserServer(this, this.vite.config.configFile, [
|
|
7390
|
+
{
|
|
7391
|
+
name: "vitest:browser-cacheDir",
|
|
7392
|
+
configResolved(config) {
|
|
7393
|
+
cacheDir = config.cacheDir;
|
|
7394
|
+
}
|
|
7395
|
+
},
|
|
7396
|
+
...MocksPlugins({ filter(id) {
|
|
7397
|
+
return !(id.includes(distRoot) || id.includes(cacheDir));
|
|
7398
|
+
} }),
|
|
7399
|
+
MetaEnvReplacerPlugin()
|
|
7400
|
+
], [CoverageTransform(this.vitest)]);
|
|
7401
|
+
if (this._parentBrowser = browser, this.config.browser.ui) setup(this.vitest, browser.vite);
|
|
7249
7402
|
});
|
|
7250
7403
|
/** @internal */
|
|
7251
7404
|
_initBrowserServer = deduped(async () => {
|
|
7252
|
-
await this._parent?._initParentBrowser();
|
|
7253
|
-
if (!this.browser && this._parent?._parentBrowser) {
|
|
7254
|
-
this.browser = this._parent._parentBrowser.spawn(this);
|
|
7255
|
-
await this.vitest.report("onBrowserInit", this);
|
|
7256
|
-
}
|
|
7405
|
+
if (await this._parent?._initParentBrowser(), !this.browser && this._parent?._parentBrowser) this.browser = this._parent._parentBrowser.spawn(this), await this.vitest.report("onBrowserInit", this);
|
|
7257
7406
|
});
|
|
7258
7407
|
/**
|
|
7259
7408
|
* Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
|
|
@@ -7266,8 +7415,7 @@ class TestProject {
|
|
|
7266
7415
|
this.browser?.close(),
|
|
7267
7416
|
this.clearTmpDir()
|
|
7268
7417
|
].filter(Boolean)).then(() => {
|
|
7269
|
-
this._provided = {};
|
|
7270
|
-
this._vite = void 0;
|
|
7418
|
+
this._provided = {}, this._vite = void 0;
|
|
7271
7419
|
});
|
|
7272
7420
|
return this.closingPromise;
|
|
7273
7421
|
}
|
|
@@ -7276,66 +7424,41 @@ class TestProject {
|
|
|
7276
7424
|
* @param moduleId The ID of the module in Vite module graph
|
|
7277
7425
|
*/
|
|
7278
7426
|
import(moduleId) {
|
|
7279
|
-
return this.runner.
|
|
7280
|
-
}
|
|
7281
|
-
/** @deprecated use `name` instead */
|
|
7282
|
-
getName() {
|
|
7283
|
-
return this.config.name || "";
|
|
7284
|
-
}
|
|
7285
|
-
/** @deprecated internal */
|
|
7286
|
-
setServer(options, server) {
|
|
7287
|
-
return this._configureServer(options, server);
|
|
7427
|
+
return this.runner.import(moduleId);
|
|
7288
7428
|
}
|
|
7289
7429
|
_setHash() {
|
|
7290
7430
|
this._hash = generateHash(this._config.root + this._config.name);
|
|
7291
7431
|
}
|
|
7292
7432
|
/** @internal */
|
|
7293
7433
|
async _configureServer(options, server) {
|
|
7294
|
-
this._config = resolveConfig(this.vitest, {
|
|
7434
|
+
for (const _providedKey in this._config = resolveConfig(this.vitest, {
|
|
7295
7435
|
...options,
|
|
7296
7436
|
coverage: this.vitest.config.coverage
|
|
7297
|
-
}, server.config)
|
|
7298
|
-
this._setHash();
|
|
7299
|
-
for (const _providedKey in this.config.provide) {
|
|
7437
|
+
}, server.config), this._setHash(), this.config.provide) {
|
|
7300
7438
|
const providedKey = _providedKey;
|
|
7301
7439
|
// type is very strict here, so we cast it to any
|
|
7302
7440
|
this.provide(providedKey, this.config.provide[providedKey]);
|
|
7303
7441
|
}
|
|
7304
|
-
this.closingPromise = void 0;
|
|
7305
|
-
|
|
7306
|
-
this.
|
|
7307
|
-
const node = this.vitenode;
|
|
7308
|
-
this.runner = new ViteNodeRunner({
|
|
7309
|
-
root: server.config.root,
|
|
7310
|
-
base: server.config.base,
|
|
7311
|
-
fetchModule(id) {
|
|
7312
|
-
return node.fetchModule(id);
|
|
7313
|
-
},
|
|
7314
|
-
resolveId(id, importer) {
|
|
7315
|
-
return node.resolveId(id, importer);
|
|
7316
|
-
}
|
|
7317
|
-
});
|
|
7442
|
+
this.closingPromise = void 0, this._resolver = new VitestResolver(server.config.cacheDir, this._config), this._vite = server, this._serializedDefines = createDefinesScript(server.config.define);
|
|
7443
|
+
const environment = server.environments.__vitest__;
|
|
7444
|
+
this.runner = new ServerModuleRunner(environment, this._resolver, this._config);
|
|
7318
7445
|
}
|
|
7319
7446
|
_serializeOverriddenConfig() {
|
|
7320
7447
|
// TODO: serialize the config _once_ or when needed
|
|
7321
|
-
const config = serializeConfig(this
|
|
7322
|
-
|
|
7323
|
-
return deepMerge(config, this.vitest.configOverride);
|
|
7448
|
+
const config = serializeConfig(this);
|
|
7449
|
+
return this.vitest.configOverride ? deepMerge(config, this.vitest.configOverride) : config;
|
|
7324
7450
|
}
|
|
7325
7451
|
async clearTmpDir() {
|
|
7326
7452
|
try {
|
|
7327
7453
|
await rm(this.tmpDir, { recursive: true });
|
|
7328
7454
|
} catch {}
|
|
7329
7455
|
}
|
|
7330
|
-
/** @deprecated */
|
|
7331
|
-
initBrowserProvider() {
|
|
7332
|
-
return this._initBrowserProvider();
|
|
7333
|
-
}
|
|
7334
7456
|
/** @internal */
|
|
7335
7457
|
_initBrowserProvider = deduped(async () => {
|
|
7336
|
-
if (!this.isBrowserEnabled() || this.browser?.provider)
|
|
7337
|
-
|
|
7338
|
-
|
|
7458
|
+
if (!(!this.isBrowserEnabled() || this.browser?.provider)) {
|
|
7459
|
+
if (!this.browser) await this._initBrowserServer();
|
|
7460
|
+
await this.browser?.initBrowserProvider(this);
|
|
7461
|
+
}
|
|
7339
7462
|
});
|
|
7340
7463
|
/** @internal */
|
|
7341
7464
|
_provideObject(context) {
|
|
@@ -7347,41 +7470,26 @@ class TestProject {
|
|
|
7347
7470
|
}
|
|
7348
7471
|
/** @internal */
|
|
7349
7472
|
static _createBasicProject(vitest) {
|
|
7350
|
-
const project = new TestProject(vitest
|
|
7351
|
-
project.
|
|
7352
|
-
project.runner = vitest.runner;
|
|
7353
|
-
project._vite = vitest.server;
|
|
7354
|
-
project._config = vitest.config;
|
|
7355
|
-
project._setHash();
|
|
7356
|
-
project._provideObject(vitest.config.provide);
|
|
7357
|
-
return project;
|
|
7473
|
+
const project = new TestProject(vitest);
|
|
7474
|
+
return project.runner = vitest.runner, project._vite = vitest.vite, project._config = vitest.config, project._resolver = vitest._resolver, project._serializedDefines = createDefinesScript(vitest.vite.config.define), project._setHash(), project._provideObject(vitest.config.provide), project;
|
|
7358
7475
|
}
|
|
7359
7476
|
/** @internal */
|
|
7360
7477
|
static _cloneBrowserProject(parent, config) {
|
|
7361
|
-
const clone = new TestProject(parent.
|
|
7362
|
-
clone.
|
|
7363
|
-
clone.runner = parent.runner;
|
|
7364
|
-
clone._vite = parent._vite;
|
|
7365
|
-
clone._config = config;
|
|
7366
|
-
clone._setHash();
|
|
7367
|
-
clone._parent = parent;
|
|
7368
|
-
clone._provideObject(config.provide);
|
|
7369
|
-
return clone;
|
|
7478
|
+
const clone = new TestProject(parent.vitest);
|
|
7479
|
+
return clone.runner = parent.runner, clone._vite = parent._vite, clone._resolver = parent._resolver, clone._config = config, clone._setHash(), clone._parent = parent, clone._serializedDefines = parent._serializedDefines, clone._provideObject(config.provide), clone;
|
|
7370
7480
|
}
|
|
7371
7481
|
}
|
|
7372
7482
|
function deduped(cb) {
|
|
7373
7483
|
let _promise;
|
|
7374
|
-
return (...args) => {
|
|
7484
|
+
return ((...args) => {
|
|
7375
7485
|
if (!_promise) _promise = cb(...args).finally(() => {
|
|
7376
7486
|
_promise = void 0;
|
|
7377
7487
|
});
|
|
7378
7488
|
return _promise;
|
|
7379
|
-
};
|
|
7489
|
+
});
|
|
7380
7490
|
}
|
|
7381
7491
|
async function initializeProject(workspacePath, ctx, options) {
|
|
7382
|
-
const project = new TestProject(
|
|
7383
|
-
const { configFile,...restOptions } = options;
|
|
7384
|
-
const config = {
|
|
7492
|
+
const project = new TestProject(ctx, options), { configFile,...restOptions } = options, config = {
|
|
7385
7493
|
...restOptions,
|
|
7386
7494
|
configFile,
|
|
7387
7495
|
configLoader: ctx.vite.config.inlineConfig.configLoader,
|
|
@@ -7391,25 +7499,20 @@ async function initializeProject(workspacePath, ctx, options) {
|
|
|
7391
7499
|
workspacePath
|
|
7392
7500
|
})]
|
|
7393
7501
|
};
|
|
7394
|
-
await createViteServer(config);
|
|
7395
|
-
return project;
|
|
7502
|
+
return await createViteServer(config), project;
|
|
7396
7503
|
}
|
|
7397
7504
|
function generateHash(str) {
|
|
7398
7505
|
let hash = 0;
|
|
7399
7506
|
if (str.length === 0) return `${hash}`;
|
|
7400
7507
|
for (let i = 0; i < str.length; i++) {
|
|
7401
7508
|
const char = str.charCodeAt(i);
|
|
7402
|
-
hash = (hash << 5) - hash + char;
|
|
7403
|
-
hash = hash & hash;
|
|
7509
|
+
hash = (hash << 5) - hash + char, hash = hash & hash;
|
|
7404
7510
|
}
|
|
7405
7511
|
return `${hash}`;
|
|
7406
7512
|
}
|
|
7407
7513
|
|
|
7408
7514
|
async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projectsDefinition, names) {
|
|
7409
|
-
const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition)
|
|
7410
|
-
// cli options that affect the project config,
|
|
7411
|
-
// not all options are allowed to be overridden
|
|
7412
|
-
const overridesOptions = [
|
|
7515
|
+
const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition), overridesOptions = [
|
|
7413
7516
|
"logHeapUsage",
|
|
7414
7517
|
"allowOnly",
|
|
7415
7518
|
"sequence",
|
|
@@ -7428,21 +7531,12 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7428
7531
|
"inspect",
|
|
7429
7532
|
"inspectBrk",
|
|
7430
7533
|
"fileParallelism"
|
|
7431
|
-
]
|
|
7432
|
-
const cliOverrides = overridesOptions.reduce((acc, name) => {
|
|
7534
|
+
], cliOverrides = overridesOptions.reduce((acc, name) => {
|
|
7433
7535
|
if (name in cliOptions) acc[name] = cliOptions[name];
|
|
7434
7536
|
return acc;
|
|
7435
|
-
}, {});
|
|
7436
|
-
const projectPromises = [];
|
|
7437
|
-
const fileProjects = [...configFiles, ...nonConfigDirectories];
|
|
7438
|
-
const concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
|
|
7537
|
+
}, {}), projectPromises = [], fileProjects = [...configFiles, ...nonConfigDirectories], concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
|
|
7439
7538
|
projectConfigs.forEach((options, index) => {
|
|
7440
|
-
const configRoot =
|
|
7441
|
-
// if extends a config file, resolve the file path
|
|
7442
|
-
const configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false;
|
|
7443
|
-
// if `root` is configured, resolve it relative to the workspace file or vite root (like other options)
|
|
7444
|
-
// if `root` is not specified, inline configs use the same root as the root project
|
|
7445
|
-
const root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
|
|
7539
|
+
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;
|
|
7446
7540
|
projectPromises.push(concurrent(() => initializeProject(index, vitest, {
|
|
7447
7541
|
...options,
|
|
7448
7542
|
root,
|
|
@@ -7460,8 +7554,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7460
7554
|
if (project) projectPromises.push(Promise.resolve(project));
|
|
7461
7555
|
continue;
|
|
7462
7556
|
}
|
|
7463
|
-
const configFile = path.endsWith("/") ? false : path;
|
|
7464
|
-
const root = path.endsWith("/") ? path : dirname(path);
|
|
7557
|
+
const configFile = path.endsWith("/") ? false : path, root = path.endsWith("/") ? path : dirname(path);
|
|
7465
7558
|
projectPromises.push(concurrent(() => initializeProject(path, vitest, {
|
|
7466
7559
|
root,
|
|
7467
7560
|
configFile,
|
|
@@ -7474,9 +7567,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7474
7567
|
vitest.config.project.length ? `The filter matched no projects: ${vitest.config.project.join(", ")}. ` : "",
|
|
7475
7568
|
`The projects definition: ${JSON.stringify(projectsDefinition, null, 4)}.`
|
|
7476
7569
|
].join(""));
|
|
7477
|
-
const resolvedProjectsPromises = await Promise.allSettled(projectPromises);
|
|
7478
|
-
const errors = [];
|
|
7479
|
-
const resolvedProjects = [];
|
|
7570
|
+
const resolvedProjectsPromises = await Promise.allSettled(projectPromises), errors = [], resolvedProjects = [];
|
|
7480
7571
|
for (const result of resolvedProjectsPromises) if (result.status === "rejected") {
|
|
7481
7572
|
if (result.reason instanceof VitestFilteredOutProjectError)
|
|
7482
7573
|
// filter out filtered out projects
|
|
@@ -7488,8 +7579,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7488
7579
|
for (const project of resolvedProjects) {
|
|
7489
7580
|
const name = project.name;
|
|
7490
7581
|
if (names.has(name)) {
|
|
7491
|
-
const duplicate = resolvedProjects.find((p) => p.name === name && p !== project)
|
|
7492
|
-
const filesError = fileProjects.length ? [
|
|
7582
|
+
const duplicate = resolvedProjects.find((p) => p.name === name && p !== project), filesError = fileProjects.length ? [
|
|
7493
7583
|
"\n\nYour config matched these files:\n",
|
|
7494
7584
|
fileProjects.map((p) => ` - ${relative(vitest.config.root, p)}`).join("\n"),
|
|
7495
7585
|
"\n\n"
|
|
@@ -7511,24 +7601,18 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7511
7601
|
const removeProjects = /* @__PURE__ */ new Set();
|
|
7512
7602
|
resolvedProjects.forEach((project) => {
|
|
7513
7603
|
if (!project.config.browser.enabled) return;
|
|
7514
|
-
const instances = project.config.browser.instances || [];
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
}
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
"Read more: https://vitest.dev/guide/browser/config#browser-instances"
|
|
7527
|
-
].filter(Boolean).join("")));
|
|
7528
|
-
}
|
|
7529
|
-
const originalName = project.config.name;
|
|
7530
|
-
// if original name is in the --project=name filter, keep all instances
|
|
7531
|
-
const filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
|
|
7604
|
+
const instances = project.config.browser.instances || [], browser = project.config.browser.name;
|
|
7605
|
+
if (instances.length === 0 && browser) instances.push({
|
|
7606
|
+
browser,
|
|
7607
|
+
name: project.name ? `${project.name} (${browser})` : browser
|
|
7608
|
+
}), vitest.logger.warn(withLabel("yellow", "Vitest", [
|
|
7609
|
+
`No browser "instances" were defined`,
|
|
7610
|
+
project.name ? ` for the "${project.name}" project. ` : ". ",
|
|
7611
|
+
`Running tests in "${project.config.browser.name}" browser. `,
|
|
7612
|
+
"The \"browser.name\" field is deprecated since Vitest 3. ",
|
|
7613
|
+
"Read more: https://vitest.dev/guide/browser/config#browser-instances"
|
|
7614
|
+
].filter(Boolean).join("")));
|
|
7615
|
+
const originalName = project.config.name, filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
|
|
7532
7616
|
const newName = instance.name;
|
|
7533
7617
|
return vitest.matchesProjectFilter(newName);
|
|
7534
7618
|
});
|
|
@@ -7537,12 +7621,10 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7537
7621
|
removeProjects.add(project);
|
|
7538
7622
|
return;
|
|
7539
7623
|
}
|
|
7540
|
-
if (project.config.browser.providerOptions) vitest.logger.warn(withLabel("yellow", "Vitest", `"providerOptions"${originalName ? ` in "${originalName}" project` : ""} is ignored because it's overridden by the configs. To hide this warning, remove the "providerOptions" property from the browser configuration.`));
|
|
7541
7624
|
filteredInstances.forEach((config, index) => {
|
|
7542
7625
|
const browser = config.browser;
|
|
7543
7626
|
if (!browser) {
|
|
7544
|
-
const nth = index + 1;
|
|
7545
|
-
const ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
|
|
7627
|
+
const nth = index + 1, ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
|
|
7546
7628
|
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.`);
|
|
7547
7629
|
}
|
|
7548
7630
|
const name = config.name;
|
|
@@ -7557,18 +7639,15 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7557
7639
|
clonedConfig.name = name;
|
|
7558
7640
|
const clone = TestProject._cloneBrowserProject(project, clonedConfig);
|
|
7559
7641
|
resolvedProjects.push(clone);
|
|
7560
|
-
});
|
|
7561
|
-
|
|
7562
|
-
});
|
|
7563
|
-
resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
|
|
7642
|
+
}), removeProjects.add(project);
|
|
7643
|
+
}), resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
|
|
7564
7644
|
const headedBrowserProjects = resolvedProjects.filter((project) => {
|
|
7565
7645
|
return project.config.browser.enabled && !project.config.browser.headless;
|
|
7566
7646
|
});
|
|
7567
7647
|
if (headedBrowserProjects.length > 1) {
|
|
7568
7648
|
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("");
|
|
7569
7649
|
if (!isTTY) throw new Error(`${message} Please, filter projects with --browser=name or --project=name flag or run tests with "headless: true" option.`);
|
|
7570
|
-
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; })
|
|
7571
|
-
const { projectName } = await prompts.default({
|
|
7650
|
+
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; }), { projectName } = await prompts.default({
|
|
7572
7651
|
type: "select",
|
|
7573
7652
|
name: "projectName",
|
|
7574
7653
|
choices: headedBrowserProjects.map((project) => ({
|
|
@@ -7583,10 +7662,9 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7583
7662
|
return resolvedProjects;
|
|
7584
7663
|
}
|
|
7585
7664
|
function cloneConfig(project, { browser,...config }) {
|
|
7586
|
-
const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name,...overrideConfig } = config;
|
|
7587
|
-
const currentConfig = project.config.browser;
|
|
7665
|
+
const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name, provider,...overrideConfig } = config, currentConfig = project.config.browser, clonedConfig = deepClone(project.config);
|
|
7588
7666
|
return mergeConfig({
|
|
7589
|
-
...
|
|
7667
|
+
...clonedConfig,
|
|
7590
7668
|
browser: {
|
|
7591
7669
|
...project.config.browser,
|
|
7592
7670
|
locators: locators ? { testIdAttribute: locators.testIdAttribute ?? currentConfig.locators.testIdAttribute } : project.config.browser.locators,
|
|
@@ -7595,21 +7673,18 @@ function cloneConfig(project, { browser,...config }) {
|
|
|
7595
7673
|
screenshotDirectory: screenshotDirectory ?? currentConfig.screenshotDirectory,
|
|
7596
7674
|
screenshotFailures: screenshotFailures ?? currentConfig.screenshotFailures,
|
|
7597
7675
|
headless: headless ?? currentConfig.headless,
|
|
7676
|
+
provider: provider ?? currentConfig.provider,
|
|
7598
7677
|
name: browser,
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7678
|
+
instances: []
|
|
7679
|
+
},
|
|
7680
|
+
include: overrideConfig.include && overrideConfig.include.length > 0 ? [] : clonedConfig.include,
|
|
7681
|
+
exclude: overrideConfig.exclude && overrideConfig.exclude.length > 0 ? [] : clonedConfig.exclude,
|
|
7682
|
+
includeSource: overrideConfig.includeSource && overrideConfig.includeSource.length > 0 ? [] : clonedConfig.includeSource
|
|
7602
7683
|
}, overrideConfig);
|
|
7603
7684
|
}
|
|
7604
7685
|
async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition) {
|
|
7605
7686
|
// project configurations that were specified directly
|
|
7606
|
-
const projectsOptions = [];
|
|
7607
|
-
// custom config files that were specified directly or resolved from a directory
|
|
7608
|
-
const projectsConfigFiles = [];
|
|
7609
|
-
// custom glob matches that should be resolved as directories or config files
|
|
7610
|
-
const projectsGlobMatches = [];
|
|
7611
|
-
// directories that don't have a config file inside, but should be treated as projects
|
|
7612
|
-
const nonConfigProjectDirectories = [];
|
|
7687
|
+
const projectsOptions = [], projectsConfigFiles = [], projectsGlobMatches = [], nonConfigProjectDirectories = [];
|
|
7613
7688
|
for (const definition of projectsDefinition) if (typeof definition === "string") {
|
|
7614
7689
|
const stringOption = definition.replace("<rootDir>", vitest.config.root);
|
|
7615
7690
|
// if the string doesn't contain a glob, we can resolve it directly
|
|
@@ -7617,8 +7692,7 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7617
7692
|
if (!isDynamicPattern(stringOption)) {
|
|
7618
7693
|
const file = resolve(vitest.config.root, stringOption);
|
|
7619
7694
|
if (!existsSync(file)) {
|
|
7620
|
-
const
|
|
7621
|
-
const note = workspaceConfigPath ? `Workspace config file "${relativeWorkspaceConfigPath}"` : "Projects definition";
|
|
7695
|
+
const note = "Projects definition";
|
|
7622
7696
|
throw new Error(`${note} references a non-existing file or a directory: ${file}`);
|
|
7623
7697
|
}
|
|
7624
7698
|
const stats = await promises.stat(file);
|
|
@@ -7628,7 +7702,7 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7628
7702
|
const configFile = await resolveDirectoryConfig(file);
|
|
7629
7703
|
if (configFile) projectsConfigFiles.push(configFile);
|
|
7630
7704
|
else {
|
|
7631
|
-
const directory = file
|
|
7705
|
+
const directory = file.at(-1) === "/" ? file : `${file}/`;
|
|
7632
7706
|
nonConfigProjectDirectories.push(directory);
|
|
7633
7707
|
}
|
|
7634
7708
|
} else
|
|
@@ -7654,8 +7728,7 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7654
7728
|
"**/*.timestamp-*",
|
|
7655
7729
|
"**/.DS_Store"
|
|
7656
7730
|
]
|
|
7657
|
-
};
|
|
7658
|
-
const projectsFs = await glob(projectsGlobMatches, globOptions);
|
|
7731
|
+
}, projectsFs = await glob(projectsGlobMatches, globOptions);
|
|
7659
7732
|
await Promise.all(projectsFs.map(async (path) => {
|
|
7660
7733
|
// directories are allowed with a glob like `packages/*`
|
|
7661
7734
|
// in this case every directory is treated as a project
|
|
@@ -7674,21 +7747,15 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7674
7747
|
};
|
|
7675
7748
|
}
|
|
7676
7749
|
async function resolveDirectoryConfig(directory) {
|
|
7677
|
-
const files = new Set(await promises.readdir(directory));
|
|
7678
|
-
|
|
7679
|
-
// this simulates how `findUp` works in packages/vitest/src/node/create.ts:29
|
|
7680
|
-
const configFile = configFiles.find((file) => files.has(file));
|
|
7681
|
-
if (configFile) return resolve(directory, configFile);
|
|
7682
|
-
return null;
|
|
7750
|
+
const files = new Set(await promises.readdir(directory)), configFile = configFiles.find((file) => files.has(file));
|
|
7751
|
+
return configFile ? resolve(directory, configFile) : null;
|
|
7683
7752
|
}
|
|
7684
7753
|
function getDefaultTestProject(vitest) {
|
|
7685
|
-
const filter = vitest.config.project;
|
|
7686
|
-
const project = vitest._ensureRootProject();
|
|
7754
|
+
const filter = vitest.config.project, project = vitest._ensureRootProject();
|
|
7687
7755
|
if (!filter.length) return project;
|
|
7688
7756
|
// check for the project name and browser names
|
|
7689
7757
|
const hasProjects = getPotentialProjectNames(project).some((p) => vitest.matchesProjectFilter(p));
|
|
7690
|
-
|
|
7691
|
-
return null;
|
|
7758
|
+
return hasProjects ? project : null;
|
|
7692
7759
|
}
|
|
7693
7760
|
function getPotentialProjectNames(project) {
|
|
7694
7761
|
const names = [project.name];
|
|
@@ -7700,7 +7767,7 @@ function getPotentialProjectNames(project) {
|
|
|
7700
7767
|
async function loadCustomReporterModule(path, runner) {
|
|
7701
7768
|
let customReporterModule;
|
|
7702
7769
|
try {
|
|
7703
|
-
customReporterModule = await runner.
|
|
7770
|
+
customReporterModule = await runner.import(path);
|
|
7704
7771
|
} catch (customReporterModuleError) {
|
|
7705
7772
|
throw new Error(`Failed to load custom Reporter from ${path}`, { cause: customReporterModuleError });
|
|
7706
7773
|
}
|
|
@@ -7708,12 +7775,11 @@ async function loadCustomReporterModule(path, runner) {
|
|
|
7708
7775
|
return customReporterModule.default;
|
|
7709
7776
|
}
|
|
7710
7777
|
function createReporters(reporterReferences, ctx) {
|
|
7711
|
-
const runner = ctx.runner
|
|
7712
|
-
const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
|
|
7778
|
+
const runner = ctx.runner, promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
|
|
7713
7779
|
if (Array.isArray(referenceOrInstance)) {
|
|
7714
7780
|
const [reporterName, reporterOptions] = referenceOrInstance;
|
|
7715
7781
|
if (reporterName === "html") {
|
|
7716
|
-
await ctx.packageInstaller.ensureInstalled("@vitest/ui",
|
|
7782
|
+
await ctx.packageInstaller.ensureInstalled("@vitest/ui", ctx.config.root, ctx.version);
|
|
7717
7783
|
const CustomReporter = await loadCustomReporterModule("@vitest/ui/reporter", runner);
|
|
7718
7784
|
return new CustomReporter(reporterOptions);
|
|
7719
7785
|
} else if (reporterName in ReportersMap) {
|
|
@@ -7750,14 +7816,12 @@ function parseFilter(filter) {
|
|
|
7750
7816
|
filename: parsedFilename,
|
|
7751
7817
|
lineNumber: Number.parseInt(lineNumber)
|
|
7752
7818
|
};
|
|
7753
|
-
|
|
7754
|
-
|
|
7819
|
+
if (lineNumber.match(/^\d+-\d+$/)) throw new RangeLocationFilterProvidedError(filter);
|
|
7820
|
+
return { filename: filter };
|
|
7755
7821
|
}
|
|
7756
7822
|
function groupFilters(filters) {
|
|
7757
|
-
const groupedFilters_ = groupBy(filters, (f) => f.filename)
|
|
7758
|
-
|
|
7759
|
-
const [filename, filters] = entry;
|
|
7760
|
-
const testLocations = filters.map((f) => f.lineNumber);
|
|
7823
|
+
const groupedFilters_ = groupBy(filters, (f) => f.filename), groupedFilters = Object.fromEntries(Object.entries(groupedFilters_).map((entry) => {
|
|
7824
|
+
const [filename, filters] = entry, testLocations = filters.map((f) => f.lineNumber);
|
|
7761
7825
|
return [filename, testLocations.filter((l) => l !== void 0)];
|
|
7762
7826
|
}));
|
|
7763
7827
|
return groupedFilters;
|
|
@@ -7776,45 +7840,35 @@ class VitestSpecifications {
|
|
|
7776
7840
|
if (project._isCachedTestFile(moduleId)) specs.push(project.createSpecification(moduleId));
|
|
7777
7841
|
if (project._isCachedTypecheckFile(moduleId)) specs.push(project.createSpecification(moduleId, [], "typescript"));
|
|
7778
7842
|
}
|
|
7779
|
-
specs.forEach((spec) => this.ensureSpecificationCached(spec));
|
|
7780
|
-
return specs;
|
|
7843
|
+
return specs.forEach((spec) => this.ensureSpecificationCached(spec)), specs;
|
|
7781
7844
|
}
|
|
7782
7845
|
async getRelevantTestSpecifications(filters = []) {
|
|
7783
7846
|
return this.filterTestsBySource(await this.globTestSpecifications(filters));
|
|
7784
7847
|
}
|
|
7785
7848
|
async globTestSpecifications(filters = []) {
|
|
7786
|
-
const files = [];
|
|
7787
|
-
const dir = process.cwd();
|
|
7788
|
-
const parsedFilters = filters.map((f) => parseFilter(f));
|
|
7849
|
+
const files = [], dir = process.cwd(), parsedFilters = filters.map((f) => parseFilter(f));
|
|
7789
7850
|
// Require includeTaskLocation when a location filter is passed
|
|
7790
7851
|
if (!this.vitest.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) throw new IncludeTaskLocationDisabledError();
|
|
7791
7852
|
const testLines = groupFilters(parsedFilters.map((f) => ({
|
|
7792
7853
|
...f,
|
|
7793
7854
|
filename: resolve(dir, f.filename)
|
|
7794
|
-
})));
|
|
7795
|
-
|
|
7796
|
-
const testLocHasMatch = {};
|
|
7797
|
-
await Promise.all(this.vitest.projects.map(async (project) => {
|
|
7855
|
+
}))), testLocHasMatch = {};
|
|
7856
|
+
return await Promise.all(this.vitest.projects.map(async (project) => {
|
|
7798
7857
|
const { testFiles, typecheckTestFiles } = await project.globTestFiles(parsedFilters.map((f) => f.filename));
|
|
7799
7858
|
testFiles.forEach((file) => {
|
|
7800
7859
|
const lines = testLines[file];
|
|
7801
7860
|
testLocHasMatch[file] = true;
|
|
7802
7861
|
const spec = project.createSpecification(file, lines);
|
|
7803
|
-
this.ensureSpecificationCached(spec);
|
|
7804
|
-
|
|
7805
|
-
});
|
|
7806
|
-
typecheckTestFiles.forEach((file) => {
|
|
7862
|
+
this.ensureSpecificationCached(spec), files.push(spec);
|
|
7863
|
+
}), typecheckTestFiles.forEach((file) => {
|
|
7807
7864
|
const lines = testLines[file];
|
|
7808
7865
|
testLocHasMatch[file] = true;
|
|
7809
7866
|
const spec = project.createSpecification(file, lines, "typescript");
|
|
7810
|
-
this.ensureSpecificationCached(spec);
|
|
7811
|
-
files.push(spec);
|
|
7867
|
+
this.ensureSpecificationCached(spec), files.push(spec);
|
|
7812
7868
|
});
|
|
7813
|
-
}))
|
|
7814
|
-
Object.entries(testLines).forEach(([filepath, loc]) => {
|
|
7869
|
+
})), Object.entries(testLines).forEach(([filepath, loc]) => {
|
|
7815
7870
|
if (loc.length !== 0 && !testLocHasMatch[filepath]) throw new LocationFilterFileNotFoundError(relative(dir, filepath));
|
|
7816
|
-
});
|
|
7817
|
-
return files;
|
|
7871
|
+
}), files;
|
|
7818
7872
|
}
|
|
7819
7873
|
clearCache(moduleId) {
|
|
7820
7874
|
if (moduleId) this._cachedSpecs.delete(moduleId);
|
|
@@ -7824,30 +7878,20 @@ class VitestSpecifications {
|
|
|
7824
7878
|
return this._cachedSpecs.get(moduleId);
|
|
7825
7879
|
}
|
|
7826
7880
|
ensureSpecificationCached(spec) {
|
|
7827
|
-
const file = spec.moduleId;
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
if (index === -1) {
|
|
7831
|
-
specs.push(spec);
|
|
7832
|
-
this._cachedSpecs.set(file, specs);
|
|
7833
|
-
} else specs.splice(index, 1, spec);
|
|
7881
|
+
const file = spec.moduleId, specs = this._cachedSpecs.get(file) || [], index = specs.findIndex((_s) => _s.project === spec.project && _s.pool === spec.pool);
|
|
7882
|
+
if (index === -1) specs.push(spec), this._cachedSpecs.set(file, specs);
|
|
7883
|
+
else specs.splice(index, 1, spec);
|
|
7834
7884
|
return specs;
|
|
7835
7885
|
}
|
|
7836
7886
|
async filterTestsBySource(specs) {
|
|
7837
7887
|
if (this.vitest.config.changed && !this.vitest.config.related) {
|
|
7838
|
-
const { VitestGit } = await import('./git.
|
|
7839
|
-
|
|
7840
|
-
const related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
|
|
7841
|
-
if (!related) {
|
|
7842
|
-
process.exitCode = 1;
|
|
7843
|
-
throw new GitNotFoundError();
|
|
7844
|
-
}
|
|
7888
|
+
const { VitestGit } = await import('./git.BFNcloKD.js'), vitestGit = new VitestGit(this.vitest.config.root), related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
|
|
7889
|
+
if (!related) throw process.exitCode = 1, new GitNotFoundError();
|
|
7845
7890
|
this.vitest.config.related = Array.from(new Set(related));
|
|
7846
7891
|
}
|
|
7847
7892
|
const related = this.vitest.config.related;
|
|
7848
7893
|
if (!related) return specs;
|
|
7849
|
-
const forceRerunTriggers = this.vitest.config.forceRerunTriggers;
|
|
7850
|
-
const matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
|
|
7894
|
+
const forceRerunTriggers = this.vitest.config.forceRerunTriggers, matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
|
|
7851
7895
|
if (matcher && related.some((file) => matcher(file))) return specs;
|
|
7852
7896
|
// don't run anything if no related sources are found
|
|
7853
7897
|
// if we are in watch mode, we want to process all tests
|
|
@@ -7855,8 +7899,7 @@ class VitestSpecifications {
|
|
|
7855
7899
|
const testGraphs = await Promise.all(specs.map(async (spec) => {
|
|
7856
7900
|
const deps = await this.getTestDependencies(spec);
|
|
7857
7901
|
return [spec, deps];
|
|
7858
|
-
}));
|
|
7859
|
-
const runningTests = [];
|
|
7902
|
+
})), runningTests = [];
|
|
7860
7903
|
for (const [specification, deps] of testGraphs)
|
|
7861
7904
|
// if deps or the test itself were changed
|
|
7862
7905
|
if (related.some((path) => path === specification.moduleId || deps.has(path))) runningTests.push(specification);
|
|
@@ -7866,8 +7909,7 @@ class VitestSpecifications {
|
|
|
7866
7909
|
const addImports = async (project, filepath) => {
|
|
7867
7910
|
if (deps.has(filepath)) return;
|
|
7868
7911
|
deps.add(filepath);
|
|
7869
|
-
const mod = project.vite.moduleGraph.getModuleById(filepath);
|
|
7870
|
-
const transformed = mod?.ssrTransformResult || await project.vitenode.transformRequest(filepath);
|
|
7912
|
+
const mod = project.vite.environments.ssr.moduleGraph.getModuleById(filepath), transformed = mod?.transformResult || await project.vite.environments.ssr.transformRequest(filepath);
|
|
7871
7913
|
if (!transformed) return;
|
|
7872
7914
|
const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
|
|
7873
7915
|
await Promise.all(dependencies.map(async (dep) => {
|
|
@@ -7875,9 +7917,7 @@ class VitestSpecifications {
|
|
|
7875
7917
|
if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) await addImports(project, fsPath);
|
|
7876
7918
|
}));
|
|
7877
7919
|
};
|
|
7878
|
-
await addImports(spec.project, spec.moduleId);
|
|
7879
|
-
deps.delete(spec.moduleId);
|
|
7880
|
-
return deps;
|
|
7920
|
+
return await addImports(spec.project, spec.moduleId), deps.delete(spec.moduleId), deps;
|
|
7881
7921
|
}
|
|
7882
7922
|
}
|
|
7883
7923
|
|
|
@@ -7903,10 +7943,7 @@ class ReportedTaskImplementation {
|
|
|
7903
7943
|
location;
|
|
7904
7944
|
/** @internal */
|
|
7905
7945
|
constructor(task, project) {
|
|
7906
|
-
this.task = task;
|
|
7907
|
-
this.project = project;
|
|
7908
|
-
this.id = task.id;
|
|
7909
|
-
this.location = task.location;
|
|
7946
|
+
this.task = task, this.project = project, this.id = task.id, this.location = task.location;
|
|
7910
7947
|
}
|
|
7911
7948
|
/**
|
|
7912
7949
|
* Checks if the test did not fail the suite.
|
|
@@ -7928,8 +7965,7 @@ class ReportedTaskImplementation {
|
|
|
7928
7965
|
*/
|
|
7929
7966
|
static register(task, project) {
|
|
7930
7967
|
const state = new this(task, project);
|
|
7931
|
-
storeTask(project, task, state);
|
|
7932
|
-
return state;
|
|
7968
|
+
return storeTask(project, task, state), state;
|
|
7933
7969
|
}
|
|
7934
7970
|
}
|
|
7935
7971
|
class TestCase extends ReportedTaskImplementation {
|
|
@@ -7953,9 +7989,7 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
7953
7989
|
parent;
|
|
7954
7990
|
/** @internal */
|
|
7955
7991
|
constructor(task, project) {
|
|
7956
|
-
super(task, project);
|
|
7957
|
-
this.name = task.name;
|
|
7958
|
-
this.module = getReportedTask(project, task.file);
|
|
7992
|
+
super(task, project), this.name = task.name, this.module = getReportedTask(project, task.file);
|
|
7959
7993
|
const suite = this.task.suite;
|
|
7960
7994
|
if (suite) this.parent = getReportedTask(project, suite);
|
|
7961
7995
|
else this.parent = this.module;
|
|
@@ -7977,8 +8011,7 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
7977
8011
|
* - **skipped**: Test was skipped during collection or dynamically with `ctx.skip()`.
|
|
7978
8012
|
*/
|
|
7979
8013
|
result() {
|
|
7980
|
-
const result = this.task.result;
|
|
7981
|
-
const mode = result?.state || this.task.mode;
|
|
8014
|
+
const result = this.task.result, mode = result?.state || this.task.mode;
|
|
7982
8015
|
if (!result && (mode === "skip" || mode === "todo")) return {
|
|
7983
8016
|
state: "skipped",
|
|
7984
8017
|
note: void 0,
|
|
@@ -7989,16 +8022,14 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
7989
8022
|
errors: void 0
|
|
7990
8023
|
};
|
|
7991
8024
|
const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
|
|
7992
|
-
|
|
8025
|
+
return state === "skipped" ? {
|
|
7993
8026
|
state,
|
|
7994
8027
|
note: result.note,
|
|
7995
8028
|
errors: void 0
|
|
7996
|
-
}
|
|
7997
|
-
if (state === "passed") return {
|
|
8029
|
+
} : state === "passed" ? {
|
|
7998
8030
|
state,
|
|
7999
8031
|
errors: result.errors
|
|
8000
|
-
}
|
|
8001
|
-
return {
|
|
8032
|
+
} : {
|
|
8002
8033
|
state,
|
|
8003
8034
|
errors: result.errors || []
|
|
8004
8035
|
};
|
|
@@ -8017,8 +8048,7 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8017
8048
|
const result = this.task.result;
|
|
8018
8049
|
// startTime should always be available if the test has properly finished
|
|
8019
8050
|
if (!result || !result.startTime) return void 0;
|
|
8020
|
-
const duration = result.duration || 0;
|
|
8021
|
-
const slow = duration > this.project.globalConfig.slowTestThreshold;
|
|
8051
|
+
const duration = result.duration || 0, slow = duration > this.project.globalConfig.slowTestThreshold;
|
|
8022
8052
|
return {
|
|
8023
8053
|
slow,
|
|
8024
8054
|
heap: result.heap,
|
|
@@ -8034,8 +8064,7 @@ class TestCollection {
|
|
|
8034
8064
|
#task;
|
|
8035
8065
|
#project;
|
|
8036
8066
|
constructor(task, project) {
|
|
8037
|
-
this.#task = task;
|
|
8038
|
-
this.#project = project;
|
|
8067
|
+
this.#task = task, this.#project = project;
|
|
8039
8068
|
}
|
|
8040
8069
|
/**
|
|
8041
8070
|
* Returns the test or suite at a specific index.
|
|
@@ -8088,10 +8117,7 @@ class TestCollection {
|
|
|
8088
8117
|
* Filters all suites that are part of this collection and its children.
|
|
8089
8118
|
*/
|
|
8090
8119
|
*allSuites() {
|
|
8091
|
-
for (const child of this) if (child.type === "suite")
|
|
8092
|
-
yield child;
|
|
8093
|
-
yield* child.children.allSuites();
|
|
8094
|
-
}
|
|
8120
|
+
for (const child of this) if (child.type === "suite") yield child, yield* child.children.allSuites();
|
|
8095
8121
|
}
|
|
8096
8122
|
*[Symbol.iterator]() {
|
|
8097
8123
|
for (const task of this.#task.tasks) yield getReportedTask(this.#project, task);
|
|
@@ -8104,8 +8130,7 @@ class SuiteImplementation extends ReportedTaskImplementation {
|
|
|
8104
8130
|
children;
|
|
8105
8131
|
/** @internal */
|
|
8106
8132
|
constructor(task, project) {
|
|
8107
|
-
super(task, project);
|
|
8108
|
-
this.children = new TestCollection(task, project);
|
|
8133
|
+
super(task, project), this.children = new TestCollection(task, project);
|
|
8109
8134
|
}
|
|
8110
8135
|
/**
|
|
8111
8136
|
* Errors that happened outside of the test run during collection, like syntax errors.
|
|
@@ -8135,9 +8160,7 @@ class TestSuite extends SuiteImplementation {
|
|
|
8135
8160
|
options;
|
|
8136
8161
|
/** @internal */
|
|
8137
8162
|
constructor(task, project) {
|
|
8138
|
-
super(task, project);
|
|
8139
|
-
this.name = task.name;
|
|
8140
|
-
this.module = getReportedTask(project, task.file);
|
|
8163
|
+
super(task, project), this.name = task.name, this.module = getReportedTask(project, task.file);
|
|
8141
8164
|
const suite = this.task.suite;
|
|
8142
8165
|
if (suite) this.parent = getReportedTask(project, suite);
|
|
8143
8166
|
else this.parent = this.module;
|
|
@@ -8166,31 +8189,27 @@ class TestModule extends SuiteImplementation {
|
|
|
8166
8189
|
* This value corresponds to the ID in the Vite's module graph.
|
|
8167
8190
|
*/
|
|
8168
8191
|
moduleId;
|
|
8192
|
+
/**
|
|
8193
|
+
* Module id relative to the project. This is the same as `task.name`.
|
|
8194
|
+
*/
|
|
8195
|
+
relativeModuleId;
|
|
8169
8196
|
/** @internal */
|
|
8170
8197
|
constructor(task, project) {
|
|
8171
|
-
super(task, project);
|
|
8172
|
-
this.moduleId = task.filepath;
|
|
8198
|
+
super(task, project), this.moduleId = task.filepath, this.relativeModuleId = task.name;
|
|
8173
8199
|
}
|
|
8174
8200
|
/**
|
|
8175
8201
|
* Checks the running state of the test file.
|
|
8176
8202
|
*/
|
|
8177
8203
|
state() {
|
|
8178
8204
|
const state = this.task.result?.state;
|
|
8179
|
-
|
|
8180
|
-
return getSuiteState(this.task);
|
|
8205
|
+
return state === "queued" ? "queued" : getSuiteState(this.task);
|
|
8181
8206
|
}
|
|
8182
8207
|
/**
|
|
8183
8208
|
* Useful information about the module like duration, memory usage, etc.
|
|
8184
8209
|
* If the module was not executed yet, all diagnostic values will return `0`.
|
|
8185
8210
|
*/
|
|
8186
8211
|
diagnostic() {
|
|
8187
|
-
const setupDuration = this.task.setupDuration || 0;
|
|
8188
|
-
const collectDuration = this.task.collectDuration || 0;
|
|
8189
|
-
const prepareDuration = this.task.prepareDuration || 0;
|
|
8190
|
-
const environmentSetupDuration = this.task.environmentLoad || 0;
|
|
8191
|
-
const duration = this.task.result?.duration || 0;
|
|
8192
|
-
const heap = this.task.result?.heap;
|
|
8193
|
-
const importDurations = this.task.importDurations ?? {};
|
|
8212
|
+
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 ?? {};
|
|
8194
8213
|
return {
|
|
8195
8214
|
environmentSetupDuration,
|
|
8196
8215
|
prepareDuration,
|
|
@@ -8222,18 +8241,19 @@ function getReportedTask(project, runnerTask) {
|
|
|
8222
8241
|
return reportedTask;
|
|
8223
8242
|
}
|
|
8224
8243
|
function getSuiteState(task) {
|
|
8225
|
-
const mode = task.mode;
|
|
8226
|
-
const state = task.result?.state;
|
|
8244
|
+
const mode = task.mode, state = task.result?.state;
|
|
8227
8245
|
if (mode === "skip" || mode === "todo" || state === "skip" || state === "todo") return "skipped";
|
|
8228
8246
|
if (state == null || state === "run" || state === "only") return "pending";
|
|
8229
8247
|
if (state === "fail") return "failed";
|
|
8230
8248
|
if (state === "pass") return "passed";
|
|
8231
8249
|
throw new Error(`Unknown suite state: ${state}`);
|
|
8232
8250
|
}
|
|
8251
|
+
function experimental_getRunnerTask(entity) {
|
|
8252
|
+
return entity.task;
|
|
8253
|
+
}
|
|
8233
8254
|
|
|
8234
8255
|
function isAggregateError(err) {
|
|
8235
|
-
|
|
8236
|
-
return err instanceof Error && "errors" in err;
|
|
8256
|
+
return typeof AggregateError !== "undefined" && err instanceof AggregateError ? true : err instanceof Error && "errors" in err;
|
|
8237
8257
|
}
|
|
8238
8258
|
class StateManager {
|
|
8239
8259
|
filesMap = /* @__PURE__ */ new Map();
|
|
@@ -8244,25 +8264,30 @@ class StateManager {
|
|
|
8244
8264
|
processTimeoutCauses = /* @__PURE__ */ new Set();
|
|
8245
8265
|
reportedTasksMap = /* @__PURE__ */ new WeakMap();
|
|
8246
8266
|
blobs;
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8267
|
+
transformTime = 0;
|
|
8268
|
+
onUnhandledError;
|
|
8269
|
+
/** @internal */
|
|
8270
|
+
_data = {
|
|
8271
|
+
browserLastPort: defaultBrowserPort,
|
|
8272
|
+
timeoutIncreased: false
|
|
8273
|
+
};
|
|
8274
|
+
constructor(options) {
|
|
8275
|
+
this.onUnhandledError = options.onUnhandledError;
|
|
8276
|
+
}
|
|
8277
|
+
catchError(error, type) {
|
|
8278
|
+
if (isAggregateError(error)) return error.errors.forEach((error) => this.catchError(error, type));
|
|
8279
|
+
if (typeof error === "object" && error !== null) error.type = type;
|
|
8280
|
+
else error = {
|
|
8251
8281
|
type,
|
|
8252
|
-
message:
|
|
8282
|
+
message: error
|
|
8253
8283
|
};
|
|
8254
|
-
const
|
|
8255
|
-
if (
|
|
8256
|
-
const task = this.idMap.get(
|
|
8257
|
-
if (task) {
|
|
8258
|
-
task.mode = "skip";
|
|
8259
|
-
task.result ??= { state: "skip" };
|
|
8260
|
-
task.result.state = "skip";
|
|
8261
|
-
task.result.note = _err.note;
|
|
8262
|
-
}
|
|
8284
|
+
const _error = error;
|
|
8285
|
+
if (_error && typeof _error === "object" && _error.code === "VITEST_PENDING") {
|
|
8286
|
+
const task = this.idMap.get(_error.taskId);
|
|
8287
|
+
if (task) task.mode = "skip", task.result ??= { state: "skip" }, task.result.state = "skip", task.result.note = _error.note;
|
|
8263
8288
|
return;
|
|
8264
8289
|
}
|
|
8265
|
-
this.errorsSet.add(
|
|
8290
|
+
if (!this.onUnhandledError || this.onUnhandledError(error) !== false) this.errorsSet.add(error);
|
|
8266
8291
|
}
|
|
8267
8292
|
clearErrors() {
|
|
8268
8293
|
this.errorsSet.clear();
|
|
@@ -8283,12 +8308,8 @@ class StateManager {
|
|
|
8283
8308
|
* Return files that were running or collected.
|
|
8284
8309
|
*/
|
|
8285
8310
|
getFiles(keys) {
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
// print typecheck files first
|
|
8289
|
-
if (f1.meta?.typecheck && f2.meta?.typecheck) return 0;
|
|
8290
|
-
if (f1.meta?.typecheck) return -1;
|
|
8291
|
-
return 1;
|
|
8311
|
+
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) => {
|
|
8312
|
+
return f1.meta?.typecheck && f2.meta?.typecheck ? 0 : f1.meta?.typecheck ? -1 : 1;
|
|
8292
8313
|
});
|
|
8293
8314
|
}
|
|
8294
8315
|
getTestModules(keys) {
|
|
@@ -8307,25 +8328,17 @@ class StateManager {
|
|
|
8307
8328
|
}
|
|
8308
8329
|
collectFiles(project, files = []) {
|
|
8309
8330
|
files.forEach((file) => {
|
|
8310
|
-
const existing = this.filesMap.get(file.filepath) || [];
|
|
8311
|
-
const otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck);
|
|
8312
|
-
const currentFile = existing.find((i) => i.projectName === file.projectName);
|
|
8331
|
+
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);
|
|
8313
8332
|
// keep logs for the previous file because it should always be initiated before the collections phase
|
|
8314
8333
|
// which means that all logs are collected during the collection and not inside tests
|
|
8315
8334
|
if (currentFile) file.logs = currentFile.logs;
|
|
8316
|
-
otherFiles.push(file);
|
|
8317
|
-
this.filesMap.set(file.filepath, otherFiles);
|
|
8318
|
-
this.updateId(file, project);
|
|
8335
|
+
otherFiles.push(file), this.filesMap.set(file.filepath, otherFiles), this.updateId(file, project);
|
|
8319
8336
|
});
|
|
8320
8337
|
}
|
|
8321
8338
|
clearFiles(project, paths = []) {
|
|
8322
8339
|
paths.forEach((path) => {
|
|
8323
|
-
const files = this.filesMap.get(path);
|
|
8324
|
-
|
|
8325
|
-
fileTask.local = true;
|
|
8326
|
-
TestModule.register(fileTask, project);
|
|
8327
|
-
this.idMap.set(fileTask.id, fileTask);
|
|
8328
|
-
if (!files) {
|
|
8340
|
+
const files = this.filesMap.get(path), fileTask = createFileTask$1(path, project.config.root, project.config.name);
|
|
8341
|
+
if (fileTask.local = true, TestModule.register(fileTask, project), this.idMap.set(fileTask.id, fileTask), !files) {
|
|
8329
8342
|
this.filesMap.set(path, [fileTask]);
|
|
8330
8343
|
return;
|
|
8331
8344
|
}
|
|
@@ -8336,14 +8349,14 @@ class StateManager {
|
|
|
8336
8349
|
});
|
|
8337
8350
|
}
|
|
8338
8351
|
updateId(task, project) {
|
|
8339
|
-
if (this.idMap.get(task.id)
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
}
|
|
8352
|
+
if (this.idMap.get(task.id) !== task) {
|
|
8353
|
+
if (task.type === "suite" && "filepath" in task) TestModule.register(task, project);
|
|
8354
|
+
else if (task.type === "suite") TestSuite.register(task, project);
|
|
8355
|
+
else TestCase.register(task, project);
|
|
8356
|
+
if (this.idMap.set(task.id, task), task.type === "suite") task.tasks.forEach((task) => {
|
|
8357
|
+
this.updateId(task, project);
|
|
8358
|
+
});
|
|
8359
|
+
}
|
|
8347
8360
|
}
|
|
8348
8361
|
getReportedEntity(task) {
|
|
8349
8362
|
return this.reportedTasksMap.get(task);
|
|
@@ -8352,10 +8365,8 @@ class StateManager {
|
|
|
8352
8365
|
for (const [id, result, meta] of packs) {
|
|
8353
8366
|
const task = this.idMap.get(id);
|
|
8354
8367
|
if (task) {
|
|
8355
|
-
task.result = result;
|
|
8356
|
-
task.meta = meta;
|
|
8357
8368
|
// skipped with new PendingError
|
|
8358
|
-
if (result?.state === "skip") task.mode = "skip";
|
|
8369
|
+
if (task.result = result, task.meta = meta, result?.state === "skip") task.mode = "skip";
|
|
8359
8370
|
}
|
|
8360
8371
|
}
|
|
8361
8372
|
}
|
|
@@ -8370,7 +8381,7 @@ class StateManager {
|
|
|
8370
8381
|
return Array.from(this.idMap.values()).filter((t) => t.result?.state === "fail").length;
|
|
8371
8382
|
}
|
|
8372
8383
|
cancelFiles(files, project) {
|
|
8373
|
-
this.collectFiles(project, files.map((filepath) => createFileTask(filepath, project.config.root, project.config.name)));
|
|
8384
|
+
this.collectFiles(project, files.map((filepath) => createFileTask$1(filepath, project.config.root, project.config.name)));
|
|
8374
8385
|
}
|
|
8375
8386
|
}
|
|
8376
8387
|
|
|
@@ -8832,10 +8843,7 @@ class TestRun {
|
|
|
8832
8843
|
}
|
|
8833
8844
|
async start(specifications) {
|
|
8834
8845
|
const filepaths = specifications.map((spec) => spec.moduleId);
|
|
8835
|
-
this.vitest.state.collectPaths(filepaths);
|
|
8836
|
-
await this.vitest.report("onPathsCollected", Array.from(new Set(filepaths)));
|
|
8837
|
-
await this.vitest.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
|
|
8838
|
-
await this.vitest.report("onTestRunStart", [...specifications]);
|
|
8846
|
+
this.vitest.state.collectPaths(filepaths), await this.vitest.report("onTestRunStart", [...specifications]);
|
|
8839
8847
|
}
|
|
8840
8848
|
async enqueued(project, file) {
|
|
8841
8849
|
this.vitest.state.collectFiles(project, [file]);
|
|
@@ -8843,30 +8851,22 @@ class TestRun {
|
|
|
8843
8851
|
await this.vitest.report("onTestModuleQueued", testModule);
|
|
8844
8852
|
}
|
|
8845
8853
|
async collected(project, files) {
|
|
8846
|
-
this.vitest.state.collectFiles(project, files)
|
|
8847
|
-
await Promise.all([this.vitest.report("onCollected", files), ...files.map((file) => {
|
|
8854
|
+
this.vitest.state.collectFiles(project, files), await Promise.all(files.map((file) => {
|
|
8848
8855
|
const testModule = this.vitest.state.getReportedEntity(file);
|
|
8849
8856
|
return this.vitest.report("onTestModuleCollected", testModule);
|
|
8850
|
-
})
|
|
8857
|
+
}));
|
|
8851
8858
|
}
|
|
8852
8859
|
async log(log) {
|
|
8853
|
-
this.vitest.state.updateUserLog(log);
|
|
8854
|
-
await this.vitest.report("onUserConsoleLog", log);
|
|
8860
|
+
this.vitest.state.updateUserLog(log), await this.vitest.report("onUserConsoleLog", log);
|
|
8855
8861
|
}
|
|
8856
8862
|
async annotate(testId, annotation) {
|
|
8857
|
-
const task = this.vitest.state.idMap.get(testId);
|
|
8858
|
-
|
|
8859
|
-
assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
|
|
8860
|
-
assert$1(entity.type === "test", `Annotation can only be added to a test, instead got ${entity.type}`);
|
|
8861
|
-
await this.resolveTestAttachment(entity, annotation);
|
|
8862
|
-
entity.task.annotations.push(annotation);
|
|
8863
|
-
await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
8864
|
-
return annotation;
|
|
8863
|
+
const task = this.vitest.state.idMap.get(testId), entity = task && this.vitest.state.getReportedEntity(task);
|
|
8864
|
+
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;
|
|
8865
8865
|
}
|
|
8866
8866
|
async updated(update, events) {
|
|
8867
|
-
this.vitest.state.updateTasks(update);
|
|
8867
|
+
this.syncUpdateStacks(update), this.vitest.state.updateTasks(update);
|
|
8868
8868
|
for (const [id, event, data] of events) await this.reportEvent(id, event, data).catch((error) => {
|
|
8869
|
-
this.vitest.state.catchError(serializeError(error), "Unhandled Reporter Error");
|
|
8869
|
+
this.vitest.state.catchError(serializeError$1(error), "Unhandled Reporter Error");
|
|
8870
8870
|
});
|
|
8871
8871
|
// TODO: what is the order or reports here?
|
|
8872
8872
|
// "onTaskUpdate" in parallel with others or before all or after all?
|
|
@@ -8874,30 +8874,32 @@ class TestRun {
|
|
|
8874
8874
|
await this.vitest.report("onTaskUpdate", update, events);
|
|
8875
8875
|
}
|
|
8876
8876
|
async end(specifications, errors, coverage) {
|
|
8877
|
+
if (coverage) await this.vitest.report("onCoverage", coverage);
|
|
8877
8878
|
// specification won't have the File task if they were filtered by the --shard command
|
|
8878
|
-
const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null);
|
|
8879
|
-
const files = modules.map((m) => m.task);
|
|
8880
|
-
const state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
|
|
8879
|
+
const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null), state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
|
|
8881
8880
|
if (state !== "passed") process.exitCode = 1;
|
|
8882
|
-
|
|
8883
|
-
await Promise.all([this.vitest.report("onTestRunEnd", modules, [...errors], state), this.vitest.report("onFinished", files, errors, coverage)]);
|
|
8884
|
-
} finally {
|
|
8885
|
-
if (coverage) await this.vitest.report("onCoverage", coverage);
|
|
8886
|
-
}
|
|
8881
|
+
await this.vitest.report("onTestRunEnd", modules, [...errors], state);
|
|
8887
8882
|
}
|
|
8888
8883
|
hasFailed(modules) {
|
|
8889
|
-
|
|
8890
|
-
|
|
8884
|
+
return modules.length ? modules.some((m) => !m.ok()) : !this.vitest.config.passWithNoTests;
|
|
8885
|
+
}
|
|
8886
|
+
syncUpdateStacks(update) {
|
|
8887
|
+
update.forEach(([taskId, result]) => {
|
|
8888
|
+
const task = this.vitest.state.idMap.get(taskId), isBrowser = task && task.file.pool === "browser";
|
|
8889
|
+
result?.errors?.forEach((error) => {
|
|
8890
|
+
if (isPrimitive(error)) return;
|
|
8891
|
+
const project = this.vitest.getProjectByName(task.file.projectName || "");
|
|
8892
|
+
if (isBrowser) error.stacks = project.browser?.parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace }) || [];
|
|
8893
|
+
else error.stacks = parseErrorStacktrace(error, { frameFilter: project.config.onStackTrace });
|
|
8894
|
+
});
|
|
8895
|
+
});
|
|
8891
8896
|
}
|
|
8892
8897
|
async reportEvent(id, event, data) {
|
|
8893
|
-
const task = this.vitest.state.idMap.get(id);
|
|
8894
|
-
|
|
8895
|
-
assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
|
|
8896
|
-
if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
|
|
8898
|
+
const task = this.vitest.state.idMap.get(id), entity = task && this.vitest.state.getReportedEntity(task);
|
|
8899
|
+
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);
|
|
8897
8900
|
if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
|
|
8898
8901
|
if (event === "suite-finished") {
|
|
8899
|
-
assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module")
|
|
8900
|
-
if (entity.state() === "skipped")
|
|
8902
|
+
if (assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module"), entity.state() === "skipped")
|
|
8901
8903
|
// everything inside suite or a module is skipped,
|
|
8902
8904
|
// so we won't get any children events
|
|
8903
8905
|
// we need to report everything manually
|
|
@@ -8909,8 +8911,7 @@ class TestRun {
|
|
|
8909
8911
|
if (event === "test-prepare" && entity.type === "test") return await this.vitest.report("onTestCaseReady", entity);
|
|
8910
8912
|
if (event === "test-finished" && entity.type === "test") return await this.vitest.report("onTestCaseResult", entity);
|
|
8911
8913
|
if (event.startsWith("before-hook") || event.startsWith("after-hook")) {
|
|
8912
|
-
const isBefore = event.startsWith("before-hook")
|
|
8913
|
-
const hook = entity.type === "test" ? {
|
|
8914
|
+
const isBefore = event.startsWith("before-hook"), hook = entity.type === "test" ? {
|
|
8914
8915
|
name: isBefore ? "beforeEach" : "afterEach",
|
|
8915
8916
|
entity
|
|
8916
8917
|
} : {
|
|
@@ -8922,37 +8923,25 @@ class TestRun {
|
|
|
8922
8923
|
// this can only happen in --merge-reports, and annotation is already resolved
|
|
8923
8924
|
if (event === "test-annotation") {
|
|
8924
8925
|
const annotation = data?.annotation;
|
|
8925
|
-
assert$1(annotation && entity.type === "test");
|
|
8926
|
-
await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
8926
|
+
assert$1(annotation && entity.type === "test"), await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
8927
8927
|
}
|
|
8928
8928
|
}
|
|
8929
8929
|
}
|
|
8930
8930
|
async resolveTestAttachment(test, annotation) {
|
|
8931
|
-
const project = test.project;
|
|
8932
|
-
const attachment = annotation.attachment;
|
|
8931
|
+
const project = test.project, attachment = annotation.attachment;
|
|
8933
8932
|
if (!attachment) return attachment;
|
|
8934
8933
|
const path = attachment.path;
|
|
8935
8934
|
if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
|
|
8936
|
-
const currentPath = resolve(project.config.root, path);
|
|
8937
|
-
|
|
8938
|
-
const newPath = resolve(project.config.attachmentsDir, `${sanitizeFilePath(annotation.message)}-${hash}${extname(currentPath)}`);
|
|
8939
|
-
await mkdir(dirname(newPath), { recursive: true });
|
|
8940
|
-
await copyFile(currentPath, newPath);
|
|
8941
|
-
attachment.path = newPath;
|
|
8935
|
+
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)}`);
|
|
8936
|
+
await mkdir(dirname(newPath), { recursive: true }), await copyFile(currentPath, newPath), attachment.path = newPath;
|
|
8942
8937
|
const contentType = attachment.contentType ?? mime.getType(basename(currentPath));
|
|
8943
8938
|
attachment.contentType = contentType || void 0;
|
|
8944
8939
|
}
|
|
8945
8940
|
return attachment;
|
|
8946
8941
|
}
|
|
8947
8942
|
async reportChildren(children) {
|
|
8948
|
-
for (const child of children) if (child.type === "test")
|
|
8949
|
-
|
|
8950
|
-
await this.vitest.report("onTestCaseResult", child);
|
|
8951
|
-
} else {
|
|
8952
|
-
await this.vitest.report("onTestSuiteReady", child);
|
|
8953
|
-
await this.reportChildren(child.children);
|
|
8954
|
-
await this.vitest.report("onTestSuiteResult", child);
|
|
8955
|
-
}
|
|
8943
|
+
for (const child of children) if (child.type === "test") await this.vitest.report("onTestCaseReady", child), await this.vitest.report("onTestCaseResult", child);
|
|
8944
|
+
else await this.vitest.report("onTestSuiteReady", child), await this.reportChildren(child.children), await this.vitest.report("onTestSuiteResult", child);
|
|
8956
8945
|
}
|
|
8957
8946
|
}
|
|
8958
8947
|
function sanitizeFilePath(s) {
|
|
@@ -8980,23 +8969,15 @@ class VitestWatcher {
|
|
|
8980
8969
|
* @internal
|
|
8981
8970
|
*/
|
|
8982
8971
|
onWatcherRerun(cb) {
|
|
8983
|
-
this._onRerun.push(cb);
|
|
8984
|
-
return this;
|
|
8972
|
+
return this._onRerun.push(cb), this;
|
|
8985
8973
|
}
|
|
8986
8974
|
unregisterWatcher = noop;
|
|
8987
8975
|
registerWatcher() {
|
|
8988
8976
|
const watcher = this.vitest.vite.watcher;
|
|
8989
8977
|
if (this.vitest.config.forceRerunTriggers.length) watcher.add(this.vitest.config.forceRerunTriggers);
|
|
8990
|
-
watcher.on("change", this.
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
this.unregisterWatcher = () => {
|
|
8994
|
-
watcher.off("change", this.onChange);
|
|
8995
|
-
watcher.off("unlink", this.onUnlink);
|
|
8996
|
-
watcher.off("add", this.onAdd);
|
|
8997
|
-
this.unregisterWatcher = noop;
|
|
8998
|
-
};
|
|
8999
|
-
return this;
|
|
8978
|
+
return watcher.on("change", this.onFileChange), watcher.on("unlink", this.onFileDelete), watcher.on("add", this.onFileCreate), this.unregisterWatcher = () => {
|
|
8979
|
+
watcher.off("change", this.onFileChange), watcher.off("unlink", this.onFileDelete), watcher.off("add", this.onFileCreate), this.unregisterWatcher = noop;
|
|
8980
|
+
}, this;
|
|
9000
8981
|
}
|
|
9001
8982
|
scheduleRerun(file) {
|
|
9002
8983
|
this._onRerun.forEach((cb) => cb(file));
|
|
@@ -9004,25 +8985,17 @@ class VitestWatcher {
|
|
|
9004
8985
|
getTestFilesFromWatcherTrigger(id) {
|
|
9005
8986
|
if (!this.vitest.config.watchTriggerPatterns) return false;
|
|
9006
8987
|
let triggered = false;
|
|
9007
|
-
this.vitest.config.watchTriggerPatterns.forEach((definition) => {
|
|
8988
|
+
return this.vitest.config.watchTriggerPatterns.forEach((definition) => {
|
|
9008
8989
|
const exec = definition.pattern.exec(id);
|
|
9009
8990
|
if (exec) {
|
|
9010
8991
|
const files = definition.testsToRun(id, exec);
|
|
9011
|
-
if (Array.isArray(files))
|
|
9012
|
-
|
|
9013
|
-
files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
|
|
9014
|
-
} else if (typeof files === "string") {
|
|
9015
|
-
triggered = true;
|
|
9016
|
-
this.changedTests.add(resolve(this.vitest.config.root, files));
|
|
9017
|
-
}
|
|
8992
|
+
if (Array.isArray(files)) triggered = true, files.forEach((file) => this.changedTests.add(resolve(this.vitest.config.root, file)));
|
|
8993
|
+
else if (typeof files === "string") triggered = true, this.changedTests.add(resolve(this.vitest.config.root, files));
|
|
9018
8994
|
}
|
|
9019
|
-
});
|
|
9020
|
-
return triggered;
|
|
8995
|
+
}), triggered;
|
|
9021
8996
|
}
|
|
9022
|
-
|
|
9023
|
-
id = slash(id);
|
|
9024
|
-
this.vitest.logger.clearHighlightCache(id);
|
|
9025
|
-
this.vitest.invalidateFile(id);
|
|
8997
|
+
onFileChange = (id) => {
|
|
8998
|
+
id = slash(id), this.vitest.logger.clearHighlightCache(id), this.vitest.invalidateFile(id);
|
|
9026
8999
|
const testFiles = this.getTestFilesFromWatcherTrigger(id);
|
|
9027
9000
|
if (testFiles) this.scheduleRerun(id);
|
|
9028
9001
|
else {
|
|
@@ -9030,22 +9003,11 @@ class VitestWatcher {
|
|
|
9030
9003
|
if (needsRerun) this.scheduleRerun(id);
|
|
9031
9004
|
}
|
|
9032
9005
|
};
|
|
9033
|
-
|
|
9034
|
-
id = slash(id);
|
|
9035
|
-
this.vitest.logger.clearHighlightCache(id);
|
|
9036
|
-
this.invalidates.add(id);
|
|
9037
|
-
if (this.vitest.state.filesMap.has(id)) {
|
|
9038
|
-
this.vitest.projects.forEach((project) => project._removeCachedTestFile(id));
|
|
9039
|
-
this.vitest.state.filesMap.delete(id);
|
|
9040
|
-
this.vitest.cache.results.removeFromCache(id);
|
|
9041
|
-
this.vitest.cache.stats.removeStats(id);
|
|
9042
|
-
this.changedTests.delete(id);
|
|
9043
|
-
this.vitest.report("onTestRemoved", id);
|
|
9044
|
-
}
|
|
9006
|
+
onFileDelete = (id) => {
|
|
9007
|
+
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);
|
|
9045
9008
|
};
|
|
9046
|
-
|
|
9047
|
-
id = slash(id);
|
|
9048
|
-
this.vitest.invalidateFile(id);
|
|
9009
|
+
onFileCreate = (id) => {
|
|
9010
|
+
id = slash(id), this.vitest.invalidateFile(id);
|
|
9049
9011
|
const testFiles = this.getTestFilesFromWatcherTrigger(id);
|
|
9050
9012
|
if (testFiles) {
|
|
9051
9013
|
this.scheduleRerun(id);
|
|
@@ -9053,13 +9015,10 @@ class VitestWatcher {
|
|
|
9053
9015
|
}
|
|
9054
9016
|
let fileContent;
|
|
9055
9017
|
const matchingProjects = [];
|
|
9056
|
-
this.vitest.projects.forEach((project) => {
|
|
9018
|
+
if (this.vitest.projects.forEach((project) => {
|
|
9057
9019
|
if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8"))) matchingProjects.push(project);
|
|
9058
|
-
});
|
|
9059
|
-
|
|
9060
|
-
this.changedTests.add(id);
|
|
9061
|
-
this.scheduleRerun(id);
|
|
9062
|
-
} else {
|
|
9020
|
+
}), matchingProjects.length > 0) this.changedTests.add(id), this.scheduleRerun(id);
|
|
9021
|
+
else {
|
|
9063
9022
|
// it's possible that file was already there but watcher triggered "add" event instead
|
|
9064
9023
|
const needsRerun = this.handleFileChanged(id);
|
|
9065
9024
|
if (needsRerun) this.scheduleRerun(id);
|
|
@@ -9067,51 +9026,33 @@ class VitestWatcher {
|
|
|
9067
9026
|
};
|
|
9068
9027
|
handleSetupFile(filepath) {
|
|
9069
9028
|
let isSetupFile = false;
|
|
9070
|
-
this.vitest.projects.forEach((project) => {
|
|
9071
|
-
|
|
9072
|
-
this.vitest.state.filesMap.forEach((files) => {
|
|
9029
|
+
return this.vitest.projects.forEach((project) => {
|
|
9030
|
+
project.config.setupFiles.includes(filepath) && this.vitest.state.filesMap.forEach((files) => {
|
|
9073
9031
|
files.forEach((file) => {
|
|
9074
|
-
if (file.projectName === project.name)
|
|
9075
|
-
isSetupFile = true;
|
|
9076
|
-
this.changedTests.add(file.filepath);
|
|
9077
|
-
}
|
|
9032
|
+
if (file.projectName === project.name) isSetupFile = true, this.changedTests.add(file.filepath);
|
|
9078
9033
|
});
|
|
9079
9034
|
});
|
|
9080
|
-
});
|
|
9081
|
-
return isSetupFile;
|
|
9035
|
+
}), isSetupFile;
|
|
9082
9036
|
}
|
|
9083
9037
|
/**
|
|
9084
9038
|
* @returns A value indicating whether rerun is needed (changedTests was mutated)
|
|
9085
9039
|
*/
|
|
9086
9040
|
handleFileChanged(filepath) {
|
|
9087
9041
|
if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) return false;
|
|
9088
|
-
if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers))
|
|
9089
|
-
this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file));
|
|
9090
|
-
return true;
|
|
9091
|
-
}
|
|
9042
|
+
if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) return this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file)), true;
|
|
9092
9043
|
if (this.handleSetupFile(filepath)) return true;
|
|
9093
9044
|
const projects = this.vitest.projects.filter((project) => {
|
|
9094
9045
|
const moduleGraph = project.browser?.vite.moduleGraph || project.vite.moduleGraph;
|
|
9095
9046
|
return moduleGraph.getModulesByFile(filepath)?.size;
|
|
9096
9047
|
});
|
|
9097
|
-
if (!projects.length)
|
|
9098
|
-
// if there are no modules it's possible that server was restarted
|
|
9099
|
-
// we don't have information about importers anymore, so let's check if the file is a test file at least
|
|
9100
|
-
if (this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath))) {
|
|
9101
|
-
this.changedTests.add(filepath);
|
|
9102
|
-
return true;
|
|
9103
|
-
}
|
|
9104
|
-
return false;
|
|
9105
|
-
}
|
|
9048
|
+
if (!projects.length) return this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath)) ? (this.changedTests.add(filepath), true) : false;
|
|
9106
9049
|
const files = [];
|
|
9107
9050
|
for (const project of projects) {
|
|
9108
9051
|
const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath) || project.vite.moduleGraph.getModulesByFile(filepath);
|
|
9109
9052
|
if (!mods || !mods.size) continue;
|
|
9110
|
-
this.invalidates.add(filepath);
|
|
9111
9053
|
// one of test files that we already run, or one of test files that we can run
|
|
9112
|
-
if (this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
|
|
9113
|
-
this.changedTests.add(filepath);
|
|
9114
|
-
files.push(filepath);
|
|
9054
|
+
if (this.invalidates.add(filepath), this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
|
|
9055
|
+
this.changedTests.add(filepath), files.push(filepath);
|
|
9115
9056
|
continue;
|
|
9116
9057
|
}
|
|
9117
9058
|
let rerun = false;
|
|
@@ -9158,43 +9099,38 @@ class Vitest {
|
|
|
9158
9099
|
* If projects were filtered with `--project` flag, they won't appear here.
|
|
9159
9100
|
*/
|
|
9160
9101
|
projects = [];
|
|
9102
|
+
/**
|
|
9103
|
+
* A watcher handler. This is not the file system watcher. The handler only
|
|
9104
|
+
* exposes methods to handle changed files.
|
|
9105
|
+
*
|
|
9106
|
+
* If you have your own watcher, you can use these methods to replicate
|
|
9107
|
+
* Vitest behaviour.
|
|
9108
|
+
*/
|
|
9109
|
+
watcher;
|
|
9161
9110
|
/** @internal */ configOverride = {};
|
|
9162
|
-
/** @internal */ coverageProvider;
|
|
9163
9111
|
/** @internal */ filenamePattern;
|
|
9164
9112
|
/** @internal */ runningPromise;
|
|
9165
9113
|
/** @internal */ closingPromise;
|
|
9166
9114
|
/** @internal */ isCancelling = false;
|
|
9167
9115
|
/** @internal */ coreWorkspaceProject;
|
|
9168
|
-
/**
|
|
9169
|
-
* @internal
|
|
9170
|
-
* @deprecated
|
|
9171
|
-
*/
|
|
9172
|
-
resolvedProjects = [];
|
|
9173
|
-
/** @internal */ _browserLastPort = defaultBrowserPort;
|
|
9174
9116
|
/** @internal */ _browserSessions = new BrowserSessions();
|
|
9175
9117
|
/** @internal */ _cliOptions = {};
|
|
9176
9118
|
/** @internal */ reporters = [];
|
|
9177
|
-
/** @internal */
|
|
9178
|
-
/** @internal */ runner = void 0;
|
|
9119
|
+
/** @internal */ runner;
|
|
9179
9120
|
/** @internal */ _testRun = void 0;
|
|
9121
|
+
/** @internal */ _resolver;
|
|
9180
9122
|
isFirstRun = true;
|
|
9181
9123
|
restartsCount = 0;
|
|
9182
9124
|
specifications;
|
|
9183
|
-
watcher;
|
|
9184
9125
|
pool;
|
|
9185
9126
|
_config;
|
|
9186
9127
|
_vite;
|
|
9187
9128
|
_state;
|
|
9188
9129
|
_cache;
|
|
9189
9130
|
_snapshot;
|
|
9190
|
-
|
|
9131
|
+
_coverageProvider;
|
|
9191
9132
|
constructor(mode, cliOptions, options = {}) {
|
|
9192
|
-
this.mode = mode;
|
|
9193
|
-
this._cliOptions = cliOptions;
|
|
9194
|
-
this.logger = new Logger(this, options.stdout, options.stderr);
|
|
9195
|
-
this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
|
|
9196
|
-
this.specifications = new VitestSpecifications(this);
|
|
9197
|
-
this.watcher = new VitestWatcher(this).onWatcherRerun((file) => this.scheduleRerun([file]));
|
|
9133
|
+
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));
|
|
9198
9134
|
}
|
|
9199
9135
|
_onRestartListeners = [];
|
|
9200
9136
|
_onClose = [];
|
|
@@ -9202,114 +9138,54 @@ class Vitest {
|
|
|
9202
9138
|
_onCancelListeners = [];
|
|
9203
9139
|
_onUserTestsRerun = [];
|
|
9204
9140
|
_onFilterWatchedSpecification = [];
|
|
9205
|
-
/** @deprecated will be removed in 4.0, use `onFilterWatchedSpecification` instead */
|
|
9206
|
-
get invalidates() {
|
|
9207
|
-
return this.watcher.invalidates;
|
|
9208
|
-
}
|
|
9209
|
-
/** @deprecated will be removed in 4.0, use `onFilterWatchedSpecification` instead */
|
|
9210
|
-
get changedTests() {
|
|
9211
|
-
return this.watcher.changedTests;
|
|
9212
|
-
}
|
|
9213
9141
|
/**
|
|
9214
9142
|
* The global config.
|
|
9215
9143
|
*/
|
|
9216
9144
|
get config() {
|
|
9217
|
-
assert(this._config, "config");
|
|
9218
|
-
return this._config;
|
|
9219
|
-
}
|
|
9220
|
-
/** @deprecated use `vitest.vite` instead */
|
|
9221
|
-
get server() {
|
|
9222
|
-
return this._vite;
|
|
9145
|
+
return assert(this._config, "config"), this._config;
|
|
9223
9146
|
}
|
|
9224
9147
|
/**
|
|
9225
9148
|
* Global Vite's dev server instance.
|
|
9226
9149
|
*/
|
|
9227
9150
|
get vite() {
|
|
9228
|
-
assert(this._vite, "vite", "server");
|
|
9229
|
-
return this._vite;
|
|
9151
|
+
return assert(this._vite, "vite", "server"), this._vite;
|
|
9230
9152
|
}
|
|
9231
9153
|
/**
|
|
9232
9154
|
* The global test state manager.
|
|
9233
9155
|
* @experimental The State API is experimental and not subject to semver.
|
|
9234
9156
|
*/
|
|
9235
9157
|
get state() {
|
|
9236
|
-
assert(this._state, "state");
|
|
9237
|
-
return this._state;
|
|
9158
|
+
return assert(this._state, "state"), this._state;
|
|
9238
9159
|
}
|
|
9239
9160
|
/**
|
|
9240
9161
|
* The global snapshot manager. You can access the current state on `snapshot.summary`.
|
|
9241
9162
|
*/
|
|
9242
9163
|
get snapshot() {
|
|
9243
|
-
assert(this._snapshot, "snapshot", "snapshot manager");
|
|
9244
|
-
return this._snapshot;
|
|
9164
|
+
return assert(this._snapshot, "snapshot", "snapshot manager"), this._snapshot;
|
|
9245
9165
|
}
|
|
9246
9166
|
/**
|
|
9247
9167
|
* Test results and test file stats cache. Primarily used by the sequencer to sort tests.
|
|
9248
9168
|
*/
|
|
9249
9169
|
get cache() {
|
|
9250
|
-
assert(this._cache, "cache");
|
|
9251
|
-
return this._cache;
|
|
9252
|
-
}
|
|
9253
|
-
/** @deprecated internal */
|
|
9254
|
-
setServer(options, server) {
|
|
9255
|
-
return this._setServer(options, server);
|
|
9170
|
+
return assert(this._cache, "cache"), this._cache;
|
|
9256
9171
|
}
|
|
9257
9172
|
/** @internal */
|
|
9258
9173
|
async _setServer(options, server) {
|
|
9259
|
-
this.watcher.unregisterWatcher();
|
|
9260
|
-
clearTimeout(this._rerunTimer);
|
|
9261
|
-
this.restartsCount += 1;
|
|
9262
|
-
this._browserLastPort = defaultBrowserPort;
|
|
9263
|
-
this.pool?.close?.();
|
|
9264
|
-
this.pool = void 0;
|
|
9265
|
-
this.closingPromise = void 0;
|
|
9266
|
-
this.projects = [];
|
|
9267
|
-
this.resolvedProjects = [];
|
|
9268
|
-
this._workspaceConfigPath = void 0;
|
|
9269
|
-
this.coverageProvider = void 0;
|
|
9270
|
-
this.runningPromise = void 0;
|
|
9271
|
-
this.coreWorkspaceProject = void 0;
|
|
9272
|
-
this.specifications.clearCache();
|
|
9273
|
-
this._onUserTestsRerun = [];
|
|
9274
|
-
this._vite = server;
|
|
9174
|
+
this.watcher.unregisterWatcher(), clearTimeout(this._rerunTimer), this.restartsCount += 1, this.pool?.close?.(), this.pool = void 0, this.closingPromise = void 0, this.projects = [], this.runningPromise = void 0, this.coreWorkspaceProject = void 0, this.specifications.clearCache(), this._coverageProvider = void 0, this._onUserTestsRerun = [], this._vite = server;
|
|
9275
9175
|
const resolved = resolveConfig(this, options, server.config);
|
|
9276
|
-
this._config = resolved;
|
|
9277
|
-
this.
|
|
9278
|
-
|
|
9279
|
-
this.
|
|
9280
|
-
this._testRun = new TestRun(this);
|
|
9281
|
-
if (this.config.watch) this.watcher.registerWatcher();
|
|
9282
|
-
this.vitenode = new ViteNodeServer(server, this.config.server);
|
|
9283
|
-
const node = this.vitenode;
|
|
9284
|
-
this.runner = new ViteNodeRunner({
|
|
9285
|
-
root: server.config.root,
|
|
9286
|
-
base: server.config.base,
|
|
9287
|
-
fetchModule(id) {
|
|
9288
|
-
return node.fetchModule(id);
|
|
9289
|
-
},
|
|
9290
|
-
resolveId(id, importer) {
|
|
9291
|
-
return node.resolveId(id, importer);
|
|
9292
|
-
}
|
|
9293
|
-
});
|
|
9294
|
-
if (this.config.watch) {
|
|
9176
|
+
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();
|
|
9177
|
+
this._resolver = new VitestResolver(server.config.cacheDir, resolved);
|
|
9178
|
+
const environment = server.environments.__vitest__;
|
|
9179
|
+
if (this.runner = new ServerModuleRunner(environment, this._resolver, resolved), this.config.watch) {
|
|
9295
9180
|
// hijack server restart
|
|
9296
9181
|
const serverRestart = server.restart;
|
|
9297
|
-
server.restart = async (...args) => {
|
|
9298
|
-
await Promise.all(this._onRestartListeners.map((fn) => fn()));
|
|
9299
|
-
this.report("onServerRestart");
|
|
9300
|
-
await this.close();
|
|
9301
|
-
await serverRestart(...args);
|
|
9302
|
-
};
|
|
9303
9182
|
// since we set `server.hmr: false`, Vite does not auto restart itself
|
|
9304
|
-
server.
|
|
9183
|
+
server.restart = async (...args) => {
|
|
9184
|
+
await Promise.all(this._onRestartListeners.map((fn) => fn())), this.report("onServerRestart"), await this.close(), await serverRestart(...args);
|
|
9185
|
+
}, server.watcher.on("change", async (file) => {
|
|
9305
9186
|
file = normalize(file);
|
|
9306
|
-
const isConfig = file === server.config.configFile || this.projects.some((p) => p.vite.config.configFile === file)
|
|
9307
|
-
if (isConfig)
|
|
9308
|
-
await Promise.all(this._onRestartListeners.map((fn) => fn("config")));
|
|
9309
|
-
this.report("onServerRestart", "config");
|
|
9310
|
-
await this.close();
|
|
9311
|
-
await serverRestart();
|
|
9312
|
-
}
|
|
9187
|
+
const isConfig = file === server.config.configFile || this.projects.some((p) => p.vite.config.configFile === file);
|
|
9188
|
+
if (isConfig) await Promise.all(this._onRestartListeners.map((fn) => fn("config"))), this.report("onServerRestart", "config"), await this.close(), await serverRestart();
|
|
9313
9189
|
});
|
|
9314
9190
|
}
|
|
9315
9191
|
this.cache.results.setConfig(resolved.root, resolved.cache);
|
|
@@ -9317,29 +9193,44 @@ class Vitest {
|
|
|
9317
9193
|
await this.cache.results.readFromCache();
|
|
9318
9194
|
} catch {}
|
|
9319
9195
|
const projects = await this.resolveProjects(this._cliOptions);
|
|
9320
|
-
this.
|
|
9321
|
-
this.projects = projects;
|
|
9322
|
-
await Promise.all(projects.flatMap((project) => {
|
|
9196
|
+
if (this.projects = projects, await Promise.all(projects.flatMap((project) => {
|
|
9323
9197
|
const hooks = project.vite.config.getSortedPluginHooks("configureVitest");
|
|
9324
9198
|
return hooks.map((hook) => hook({
|
|
9325
9199
|
project,
|
|
9326
9200
|
vitest: this,
|
|
9327
9201
|
injectTestProjects: this.injectTestProject
|
|
9328
9202
|
}));
|
|
9329
|
-
}))
|
|
9330
|
-
if (this._cliOptions.browser?.enabled) {
|
|
9203
|
+
})), this._cliOptions.browser?.enabled) {
|
|
9331
9204
|
const browserProjects = this.projects.filter((p) => p.config.browser.enabled);
|
|
9332
9205
|
if (!browserProjects.length) throw new Error(`Vitest received --browser flag, but no project had a browser configuration.`);
|
|
9333
9206
|
}
|
|
9334
9207
|
if (!this.projects.length) {
|
|
9335
9208
|
const filter = toArray(resolved.project).join("\", \"");
|
|
9336
|
-
|
|
9337
|
-
else throw new Error(`Vitest wasn't able to resolve any project.`);
|
|
9209
|
+
throw filter ? new Error(`No projects matched the filter "${filter}".`) : new Error(`Vitest wasn't able to resolve any project.`);
|
|
9338
9210
|
}
|
|
9339
9211
|
if (!this.coreWorkspaceProject) this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9340
9212
|
if (this.config.testNamePattern) this.configOverride.testNamePattern = this.config.testNamePattern;
|
|
9341
|
-
this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
|
|
9342
|
-
|
|
9213
|
+
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()));
|
|
9214
|
+
}
|
|
9215
|
+
/** @internal */
|
|
9216
|
+
get coverageProvider() {
|
|
9217
|
+
return this.configOverride.coverage?.enabled === false ? null : this._coverageProvider;
|
|
9218
|
+
}
|
|
9219
|
+
async enableCoverage() {
|
|
9220
|
+
this.configOverride.coverage = {}, this.configOverride.coverage.enabled = true, await this.createCoverageProvider(), await this.coverageProvider?.onEnabled?.();
|
|
9221
|
+
}
|
|
9222
|
+
disableCoverage() {
|
|
9223
|
+
this.configOverride.coverage ??= {}, this.configOverride.coverage.enabled = false;
|
|
9224
|
+
}
|
|
9225
|
+
_coverageOverrideCache = /* @__PURE__ */ new WeakMap();
|
|
9226
|
+
/** @internal */
|
|
9227
|
+
get _coverageOptions() {
|
|
9228
|
+
if (!this.configOverride.coverage) return this.config.coverage;
|
|
9229
|
+
if (!this._coverageOverrideCache.has(this.configOverride.coverage)) {
|
|
9230
|
+
const coverage = deepClone(this.config.coverage), options = deepMerge(coverage, this.configOverride.coverage);
|
|
9231
|
+
this._coverageOverrideCache.set(this.configOverride.coverage, options);
|
|
9232
|
+
}
|
|
9233
|
+
return this._coverageOverrideCache.get(this.configOverride.coverage);
|
|
9343
9234
|
}
|
|
9344
9235
|
/**
|
|
9345
9236
|
* Inject new test projects into the workspace.
|
|
@@ -9347,10 +9238,8 @@ class Vitest {
|
|
|
9347
9238
|
* @returns An array of new test projects. Can be empty if the name was filtered out.
|
|
9348
9239
|
*/
|
|
9349
9240
|
injectTestProject = async (config) => {
|
|
9350
|
-
const currentNames = new Set(this.projects.map((p) => p.name));
|
|
9351
|
-
|
|
9352
|
-
this.projects.push(...projects);
|
|
9353
|
-
return projects;
|
|
9241
|
+
const currentNames = new Set(this.projects.map((p) => p.name)), projects = await resolveProjects(this, this._cliOptions, void 0, Array.isArray(config) ? config : [config], currentNames);
|
|
9242
|
+
return this.projects.push(...projects), projects;
|
|
9354
9243
|
};
|
|
9355
9244
|
/**
|
|
9356
9245
|
* Provide a value to the test context. This value will be available to all tests with `inject`.
|
|
@@ -9366,13 +9255,7 @@ class Vitest {
|
|
|
9366
9255
|
}
|
|
9367
9256
|
/** @internal */
|
|
9368
9257
|
_ensureRootProject() {
|
|
9369
|
-
|
|
9370
|
-
this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9371
|
-
return this.coreWorkspaceProject;
|
|
9372
|
-
}
|
|
9373
|
-
/** @deprecated use `getRootProject` instead */
|
|
9374
|
-
getCoreWorkspaceProject() {
|
|
9375
|
-
return this.getRootProject();
|
|
9258
|
+
return this.coreWorkspaceProject ||= TestProject._createBasicProject(this), this.coreWorkspaceProject;
|
|
9376
9259
|
}
|
|
9377
9260
|
/**
|
|
9378
9261
|
* Return project that has the root (or "global") config.
|
|
@@ -9381,14 +9264,6 @@ class Vitest {
|
|
|
9381
9264
|
if (!this.coreWorkspaceProject) throw new Error(`Root project is not initialized. This means that the Vite server was not established yet and the the workspace config is not resolved.`);
|
|
9382
9265
|
return this.coreWorkspaceProject;
|
|
9383
9266
|
}
|
|
9384
|
-
/**
|
|
9385
|
-
* @deprecated use Reported Task API instead
|
|
9386
|
-
*/
|
|
9387
|
-
getProjectByTaskId(taskId) {
|
|
9388
|
-
const task = this.state.idMap.get(taskId);
|
|
9389
|
-
const projectName = task.projectName || task?.file?.projectName || "";
|
|
9390
|
-
return this.getProjectByName(projectName);
|
|
9391
|
-
}
|
|
9392
9267
|
getProjectByName(name) {
|
|
9393
9268
|
const project = this.projects.find((p) => p.name === name) || this.coreWorkspaceProject || this.projects[0];
|
|
9394
9269
|
if (!project) throw new Error(`Project "${name}" was not found.`);
|
|
@@ -9399,43 +9274,25 @@ class Vitest {
|
|
|
9399
9274
|
* @param moduleId The ID of the module in Vite module graph
|
|
9400
9275
|
*/
|
|
9401
9276
|
import(moduleId) {
|
|
9402
|
-
return this.runner.
|
|
9403
|
-
}
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
return join(configDir, workspaceConfigName);
|
|
9277
|
+
return this.runner.import(moduleId);
|
|
9278
|
+
}
|
|
9279
|
+
/**
|
|
9280
|
+
* Creates a coverage provider if `coverage` is enabled in the config.
|
|
9281
|
+
*/
|
|
9282
|
+
async createCoverageProvider() {
|
|
9283
|
+
if (this._coverageProvider) return this._coverageProvider;
|
|
9284
|
+
const coverageProvider = await this.initCoverageProvider();
|
|
9285
|
+
if (coverageProvider) await coverageProvider.clean(this._coverageOptions.clean);
|
|
9286
|
+
return coverageProvider || null;
|
|
9413
9287
|
}
|
|
9414
9288
|
async resolveProjects(cliOptions) {
|
|
9415
9289
|
const names = /* @__PURE__ */ new Set();
|
|
9416
|
-
if (this.config.projects)
|
|
9417
|
-
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
return resolveProjects(this, cliOptions, void 0, this.config.workspace, names);
|
|
9423
|
-
}
|
|
9424
|
-
const workspaceConfigPath = await this.resolveWorkspaceConfigPath();
|
|
9425
|
-
this._workspaceConfigPath = workspaceConfigPath;
|
|
9426
|
-
// user doesn't have a workspace config, return default project
|
|
9427
|
-
if (!workspaceConfigPath) {
|
|
9428
|
-
// user can filter projects with --project flag, `getDefaultTestProject`
|
|
9429
|
-
// returns the project only if it matches the filter
|
|
9430
|
-
const project = getDefaultTestProject(this);
|
|
9431
|
-
if (!project) return [];
|
|
9432
|
-
return resolveBrowserProjects(this, new Set([project.name]), [project]);
|
|
9433
|
-
}
|
|
9434
|
-
const configFile = this.vite.config.configFile ? resolve(this.vite.config.root, this.vite.config.configFile) : "the root config file";
|
|
9435
|
-
this.logger.deprecate(`The workspace file is deprecated and will be removed in the next major. Please, use the \`test.projects\` field in ${configFile} instead.`);
|
|
9436
|
-
const workspaceModule = await this.import(workspaceConfigPath);
|
|
9437
|
-
if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) throw new TypeError(`Workspace config file "${workspaceConfigPath}" must export a default array of project paths.`);
|
|
9438
|
-
return resolveProjects(this, cliOptions, workspaceConfigPath, workspaceModule.default, names);
|
|
9290
|
+
if (this.config.projects) return resolveProjects(this, cliOptions, void 0, this.config.projects, names);
|
|
9291
|
+
if ("workspace" in this.config) throw new Error("The `test.workspace` option was removed in Vitest 4. Please, migrate to `test.projects` instead. See https://vitest.dev/guide/projects for examples.");
|
|
9292
|
+
// user can filter projects with --project flag, `getDefaultTestProject`
|
|
9293
|
+
// returns the project only if it matches the filter
|
|
9294
|
+
const project = getDefaultTestProject(this);
|
|
9295
|
+
return project ? resolveBrowserProjects(this, new Set([project.name]), [project]) : [];
|
|
9439
9296
|
}
|
|
9440
9297
|
/**
|
|
9441
9298
|
* Glob test files in every project and create a TestSpecification for each file and pool.
|
|
@@ -9445,13 +9302,10 @@ class Vitest {
|
|
|
9445
9302
|
return this.specifications.globTestSpecifications(filters);
|
|
9446
9303
|
}
|
|
9447
9304
|
async initCoverageProvider() {
|
|
9448
|
-
if (this.
|
|
9449
|
-
this.
|
|
9450
|
-
if (this.
|
|
9451
|
-
|
|
9452
|
-
this.config.coverage = this.coverageProvider.resolveOptions();
|
|
9453
|
-
}
|
|
9454
|
-
return this.coverageProvider;
|
|
9305
|
+
if (this._coverageProvider != null) return;
|
|
9306
|
+
const coverageConfig = this.configOverride.coverage ? this.getRootProject().serializedConfig.coverage : this.config.coverage;
|
|
9307
|
+
if (this._coverageProvider = await getCoverageProvider(coverageConfig, this.runner), this._coverageProvider) await this._coverageProvider.initialize(this), this.config.coverage = this._coverageProvider.resolveOptions();
|
|
9308
|
+
return this._coverageProvider;
|
|
9455
9309
|
}
|
|
9456
9310
|
/**
|
|
9457
9311
|
* Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
|
|
@@ -9464,23 +9318,15 @@ class Vitest {
|
|
|
9464
9318
|
errors,
|
|
9465
9319
|
coverages,
|
|
9466
9320
|
executionTimes
|
|
9467
|
-
};
|
|
9468
|
-
await this.report("onInit", this);
|
|
9469
|
-
await this.report("onPathsCollected", files.flatMap((f) => f.filepath));
|
|
9321
|
+
}, await this.report("onInit", this);
|
|
9470
9322
|
const specifications = [];
|
|
9471
9323
|
for (const file of files) {
|
|
9472
|
-
const project = this.getProjectByName(file.projectName || "");
|
|
9473
|
-
const specification = project.createSpecification(file.filepath, void 0, file.pool);
|
|
9324
|
+
const project = this.getProjectByName(file.projectName || ""), specification = project.createSpecification(file.filepath, void 0, file.pool);
|
|
9474
9325
|
specifications.push(specification);
|
|
9475
9326
|
}
|
|
9476
|
-
await this.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
|
|
9477
9327
|
await this._testRun.start(specifications).catch(noop);
|
|
9478
9328
|
for (const file of files) await this._reportFileTask(file);
|
|
9479
|
-
this._checkUnhandledErrors(errors)
|
|
9480
|
-
await this._testRun.end(specifications, errors).catch(noop);
|
|
9481
|
-
await this.initCoverageProvider();
|
|
9482
|
-
await this.coverageProvider?.mergeReports?.(coverages);
|
|
9483
|
-
return {
|
|
9329
|
+
return this._checkUnhandledErrors(errors), await this._testRun.end(specifications, errors).catch(noop), await this.initCoverageProvider(), await this.coverageProvider?.mergeReports?.(coverages), {
|
|
9484
9330
|
testModules: this.state.getTestModules(),
|
|
9485
9331
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9486
9332
|
};
|
|
@@ -9488,10 +9334,8 @@ class Vitest {
|
|
|
9488
9334
|
/** @internal */
|
|
9489
9335
|
async _reportFileTask(file) {
|
|
9490
9336
|
const project = this.getProjectByName(file.projectName || "");
|
|
9491
|
-
await this._testRun.enqueued(project, file).catch(noop);
|
|
9492
|
-
|
|
9493
|
-
const logs = [];
|
|
9494
|
-
const { packs, events } = convertTasksToEvents(file, (task) => {
|
|
9337
|
+
await this._testRun.enqueued(project, file).catch(noop), await this._testRun.collected(project, [file]).catch(noop);
|
|
9338
|
+
const logs = [], { packs, events } = convertTasksToEvents(file, (task) => {
|
|
9495
9339
|
if (task.logs) logs.push(...task.logs);
|
|
9496
9340
|
});
|
|
9497
9341
|
logs.sort((log1, log2) => log1.time - log2.time);
|
|
@@ -9500,16 +9344,10 @@ class Vitest {
|
|
|
9500
9344
|
}
|
|
9501
9345
|
async collect(filters) {
|
|
9502
9346
|
const files = await this.specifications.getRelevantTestSpecifications(filters);
|
|
9503
|
-
|
|
9504
|
-
if (!files.length) return {
|
|
9347
|
+
return files.length ? this.collectTests(files) : {
|
|
9505
9348
|
testModules: [],
|
|
9506
9349
|
unhandledErrors: []
|
|
9507
9350
|
};
|
|
9508
|
-
return this.collectTests(files);
|
|
9509
|
-
}
|
|
9510
|
-
/** @deprecated use `getRelevantTestSpecifications` instead */
|
|
9511
|
-
listFiles(filters) {
|
|
9512
|
-
return this.getRelevantTestSpecifications(filters);
|
|
9513
9351
|
}
|
|
9514
9352
|
/**
|
|
9515
9353
|
* Returns the list of test files that match the config and filters.
|
|
@@ -9528,8 +9366,7 @@ class Vitest {
|
|
|
9528
9366
|
*/
|
|
9529
9367
|
async start(filters) {
|
|
9530
9368
|
try {
|
|
9531
|
-
await this.initCoverageProvider();
|
|
9532
|
-
await this.coverageProvider?.clean(this.config.coverage.clean);
|
|
9369
|
+
await this.initCoverageProvider(), await this.coverageProvider?.clean(this._coverageOptions.clean);
|
|
9533
9370
|
} finally {
|
|
9534
9371
|
await this.report("onInit", this);
|
|
9535
9372
|
}
|
|
@@ -9539,20 +9376,13 @@ class Vitest {
|
|
|
9539
9376
|
if (!files.length) {
|
|
9540
9377
|
await this._testRun.start([]);
|
|
9541
9378
|
const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
|
|
9542
|
-
await this._testRun.end([], [], coverage);
|
|
9543
|
-
// Report coverage for uncovered files
|
|
9544
|
-
await this.reportCoverage(coverage, true);
|
|
9545
|
-
if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
|
|
9379
|
+
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);
|
|
9546
9380
|
}
|
|
9547
9381
|
let testModules = {
|
|
9548
9382
|
testModules: [],
|
|
9549
9383
|
unhandledErrors: []
|
|
9550
9384
|
};
|
|
9551
|
-
if (files.length)
|
|
9552
|
-
// populate once, update cache on watch
|
|
9553
|
-
await this.cache.stats.populateStats(this.config.root, files);
|
|
9554
|
-
testModules = await this.runFiles(files, true);
|
|
9555
|
-
}
|
|
9385
|
+
if (files.length) await this.cache.stats.populateStats(this.config.root, files), testModules = await this.runFiles(files, true);
|
|
9556
9386
|
if (this.config.watch) await this.report("onWatcherStart");
|
|
9557
9387
|
return testModules;
|
|
9558
9388
|
}
|
|
@@ -9562,24 +9392,18 @@ class Vitest {
|
|
|
9562
9392
|
*/
|
|
9563
9393
|
async init() {
|
|
9564
9394
|
try {
|
|
9565
|
-
await this.initCoverageProvider();
|
|
9566
|
-
await this.coverageProvider?.clean(this.config.coverage.clean);
|
|
9395
|
+
await this.initCoverageProvider(), await this.coverageProvider?.clean(this._coverageOptions.clean);
|
|
9567
9396
|
} finally {
|
|
9568
9397
|
await this.report("onInit", this);
|
|
9569
9398
|
}
|
|
9570
|
-
|
|
9571
|
-
await this.globTestSpecifications();
|
|
9572
|
-
if (this.config.watch) await this.report("onWatcherStart");
|
|
9399
|
+
if (await this.globTestSpecifications(), this.config.watch) await this.report("onWatcherStart");
|
|
9573
9400
|
}
|
|
9574
9401
|
/**
|
|
9575
|
-
*
|
|
9402
|
+
* If there is a test run happening, returns a promise that will
|
|
9403
|
+
* resolve when the test run is finished.
|
|
9576
9404
|
*/
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
}
|
|
9580
|
-
/** @deprecated */
|
|
9581
|
-
getFileWorkspaceSpecs(file) {
|
|
9582
|
-
return this.getModuleSpecifications(file);
|
|
9405
|
+
async waitForTestRunEnd() {
|
|
9406
|
+
this.runningPromise && await this.runningPromise;
|
|
9583
9407
|
}
|
|
9584
9408
|
/**
|
|
9585
9409
|
* Get test specifications associated with the given module. If module is not a test file, an empty array is returned.
|
|
@@ -9594,7 +9418,9 @@ class Vitest {
|
|
|
9594
9418
|
* Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache altogether.
|
|
9595
9419
|
*/
|
|
9596
9420
|
clearSpecificationsCache(moduleId) {
|
|
9597
|
-
this.specifications.clearCache(moduleId)
|
|
9421
|
+
if (this.specifications.clearCache(moduleId), !moduleId) this.projects.forEach((project) => {
|
|
9422
|
+
project.testFilesList = null;
|
|
9423
|
+
});
|
|
9598
9424
|
}
|
|
9599
9425
|
/**
|
|
9600
9426
|
* Run tests for the given test specifications. This does not trigger `onWatcher*` events.
|
|
@@ -9602,8 +9428,7 @@ class Vitest {
|
|
|
9602
9428
|
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
9603
9429
|
*/
|
|
9604
9430
|
runTestSpecifications(specifications, allTestsRun = false) {
|
|
9605
|
-
specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec));
|
|
9606
|
-
return this.runFiles(specifications, allTestsRun);
|
|
9431
|
+
return specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec)), this.runFiles(specifications, allTestsRun);
|
|
9607
9432
|
}
|
|
9608
9433
|
/**
|
|
9609
9434
|
* Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
|
|
@@ -9611,28 +9436,17 @@ class Vitest {
|
|
|
9611
9436
|
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
9612
9437
|
*/
|
|
9613
9438
|
async rerunTestSpecifications(specifications, allTestsRun = false) {
|
|
9614
|
-
this.configOverride.testNamePattern = void 0;
|
|
9615
9439
|
const files = specifications.map((spec) => spec.moduleId);
|
|
9616
9440
|
await Promise.all([this.report("onWatcherRerun", files, "rerun test"), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
9617
9441
|
const result = await this.runTestSpecifications(specifications, allTestsRun);
|
|
9618
|
-
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
9619
|
-
return result;
|
|
9442
|
+
return await this.report("onWatcherStart", this.state.getFiles(files)), result;
|
|
9620
9443
|
}
|
|
9621
9444
|
async runFiles(specs, allTestsRun) {
|
|
9622
|
-
await this._testRun.start(specs)
|
|
9623
|
-
// previous run
|
|
9624
|
-
await this.runningPromise;
|
|
9625
|
-
this._onCancelListeners = [];
|
|
9626
|
-
this.isCancelling = false;
|
|
9627
|
-
// schedule the new run
|
|
9628
|
-
this.runningPromise = (async () => {
|
|
9445
|
+
return await this._testRun.start(specs), await this.runningPromise, this._onCancelListeners = [], this.isCancelling = false, this.runningPromise = (async () => {
|
|
9629
9446
|
try {
|
|
9630
9447
|
if (!this.pool) this.pool = createPool(this);
|
|
9631
9448
|
const invalidates = Array.from(this.watcher.invalidates);
|
|
9632
|
-
this.watcher.invalidates.clear();
|
|
9633
|
-
this.snapshot.clear();
|
|
9634
|
-
this.state.clearErrors();
|
|
9635
|
-
if (!this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
|
|
9449
|
+
if (this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), !this.isFirstRun && this._coverageOptions.cleanOnRerun) await this.coverageProvider?.clean();
|
|
9636
9450
|
await this.initializeGlobalSetup(specs);
|
|
9637
9451
|
try {
|
|
9638
9452
|
await this.pool.runTests(specs, invalidates);
|
|
@@ -9649,21 +9463,24 @@ class Vitest {
|
|
|
9649
9463
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9650
9464
|
};
|
|
9651
9465
|
} finally {
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
const errors = this.state.getUnhandledErrors();
|
|
9655
|
-
this._checkUnhandledErrors(errors);
|
|
9656
|
-
await this._testRun.end(specs, errors, coverage);
|
|
9657
|
-
await this.reportCoverage(coverage, allTestsRun);
|
|
9466
|
+
const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun }), errors = this.state.getUnhandledErrors();
|
|
9467
|
+
this._checkUnhandledErrors(errors), await this._testRun.end(specs, errors, coverage), await this.reportCoverage(coverage, allTestsRun);
|
|
9658
9468
|
}
|
|
9659
9469
|
})().finally(() => {
|
|
9660
|
-
this.runningPromise = void 0;
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9470
|
+
this.runningPromise = void 0, this.isFirstRun = false, this.config.changed = false, this.config.related = void 0;
|
|
9471
|
+
}), await this.runningPromise;
|
|
9472
|
+
}
|
|
9473
|
+
async experimental_parseSpecifications(specifications, options) {
|
|
9474
|
+
if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecifications\` does not support "${this.mode}" mode.`);
|
|
9475
|
+
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)));
|
|
9476
|
+
return Promise.all(promises);
|
|
9477
|
+
}
|
|
9478
|
+
async experimental_parseSpecification(specification) {
|
|
9479
|
+
if (this.mode !== "test") throw new Error(`The \`experimental_parseSpecification\` does not support "${this.mode}" mode.`);
|
|
9480
|
+
const file = await astCollectTests(specification.project, specification.moduleId).catch((error) => {
|
|
9481
|
+
return createFailedFileTask(specification.project, specification.moduleId, error);
|
|
9665
9482
|
});
|
|
9666
|
-
return
|
|
9483
|
+
return this.state.collectFiles(specification.project, [file]), this.state.getReportedEntity(file);
|
|
9667
9484
|
}
|
|
9668
9485
|
/**
|
|
9669
9486
|
* Collect tests in specified modules. Vitest will run the files to collect tests.
|
|
@@ -9671,19 +9488,10 @@ class Vitest {
|
|
|
9671
9488
|
*/
|
|
9672
9489
|
async collectTests(specifications) {
|
|
9673
9490
|
const filepaths = specifications.map((spec) => spec.moduleId);
|
|
9674
|
-
this.state.collectPaths(filepaths)
|
|
9675
|
-
// previous run
|
|
9676
|
-
await this.runningPromise;
|
|
9677
|
-
this._onCancelListeners = [];
|
|
9678
|
-
this.isCancelling = false;
|
|
9679
|
-
// schedule the new run
|
|
9680
|
-
this.runningPromise = (async () => {
|
|
9491
|
+
return this.state.collectPaths(filepaths), await this.runningPromise, this._onCancelListeners = [], this.isCancelling = false, this.runningPromise = (async () => {
|
|
9681
9492
|
if (!this.pool) this.pool = createPool(this);
|
|
9682
9493
|
const invalidates = Array.from(this.watcher.invalidates);
|
|
9683
|
-
this.watcher.invalidates.clear();
|
|
9684
|
-
this.snapshot.clear();
|
|
9685
|
-
this.state.clearErrors();
|
|
9686
|
-
await this.initializeGlobalSetup(specifications);
|
|
9494
|
+
this.watcher.invalidates.clear(), this.snapshot.clear(), this.state.clearErrors(), await this.initializeGlobalSetup(specifications);
|
|
9687
9495
|
try {
|
|
9688
9496
|
await this.pool.collectTests(specifications, invalidates);
|
|
9689
9497
|
} catch (err) {
|
|
@@ -9698,28 +9506,21 @@ class Vitest {
|
|
|
9698
9506
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9699
9507
|
};
|
|
9700
9508
|
})().finally(() => {
|
|
9701
|
-
this.runningPromise = void 0;
|
|
9702
|
-
|
|
9703
|
-
this.config.changed = false;
|
|
9704
|
-
this.config.related = void 0;
|
|
9705
|
-
});
|
|
9706
|
-
return await this.runningPromise;
|
|
9509
|
+
this.runningPromise = void 0, this.config.changed = false, this.config.related = void 0;
|
|
9510
|
+
}), await this.runningPromise;
|
|
9707
9511
|
}
|
|
9708
9512
|
/**
|
|
9709
9513
|
* Gracefully cancel the current test run. Vitest will wait until all running tests are finished before cancelling.
|
|
9710
9514
|
*/
|
|
9711
9515
|
async cancelCurrentRun(reason) {
|
|
9712
|
-
this.isCancelling = true;
|
|
9713
|
-
await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason)));
|
|
9714
|
-
await this.runningPromise;
|
|
9516
|
+
this.isCancelling = true, await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason))), await this.runningPromise;
|
|
9715
9517
|
}
|
|
9716
9518
|
/** @internal */
|
|
9717
9519
|
async _initBrowserServers() {
|
|
9718
9520
|
await Promise.all(this.projects.map((p) => p._initBrowserServer()));
|
|
9719
9521
|
}
|
|
9720
9522
|
async initializeGlobalSetup(paths) {
|
|
9721
|
-
const projects = new Set(paths.map((spec) => spec.project));
|
|
9722
|
-
const coreProject = this.getRootProject();
|
|
9523
|
+
const projects = new Set(paths.map((spec) => spec.project)), coreProject = this.getRootProject();
|
|
9723
9524
|
if (!projects.has(coreProject)) projects.add(coreProject);
|
|
9724
9525
|
for (const project of projects) await project._initializeGlobalSetup();
|
|
9725
9526
|
}
|
|
@@ -9733,8 +9534,7 @@ class Vitest {
|
|
|
9733
9534
|
const specifications = files.flatMap((file) => this.getModuleSpecifications(file));
|
|
9734
9535
|
await Promise.all([this.report("onWatcherRerun", files, trigger), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
9735
9536
|
const testResult = await this.runFiles(specifications, allTestsRun);
|
|
9736
|
-
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
9737
|
-
return testResult;
|
|
9537
|
+
return await this.report("onWatcherStart", this.state.getFiles(files)), testResult;
|
|
9738
9538
|
}
|
|
9739
9539
|
/** @internal */
|
|
9740
9540
|
async rerunTask(id) {
|
|
@@ -9754,9 +9554,8 @@ class Vitest {
|
|
|
9754
9554
|
// Empty test name pattern should reset filename pattern as well
|
|
9755
9555
|
if (pattern === "") this.filenamePattern = void 0;
|
|
9756
9556
|
const testNamePattern = pattern ? new RegExp(pattern) : void 0;
|
|
9757
|
-
this.configOverride.testNamePattern = testNamePattern;
|
|
9758
9557
|
// filter only test files that have tests matching the pattern
|
|
9759
|
-
if (testNamePattern) files = files.filter((filepath) => {
|
|
9558
|
+
if (this.configOverride.testNamePattern = testNamePattern, testNamePattern) files = files.filter((filepath) => {
|
|
9760
9559
|
const files = this.state.getFiles([filepath]);
|
|
9761
9560
|
return !files.length || files.some((file) => {
|
|
9762
9561
|
const tasks = getTasks(file);
|
|
@@ -9780,9 +9579,7 @@ class Vitest {
|
|
|
9780
9579
|
* @param files The list of files on the file system
|
|
9781
9580
|
*/
|
|
9782
9581
|
async updateSnapshot(files) {
|
|
9783
|
-
|
|
9784
|
-
files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)];
|
|
9785
|
-
this.enableSnapshotUpdate();
|
|
9582
|
+
files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)], this.enableSnapshotUpdate();
|
|
9786
9583
|
try {
|
|
9787
9584
|
return await this.rerunFiles(files, "update snapshot", false);
|
|
9788
9585
|
} finally {
|
|
@@ -9800,15 +9597,13 @@ class Vitest {
|
|
|
9800
9597
|
this.configOverride.snapshotOptions = {
|
|
9801
9598
|
updateSnapshot: "all",
|
|
9802
9599
|
snapshotEnvironment: null
|
|
9803
|
-
};
|
|
9804
|
-
this.snapshot.options.updateSnapshot = "all";
|
|
9600
|
+
}, this.snapshot.options.updateSnapshot = "all";
|
|
9805
9601
|
}
|
|
9806
9602
|
/**
|
|
9807
9603
|
* Disable the mode that allows updating snapshots when running tests.
|
|
9808
9604
|
*/
|
|
9809
9605
|
resetSnapshotUpdate() {
|
|
9810
|
-
delete this.configOverride.snapshotOptions;
|
|
9811
|
-
this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
|
|
9606
|
+
delete this.configOverride.snapshotOptions, this.snapshot.options.updateSnapshot = this.config.snapshotOptions.updateSnapshot;
|
|
9812
9607
|
}
|
|
9813
9608
|
/**
|
|
9814
9609
|
* Set the global test name pattern to a regexp.
|
|
@@ -9819,74 +9614,60 @@ class Vitest {
|
|
|
9819
9614
|
else this.configOverride.testNamePattern = pattern ? new RegExp(pattern) : void 0;
|
|
9820
9615
|
}
|
|
9821
9616
|
/**
|
|
9617
|
+
* Returns the regexp used for the global test name pattern.
|
|
9618
|
+
*/
|
|
9619
|
+
getGlobalTestNamePattern() {
|
|
9620
|
+
return this.configOverride.testNamePattern == null ? this.config.testNamePattern : this.configOverride.testNamePattern;
|
|
9621
|
+
}
|
|
9622
|
+
/**
|
|
9822
9623
|
* Resets the global test name pattern. This method doesn't run any tests.
|
|
9823
9624
|
*/
|
|
9824
9625
|
resetGlobalTestNamePattern() {
|
|
9825
9626
|
this.configOverride.testNamePattern = void 0;
|
|
9826
9627
|
}
|
|
9827
9628
|
_rerunTimer;
|
|
9828
|
-
// we can't use a single `triggerId` yet because vscode extension relies on this
|
|
9829
9629
|
async scheduleRerun(triggerId) {
|
|
9830
9630
|
const currentCount = this.restartsCount;
|
|
9831
|
-
clearTimeout(this._rerunTimer)
|
|
9832
|
-
await this.runningPromise;
|
|
9833
|
-
clearTimeout(this._rerunTimer);
|
|
9834
|
-
// server restarted
|
|
9835
|
-
if (this.restartsCount !== currentCount) return;
|
|
9836
|
-
this._rerunTimer = setTimeout(async () => {
|
|
9631
|
+
clearTimeout(this._rerunTimer), await this.runningPromise, clearTimeout(this._rerunTimer), this.restartsCount === currentCount && (this._rerunTimer = setTimeout(async () => {
|
|
9837
9632
|
if (this.watcher.changedTests.size === 0) {
|
|
9838
9633
|
this.watcher.invalidates.clear();
|
|
9839
9634
|
return;
|
|
9840
9635
|
}
|
|
9841
9636
|
// server restarted
|
|
9842
9637
|
if (this.restartsCount !== currentCount) return;
|
|
9843
|
-
this.isFirstRun = false;
|
|
9844
|
-
this.snapshot.clear();
|
|
9638
|
+
this.isFirstRun = false, this.snapshot.clear();
|
|
9845
9639
|
let files = Array.from(this.watcher.changedTests);
|
|
9846
9640
|
if (this.filenamePattern) {
|
|
9847
9641
|
const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
|
|
9848
|
-
files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
|
|
9849
9642
|
// A file that does not match the current filename pattern was changed
|
|
9850
|
-
if (files.length === 0) return;
|
|
9643
|
+
if (files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file)), files.length === 0) return;
|
|
9851
9644
|
}
|
|
9852
9645
|
this.watcher.changedTests.clear();
|
|
9853
|
-
const
|
|
9854
|
-
|
|
9855
|
-
// get file specifications and filter them if needed
|
|
9856
|
-
const specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
|
|
9857
|
-
if (this._onFilterWatchedSpecification.length === 0) return true;
|
|
9858
|
-
return this._onFilterWatchedSpecification.every((fn) => fn(specification));
|
|
9646
|
+
const triggerLabel = relative(this.config.root, triggerId), specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
|
|
9647
|
+
return this._onFilterWatchedSpecification.length === 0 ? true : this._onFilterWatchedSpecification.every((fn) => fn(specification));
|
|
9859
9648
|
});
|
|
9860
|
-
await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
9861
|
-
|
|
9862
|
-
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
9863
|
-
}, WATCHER_DEBOUNCE);
|
|
9649
|
+
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));
|
|
9650
|
+
}, WATCHER_DEBOUNCE));
|
|
9864
9651
|
}
|
|
9865
9652
|
/**
|
|
9866
9653
|
* Invalidate a file in all projects.
|
|
9867
9654
|
*/
|
|
9868
9655
|
invalidateFile(filepath) {
|
|
9869
9656
|
this.projects.forEach(({ vite, browser }) => {
|
|
9870
|
-
const
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
}
|
|
9657
|
+
const environments = [...Object.values(vite.environments), ...Object.values(browser?.vite.environments || {})];
|
|
9658
|
+
environments.forEach(({ moduleGraph }) => {
|
|
9659
|
+
const modules = moduleGraph.getModulesByFile(filepath);
|
|
9660
|
+
modules?.forEach((module) => moduleGraph.invalidateModule(module));
|
|
9661
|
+
});
|
|
9876
9662
|
});
|
|
9877
9663
|
}
|
|
9878
|
-
/** @deprecated use `invalidateFile` */
|
|
9879
|
-
updateLastChanged(filepath) {
|
|
9880
|
-
this.invalidateFile(filepath);
|
|
9881
|
-
}
|
|
9882
9664
|
/** @internal */
|
|
9883
9665
|
_checkUnhandledErrors(errors) {
|
|
9884
9666
|
if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) process.exitCode = 1;
|
|
9885
9667
|
}
|
|
9886
9668
|
async reportCoverage(coverage, allTestsRun) {
|
|
9887
9669
|
if (this.state.getCountOfFailedTests() > 0) {
|
|
9888
|
-
await this.coverageProvider?.onTestFailure?.();
|
|
9889
|
-
if (!this.config.coverage.reportOnFailure) return;
|
|
9670
|
+
if (await this.coverageProvider?.onTestFailure?.(), !this._coverageOptions.reportOnFailure) return;
|
|
9890
9671
|
}
|
|
9891
9672
|
if (this.coverageProvider) {
|
|
9892
9673
|
await this.coverageProvider.reportCoverage(coverage, { allTestsRun });
|
|
@@ -9909,11 +9690,9 @@ class Vitest {
|
|
|
9909
9690
|
// it's possible that it's not initialized at all because it's not running any tests
|
|
9910
9691
|
if (this.coreWorkspaceProject && !this.projects.includes(this.coreWorkspaceProject)) closePromises.push(this.coreWorkspaceProject.close().then(() => this._vite = void 0));
|
|
9911
9692
|
if (this.pool) closePromises.push((async () => {
|
|
9912
|
-
await this.pool?.close?.();
|
|
9913
|
-
this.pool = void 0;
|
|
9693
|
+
await this.pool?.close?.(), this.pool = void 0;
|
|
9914
9694
|
})());
|
|
9915
|
-
closePromises.push(...this._onClose.map((fn) => fn()))
|
|
9916
|
-
return Promise.allSettled(closePromises).then((results) => {
|
|
9695
|
+
return closePromises.push(...this._onClose.map((fn) => fn())), Promise.allSettled(closePromises).then((results) => {
|
|
9917
9696
|
results.forEach((r) => {
|
|
9918
9697
|
if (r.status === "rejected") this.logger.error("error during close", r.reason);
|
|
9919
9698
|
});
|
|
@@ -9926,11 +9705,9 @@ class Vitest {
|
|
|
9926
9705
|
* @param force If true, the process will exit immediately after closing the projects.
|
|
9927
9706
|
*/
|
|
9928
9707
|
async exit(force = false) {
|
|
9929
|
-
setTimeout(() => {
|
|
9708
|
+
if (setTimeout(() => {
|
|
9930
9709
|
this.report("onProcessTimeout").then(() => {
|
|
9931
|
-
console.warn(`close timed out after ${this.config.teardownTimeout}ms`)
|
|
9932
|
-
this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause));
|
|
9933
|
-
if (!this.pool) {
|
|
9710
|
+
if (console.warn(`close timed out after ${this.config.teardownTimeout}ms`), this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause)), !this.pool) {
|
|
9934
9711
|
const runningServers = [this._vite, ...this.projects.map((p) => p._vite)].filter(Boolean).length;
|
|
9935
9712
|
if (runningServers === 1) console.warn("Tests closed successfully but something prevents Vite server from exiting");
|
|
9936
9713
|
else if (runningServers > 1) console.warn(`Tests closed successfully but something prevents ${runningServers} Vite servers from exiting`);
|
|
@@ -9939,9 +9716,7 @@ class Vitest {
|
|
|
9939
9716
|
}
|
|
9940
9717
|
process.exit();
|
|
9941
9718
|
});
|
|
9942
|
-
}, this.config.teardownTimeout).unref();
|
|
9943
|
-
await this.close();
|
|
9944
|
-
if (force) process.exit();
|
|
9719
|
+
}, this.config.teardownTimeout).unref(), await this.close(), force) process.exit();
|
|
9945
9720
|
}
|
|
9946
9721
|
/** @internal */
|
|
9947
9722
|
async report(name, ...args) {
|
|
@@ -9956,25 +9731,6 @@ class Vitest {
|
|
|
9956
9731
|
return Array.from(new Set(specifications.map((spec) => spec.moduleId)));
|
|
9957
9732
|
}
|
|
9958
9733
|
/**
|
|
9959
|
-
* @deprecated use `globTestSpecifications` instead
|
|
9960
|
-
*/
|
|
9961
|
-
async globTestSpecs(filters = []) {
|
|
9962
|
-
return this.globTestSpecifications(filters);
|
|
9963
|
-
}
|
|
9964
|
-
/**
|
|
9965
|
-
* @deprecated use `globTestSpecifications` instead
|
|
9966
|
-
*/
|
|
9967
|
-
async globTestFiles(filters = []) {
|
|
9968
|
-
return this.globTestSpecifications(filters);
|
|
9969
|
-
}
|
|
9970
|
-
/** @deprecated filter by `this.projects` yourself */
|
|
9971
|
-
getModuleProjects(filepath) {
|
|
9972
|
-
return this.projects.filter((project) => {
|
|
9973
|
-
return project.getModulesByFilepath(filepath).size;
|
|
9974
|
-
// TODO: reevaluate || project.browser?.moduleGraph.getModulesByFile(id)?.size
|
|
9975
|
-
});
|
|
9976
|
-
}
|
|
9977
|
-
/**
|
|
9978
9734
|
* Should the server be kept running after the tests are done.
|
|
9979
9735
|
*/
|
|
9980
9736
|
shouldKeepServer() {
|
|
@@ -10023,9 +9779,7 @@ class Vitest {
|
|
|
10023
9779
|
*/
|
|
10024
9780
|
matchesProjectFilter(name) {
|
|
10025
9781
|
const projects = this._config?.project || this._cliOptions?.project;
|
|
10026
|
-
|
|
10027
|
-
if (!projects || !projects.length) return true;
|
|
10028
|
-
return toArray(projects).some((project) => {
|
|
9782
|
+
return !projects || !projects.length ? true : toArray(projects).some((project) => {
|
|
10029
9783
|
const regexp = wildcardPatternToRegExp(project);
|
|
10030
9784
|
return regexp.test(name);
|
|
10031
9785
|
});
|
|
@@ -10038,8 +9792,7 @@ function assert(condition, property, name = property) {
|
|
|
10038
9792
|
async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(options))) {
|
|
10039
9793
|
const userConfig = deepMerge({}, options);
|
|
10040
9794
|
async function UIPlugin() {
|
|
10041
|
-
await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version);
|
|
10042
|
-
return (await import('@vitest/ui')).default(vitest);
|
|
9795
|
+
return await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version), (await import('@vitest/ui')).default(vitest);
|
|
10043
9796
|
}
|
|
10044
9797
|
return [
|
|
10045
9798
|
{
|
|
@@ -10065,14 +9818,9 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10065
9818
|
let open = false;
|
|
10066
9819
|
if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
|
|
10067
9820
|
const resolveOptions = getDefaultResolveOptions();
|
|
10068
|
-
|
|
9821
|
+
let config = {
|
|
10069
9822
|
root: viteConfig.test?.root || options.root,
|
|
10070
9823
|
define: { "process.env.NODE_ENV": "process.env.NODE_ENV" },
|
|
10071
|
-
esbuild: viteConfig.esbuild === false ? false : {
|
|
10072
|
-
target: viteConfig.esbuild?.target || "node18",
|
|
10073
|
-
sourcemap: "external",
|
|
10074
|
-
legalComments: "inline"
|
|
10075
|
-
},
|
|
10076
9824
|
resolve: {
|
|
10077
9825
|
...resolveOptions,
|
|
10078
9826
|
alias: testConfig.alias
|
|
@@ -10089,7 +9837,10 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10089
9837
|
outDir: "dummy-non-existing-folder",
|
|
10090
9838
|
emptyOutDir: false
|
|
10091
9839
|
},
|
|
10092
|
-
environments: {
|
|
9840
|
+
environments: {
|
|
9841
|
+
ssr: { resolve: resolveOptions },
|
|
9842
|
+
__vitest__: { dev: {} }
|
|
9843
|
+
},
|
|
10093
9844
|
test: {
|
|
10094
9845
|
poolOptions: {
|
|
10095
9846
|
threads: { isolate: options.poolOptions?.threads?.isolate ?? options.isolate ?? testConfig.poolOptions?.threads?.isolate ?? viteConfig.test?.isolate },
|
|
@@ -10099,33 +9850,29 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10099
9850
|
deps: testConfig.deps ?? viteConfig.test?.deps
|
|
10100
9851
|
}
|
|
10101
9852
|
};
|
|
9853
|
+
if ("rolldownVersion" in vite) config = {
|
|
9854
|
+
...config,
|
|
9855
|
+
oxc: viteConfig.oxc === false ? false : { target: viteConfig.oxc?.target || "node18" }
|
|
9856
|
+
};
|
|
9857
|
+
else config = {
|
|
9858
|
+
...config,
|
|
9859
|
+
esbuild: viteConfig.esbuild === false ? false : {
|
|
9860
|
+
target: viteConfig.esbuild?.target || "node18",
|
|
9861
|
+
sourcemap: "external",
|
|
9862
|
+
legalComments: "inline"
|
|
9863
|
+
}
|
|
9864
|
+
};
|
|
10102
9865
|
// inherit so it's available in VitestOptimizer
|
|
10103
9866
|
// I cannot wait to rewrite all of this in Vitest 4
|
|
10104
9867
|
if (options.cache != null) config.test.cache = options.cache;
|
|
10105
9868
|
if (vitest.configOverride.project)
|
|
10106
9869
|
// project filter was set by the user, so we need to filter the project
|
|
10107
9870
|
options.project = vitest.configOverride.project;
|
|
10108
|
-
config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
|
|
10109
|
-
config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
|
|
10110
|
-
// we want inline dependencies to be resolved by analyser plugin so module graph is populated correctly
|
|
10111
|
-
if (viteConfig.ssr?.noExternal !== true) {
|
|
10112
|
-
const inline = testConfig.server?.deps?.inline;
|
|
10113
|
-
if (inline === true) config.ssr = { noExternal: true };
|
|
10114
|
-
else {
|
|
10115
|
-
const noExternal = viteConfig.ssr?.noExternal;
|
|
10116
|
-
const noExternalArray = typeof noExternal !== "undefined" ? toArray(noExternal) : void 0;
|
|
10117
|
-
// filter the same packages
|
|
10118
|
-
const uniqueInline = inline && noExternalArray ? inline.filter((dep) => !noExternalArray.includes(dep)) : inline;
|
|
10119
|
-
config.ssr = { noExternal: uniqueInline };
|
|
10120
|
-
}
|
|
10121
|
-
}
|
|
10122
9871
|
// chokidar fsevents is unstable on macos when emitting "ready" event
|
|
10123
|
-
if (process.platform === "darwin" && false);
|
|
9872
|
+
if (config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false }), config.customLogger = silenceImportViteIgnoreWarning(config.customLogger), process.platform === "darwin" && false);
|
|
10124
9873
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
10125
9874
|
if (classNameStrategy !== "scoped") {
|
|
10126
|
-
config.css ??= {}
|
|
10127
|
-
config.css.modules ??= {};
|
|
10128
|
-
if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
9875
|
+
if (config.css ??= {}, config.css.modules ??= {}, config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
10129
9876
|
const root = vitest.config.root || options.root || process.cwd();
|
|
10130
9877
|
return generateScopedClassName(classNameStrategy, name, relative(root, filename));
|
|
10131
9878
|
};
|
|
@@ -10136,17 +9883,11 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10136
9883
|
const viteConfigTest = viteConfig.test || {};
|
|
10137
9884
|
if (viteConfigTest.watch === false) viteConfigTest.run = true;
|
|
10138
9885
|
if ("alias" in viteConfigTest) delete viteConfigTest.alias;
|
|
10139
|
-
|
|
10140
|
-
options = deepMerge({}, configDefaults, viteConfigTest, options);
|
|
10141
|
-
options.api = resolveApiServerConfig(options, defaultPort);
|
|
9886
|
+
options = deepMerge({}, configDefaults, viteConfigTest, options), options.api = resolveApiServerConfig(options, defaultPort);
|
|
10142
9887
|
// we replace every "import.meta.env" with "process.env"
|
|
10143
9888
|
// to allow reassigning, so we need to put all envs on process.env
|
|
10144
9889
|
const { PROD, DEV,...envs } = viteConfig.env;
|
|
10145
|
-
|
|
10146
|
-
// so we are making them truthy
|
|
10147
|
-
process.env.PROD ??= PROD ? "1" : "";
|
|
10148
|
-
process.env.DEV ??= DEV ? "1" : "";
|
|
10149
|
-
for (const name in envs) process.env[name] ??= envs[name];
|
|
9890
|
+
for (const name in process.env.PROD ??= PROD ? "1" : "", process.env.DEV ??= DEV ? "1" : "", envs) process.env[name] ??= envs[name];
|
|
10150
9891
|
// don't watch files in run mode
|
|
10151
9892
|
if (!options.watch) viteConfig.server.watch = null;
|
|
10152
9893
|
if (options.ui)
|
|
@@ -10166,20 +9907,20 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
10166
9907
|
order: "post",
|
|
10167
9908
|
async handler(server) {
|
|
10168
9909
|
if (options.watch && false);
|
|
10169
|
-
await vitest._setServer(options, server);
|
|
10170
|
-
if (options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
|
|
9910
|
+
if (await vitest._setServer(options, server), options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
|
|
10171
9911
|
// #415, in run mode we don't need the watcher, close it would improve the performance
|
|
10172
9912
|
if (!options.watch) await server.watcher.close();
|
|
10173
9913
|
}
|
|
10174
9914
|
}
|
|
10175
9915
|
},
|
|
10176
|
-
|
|
9916
|
+
MetaEnvReplacerPlugin(),
|
|
10177
9917
|
...CSSEnablerPlugin(vitest),
|
|
10178
9918
|
CoverageTransform(vitest),
|
|
10179
9919
|
VitestCoreResolver(vitest),
|
|
10180
9920
|
...MocksPlugins(),
|
|
10181
9921
|
VitestOptimizer(),
|
|
10182
|
-
NormalizeURLPlugin()
|
|
9922
|
+
NormalizeURLPlugin(),
|
|
9923
|
+
ModuleRunnerTransform()
|
|
10183
9924
|
].filter(notNullish);
|
|
10184
9925
|
}
|
|
10185
9926
|
function removeUndefinedValues(obj) {
|
|
@@ -10188,25 +9929,19 @@ function removeUndefinedValues(obj) {
|
|
|
10188
9929
|
}
|
|
10189
9930
|
|
|
10190
9931
|
async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) {
|
|
10191
|
-
const ctx = new Vitest(mode, deepClone(options), vitestOptions);
|
|
10192
|
-
const root = slash(resolve$1(options.root || process.cwd()));
|
|
10193
|
-
const configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root });
|
|
9932
|
+
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 });
|
|
10194
9933
|
options.config = configPath;
|
|
10195
|
-
const { browser: _removeBrowser,...restOptions } = options
|
|
10196
|
-
const config = {
|
|
9934
|
+
const { browser: _removeBrowser,...restOptions } = options, config = {
|
|
10197
9935
|
configFile: configPath,
|
|
10198
9936
|
configLoader: options.configLoader,
|
|
10199
9937
|
mode: options.mode || mode,
|
|
10200
9938
|
plugins: await VitestPlugin(restOptions, ctx)
|
|
10201
|
-
};
|
|
10202
|
-
const server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
|
|
9939
|
+
}, server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
|
|
10203
9940
|
if (ctx.config.api?.port) await server.listen();
|
|
10204
9941
|
return ctx;
|
|
10205
9942
|
}
|
|
10206
9943
|
|
|
10207
|
-
const MAX_RESULT_COUNT = 10;
|
|
10208
|
-
const SELECTION_MAX_INDEX = 7;
|
|
10209
|
-
const ESC = "\x1B[";
|
|
9944
|
+
const MAX_RESULT_COUNT = 10, SELECTION_MAX_INDEX = 7, ESC = "\x1B[";
|
|
10210
9945
|
class WatchFilter {
|
|
10211
9946
|
filterRL;
|
|
10212
9947
|
currentKeyword = void 0;
|
|
@@ -10217,23 +9952,17 @@ class WatchFilter {
|
|
|
10217
9952
|
stdin;
|
|
10218
9953
|
stdout;
|
|
10219
9954
|
constructor(message, stdin = process.stdin, stdout$1 = stdout()) {
|
|
10220
|
-
this.message = message
|
|
10221
|
-
this.stdin = stdin;
|
|
10222
|
-
this.stdout = stdout$1;
|
|
10223
|
-
this.filterRL = readline.createInterface({
|
|
9955
|
+
if (this.message = message, this.stdin = stdin, this.stdout = stdout$1, this.filterRL = readline.createInterface({
|
|
10224
9956
|
input: this.stdin,
|
|
10225
9957
|
escapeCodeTimeout: 50
|
|
10226
|
-
});
|
|
10227
|
-
readline.emitKeypressEvents(this.stdin, this.filterRL);
|
|
10228
|
-
if (this.stdin.isTTY) this.stdin.setRawMode(true);
|
|
9958
|
+
}), readline.emitKeypressEvents(this.stdin, this.filterRL), this.stdin.isTTY) this.stdin.setRawMode(true);
|
|
10229
9959
|
}
|
|
10230
9960
|
async filter(filterFunc) {
|
|
10231
9961
|
this.write(this.promptLine());
|
|
10232
9962
|
const resultPromise = createDefer();
|
|
10233
9963
|
this.onKeyPress = this.filterHandler(filterFunc, (result) => {
|
|
10234
9964
|
resultPromise.resolve(result);
|
|
10235
|
-
});
|
|
10236
|
-
this.stdin.on("keypress", this.onKeyPress);
|
|
9965
|
+
}), this.stdin.on("keypress", this.onKeyPress);
|
|
10237
9966
|
try {
|
|
10238
9967
|
return await resultPromise;
|
|
10239
9968
|
} finally {
|
|
@@ -10249,13 +9978,11 @@ class WatchFilter {
|
|
|
10249
9978
|
break;
|
|
10250
9979
|
case key?.ctrl && key?.name === "c":
|
|
10251
9980
|
case key?.name === "escape":
|
|
10252
|
-
this.write(`${ESC}1G${ESC}0J`);
|
|
10253
|
-
onSubmit(void 0);
|
|
9981
|
+
this.write(`${ESC}1G${ESC}0J`), onSubmit(void 0);
|
|
10254
9982
|
return;
|
|
10255
9983
|
case key?.name === "enter":
|
|
10256
9984
|
case key?.name === "return":
|
|
10257
|
-
onSubmit(this.results[this.selectionIndex] || this.currentKeyword || "");
|
|
10258
|
-
this.currentKeyword = void 0;
|
|
9985
|
+
onSubmit(this.results[this.selectionIndex] || this.currentKeyword || ""), this.currentKeyword = void 0;
|
|
10259
9986
|
break;
|
|
10260
9987
|
case key?.name === "up":
|
|
10261
9988
|
if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--;
|
|
@@ -10282,17 +10009,13 @@ class WatchFilter {
|
|
|
10282
10009
|
const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`;
|
|
10283
10010
|
let resultBody = "";
|
|
10284
10011
|
if (this.results.length > MAX_RESULT_COUNT) {
|
|
10285
|
-
const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0;
|
|
10286
|
-
|
|
10287
|
-
const remainingResultCount = this.results.length - offset - displayResults.length;
|
|
10288
|
-
resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`;
|
|
10289
|
-
if (remainingResultCount > 0) resultBody += `
|
|
10012
|
+
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;
|
|
10013
|
+
if (resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`, remainingResultCount > 0) resultBody += `
|
|
10290
10014
|
${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}`)}`;
|
|
10291
10015
|
} else resultBody = this.results.map((result, index) => index === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n");
|
|
10292
10016
|
printStr += `\n${resultCountLine}\n${resultBody}`;
|
|
10293
10017
|
}
|
|
10294
|
-
this.eraseAndPrint(printStr);
|
|
10295
|
-
this.restoreCursor();
|
|
10018
|
+
this.eraseAndPrint(printStr), this.restoreCursor();
|
|
10296
10019
|
}
|
|
10297
10020
|
keywordOffset() {
|
|
10298
10021
|
return `? ${this.message} › `.length + 1;
|
|
@@ -10308,14 +10031,10 @@ ${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "
|
|
|
10308
10031
|
// We have to take care of screen width in case of long lines
|
|
10309
10032
|
rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns);
|
|
10310
10033
|
}
|
|
10311
|
-
this.write(`${ESC}1G`);
|
|
10312
|
-
this.write(`${ESC}J`);
|
|
10313
|
-
this.write(str);
|
|
10314
|
-
this.write(`${ESC}${rows - 1}A`);
|
|
10034
|
+
this.write(`${ESC}1G`), this.write(`${ESC}J`), this.write(str), this.write(`${ESC}${rows - 1}A`);
|
|
10315
10035
|
}
|
|
10316
10036
|
close() {
|
|
10317
|
-
this.filterRL.close();
|
|
10318
|
-
if (this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
|
|
10037
|
+
if (this.filterRL.close(), this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
|
|
10319
10038
|
if (this.stdin.isTTY) this.stdin.setRawMode(false);
|
|
10320
10039
|
}
|
|
10321
10040
|
restoreCursor() {
|
|
@@ -10340,8 +10059,7 @@ const keys = [
|
|
|
10340
10059
|
["w", "filter by a project name"],
|
|
10341
10060
|
["b", "start the browser server if not started yet"],
|
|
10342
10061
|
["q", "quit"]
|
|
10343
|
-
]
|
|
10344
|
-
const cancelKeys = [
|
|
10062
|
+
], cancelKeys = [
|
|
10345
10063
|
"space",
|
|
10346
10064
|
"c",
|
|
10347
10065
|
"h",
|
|
@@ -10359,17 +10077,12 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10359
10077
|
// Cancel run and exit when ctrl-c or esc is pressed.
|
|
10360
10078
|
// If cancelling takes long and key is pressed multiple times, exit forcefully.
|
|
10361
10079
|
if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") {
|
|
10362
|
-
if (!ctx.isCancelling)
|
|
10363
|
-
ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n"));
|
|
10364
|
-
process.exitCode = 130;
|
|
10365
|
-
await ctx.cancelCurrentRun("keyboard-input");
|
|
10366
|
-
}
|
|
10080
|
+
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");
|
|
10367
10081
|
return ctx.exit(true);
|
|
10368
10082
|
}
|
|
10369
10083
|
// window not support suspend
|
|
10370
10084
|
if (!isWindows && key && key.ctrl && key.name === "z") {
|
|
10371
|
-
process.kill(process.ppid, "SIGTSTP");
|
|
10372
|
-
process.kill(process.pid, "SIGTSTP");
|
|
10085
|
+
process.kill(process.ppid, "SIGTSTP"), process.kill(process.pid, "SIGTSTP");
|
|
10373
10086
|
return;
|
|
10374
10087
|
}
|
|
10375
10088
|
const name = key?.name;
|
|
@@ -10398,24 +10111,17 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10398
10111
|
if (name === "t") return inputNamePattern();
|
|
10399
10112
|
// change fileNamePattern
|
|
10400
10113
|
if (name === "p") return inputFilePattern();
|
|
10401
|
-
if (name === "b") {
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
ctx.logger.log();
|
|
10405
|
-
ctx.logger.printBrowserBanner(project);
|
|
10406
|
-
});
|
|
10407
|
-
return null;
|
|
10408
|
-
}
|
|
10114
|
+
if (name === "b") return await ctx._initBrowserServers(), ctx.projects.forEach((project) => {
|
|
10115
|
+
ctx.logger.log(), ctx.logger.printBrowserBanner(project);
|
|
10116
|
+
}), null;
|
|
10409
10117
|
}
|
|
10410
10118
|
async function keypressHandler(str, key) {
|
|
10411
10119
|
await _keypressHandler(str, key);
|
|
10412
10120
|
}
|
|
10413
10121
|
async function inputNamePattern() {
|
|
10414
10122
|
off();
|
|
10415
|
-
const watchFilter = new WatchFilter("Input test name pattern (RegExp)", stdin, stdout)
|
|
10416
|
-
|
|
10417
|
-
const files = ctx.state.getFiles();
|
|
10418
|
-
const tests = getTests(files);
|
|
10123
|
+
const watchFilter = new WatchFilter("Input test name pattern (RegExp)", stdin, stdout), filter = await watchFilter.filter((str) => {
|
|
10124
|
+
const files = ctx.state.getFiles(), tests = getTests(files);
|
|
10419
10125
|
try {
|
|
10420
10126
|
const reg = new RegExp(str);
|
|
10421
10127
|
return tests.map((test) => test.name).filter((testName) => testName.match(reg));
|
|
@@ -10424,11 +10130,8 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10424
10130
|
return [];
|
|
10425
10131
|
}
|
|
10426
10132
|
});
|
|
10427
|
-
on();
|
|
10428
|
-
|
|
10429
|
-
const files = ctx.state.getFilepaths();
|
|
10430
|
-
// if running in standalone mode, Vitest instance doesn't know about any test file
|
|
10431
|
-
const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
|
|
10133
|
+
if (on(), typeof filter === "undefined") return;
|
|
10134
|
+
const files = ctx.state.getFilepaths(), cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
|
|
10432
10135
|
await ctx.changeNamePattern(filter?.trim() || "", cliFiles, "change pattern");
|
|
10433
10136
|
}
|
|
10434
10137
|
async function inputProjectName() {
|
|
@@ -10439,41 +10142,31 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10439
10142
|
message: "Input a single project name",
|
|
10440
10143
|
initial: ctx.config.project[0] || ""
|
|
10441
10144
|
}]);
|
|
10442
|
-
on();
|
|
10443
|
-
await ctx.changeProjectName(filter.trim());
|
|
10145
|
+
on(), await ctx.changeProjectName(filter.trim());
|
|
10444
10146
|
}
|
|
10445
10147
|
async function inputFilePattern() {
|
|
10446
10148
|
off();
|
|
10447
|
-
const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout)
|
|
10448
|
-
|
|
10449
|
-
|
|
10450
|
-
return files.map((file) => relative(ctx.config.root, file[1]));
|
|
10149
|
+
const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout), filter = await watchFilter.filter(async (str) => {
|
|
10150
|
+
const specifications = await ctx.globTestSpecifications([str]);
|
|
10151
|
+
return specifications.map((specification) => relative(ctx.config.root, specification.moduleId)).filter((file, index, all) => all.indexOf(file) === index);
|
|
10451
10152
|
});
|
|
10452
|
-
on();
|
|
10453
|
-
if (typeof filter === "undefined") return;
|
|
10153
|
+
if (on(), typeof filter === "undefined") return;
|
|
10454
10154
|
latestFilename = filter?.trim() || "";
|
|
10455
10155
|
const lastResults = watchFilter.getLastResults();
|
|
10456
10156
|
await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0);
|
|
10457
10157
|
}
|
|
10458
10158
|
let rl;
|
|
10459
10159
|
function on() {
|
|
10460
|
-
off()
|
|
10461
|
-
rl = readline.createInterface({
|
|
10160
|
+
if (off(), rl = readline.createInterface({
|
|
10462
10161
|
input: stdin,
|
|
10463
10162
|
escapeCodeTimeout: 50
|
|
10464
|
-
});
|
|
10465
|
-
readline.emitKeypressEvents(stdin, rl);
|
|
10466
|
-
if (stdin.isTTY) stdin.setRawMode(true);
|
|
10163
|
+
}), readline.emitKeypressEvents(stdin, rl), stdin.isTTY) stdin.setRawMode(true);
|
|
10467
10164
|
stdin.on("keypress", keypressHandler);
|
|
10468
10165
|
}
|
|
10469
10166
|
function off() {
|
|
10470
|
-
rl?.close();
|
|
10471
|
-
rl = void 0;
|
|
10472
|
-
stdin.removeListener("keypress", keypressHandler);
|
|
10473
|
-
if (stdin.isTTY) stdin.setRawMode(false);
|
|
10167
|
+
if (rl?.close(), rl = void 0, stdin.removeListener("keypress", keypressHandler), stdin.isTTY) stdin.setRawMode(false);
|
|
10474
10168
|
}
|
|
10475
|
-
on()
|
|
10476
|
-
return function cleanup() {
|
|
10169
|
+
return on(), function cleanup() {
|
|
10477
10170
|
off();
|
|
10478
10171
|
};
|
|
10479
10172
|
}
|
|
@@ -10484,20 +10177,14 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10484
10177
|
* Returns a Vitest instance if initialized successfully.
|
|
10485
10178
|
*/
|
|
10486
10179
|
async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) {
|
|
10487
|
-
const root = resolve(options.root || process.cwd());
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
const provider = ctx.config.coverage.provider || "v8";
|
|
10491
|
-
const requiredPackages = CoverageProviderMap[provider];
|
|
10180
|
+
const root = resolve(options.root || process.cwd()), ctx = await prepareVitest(mode, options, viteOverrides, vitestOptions, cliFilters);
|
|
10181
|
+
if (mode === "test" && ctx._coverageOptions.enabled) {
|
|
10182
|
+
const provider = ctx._coverageOptions.provider || "v8", requiredPackages = CoverageProviderMap[provider];
|
|
10492
10183
|
if (requiredPackages) {
|
|
10493
|
-
if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version))
|
|
10494
|
-
process.exitCode = 1;
|
|
10495
|
-
return ctx;
|
|
10496
|
-
}
|
|
10184
|
+
if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) return process.exitCode = 1, ctx;
|
|
10497
10185
|
}
|
|
10498
10186
|
}
|
|
10499
|
-
const stdin = vitestOptions?.stdin || process.stdin;
|
|
10500
|
-
const stdout = vitestOptions?.stdout || process.stdout;
|
|
10187
|
+
const stdin = vitestOptions?.stdin || process.stdin, stdout = vitestOptions?.stdout || process.stdout;
|
|
10501
10188
|
let stdinCleanup;
|
|
10502
10189
|
if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout);
|
|
10503
10190
|
ctx.onAfterSetServer(() => {
|
|
@@ -10509,54 +10196,27 @@ async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, v
|
|
|
10509
10196
|
else if (ctx.config.standalone) await ctx.init();
|
|
10510
10197
|
else await ctx.start(cliFilters);
|
|
10511
10198
|
} catch (e) {
|
|
10512
|
-
|
|
10513
|
-
if (e instanceof GitNotFoundError) {
|
|
10514
|
-
ctx.logger.error(e.message);
|
|
10515
|
-
return ctx;
|
|
10516
|
-
}
|
|
10517
|
-
if (e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError) {
|
|
10518
|
-
ctx.logger.printError(e, { verbose: false });
|
|
10519
|
-
return ctx;
|
|
10520
|
-
}
|
|
10521
|
-
process.exitCode = 1;
|
|
10522
|
-
ctx.logger.printError(e, {
|
|
10199
|
+
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, {
|
|
10523
10200
|
fullStack: true,
|
|
10524
10201
|
type: "Unhandled Error"
|
|
10525
|
-
});
|
|
10526
|
-
ctx.logger.error("\n\n");
|
|
10527
|
-
return ctx;
|
|
10202
|
+
}), ctx.logger.error("\n\n"), ctx);
|
|
10528
10203
|
}
|
|
10529
|
-
|
|
10530
|
-
stdinCleanup?.();
|
|
10531
|
-
await ctx.close();
|
|
10532
|
-
return ctx;
|
|
10204
|
+
return ctx.shouldKeepServer() ? ctx : (stdinCleanup?.(), await ctx.close(), ctx);
|
|
10533
10205
|
}
|
|
10534
|
-
async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions) {
|
|
10535
|
-
process.env.TEST = "true";
|
|
10536
|
-
|
|
10537
|
-
process.env.NODE_ENV ??= "test";
|
|
10538
|
-
if (options.run) options.watch = false;
|
|
10206
|
+
async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions, cliFilters) {
|
|
10207
|
+
if (process.env.TEST = "true", process.env.VITEST = "true", process.env.NODE_ENV ??= "test", options.run) options.watch = false;
|
|
10208
|
+
if (options.standalone && (cliFilters?.length || 0) > 0) options.standalone = false;
|
|
10539
10209
|
// this shouldn't affect _application root_ that can be changed inside config
|
|
10540
|
-
const root = resolve(options.root || process.cwd());
|
|
10541
|
-
|
|
10542
|
-
const environmentPackage = getEnvPackageName(ctx.config.environment);
|
|
10543
|
-
if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) {
|
|
10544
|
-
process.exitCode = 1;
|
|
10545
|
-
return ctx;
|
|
10546
|
-
}
|
|
10547
|
-
return ctx;
|
|
10210
|
+
const root = resolve(options.root || process.cwd()), ctx = await createVitest(mode, options, viteOverrides, vitestOptions), environmentPackage = getEnvPackageName(ctx.config.environment);
|
|
10211
|
+
return environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root) && (process.exitCode = 1), ctx;
|
|
10548
10212
|
}
|
|
10549
10213
|
function processCollected(ctx, files, options) {
|
|
10550
10214
|
let errorsPrinted = false;
|
|
10551
|
-
forEachSuite(files, (suite) => {
|
|
10215
|
+
if (forEachSuite(files, (suite) => {
|
|
10552
10216
|
suite.errors().forEach((error) => {
|
|
10553
|
-
errorsPrinted = true;
|
|
10554
|
-
ctx.logger.printError(error, { project: suite.project });
|
|
10217
|
+
errorsPrinted = true, ctx.logger.printError(error, { project: suite.project });
|
|
10555
10218
|
});
|
|
10556
|
-
});
|
|
10557
|
-
if (errorsPrinted) return;
|
|
10558
|
-
if (typeof options.json !== "undefined") return processJsonOutput(files, options);
|
|
10559
|
-
return formatCollectedAsString(files).forEach((test) => console.log(test));
|
|
10219
|
+
}), !errorsPrinted) return typeof options.json === "undefined" ? formatCollectedAsString(files).forEach((test) => console.log(test)) : processJsonOutput(files, options);
|
|
10560
10220
|
}
|
|
10561
10221
|
function outputFileList(files, options) {
|
|
10562
10222
|
if (typeof options.json !== "undefined") return outputJsonFileList(files, options);
|
|
@@ -10566,8 +10226,7 @@ function outputJsonFileList(files, options) {
|
|
|
10566
10226
|
if (typeof options.json === "boolean") return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10567
10227
|
if (typeof options.json === "string") {
|
|
10568
10228
|
const jsonPath = resolve(options.root || process.cwd(), options.json);
|
|
10569
|
-
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
10570
|
-
writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10229
|
+
mkdirSync(dirname(jsonPath), { recursive: true }), writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10571
10230
|
}
|
|
10572
10231
|
}
|
|
10573
10232
|
function formatFilesAsJSON(files) {
|
|
@@ -10588,8 +10247,7 @@ function processJsonOutput(files, options) {
|
|
|
10588
10247
|
if (typeof options.json === "boolean") return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10589
10248
|
if (typeof options.json === "string") {
|
|
10590
10249
|
const jsonPath = resolve(options.root || process.cwd(), options.json);
|
|
10591
|
-
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
10592
|
-
writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10250
|
+
mkdirSync(dirname(jsonPath), { recursive: true }), writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10593
10251
|
}
|
|
10594
10252
|
}
|
|
10595
10253
|
function forEachSuite(modules, callback) {
|
|
@@ -10600,7 +10258,7 @@ function forEachSuite(modules, callback) {
|
|
|
10600
10258
|
}
|
|
10601
10259
|
function formatCollectedAsJSON(files) {
|
|
10602
10260
|
const results = [];
|
|
10603
|
-
files.forEach((file) => {
|
|
10261
|
+
return files.forEach((file) => {
|
|
10604
10262
|
for (const test of file.children.allTests()) {
|
|
10605
10263
|
if (test.result().state === "skipped") continue;
|
|
10606
10264
|
const result = {
|
|
@@ -10611,19 +10269,17 @@ function formatCollectedAsJSON(files) {
|
|
|
10611
10269
|
if (test.location) result.location = test.location;
|
|
10612
10270
|
results.push(result);
|
|
10613
10271
|
}
|
|
10614
|
-
});
|
|
10615
|
-
return results;
|
|
10272
|
+
}), results;
|
|
10616
10273
|
}
|
|
10617
10274
|
function formatCollectedAsString(testModules) {
|
|
10618
10275
|
const results = [];
|
|
10619
|
-
testModules.forEach((testModule) => {
|
|
10276
|
+
return testModules.forEach((testModule) => {
|
|
10620
10277
|
for (const test of testModule.children.allTests()) {
|
|
10621
10278
|
if (test.result().state === "skipped") continue;
|
|
10622
10279
|
const fullName = `${test.module.task.name} > ${test.fullName}`;
|
|
10623
10280
|
results.push((test.project.name ? `[${test.project.name}] ` : "") + fullName);
|
|
10624
10281
|
}
|
|
10625
|
-
});
|
|
10626
|
-
return results;
|
|
10282
|
+
}), results;
|
|
10627
10283
|
}
|
|
10628
10284
|
const envPackageNames = {
|
|
10629
10285
|
"jsdom": "jsdom",
|
|
@@ -10631,10 +10287,7 @@ const envPackageNames = {
|
|
|
10631
10287
|
"edge-runtime": "@edge-runtime/vm"
|
|
10632
10288
|
};
|
|
10633
10289
|
function getEnvPackageName(env) {
|
|
10634
|
-
|
|
10635
|
-
if (env in envPackageNames) return envPackageNames[env];
|
|
10636
|
-
if (env[0] === "." || isAbsolute(env)) return null;
|
|
10637
|
-
return `vitest-environment-${env}`;
|
|
10290
|
+
return env === "node" ? null : env in envPackageNames ? envPackageNames[env] : env[0] === "." || isAbsolute(env) ? null : `vitest-environment-${env}`;
|
|
10638
10291
|
}
|
|
10639
10292
|
|
|
10640
10293
|
var cliApi = /*#__PURE__*/Object.freeze({
|
|
@@ -10647,4 +10300,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
|
|
|
10647
10300
|
startVitest: startVitest
|
|
10648
10301
|
});
|
|
10649
10302
|
|
|
10650
|
-
export { FilesNotFoundError as F, GitNotFoundError as G,
|
|
10303
|
+
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 };
|