vitest 3.2.0-beta.2 → 3.2.0
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 +29 -0
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +2 -2
- package/dist/chunks/{base.DwtwORaC.js → base.Cg0miDlQ.js} +11 -14
- package/dist/chunks/{benchmark.BoF7jW0Q.js → benchmark.CYdenmiT.js} +4 -6
- package/dist/chunks/{cac.I9MLYfT-.js → cac.6rXCxFY1.js} +76 -143
- package/dist/chunks/{cli-api.d6IK1pnk.js → cli-api.Cej3MBjA.js} +1460 -1344
- package/dist/chunks/{config.d.UqE-KR0o.d.ts → config.d.D2ROskhv.d.ts} +2 -0
- package/dist/chunks/{console.K1NMVOSc.js → console.CtFJOzRO.js} +25 -45
- package/dist/chunks/{constants.BZZyIeIE.js → constants.DnKduX2e.js} +1 -0
- package/dist/chunks/{coverage.0iPg4Wrz.js → coverage.DVF1vEu8.js} +4 -12
- package/dist/chunks/{coverage.OGU09Jbh.js → coverage.EIiagJJP.js} +578 -993
- package/dist/chunks/{creator.DGAdZ4Hj.js → creator.GK6I-cL4.js} +39 -83
- package/dist/chunks/date.Bq6ZW5rf.js +73 -0
- package/dist/chunks/{defaults.DSxsTG0h.js → defaults.B7q_naMc.js} +2 -1
- package/dist/chunks/{env.Dq0hM4Xv.js → env.D4Lgay0q.js} +1 -1
- package/dist/chunks/{environment.d.D8YDy2v5.d.ts → environment.d.cL3nLXbE.d.ts} +1 -0
- package/dist/chunks/{execute.JlGHLJZT.js → execute.B7h3T_Hc.js} +126 -217
- package/dist/chunks/{git.DXfdBEfR.js → git.BVQ8w_Sw.js} +1 -3
- package/dist/chunks/{global.d.BPa1eL3O.d.ts → global.d.MAmajcmJ.d.ts} +5 -1
- package/dist/chunks/{globals.CpxW8ccg.js → globals.DEHgCU4V.js} +7 -6
- package/dist/chunks/{index.CV36oG_L.js → index.BZ0g1JD2.js} +430 -625
- package/dist/chunks/{index.DswW_LEs.js → index.BbB8_kAK.js} +25 -24
- package/dist/chunks/{index.CmC5OK9L.js → index.CIyJn3t1.js} +38 -82
- package/dist/chunks/{index.CfXMNXHg.js → index.CdQS2e2Q.js} +4 -2
- package/dist/chunks/{index.DFXFpH3w.js → index.CmSc2RE5.js} +85 -105
- package/dist/chunks/index.D3XRDfWc.js +213 -0
- package/dist/chunks/{inspector.DbDkSkFn.js → inspector.C914Efll.js} +4 -1
- package/dist/chunks/{node.3xsWotC9.js → node.fjCdwEIl.js} +1 -1
- package/dist/chunks/{reporters.d.CLC9rhKy.d.ts → reporters.d.C1ogPriE.d.ts} +47 -9
- package/dist/chunks/{rpc.D9_013TY.js → rpc.Iovn4oWe.js} +10 -19
- package/dist/chunks/{runBaseTests.Dn2vyej_.js → runBaseTests.Dd85QTll.js} +27 -31
- package/dist/chunks/{setup-common.CYo3Y0dD.js → setup-common.Dd054P77.js} +16 -42
- package/dist/chunks/{typechecker.DnTrplSJ.js → typechecker.DRKU1-1g.js} +163 -186
- package/dist/chunks/{utils.BfxieIyZ.js → utils.CAioKnHs.js} +9 -14
- package/dist/chunks/{utils.CgTj3MsC.js → utils.XdZDrNZV.js} +6 -13
- package/dist/chunks/{vi.BFR5YIgu.js → vi.bdSIJ99Y.js} +137 -263
- package/dist/chunks/{vite.d.CBZ3M_ru.d.ts → vite.d.DqE4-hhK.d.ts} +3 -1
- package/dist/chunks/{vm.C1HHjtNS.js → vm.BThCzidc.js} +164 -212
- package/dist/chunks/{worker.d.D5Xdi-Zr.d.ts → worker.d.DvqK5Vmu.d.ts} +1 -1
- package/dist/chunks/{worker.d.CoCI7hzP.d.ts → worker.d.tQu2eJQy.d.ts} +5 -3
- package/dist/cli.js +5 -5
- package/dist/config.cjs +3 -1
- package/dist/config.d.ts +7 -6
- package/dist/config.js +3 -3
- package/dist/coverage.d.ts +4 -4
- package/dist/coverage.js +7 -7
- package/dist/environments.d.ts +6 -2
- package/dist/environments.js +1 -1
- package/dist/execute.d.ts +9 -3
- package/dist/execute.js +1 -1
- package/dist/index.d.ts +28 -15
- package/dist/index.js +5 -5
- package/dist/node.d.ts +18 -10
- package/dist/node.js +17 -17
- package/dist/reporters.d.ts +4 -4
- package/dist/reporters.js +4 -4
- package/dist/runners.d.ts +6 -3
- package/dist/runners.js +59 -80
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +39 -41
- package/dist/workers/forks.js +6 -4
- package/dist/workers/runVmTests.js +20 -21
- package/dist/workers/threads.js +4 -4
- package/dist/workers/vmForks.js +6 -6
- package/dist/workers/vmThreads.js +6 -6
- package/dist/workers.d.ts +4 -4
- package/dist/workers.js +10 -10
- package/package.json +21 -19
- package/dist/chunks/date.CDOsz-HY.js +0 -53
- package/dist/chunks/index.CK1YOQaa.js +0 -143
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { promises, existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import {
|
|
3
|
-
import { C as CoverageProviderMap } from './coverage.
|
|
1
|
+
import fs, { promises, existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { relative, resolve, dirname, extname, normalize, join, basename, isAbsolute } from 'pathe';
|
|
3
|
+
import { C as CoverageProviderMap } from './coverage.DVF1vEu8.js';
|
|
4
4
|
import path, { resolve as resolve$1 } from 'node:path';
|
|
5
|
-
import { noop, isPrimitive, createDefer, highlight, toArray, deepMerge, nanoid,
|
|
5
|
+
import { noop, isPrimitive, createDefer, slash, highlight, toArray, deepMerge, nanoid, deepClone, 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, w as workspacesFiles, a as defaultPort } from './constants.
|
|
8
|
+
import { searchForWorkspaceRoot, version, createServer, mergeConfig } from 'vite';
|
|
9
|
+
import { A as API_PATH, c as configFiles, d as defaultBrowserPort, w as workspacesFiles, a as defaultPort } from './constants.DnKduX2e.js';
|
|
10
10
|
import { generateFileHash, limitConcurrency, createFileTask, hasFailed, getTasks, getTests } from '@vitest/runner/utils';
|
|
11
11
|
import { SnapshotManager } from '@vitest/snapshot/manager';
|
|
12
12
|
import { ViteNodeRunner } from 'vite-node/client';
|
|
13
13
|
import { ViteNodeServer } from 'vite-node/server';
|
|
14
|
-
import { v as version$1 } from './cac.
|
|
14
|
+
import { v as version$1 } from './cac.6rXCxFY1.js';
|
|
15
15
|
import { c as createBirpc } from './index.CJ0plNrh.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.
|
|
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.BZ0g1JD2.js';
|
|
17
17
|
import require$$0$3 from 'events';
|
|
18
18
|
import require$$1$1 from 'https';
|
|
19
19
|
import require$$2 from 'http';
|
|
@@ -26,24 +26,24 @@ import require$$0 from 'zlib';
|
|
|
26
26
|
import require$$0$1 from 'buffer';
|
|
27
27
|
import { g as getDefaultExportFromCjs } from './_commonjsHelpers.BFTU3MAI.js';
|
|
28
28
|
import { parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
29
|
-
import crypto from 'node:crypto';
|
|
29
|
+
import crypto, { createHash } from 'node:crypto';
|
|
30
30
|
import { distDir, rootDir } from '../path.js';
|
|
31
|
-
import {
|
|
32
|
-
import { c as convertTasksToEvents } from './typechecker.
|
|
31
|
+
import { h as hash, R as RandomSequencer, i as isPackageExists, g as getFilePoolName, d as isBrowserEnabled, r as resolveConfig, e as groupBy, f as getCoverageProvider, j as createPool, w as wildcardPatternToRegExp, a as resolveApiServerConfig, s as stdout } from './coverage.EIiagJJP.js';
|
|
32
|
+
import { c as convertTasksToEvents } from './typechecker.DRKU1-1g.js';
|
|
33
33
|
import { Console } from 'node:console';
|
|
34
34
|
import c from 'tinyrainbow';
|
|
35
35
|
import { createRequire } from 'node:module';
|
|
36
36
|
import url from 'node:url';
|
|
37
|
-
import { i as isTTY, a as isWindows } from './env.
|
|
38
|
-
import { rm } from 'node:fs/promises';
|
|
37
|
+
import { i as isTTY, a as isWindows } from './env.D4Lgay0q.js';
|
|
38
|
+
import { rm, mkdir, copyFile } from 'node:fs/promises';
|
|
39
39
|
import nodeos__default, { tmpdir } from 'node:os';
|
|
40
40
|
import pm from 'picomatch';
|
|
41
41
|
import { glob, isDynamicPattern } from 'tinyglobby';
|
|
42
42
|
import { normalizeRequestId, cleanUrl } from 'vite-node/utils';
|
|
43
43
|
import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
|
|
44
|
-
import { c as configDefaults } from './defaults.
|
|
44
|
+
import { c as configDefaults } from './defaults.B7q_naMc.js';
|
|
45
45
|
import MagicString from 'magic-string';
|
|
46
|
-
import { a as BenchmarkReportsMap } from './index.
|
|
46
|
+
import { a as BenchmarkReportsMap } from './index.CIyJn3t1.js';
|
|
47
47
|
import assert$1 from 'node:assert';
|
|
48
48
|
import { serializeError } from '@vitest/utils/error';
|
|
49
49
|
import readline from 'node:readline';
|
|
@@ -779,6 +779,14 @@ function requirePermessageDeflate () {
|
|
|
779
779
|
this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
|
|
780
780
|
this[kError][kStatusCode] = 1009;
|
|
781
781
|
this.removeListener('data', inflateOnData);
|
|
782
|
+
|
|
783
|
+
//
|
|
784
|
+
// The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the
|
|
785
|
+
// fact that in Node.js versions prior to 13.10.0, the callback for
|
|
786
|
+
// `zlib.flush()` is not called if `zlib.close()` is used. Utilizing
|
|
787
|
+
// `zlib.reset()` ensures that either the callback is invoked or an error is
|
|
788
|
+
// emitted.
|
|
789
|
+
//
|
|
782
790
|
this.reset();
|
|
783
791
|
}
|
|
784
792
|
|
|
@@ -794,6 +802,12 @@ function requirePermessageDeflate () {
|
|
|
794
802
|
// closed when an error is emitted.
|
|
795
803
|
//
|
|
796
804
|
this[kPerMessageDeflate]._inflate = null;
|
|
805
|
+
|
|
806
|
+
if (this[kError]) {
|
|
807
|
+
this[kCallback](this[kError]);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
|
|
797
811
|
err[kStatusCode] = 1007;
|
|
798
812
|
this[kCallback](err);
|
|
799
813
|
}
|
|
@@ -3511,7 +3525,7 @@ function requireWebsocket () {
|
|
|
3511
3525
|
if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
|
|
3512
3526
|
invalidUrlMessage =
|
|
3513
3527
|
'The URL\'s protocol must be one of "ws:", "wss:", ' +
|
|
3514
|
-
'"http:", "https", or "ws+unix:"';
|
|
3528
|
+
'"http:", "https:", or "ws+unix:"';
|
|
3515
3529
|
} else if (isIpcUrl && !parsedUrl.pathname) {
|
|
3516
3530
|
invalidUrlMessage = "The URL's pathname is empty";
|
|
3517
3531
|
} else if (parsedUrl.hash) {
|
|
@@ -4993,19 +5007,13 @@ var WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExport
|
|
|
4993
5007
|
|
|
4994
5008
|
async function getModuleGraph(ctx, projectName, id, browser = false) {
|
|
4995
5009
|
const graph = {};
|
|
4996
|
-
const externalized = new Set();
|
|
4997
|
-
const inlined = new Set();
|
|
5010
|
+
const externalized = /* @__PURE__ */ new Set();
|
|
5011
|
+
const inlined = /* @__PURE__ */ new Set();
|
|
4998
5012
|
const project = ctx.getProjectByName(projectName);
|
|
4999
|
-
async function get(mod, seen = new Map()) {
|
|
5000
|
-
if (!mod || !mod.id)
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
if (mod.id === "\0@vitest/browser/context") {
|
|
5004
|
-
return;
|
|
5005
|
-
}
|
|
5006
|
-
if (seen.has(mod)) {
|
|
5007
|
-
return seen.get(mod);
|
|
5008
|
-
}
|
|
5013
|
+
async function get(mod, seen = /* @__PURE__ */ new Map()) {
|
|
5014
|
+
if (!mod || !mod.id) return;
|
|
5015
|
+
if (mod.id === "\0@vitest/browser/context") return;
|
|
5016
|
+
if (seen.has(mod)) return seen.get(mod);
|
|
5009
5017
|
let id = clearId(mod.id);
|
|
5010
5018
|
seen.set(mod, id);
|
|
5011
5019
|
const rewrote = browser ? mod.file?.includes(project.browser.vite.config.cacheDir) ? mod.id : false : await project.vitenode.shouldExternalize(id);
|
|
@@ -5013,18 +5021,13 @@ async function getModuleGraph(ctx, projectName, id, browser = false) {
|
|
|
5013
5021
|
id = rewrote;
|
|
5014
5022
|
externalized.add(id);
|
|
5015
5023
|
seen.set(mod, id);
|
|
5016
|
-
} else
|
|
5017
|
-
inlined.add(id);
|
|
5018
|
-
}
|
|
5024
|
+
} else inlined.add(id);
|
|
5019
5025
|
const mods = Array.from(mod.importedModules).filter((i) => i.id && !i.id.includes("/vitest/dist/"));
|
|
5020
5026
|
graph[id] = (await Promise.all(mods.map((m) => get(m, seen)))).filter(Boolean);
|
|
5021
5027
|
return id;
|
|
5022
5028
|
}
|
|
5023
|
-
if (browser && project.browser)
|
|
5024
|
-
|
|
5025
|
-
} else {
|
|
5026
|
-
await get(project.vite.moduleGraph.getModuleById(id));
|
|
5027
|
-
}
|
|
5029
|
+
if (browser && project.browser) await get(project.browser.vite.moduleGraph.getModuleById(id));
|
|
5030
|
+
else await get(project.vite.moduleGraph.getModuleById(id));
|
|
5028
5031
|
return {
|
|
5029
5032
|
graph,
|
|
5030
5033
|
externalized: Array.from(externalized),
|
|
@@ -5035,7 +5038,10 @@ function clearId(id) {
|
|
|
5035
5038
|
return id?.replace(/\?v=\w+$/, "") || "";
|
|
5036
5039
|
}
|
|
5037
5040
|
|
|
5041
|
+
// Serialization support utils.
|
|
5038
5042
|
function cloneByOwnProperties(value) {
|
|
5043
|
+
// Clones the value's properties into a new Object. The simpler approach of
|
|
5044
|
+
// Object.assign() won't work in the case that properties are not enumerable.
|
|
5039
5045
|
return Object.getOwnPropertyNames(value).reduce((clone, prop) => ({
|
|
5040
5046
|
...clone,
|
|
5041
5047
|
[prop]: value[prop]
|
|
@@ -5054,34 +5060,29 @@ function stringifyReplace(key, value) {
|
|
|
5054
5060
|
stack: value.stack,
|
|
5055
5061
|
...cloned
|
|
5056
5062
|
};
|
|
5057
|
-
} else
|
|
5058
|
-
return value;
|
|
5059
|
-
}
|
|
5063
|
+
} else return value;
|
|
5060
5064
|
}
|
|
5061
5065
|
|
|
5062
5066
|
function isValidApiRequest(config, req) {
|
|
5063
5067
|
const url = new URL(req.url ?? "", "http://localhost");
|
|
5068
|
+
// validate token. token is injected in ui/tester/orchestrator html, which is cross origin protected.
|
|
5064
5069
|
try {
|
|
5065
5070
|
const token = url.searchParams.get("token");
|
|
5066
|
-
if (token && crypto.timingSafeEqual(Buffer.from(token), Buffer.from(config.api.token)))
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5071
|
+
if (token && crypto.timingSafeEqual(Buffer.from(token), Buffer.from(config.api.token))) return true;
|
|
5072
|
+
}
|
|
5073
|
+
// an error is thrown when the length is incorrect
|
|
5074
|
+
catch {}
|
|
5070
5075
|
return false;
|
|
5071
5076
|
}
|
|
5072
5077
|
|
|
5073
5078
|
function setup(ctx, _server) {
|
|
5074
5079
|
const wss = new WebSocketServer({ noServer: true });
|
|
5075
|
-
const clients = new Map();
|
|
5080
|
+
const clients = /* @__PURE__ */ new Map();
|
|
5076
5081
|
const server = _server || ctx.server;
|
|
5077
5082
|
server.httpServer?.on("upgrade", (request, socket, head) => {
|
|
5078
|
-
if (!request.url)
|
|
5079
|
-
return;
|
|
5080
|
-
}
|
|
5083
|
+
if (!request.url) return;
|
|
5081
5084
|
const { pathname } = new URL(request.url, "http://localhost");
|
|
5082
|
-
if (pathname !== API_PATH)
|
|
5083
|
-
return;
|
|
5084
|
-
}
|
|
5085
|
+
if (pathname !== API_PATH) return;
|
|
5085
5086
|
if (!isValidApiRequest(ctx.config, request)) {
|
|
5086
5087
|
socket.destroy();
|
|
5087
5088
|
return;
|
|
@@ -5103,19 +5104,15 @@ function setup(ctx, _server) {
|
|
|
5103
5104
|
return ctx.state.getPaths();
|
|
5104
5105
|
},
|
|
5105
5106
|
async readTestFile(id) {
|
|
5106
|
-
if (!ctx.state.filesMap.has(id) || !existsSync(id))
|
|
5107
|
-
return null;
|
|
5108
|
-
}
|
|
5107
|
+
if (!ctx.state.filesMap.has(id) || !existsSync(id)) return null;
|
|
5109
5108
|
return promises.readFile(id, "utf-8");
|
|
5110
5109
|
},
|
|
5111
5110
|
async saveTestFile(id, content) {
|
|
5112
|
-
if (!ctx.state.filesMap.has(id) || !existsSync(id)) {
|
|
5113
|
-
throw new Error(`Test file "${id}" was not registered, so it cannot be updated using the API.`);
|
|
5114
|
-
}
|
|
5111
|
+
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.`);
|
|
5115
5112
|
return promises.writeFile(id, content, "utf-8");
|
|
5116
5113
|
},
|
|
5117
5114
|
async rerun(files, resetTestNamePattern) {
|
|
5118
|
-
await ctx.rerunFiles(files,
|
|
5115
|
+
await ctx.rerunFiles(files, void 0, true, resetTestNamePattern);
|
|
5119
5116
|
},
|
|
5120
5117
|
async rerunTask(id) {
|
|
5121
5118
|
await ctx.rerunTask(id);
|
|
@@ -5146,11 +5143,8 @@ function setup(ctx, _server) {
|
|
|
5146
5143
|
return getModuleGraph(ctx, project, id, browser);
|
|
5147
5144
|
},
|
|
5148
5145
|
async updateSnapshot(file) {
|
|
5149
|
-
if (!file)
|
|
5150
|
-
|
|
5151
|
-
} else {
|
|
5152
|
-
await ctx.updateSnapshot([file.filepath]);
|
|
5153
|
-
}
|
|
5146
|
+
if (!file) await ctx.updateSnapshot();
|
|
5147
|
+
else await ctx.updateSnapshot([file.filepath]);
|
|
5154
5148
|
},
|
|
5155
5149
|
getUnhandledErrors() {
|
|
5156
5150
|
return ctx.state.getUnhandledErrors();
|
|
@@ -5196,42 +5190,38 @@ class WebSocketReporter {
|
|
|
5196
5190
|
this.clients = clients;
|
|
5197
5191
|
}
|
|
5198
5192
|
onCollected(files) {
|
|
5199
|
-
if (this.clients.size === 0)
|
|
5200
|
-
return;
|
|
5201
|
-
}
|
|
5193
|
+
if (this.clients.size === 0) return;
|
|
5202
5194
|
this.clients.forEach((client) => {
|
|
5203
5195
|
client.onCollected?.(files)?.catch?.(noop);
|
|
5204
5196
|
});
|
|
5205
5197
|
}
|
|
5206
5198
|
onSpecsCollected(specs) {
|
|
5207
|
-
if (this.clients.size === 0)
|
|
5208
|
-
return;
|
|
5209
|
-
}
|
|
5199
|
+
if (this.clients.size === 0) return;
|
|
5210
5200
|
this.clients.forEach((client) => {
|
|
5211
5201
|
client.onSpecsCollected?.(specs)?.catch?.(noop);
|
|
5212
5202
|
});
|
|
5213
5203
|
}
|
|
5214
|
-
async
|
|
5215
|
-
if (this.clients.size === 0)
|
|
5216
|
-
|
|
5217
|
-
|
|
5204
|
+
async onTestCaseAnnotate(testCase, annotation) {
|
|
5205
|
+
if (this.clients.size === 0) return;
|
|
5206
|
+
this.clients.forEach((client) => {
|
|
5207
|
+
client.onTestAnnotate?.(testCase.id, annotation)?.catch?.(noop);
|
|
5208
|
+
});
|
|
5209
|
+
}
|
|
5210
|
+
async onTaskUpdate(packs, events) {
|
|
5211
|
+
if (this.clients.size === 0) return;
|
|
5218
5212
|
packs.forEach(([taskId, result]) => {
|
|
5219
5213
|
const task = this.ctx.state.idMap.get(taskId);
|
|
5220
5214
|
const isBrowser = task && task.file.pool === "browser";
|
|
5221
5215
|
result?.errors?.forEach((error) => {
|
|
5222
|
-
if (isPrimitive(error))
|
|
5223
|
-
return;
|
|
5224
|
-
}
|
|
5216
|
+
if (isPrimitive(error)) return;
|
|
5225
5217
|
if (isBrowser) {
|
|
5226
5218
|
const project = this.ctx.getProjectByName(task.file.projectName || "");
|
|
5227
5219
|
error.stacks = project.browser?.parseErrorStacktrace(error);
|
|
5228
|
-
} else
|
|
5229
|
-
error.stacks = parseErrorStacktrace(error);
|
|
5230
|
-
}
|
|
5220
|
+
} else error.stacks = parseErrorStacktrace(error);
|
|
5231
5221
|
});
|
|
5232
5222
|
});
|
|
5233
5223
|
this.clients.forEach((client) => {
|
|
5234
|
-
client.onTaskUpdate?.(packs)?.catch?.(noop);
|
|
5224
|
+
client.onTaskUpdate?.(packs, events)?.catch?.(noop);
|
|
5235
5225
|
});
|
|
5236
5226
|
}
|
|
5237
5227
|
onFinished(files, errors) {
|
|
@@ -5258,8 +5248,8 @@ var setup$1 = /*#__PURE__*/Object.freeze({
|
|
|
5258
5248
|
});
|
|
5259
5249
|
|
|
5260
5250
|
class BrowserSessions {
|
|
5261
|
-
sessions = new Map();
|
|
5262
|
-
sessionIds = new Set();
|
|
5251
|
+
sessions = /* @__PURE__ */ new Map();
|
|
5252
|
+
sessionIds = /* @__PURE__ */ new Set();
|
|
5263
5253
|
getSession(sessionId) {
|
|
5264
5254
|
return this.sessions.get(sessionId);
|
|
5265
5255
|
}
|
|
@@ -5267,6 +5257,7 @@ class BrowserSessions {
|
|
|
5267
5257
|
this.sessions.delete(sessionId);
|
|
5268
5258
|
}
|
|
5269
5259
|
createSession(sessionId, project, pool) {
|
|
5260
|
+
// this promise only waits for the WS connection with the orhcestrator to be established
|
|
5270
5261
|
const defer = createDefer();
|
|
5271
5262
|
const timeout = setTimeout(() => {
|
|
5272
5263
|
defer.reject(new Error(`Failed to connect to the browser session "${sessionId}" [${project.name}] within the timeout.`));
|
|
@@ -5287,6 +5278,116 @@ class BrowserSessions {
|
|
|
5287
5278
|
}
|
|
5288
5279
|
}
|
|
5289
5280
|
|
|
5281
|
+
class FilesStatsCache {
|
|
5282
|
+
cache = /* @__PURE__ */ new Map();
|
|
5283
|
+
getStats(key) {
|
|
5284
|
+
return this.cache.get(key);
|
|
5285
|
+
}
|
|
5286
|
+
async populateStats(root, specs) {
|
|
5287
|
+
const promises = specs.map((spec) => {
|
|
5288
|
+
const key = `${spec[0].name}:${relative(root, spec.moduleId)}`;
|
|
5289
|
+
return this.updateStats(spec.moduleId, key);
|
|
5290
|
+
});
|
|
5291
|
+
await Promise.all(promises);
|
|
5292
|
+
}
|
|
5293
|
+
async updateStats(fsPath, key) {
|
|
5294
|
+
if (!fs.existsSync(fsPath)) return;
|
|
5295
|
+
const stats = await fs.promises.stat(fsPath);
|
|
5296
|
+
this.cache.set(key, { size: stats.size });
|
|
5297
|
+
}
|
|
5298
|
+
removeStats(fsPath) {
|
|
5299
|
+
this.cache.forEach((_, key) => {
|
|
5300
|
+
if (key.endsWith(fsPath)) this.cache.delete(key);
|
|
5301
|
+
});
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
|
|
5305
|
+
class ResultsCache {
|
|
5306
|
+
cache = /* @__PURE__ */ new Map();
|
|
5307
|
+
workspacesKeyMap = /* @__PURE__ */ new Map();
|
|
5308
|
+
cachePath = null;
|
|
5309
|
+
version;
|
|
5310
|
+
root = "/";
|
|
5311
|
+
constructor(version) {
|
|
5312
|
+
this.version = version;
|
|
5313
|
+
}
|
|
5314
|
+
getCachePath() {
|
|
5315
|
+
return this.cachePath;
|
|
5316
|
+
}
|
|
5317
|
+
setConfig(root, config) {
|
|
5318
|
+
this.root = root;
|
|
5319
|
+
if (config) this.cachePath = resolve(config.dir, "results.json");
|
|
5320
|
+
}
|
|
5321
|
+
getResults(key) {
|
|
5322
|
+
return this.cache.get(key);
|
|
5323
|
+
}
|
|
5324
|
+
async readFromCache() {
|
|
5325
|
+
if (!this.cachePath) return;
|
|
5326
|
+
if (!fs.existsSync(this.cachePath)) return;
|
|
5327
|
+
const resultsCache = await fs.promises.readFile(this.cachePath, "utf8");
|
|
5328
|
+
const { results, version } = JSON.parse(resultsCache || "[]");
|
|
5329
|
+
const [major, minor] = version.split(".");
|
|
5330
|
+
// handling changed in 0.30.0
|
|
5331
|
+
if (major > 0 || Number(minor) >= 30) {
|
|
5332
|
+
this.cache = new Map(results);
|
|
5333
|
+
this.version = version;
|
|
5334
|
+
results.forEach(([spec]) => {
|
|
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
|
+
}
|
|
5341
|
+
}
|
|
5342
|
+
updateResults(files) {
|
|
5343
|
+
files.forEach((file) => {
|
|
5344
|
+
const result = file.result;
|
|
5345
|
+
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);
|
|
5349
|
+
this.cache.set(`${file.projectName || ""}:${relativePath}`, {
|
|
5350
|
+
duration: duration >= 0 ? duration : 0,
|
|
5351
|
+
failed: result.state === "fail"
|
|
5352
|
+
});
|
|
5353
|
+
});
|
|
5354
|
+
}
|
|
5355
|
+
removeFromCache(filepath) {
|
|
5356
|
+
this.cache.forEach((_, key) => {
|
|
5357
|
+
if (key.endsWith(filepath)) this.cache.delete(key);
|
|
5358
|
+
});
|
|
5359
|
+
}
|
|
5360
|
+
async writeToCache() {
|
|
5361
|
+
if (!this.cachePath) return;
|
|
5362
|
+
const results = Array.from(this.cache.entries());
|
|
5363
|
+
const cacheDirname = dirname(this.cachePath);
|
|
5364
|
+
if (!fs.existsSync(cacheDirname)) await fs.promises.mkdir(cacheDirname, { recursive: true });
|
|
5365
|
+
const cache = JSON.stringify({
|
|
5366
|
+
version: this.version,
|
|
5367
|
+
results
|
|
5368
|
+
});
|
|
5369
|
+
await fs.promises.writeFile(this.cachePath, cache);
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5372
|
+
|
|
5373
|
+
class VitestCache {
|
|
5374
|
+
results;
|
|
5375
|
+
stats = new FilesStatsCache();
|
|
5376
|
+
constructor(version) {
|
|
5377
|
+
this.results = new ResultsCache(version);
|
|
5378
|
+
}
|
|
5379
|
+
getFileTestResults(key) {
|
|
5380
|
+
return this.results.getResults(key);
|
|
5381
|
+
}
|
|
5382
|
+
getFileStats(key) {
|
|
5383
|
+
return this.stats.getStats(key);
|
|
5384
|
+
}
|
|
5385
|
+
static resolveCacheDir(root, dir, projectName) {
|
|
5386
|
+
const baseDir = slash(dir || "node_modules/.vite");
|
|
5387
|
+
return resolve(root, baseDir, "vitest", hash("md5", projectName || "", "hex"));
|
|
5388
|
+
}
|
|
5389
|
+
}
|
|
5390
|
+
|
|
5290
5391
|
class FilesNotFoundError extends Error {
|
|
5291
5392
|
code = "VITEST_FILES_NOT_FOUND";
|
|
5292
5393
|
constructor(mode) {
|
|
@@ -5302,7 +5403,7 @@ class GitNotFoundError extends Error {
|
|
|
5302
5403
|
class LocationFilterFileNotFoundError extends Error {
|
|
5303
5404
|
code = "VITEST_LOCATION_FILTER_FILE_NOT_FOUND";
|
|
5304
5405
|
constructor(filename) {
|
|
5305
|
-
super(`Couldn\'t find file ${filename}. Note when specifying the test
|
|
5406
|
+
super(`Couldn\'t find file ${filename}. Note when specifying the test location you have to specify the full test filename.`);
|
|
5306
5407
|
}
|
|
5307
5408
|
}
|
|
5308
5409
|
class IncludeTaskLocationDisabledError extends Error {
|
|
@@ -5314,7 +5415,7 @@ class IncludeTaskLocationDisabledError extends Error {
|
|
|
5314
5415
|
class RangeLocationFilterProvidedError extends Error {
|
|
5315
5416
|
code = "VITEST_RANGE_LOCATION_FILTER_PROVIDED";
|
|
5316
5417
|
constructor(filter) {
|
|
5317
|
-
super(`Found "-" in location filter ${filter}. Note that range location filters
|
|
5418
|
+
super(`Found "-" in location filter ${filter}. Note that range location filters are not supported. Consider specifying the exact line numbers of your tests.`);
|
|
5318
5419
|
}
|
|
5319
5420
|
}
|
|
5320
5421
|
class VitestFilteredOutProjectError extends Error {
|
|
@@ -5334,9 +5435,7 @@ const HIGHLIGHT_SUPPORTED_EXTS = new Set(["js", "ts"].flatMap((lang) => [
|
|
|
5334
5435
|
]));
|
|
5335
5436
|
function highlightCode(id, source, colors) {
|
|
5336
5437
|
const ext = extname(id);
|
|
5337
|
-
if (!HIGHLIGHT_SUPPORTED_EXTS.has(ext))
|
|
5338
|
-
return source;
|
|
5339
|
-
}
|
|
5438
|
+
if (!HIGHLIGHT_SUPPORTED_EXTS.has(ext)) return source;
|
|
5340
5439
|
const isJsx = ext.endsWith("x");
|
|
5341
5440
|
return highlight(source, {
|
|
5342
5441
|
jsx: isJsx,
|
|
@@ -5354,7 +5453,7 @@ const SHOW_CURSOR = `${ESC$1}?25h`;
|
|
|
5354
5453
|
const CLEAR_SCREEN = "\x1Bc";
|
|
5355
5454
|
class Logger {
|
|
5356
5455
|
_clearScreenPending;
|
|
5357
|
-
_highlights = new Map();
|
|
5456
|
+
_highlights = /* @__PURE__ */ new Map();
|
|
5358
5457
|
cleanupListeners = [];
|
|
5359
5458
|
console;
|
|
5360
5459
|
constructor(ctx, outputStream = process.stdout, errorStream = process.stderr) {
|
|
@@ -5368,9 +5467,7 @@ class Logger {
|
|
|
5368
5467
|
this._highlights.clear();
|
|
5369
5468
|
this.addCleanupListeners();
|
|
5370
5469
|
this.registerUnhandledRejection();
|
|
5371
|
-
if (this.outputStream.isTTY)
|
|
5372
|
-
this.outputStream.write(HIDE_CURSOR);
|
|
5373
|
-
}
|
|
5470
|
+
if (this.outputStream.isTTY) this.outputStream.write(HIDE_CURSOR);
|
|
5374
5471
|
}
|
|
5375
5472
|
log(...args) {
|
|
5376
5473
|
this._clearScreen();
|
|
@@ -5389,11 +5486,8 @@ class Logger {
|
|
|
5389
5486
|
this.console.log(message);
|
|
5390
5487
|
return;
|
|
5391
5488
|
}
|
|
5392
|
-
if (message) {
|
|
5393
|
-
|
|
5394
|
-
} else {
|
|
5395
|
-
this.outputStream.write(`${CLEAR_SCREEN}${ERASE_SCROLLBACK}`);
|
|
5396
|
-
}
|
|
5489
|
+
if (message) this.console.log(`${CLEAR_SCREEN}${ERASE_SCROLLBACK}${message}`);
|
|
5490
|
+
else this.outputStream.write(`${CLEAR_SCREEN}${ERASE_SCROLLBACK}`);
|
|
5397
5491
|
}
|
|
5398
5492
|
clearScreen(message, force = false) {
|
|
5399
5493
|
if (!this.ctx.config.clearScreen) {
|
|
@@ -5401,72 +5495,46 @@ class Logger {
|
|
|
5401
5495
|
return;
|
|
5402
5496
|
}
|
|
5403
5497
|
this._clearScreenPending = message;
|
|
5404
|
-
if (force)
|
|
5405
|
-
this._clearScreen();
|
|
5406
|
-
}
|
|
5498
|
+
if (force) this._clearScreen();
|
|
5407
5499
|
}
|
|
5408
5500
|
_clearScreen() {
|
|
5409
|
-
if (this._clearScreenPending == null)
|
|
5410
|
-
return;
|
|
5411
|
-
}
|
|
5501
|
+
if (this._clearScreenPending == null) return;
|
|
5412
5502
|
const log = this._clearScreenPending;
|
|
5413
|
-
this._clearScreenPending =
|
|
5503
|
+
this._clearScreenPending = void 0;
|
|
5414
5504
|
this.console.log(`${CURSOR_TO_START}${ERASE_DOWN}${log}`);
|
|
5415
5505
|
}
|
|
5416
5506
|
printError(err, options = {}) {
|
|
5417
5507
|
printError(err, this.ctx, this, options);
|
|
5418
5508
|
}
|
|
5419
5509
|
deprecate(message) {
|
|
5420
|
-
this.
|
|
5510
|
+
this.error(c.bold(c.bgYellow(" DEPRECATED ")), c.yellow(message));
|
|
5421
5511
|
}
|
|
5422
5512
|
clearHighlightCache(filename) {
|
|
5423
|
-
if (filename)
|
|
5424
|
-
|
|
5425
|
-
} else {
|
|
5426
|
-
this._highlights.clear();
|
|
5427
|
-
}
|
|
5513
|
+
if (filename) this._highlights.delete(filename);
|
|
5514
|
+
else this._highlights.clear();
|
|
5428
5515
|
}
|
|
5429
5516
|
highlight(filename, source) {
|
|
5430
|
-
if (this._highlights.has(filename))
|
|
5431
|
-
return this._highlights.get(filename);
|
|
5432
|
-
}
|
|
5517
|
+
if (this._highlights.has(filename)) return this._highlights.get(filename);
|
|
5433
5518
|
const code = highlightCode(filename, source);
|
|
5434
5519
|
this._highlights.set(filename, code);
|
|
5435
5520
|
return code;
|
|
5436
5521
|
}
|
|
5437
5522
|
printNoTestFound(filters) {
|
|
5438
5523
|
const config = this.ctx.config;
|
|
5439
|
-
if (config.watch && (config.changed || config.related?.length)) {
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
} else {
|
|
5444
|
-
if (config.passWithNoTests) {
|
|
5445
|
-
this.log(`No ${config.mode} files found, exiting with code 0\n`);
|
|
5446
|
-
} else {
|
|
5447
|
-
this.error(c.red(`No ${config.mode} files found, exiting with code 1\n`));
|
|
5448
|
-
}
|
|
5449
|
-
}
|
|
5524
|
+
if (config.watch && (config.changed || config.related?.length)) this.log(`No affected ${config.mode} files found\n`);
|
|
5525
|
+
else if (config.watch) this.log(c.red(`No ${config.mode} files found. You can change the file name pattern by pressing "p"\n`));
|
|
5526
|
+
else if (config.passWithNoTests) this.log(`No ${config.mode} files found, exiting with code 0\n`);
|
|
5527
|
+
else this.error(c.red(`No ${config.mode} files found, exiting with code 1\n`));
|
|
5450
5528
|
const comma = c.dim(", ");
|
|
5451
|
-
if (filters?.length)
|
|
5452
|
-
this.console.error(c.dim("filter: ") + c.yellow(filters.join(comma)));
|
|
5453
|
-
}
|
|
5529
|
+
if (filters?.length) this.console.error(c.dim("filter: ") + c.yellow(filters.join(comma)));
|
|
5454
5530
|
const projectsFilter = toArray(config.project);
|
|
5455
|
-
if (projectsFilter.length)
|
|
5456
|
-
this.console.error(c.dim("projects: ") + c.yellow(projectsFilter.join(comma)));
|
|
5457
|
-
}
|
|
5531
|
+
if (projectsFilter.length) this.console.error(c.dim("projects: ") + c.yellow(projectsFilter.join(comma)));
|
|
5458
5532
|
this.ctx.projects.forEach((project) => {
|
|
5459
5533
|
const config = project.config;
|
|
5460
5534
|
const printConfig = !project.isRootProject() && project.name;
|
|
5461
|
-
if (printConfig) {
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
if (config.include) {
|
|
5465
|
-
this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
|
|
5466
|
-
}
|
|
5467
|
-
if (config.exclude) {
|
|
5468
|
-
this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
|
|
5469
|
-
}
|
|
5535
|
+
if (printConfig) this.console.error(`\n${formatProjectName(project)}\n`);
|
|
5536
|
+
if (config.include) this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
|
|
5537
|
+
if (config.exclude) this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
|
|
5470
5538
|
if (config.typecheck.enabled) {
|
|
5471
5539
|
this.console.error(c.dim("typecheck include: ") + c.yellow(config.typecheck.include.join(comma)));
|
|
5472
5540
|
this.console.error(c.dim("typecheck exclude: ") + c.yellow(config.typecheck.exclude.join(comma)));
|
|
@@ -5479,9 +5547,7 @@ class Logger {
|
|
|
5479
5547
|
const color = this.ctx.config.watch ? "blue" : "cyan";
|
|
5480
5548
|
const mode = this.ctx.config.watch ? "DEV" : "RUN";
|
|
5481
5549
|
this.log(withLabel(color, mode, `v${this.ctx.version} `) + c.gray(this.ctx.config.root));
|
|
5482
|
-
if (this.ctx.config.sequence.sequencer === RandomSequencer) {
|
|
5483
|
-
this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
|
|
5484
|
-
}
|
|
5550
|
+
if (this.ctx.config.sequence.sequencer === RandomSequencer) this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`));
|
|
5485
5551
|
if (this.ctx.config.ui) {
|
|
5486
5552
|
const host = this.ctx.config.api?.host || "localhost";
|
|
5487
5553
|
const port = this.ctx.server.config.server.port;
|
|
@@ -5489,35 +5555,28 @@ class Logger {
|
|
|
5489
5555
|
this.log(PAD + c.dim(c.green(`UI started at http://${host}:${c.bold(port)}${base}`)));
|
|
5490
5556
|
} else if (this.ctx.config.api?.port) {
|
|
5491
5557
|
const resolvedUrls = this.ctx.server.resolvedUrls;
|
|
5558
|
+
// workaround for https://github.com/vitejs/vite/issues/15438, it was fixed in vite 5.1
|
|
5492
5559
|
const fallbackUrl = `http://${this.ctx.config.api.host || "localhost"}:${this.ctx.config.api.port}`;
|
|
5493
5560
|
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0] ?? fallbackUrl;
|
|
5494
5561
|
this.log(PAD + c.dim(c.green(`API started at ${new URL("/", origin)}`)));
|
|
5495
5562
|
}
|
|
5496
|
-
if (this.ctx.coverageProvider)
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
if (this.ctx.config.standalone) {
|
|
5500
|
-
this.log(c.yellow(`\nVitest is running in standalone mode. Edit a test file to rerun tests.`));
|
|
5501
|
-
} else {
|
|
5502
|
-
this.log();
|
|
5503
|
-
}
|
|
5563
|
+
if (this.ctx.coverageProvider) this.log(PAD + c.dim("Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
|
|
5564
|
+
if (this.ctx.config.standalone) this.log(c.yellow(`\nVitest is running in standalone mode. Edit a test file to rerun tests.`));
|
|
5565
|
+
else this.log();
|
|
5504
5566
|
}
|
|
5505
5567
|
printBrowserBanner(project) {
|
|
5506
|
-
if (!project.browser)
|
|
5507
|
-
return;
|
|
5508
|
-
}
|
|
5568
|
+
if (!project.browser) return;
|
|
5509
5569
|
const resolvedUrls = project.browser.vite.resolvedUrls;
|
|
5510
5570
|
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
|
|
5511
|
-
if (!origin)
|
|
5512
|
-
return;
|
|
5513
|
-
}
|
|
5571
|
+
if (!origin) return;
|
|
5514
5572
|
const output = project.isRootProject() ? "" : formatProjectName(project);
|
|
5515
5573
|
const provider = project.browser.provider.name;
|
|
5516
5574
|
const providerString = provider === "preview" ? "" : ` by ${c.reset(c.bold(provider))}`;
|
|
5517
5575
|
this.log(c.dim(`${output}Browser runner started${providerString} ${c.dim("at")} ${c.blue(new URL("/", origin))}\n`));
|
|
5518
5576
|
}
|
|
5519
5577
|
printUnhandledErrors(errors) {
|
|
5520
|
-
const errorMessage = c.red(c.bold(`\nVitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run
|
|
5578
|
+
const errorMessage = c.red(c.bold(`\nVitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
|
|
5579
|
+
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`));
|
|
5521
5580
|
this.error(errorBanner("Unhandled Errors"));
|
|
5522
5581
|
this.error(errorMessage);
|
|
5523
5582
|
errors.forEach((err) => {
|
|
@@ -5546,15 +5605,13 @@ class Logger {
|
|
|
5546
5605
|
addCleanupListeners() {
|
|
5547
5606
|
const cleanup = () => {
|
|
5548
5607
|
this.cleanupListeners.forEach((fn) => fn());
|
|
5549
|
-
if (this.outputStream.isTTY)
|
|
5550
|
-
this.outputStream.write(SHOW_CURSOR);
|
|
5551
|
-
}
|
|
5608
|
+
if (this.outputStream.isTTY) this.outputStream.write(SHOW_CURSOR);
|
|
5552
5609
|
};
|
|
5553
5610
|
const onExit = (signal, exitCode) => {
|
|
5554
5611
|
cleanup();
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5612
|
+
// Interrupted signals don't set exit code automatically.
|
|
5613
|
+
// 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);
|
|
5558
5615
|
process.exit();
|
|
5559
5616
|
};
|
|
5560
5617
|
process.once("SIGINT", onExit);
|
|
@@ -5590,9 +5647,7 @@ class VitestPackageInstaller {
|
|
|
5590
5647
|
return isPackageExists(name, options);
|
|
5591
5648
|
}
|
|
5592
5649
|
async ensureInstalled(dependency, root, version) {
|
|
5593
|
-
if (process.env.VITEST_SKIP_INSTALL_CHECKS)
|
|
5594
|
-
return true;
|
|
5595
|
-
}
|
|
5650
|
+
if (process.env.VITEST_SKIP_INSTALL_CHECKS) return true;
|
|
5596
5651
|
if (process.versions.pnp) {
|
|
5597
5652
|
const targetRequire = createRequire(__dirname);
|
|
5598
5653
|
try {
|
|
@@ -5600,13 +5655,9 @@ class VitestPackageInstaller {
|
|
|
5600
5655
|
return true;
|
|
5601
5656
|
} catch {}
|
|
5602
5657
|
}
|
|
5603
|
-
if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] }))
|
|
5604
|
-
return true;
|
|
5605
|
-
}
|
|
5658
|
+
if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] })) return true;
|
|
5606
5659
|
process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEPENDENCY "))} Cannot find dependency '${dependency}'\n\n`));
|
|
5607
|
-
if (!isTTY)
|
|
5608
|
-
return false;
|
|
5609
|
-
}
|
|
5660
|
+
if (!isTTY) return false;
|
|
5610
5661
|
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; });
|
|
5611
5662
|
const { install } = await prompts.default({
|
|
5612
5663
|
type: "confirm",
|
|
@@ -5615,7 +5666,8 @@ class VitestPackageInstaller {
|
|
|
5615
5666
|
});
|
|
5616
5667
|
if (install) {
|
|
5617
5668
|
const packageName = version ? `${dependency}@${version}` : dependency;
|
|
5618
|
-
await (await import('./index.
|
|
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
|
|
5619
5671
|
process.stderr.write(c.yellow(`\nPackage ${packageName} installed, re-run the command to start.\n`));
|
|
5620
5672
|
process.exit();
|
|
5621
5673
|
return true;
|
|
@@ -5627,6 +5679,7 @@ class VitestPackageInstaller {
|
|
|
5627
5679
|
function serializeConfig(config, coreConfig, viteConfig) {
|
|
5628
5680
|
const optimizer = config.deps?.optimizer;
|
|
5629
5681
|
const poolOptions = config.poolOptions;
|
|
5682
|
+
// Resolve from server.config to avoid comparing against default value
|
|
5630
5683
|
const isolate = viteConfig?.test?.isolate;
|
|
5631
5684
|
return {
|
|
5632
5685
|
environmentOptions: config.environmentOptions,
|
|
@@ -5667,8 +5720,8 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5667
5720
|
reportsDirectory: coverage.reportsDirectory,
|
|
5668
5721
|
provider: coverage.provider,
|
|
5669
5722
|
enabled: coverage.enabled,
|
|
5670
|
-
htmlReporter: htmlReporter ? { subdir } :
|
|
5671
|
-
customProviderModule: "customProviderModule" in coverage ? coverage.customProviderModule :
|
|
5723
|
+
htmlReporter: htmlReporter ? { subdir } : void 0,
|
|
5724
|
+
customProviderModule: "customProviderModule" in coverage ? coverage.customProviderModule : void 0
|
|
5672
5725
|
};
|
|
5673
5726
|
})(config.coverage),
|
|
5674
5727
|
fakeTimers: config.fakeTimers,
|
|
@@ -5694,11 +5747,11 @@ function serializeConfig(config, coreConfig, viteConfig) {
|
|
|
5694
5747
|
moduleDirectories: config.deps.moduleDirectories
|
|
5695
5748
|
},
|
|
5696
5749
|
snapshotOptions: {
|
|
5697
|
-
snapshotEnvironment:
|
|
5750
|
+
snapshotEnvironment: void 0,
|
|
5698
5751
|
updateSnapshot: coreConfig.snapshotOptions.updateSnapshot,
|
|
5699
5752
|
snapshotFormat: {
|
|
5700
5753
|
...coreConfig.snapshotOptions.snapshotFormat,
|
|
5701
|
-
compareKeys:
|
|
5754
|
+
compareKeys: void 0
|
|
5702
5755
|
},
|
|
5703
5756
|
expand: config.snapshotOptions.expand ?? coreConfig.snapshotOptions.expand
|
|
5704
5757
|
},
|
|
@@ -5747,25 +5800,17 @@ async function loadGlobalSetupFile(file, runner) {
|
|
|
5747
5800
|
"default",
|
|
5748
5801
|
"setup",
|
|
5749
5802
|
"teardown"
|
|
5750
|
-
]) {
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
}
|
|
5755
|
-
if (m.
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
return {
|
|
5762
|
-
file,
|
|
5763
|
-
setup: m.setup,
|
|
5764
|
-
teardown: m.teardown
|
|
5765
|
-
};
|
|
5766
|
-
} else {
|
|
5767
|
-
throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
|
|
5768
|
-
}
|
|
5803
|
+
]) if (m[exp] != null && typeof m[exp] !== "function") throw new Error(`invalid export in globalSetup file ${file}: ${exp} must be a function`);
|
|
5804
|
+
if (m.default) return {
|
|
5805
|
+
file,
|
|
5806
|
+
setup: m.default
|
|
5807
|
+
};
|
|
5808
|
+
else if (m.setup || m.teardown) return {
|
|
5809
|
+
file,
|
|
5810
|
+
setup: m.setup,
|
|
5811
|
+
teardown: m.teardown
|
|
5812
|
+
};
|
|
5813
|
+
else throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
|
|
5769
5814
|
}
|
|
5770
5815
|
|
|
5771
5816
|
function CoverageTransform(ctx) {
|
|
@@ -5781,12 +5826,8 @@ function MocksPlugins(options = {}) {
|
|
|
5781
5826
|
const normalizedDistDir = normalize(distDir);
|
|
5782
5827
|
return [hoistMocksPlugin({
|
|
5783
5828
|
filter(id) {
|
|
5784
|
-
if (id.includes(normalizedDistDir))
|
|
5785
|
-
|
|
5786
|
-
}
|
|
5787
|
-
if (options.filter) {
|
|
5788
|
-
return options.filter(id);
|
|
5789
|
-
}
|
|
5829
|
+
if (id.includes(normalizedDistDir)) return false;
|
|
5830
|
+
if (options.filter) return options.filter(id);
|
|
5790
5831
|
return true;
|
|
5791
5832
|
},
|
|
5792
5833
|
codeFrameGenerator(node, id, code) {
|
|
@@ -5799,12 +5840,9 @@ function generateCssFilenameHash(filepath) {
|
|
|
5799
5840
|
return hash("md5", filepath, "hex").slice(0, 6);
|
|
5800
5841
|
}
|
|
5801
5842
|
function generateScopedClassName(strategy, name, filename) {
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
if (strategy === "non-scoped") {
|
|
5806
|
-
return name;
|
|
5807
|
-
}
|
|
5843
|
+
// should be configured by Vite defaults
|
|
5844
|
+
if (strategy === "scoped") return null;
|
|
5845
|
+
if (strategy === "non-scoped") return name;
|
|
5808
5846
|
const hash = generateCssFilenameHash(filename);
|
|
5809
5847
|
return `_${name}_${hash}`;
|
|
5810
5848
|
}
|
|
@@ -5823,17 +5861,23 @@ function clearScreen(logger) {
|
|
|
5823
5861
|
let lastType;
|
|
5824
5862
|
let lastMsg;
|
|
5825
5863
|
let sameCount = 0;
|
|
5864
|
+
// Only initialize the timeFormatter when the timestamp option is used, and
|
|
5865
|
+
// reuse it across all loggers
|
|
5826
5866
|
let timeFormatter;
|
|
5827
5867
|
function getTimeFormatter() {
|
|
5828
|
-
timeFormatter ??= new Intl.DateTimeFormat(
|
|
5868
|
+
timeFormatter ??= new Intl.DateTimeFormat(void 0, {
|
|
5829
5869
|
hour: "numeric",
|
|
5830
5870
|
minute: "numeric",
|
|
5831
5871
|
second: "numeric"
|
|
5832
5872
|
});
|
|
5833
5873
|
return timeFormatter;
|
|
5834
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
|
|
5835
5879
|
function createViteLogger(console, level = "info", options = {}) {
|
|
5836
|
-
const loggedErrors = new WeakSet();
|
|
5880
|
+
const loggedErrors = /* @__PURE__ */ new WeakSet();
|
|
5837
5881
|
const { prefix = "[vite]", allowClearScreen = true } = options;
|
|
5838
5882
|
const thresh = LogLevels[level];
|
|
5839
5883
|
const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
|
|
@@ -5841,45 +5885,32 @@ function createViteLogger(console, level = "info", options = {}) {
|
|
|
5841
5885
|
function format(type, msg, options = {}) {
|
|
5842
5886
|
if (options.timestamp) {
|
|
5843
5887
|
let tag = "";
|
|
5844
|
-
if (type === "info")
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
tag = c.yellow(c.bold(prefix));
|
|
5848
|
-
} else {
|
|
5849
|
-
tag = c.red(c.bold(prefix));
|
|
5850
|
-
}
|
|
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));
|
|
5851
5891
|
const environment = options.environment ? `${options.environment} ` : "";
|
|
5852
|
-
return `${c.dim(getTimeFormatter().format(new Date()))} ${tag} ${environment}${msg}`;
|
|
5853
|
-
} else
|
|
5854
|
-
return msg;
|
|
5855
|
-
}
|
|
5892
|
+
return `${c.dim(getTimeFormatter().format(/* @__PURE__ */ new Date()))} ${tag} ${environment}${msg}`;
|
|
5893
|
+
} else return msg;
|
|
5856
5894
|
}
|
|
5857
5895
|
function output(type, msg, options = {}) {
|
|
5858
5896
|
if (thresh >= LogLevels[type]) {
|
|
5859
5897
|
const method = type === "info" ? "log" : type;
|
|
5860
|
-
if (options.error)
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
sameCount++;
|
|
5866
|
-
clear(console);
|
|
5867
|
-
console[method](format(type, msg, options), c.yellow(`(x${sameCount + 1})`));
|
|
5868
|
-
} else {
|
|
5869
|
-
sameCount = 0;
|
|
5870
|
-
lastMsg = msg;
|
|
5871
|
-
lastType = type;
|
|
5872
|
-
if (options.clear) {
|
|
5873
|
-
clear(console);
|
|
5874
|
-
}
|
|
5875
|
-
console[method](format(type, msg, options));
|
|
5876
|
-
}
|
|
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})`));
|
|
5877
5903
|
} else {
|
|
5904
|
+
sameCount = 0;
|
|
5905
|
+
lastMsg = msg;
|
|
5906
|
+
lastType = type;
|
|
5907
|
+
if (options.clear) clear(console);
|
|
5878
5908
|
console[method](format(type, msg, options));
|
|
5879
5909
|
}
|
|
5910
|
+
else console[method](format(type, msg, options));
|
|
5880
5911
|
}
|
|
5881
5912
|
}
|
|
5882
|
-
const warnedMessages = new Set();
|
|
5913
|
+
const warnedMessages = /* @__PURE__ */ new Set();
|
|
5883
5914
|
const logger = {
|
|
5884
5915
|
hasWarned: false,
|
|
5885
5916
|
info(msg, opts) {
|
|
@@ -5890,9 +5921,7 @@ function createViteLogger(console, level = "info", options = {}) {
|
|
|
5890
5921
|
output("warn", msg, opts);
|
|
5891
5922
|
},
|
|
5892
5923
|
warnOnce(msg, opts) {
|
|
5893
|
-
if (warnedMessages.has(msg))
|
|
5894
|
-
return;
|
|
5895
|
-
}
|
|
5924
|
+
if (warnedMessages.has(msg)) return;
|
|
5896
5925
|
logger.hasWarned = true;
|
|
5897
5926
|
output("warn", msg, opts);
|
|
5898
5927
|
warnedMessages.add(msg);
|
|
@@ -5902,9 +5931,7 @@ function createViteLogger(console, level = "info", options = {}) {
|
|
|
5902
5931
|
output("error", msg, opts);
|
|
5903
5932
|
},
|
|
5904
5933
|
clearScreen(type) {
|
|
5905
|
-
if (thresh >= LogLevels[type])
|
|
5906
|
-
clear(console);
|
|
5907
|
-
}
|
|
5934
|
+
if (thresh >= LogLevels[type]) clear(console);
|
|
5908
5935
|
},
|
|
5909
5936
|
hasErrorLogged(error) {
|
|
5910
5937
|
return loggedErrors.has(error);
|
|
@@ -5912,13 +5939,12 @@ function createViteLogger(console, level = "info", options = {}) {
|
|
|
5912
5939
|
};
|
|
5913
5940
|
return logger;
|
|
5914
5941
|
}
|
|
5942
|
+
// silence warning by Vite for statically not analyzable dynamic import
|
|
5915
5943
|
function silenceImportViteIgnoreWarning(logger) {
|
|
5916
5944
|
return {
|
|
5917
5945
|
...logger,
|
|
5918
5946
|
warn(msg, options) {
|
|
5919
|
-
if (msg.includes("The above dynamic import cannot be analyzed by Vite"))
|
|
5920
|
-
return;
|
|
5921
|
-
}
|
|
5947
|
+
if (msg.includes("The above dynamic import cannot be analyzed by Vite")) return;
|
|
5922
5948
|
logger.warn(msg, options);
|
|
5923
5949
|
}
|
|
5924
5950
|
};
|
|
@@ -5934,49 +5960,42 @@ function isCSS(id) {
|
|
|
5934
5960
|
function isCSSModule(id) {
|
|
5935
5961
|
return cssModuleRE.test(id);
|
|
5936
5962
|
}
|
|
5963
|
+
// inline css requests are expected to just return the
|
|
5964
|
+
// string content directly and not the proxy module
|
|
5937
5965
|
function isInline(id) {
|
|
5938
5966
|
return cssInlineRE.test(id);
|
|
5939
5967
|
}
|
|
5940
5968
|
function getCSSModuleProxyReturn(strategy, filename) {
|
|
5941
|
-
if (strategy === "non-scoped")
|
|
5942
|
-
return "style";
|
|
5943
|
-
}
|
|
5969
|
+
if (strategy === "non-scoped") return "style";
|
|
5944
5970
|
const hash = generateCssFilenameHash(filename);
|
|
5945
5971
|
return `\`_\${style}_${hash}\``;
|
|
5946
5972
|
}
|
|
5947
5973
|
function CSSEnablerPlugin(ctx) {
|
|
5948
5974
|
const shouldProcessCSS = (id) => {
|
|
5949
5975
|
const { css } = ctx.config;
|
|
5950
|
-
if (typeof css === "boolean")
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
if (toArray(css.exclude).some((re) => re.test(id))) {
|
|
5954
|
-
return false;
|
|
5955
|
-
}
|
|
5956
|
-
if (toArray(css.include).some((re) => re.test(id))) {
|
|
5957
|
-
return true;
|
|
5958
|
-
}
|
|
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;
|
|
5959
5979
|
return false;
|
|
5960
5980
|
};
|
|
5961
5981
|
return [{
|
|
5962
5982
|
name: "vitest:css-disable",
|
|
5963
5983
|
enforce: "pre",
|
|
5964
5984
|
transform(code, id) {
|
|
5965
|
-
if (!isCSS(id))
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
if (!shouldProcessCSS(id)) {
|
|
5969
|
-
return { code: "" };
|
|
5970
|
-
}
|
|
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: "" };
|
|
5971
5989
|
}
|
|
5972
5990
|
}, {
|
|
5973
5991
|
name: "vitest:css-empty-post",
|
|
5974
5992
|
enforce: "post",
|
|
5975
5993
|
transform(_, id) {
|
|
5976
|
-
if (!isCSS(id) || shouldProcessCSS(id))
|
|
5977
|
-
return;
|
|
5978
|
-
}
|
|
5994
|
+
if (!isCSS(id) || shouldProcessCSS(id)) return;
|
|
5979
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
|
|
5980
5999
|
const scopeStrategy = typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable";
|
|
5981
6000
|
const proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id));
|
|
5982
6001
|
const code = `export default new Proxy(Object.create(null), {
|
|
@@ -6475,21 +6494,24 @@ function stripLiteralDetailed(code, options) {
|
|
|
6475
6494
|
return stripLiteralJsTokens(code);
|
|
6476
6495
|
}
|
|
6477
6496
|
|
|
6478
|
-
const metaUrlLength =
|
|
6497
|
+
const metaUrlLength = 15;
|
|
6479
6498
|
const locationString = "self.location".padEnd(metaUrlLength, " ");
|
|
6499
|
+
// Vite transforms new URL('./path', import.meta.url) to new URL('/path.js', import.meta.url)
|
|
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.
|
|
6480
6503
|
function NormalizeURLPlugin() {
|
|
6481
6504
|
return {
|
|
6482
6505
|
name: "vitest:normalize-url",
|
|
6483
6506
|
enforce: "post",
|
|
6484
6507
|
transform(code, id, options) {
|
|
6485
6508
|
const ssr = options?.ssr === true;
|
|
6486
|
-
if (ssr || !code.includes("new URL") || !code.includes("import.meta.url"))
|
|
6487
|
-
return;
|
|
6488
|
-
}
|
|
6509
|
+
if (ssr || !code.includes("new URL") || !code.includes("import.meta.url")) return;
|
|
6489
6510
|
const cleanString = stripLiteral(code);
|
|
6490
6511
|
const assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*(?:'' \+ )?import\.meta\.url\s*(?:,\s*)?\)/g;
|
|
6491
6512
|
let updatedCode = code;
|
|
6492
6513
|
let match;
|
|
6514
|
+
// eslint-disable-next-line no-cond-assign
|
|
6493
6515
|
while (match = assetImportMetaUrlRE.exec(cleanString)) {
|
|
6494
6516
|
const { 0: exp, index } = match;
|
|
6495
6517
|
const metaUrlIndex = index + exp.indexOf("import.meta.url");
|
|
@@ -6503,24 +6525,20 @@ function NormalizeURLPlugin() {
|
|
|
6503
6525
|
};
|
|
6504
6526
|
}
|
|
6505
6527
|
|
|
6506
|
-
function resolveOptimizerConfig(_testOptions, viteOptions
|
|
6528
|
+
function resolveOptimizerConfig(_testOptions, viteOptions) {
|
|
6507
6529
|
const testOptions = _testOptions || {};
|
|
6508
6530
|
const newConfig = {};
|
|
6509
6531
|
const [major, minor, fix] = version.split(".").map(Number);
|
|
6510
6532
|
const allowed = major >= 5 || major === 4 && minor >= 4 || major === 4 && minor === 3 && fix >= 2;
|
|
6511
|
-
if (!allowed && testOptions?.enabled === true) {
|
|
6512
|
-
|
|
6513
|
-
} else {
|
|
6514
|
-
testOptions.enabled ??= false;
|
|
6515
|
-
}
|
|
6533
|
+
if (!allowed && testOptions?.enabled === true) console.warn(`Vitest: "deps.optimizer" is only available in Vite >= 4.3.2, current Vite version: ${version}`);
|
|
6534
|
+
else testOptions.enabled ??= false;
|
|
6516
6535
|
if (!allowed || testOptions?.enabled !== true) {
|
|
6517
|
-
newConfig.cacheDir =
|
|
6536
|
+
newConfig.cacheDir = void 0;
|
|
6518
6537
|
newConfig.optimizeDeps = {
|
|
6519
6538
|
disabled: true,
|
|
6520
6539
|
entries: []
|
|
6521
6540
|
};
|
|
6522
6541
|
} else {
|
|
6523
|
-
const root = testConfig.root ?? process.cwd();
|
|
6524
6542
|
const currentInclude = testOptions.include || viteOptions?.include || [];
|
|
6525
6543
|
const exclude = [
|
|
6526
6544
|
"vitest",
|
|
@@ -6531,8 +6549,6 @@ function resolveOptimizerConfig(_testOptions, viteOptions, testConfig, viteCache
|
|
|
6531
6549
|
const runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime"));
|
|
6532
6550
|
exclude.push(...runtime);
|
|
6533
6551
|
const include = (testOptions.include || viteOptions?.include || []).filter((n) => !exclude.includes(n));
|
|
6534
|
-
const projectName = typeof testConfig.name === "string" ? testConfig.name : testConfig.name?.label;
|
|
6535
|
-
newConfig.cacheDir = testConfig.cache !== false && testConfig.cache?.dir || VitestCache.resolveCacheDir(root, viteCacheDir, projectName);
|
|
6536
6552
|
newConfig.optimizeDeps = {
|
|
6537
6553
|
...viteOptions,
|
|
6538
6554
|
...testOptions,
|
|
@@ -6543,6 +6559,8 @@ function resolveOptimizerConfig(_testOptions, viteOptions, testConfig, viteCache
|
|
|
6543
6559
|
include
|
|
6544
6560
|
};
|
|
6545
6561
|
}
|
|
6562
|
+
// `optimizeDeps.disabled` is deprecated since v5.1.0-beta.1
|
|
6563
|
+
// https://github.com/vitejs/vite/pull/15184
|
|
6546
6564
|
if (major >= 5 && minor >= 1 || major >= 6) {
|
|
6547
6565
|
if (newConfig.optimizeDeps.disabled) {
|
|
6548
6566
|
newConfig.optimizeDeps.noDiscovery = true;
|
|
@@ -6566,14 +6584,16 @@ function deleteDefineConfig(viteConfig) {
|
|
|
6566
6584
|
try {
|
|
6567
6585
|
replacement = typeof val === "string" ? JSON.parse(val) : val;
|
|
6568
6586
|
} catch {
|
|
6587
|
+
// probably means it contains reference to some variable,
|
|
6588
|
+
// like this: "__VAR__": "process.env.VAR"
|
|
6569
6589
|
continue;
|
|
6570
6590
|
}
|
|
6571
6591
|
if (key.startsWith("import.meta.env.")) {
|
|
6572
|
-
const envKey = key.slice(
|
|
6592
|
+
const envKey = key.slice(16);
|
|
6573
6593
|
process.env[envKey] = replacement;
|
|
6574
6594
|
delete viteConfig.define[key];
|
|
6575
6595
|
} else if (key.startsWith("process.env.")) {
|
|
6576
|
-
const envKey = key.slice(
|
|
6596
|
+
const envKey = key.slice(12);
|
|
6577
6597
|
process.env[envKey] = replacement;
|
|
6578
6598
|
delete viteConfig.define[key];
|
|
6579
6599
|
} else if (!key.includes(".")) {
|
|
@@ -6584,9 +6604,7 @@ function deleteDefineConfig(viteConfig) {
|
|
|
6584
6604
|
return defines;
|
|
6585
6605
|
}
|
|
6586
6606
|
function resolveFsAllow(projectRoot, rootConfigFile) {
|
|
6587
|
-
if (!rootConfigFile)
|
|
6588
|
-
return [searchForWorkspaceRoot(projectRoot), rootDir];
|
|
6589
|
-
}
|
|
6607
|
+
if (!rootConfigFile) return [searchForWorkspaceRoot(projectRoot), rootDir];
|
|
6590
6608
|
return [
|
|
6591
6609
|
dirname(rootConfigFile),
|
|
6592
6610
|
searchForWorkspaceRoot(projectRoot),
|
|
@@ -6615,9 +6633,12 @@ function VitestOptimizer() {
|
|
|
6615
6633
|
order: "post",
|
|
6616
6634
|
handler(viteConfig) {
|
|
6617
6635
|
const testConfig = viteConfig.test || {};
|
|
6618
|
-
const webOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.web, viteConfig.optimizeDeps
|
|
6619
|
-
const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.ssr, viteConfig.ssr?.optimizeDeps
|
|
6620
|
-
|
|
6636
|
+
const webOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.web, viteConfig.optimizeDeps);
|
|
6637
|
+
const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.ssr, viteConfig.ssr?.optimizeDeps);
|
|
6638
|
+
const root = resolve(viteConfig.root || process.cwd());
|
|
6639
|
+
const name = viteConfig.test?.name;
|
|
6640
|
+
const label = typeof name === "string" ? name : name?.label || "";
|
|
6641
|
+
viteConfig.cacheDir = VitestCache.resolveCacheDir(resolve(root || process.cwd()), testConfig.cache != null && testConfig.cache !== false ? testConfig.cache.dir : viteConfig.cacheDir, label);
|
|
6621
6642
|
viteConfig.optimizeDeps = webOptimizer.optimizeDeps;
|
|
6622
6643
|
viteConfig.ssr ??= {};
|
|
6623
6644
|
viteConfig.ssr.optimizeDeps = ssrOptimizer.optimizeDeps;
|
|
@@ -6626,14 +6647,14 @@ function VitestOptimizer() {
|
|
|
6626
6647
|
};
|
|
6627
6648
|
}
|
|
6628
6649
|
|
|
6650
|
+
// so people can reassign envs at runtime
|
|
6651
|
+
// import.meta.env.VITE_NAME = 'app' -> process.env.VITE_NAME = 'app'
|
|
6629
6652
|
function SsrReplacerPlugin() {
|
|
6630
6653
|
return {
|
|
6631
6654
|
name: "vitest:ssr-replacer",
|
|
6632
6655
|
enforce: "pre",
|
|
6633
6656
|
transform(code, id) {
|
|
6634
|
-
if (!/\bimport\.meta\.env\b/.test(code))
|
|
6635
|
-
return null;
|
|
6636
|
-
}
|
|
6657
|
+
if (!/\bimport\.meta\.env\b/.test(code)) return null;
|
|
6637
6658
|
let s = null;
|
|
6638
6659
|
const cleanCode = stripLiteral(code);
|
|
6639
6660
|
const envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g);
|
|
@@ -6643,15 +6664,13 @@ function SsrReplacerPlugin() {
|
|
|
6643
6664
|
const endIndex = startIndex + env[0].length;
|
|
6644
6665
|
s.overwrite(startIndex, endIndex, "__vite_ssr_import_meta__.env");
|
|
6645
6666
|
}
|
|
6646
|
-
if (s) {
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
};
|
|
6654
|
-
}
|
|
6667
|
+
if (s) return {
|
|
6668
|
+
code: s.toString(),
|
|
6669
|
+
map: s.generateMap({
|
|
6670
|
+
hires: "boundary",
|
|
6671
|
+
source: cleanUrl(id)
|
|
6672
|
+
})
|
|
6673
|
+
};
|
|
6655
6674
|
}
|
|
6656
6675
|
};
|
|
6657
6676
|
}
|
|
@@ -6662,7 +6681,9 @@ function VitestProjectResolver(ctx) {
|
|
|
6662
6681
|
enforce: "pre",
|
|
6663
6682
|
async resolveId(id, _, { ssr }) {
|
|
6664
6683
|
if (id === "vitest" || id.startsWith("@vitest/") || id.startsWith("vitest/")) {
|
|
6665
|
-
|
|
6684
|
+
// always redirect the request to the root vitest plugin since
|
|
6685
|
+
// it will be the one used to run Vitest
|
|
6686
|
+
const resolved = await ctx.server.pluginContainer.resolveId(id, void 0, {
|
|
6666
6687
|
skip: new Set([plugin]),
|
|
6667
6688
|
ssr
|
|
6668
6689
|
});
|
|
@@ -6677,12 +6698,10 @@ function VitestCoreResolver(ctx) {
|
|
|
6677
6698
|
name: "vitest:resolve-core",
|
|
6678
6699
|
enforce: "pre",
|
|
6679
6700
|
async resolveId(id) {
|
|
6680
|
-
if (id === "vitest")
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
return this.resolve(id, join(ctx.config.root, "index.html"), { skipSelf: true });
|
|
6685
|
-
}
|
|
6701
|
+
if (id === "vitest") return resolve(distDir, "index.js");
|
|
6702
|
+
if (id.startsWith("@vitest/") || id.startsWith("vitest/"))
|
|
6703
|
+
// ignore actual importer, we want it to be resolved relative to the root
|
|
6704
|
+
return this.resolve(id, join(ctx.config.root, "index.html"), { skipSelf: true });
|
|
6686
6705
|
}
|
|
6687
6706
|
};
|
|
6688
6707
|
}
|
|
@@ -6691,7 +6710,7 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6691
6710
|
return [
|
|
6692
6711
|
{
|
|
6693
6712
|
name: "vitest:project",
|
|
6694
|
-
enforce: "
|
|
6713
|
+
enforce: "post",
|
|
6695
6714
|
options() {
|
|
6696
6715
|
this.meta.watchMode = false;
|
|
6697
6716
|
},
|
|
@@ -6703,20 +6722,13 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6703
6722
|
label: "",
|
|
6704
6723
|
...testConfig.name
|
|
6705
6724
|
};
|
|
6706
|
-
if (!name) {
|
|
6707
|
-
if
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
if (typeof name !== "string" || !name) {
|
|
6714
|
-
name = basename(dir);
|
|
6715
|
-
}
|
|
6716
|
-
} else {
|
|
6717
|
-
name = options.workspacePath.toString();
|
|
6718
|
-
}
|
|
6719
|
-
}
|
|
6725
|
+
if (!name) if (typeof options.workspacePath === "string") {
|
|
6726
|
+
// if there is a package.json, read the name from it
|
|
6727
|
+
const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath);
|
|
6728
|
+
const pkgJsonPath = resolve(dir, "package.json");
|
|
6729
|
+
if (existsSync(pkgJsonPath)) name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name;
|
|
6730
|
+
if (typeof name !== "string" || !name) name = basename(dir);
|
|
6731
|
+
} else name = options.workspacePath.toString();
|
|
6720
6732
|
const resolveOptions = getDefaultResolveOptions();
|
|
6721
6733
|
const config = {
|
|
6722
6734
|
root,
|
|
@@ -6745,40 +6757,38 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6745
6757
|
color
|
|
6746
6758
|
} }
|
|
6747
6759
|
};
|
|
6748
|
-
if (project.vitest._options.browser && viteConfig.test?.browser) {
|
|
6749
|
-
viteConfig.test.browser = mergeConfig(viteConfig.test.browser, project.vitest._options.browser);
|
|
6750
|
-
}
|
|
6751
6760
|
config.test.defines = defines;
|
|
6761
|
+
const isUserBrowserEnabled = viteConfig.test?.browser?.enabled;
|
|
6762
|
+
const isBrowserEnabled = isUserBrowserEnabled ?? (viteConfig.test?.browser && project.vitest._cliOptions.browser?.enabled);
|
|
6763
|
+
// keep project names to potentially filter it out
|
|
6752
6764
|
const workspaceNames = [name];
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
}
|
|
6765
|
+
const browser = viteConfig.test.browser || {};
|
|
6766
|
+
if (isBrowserEnabled && browser.name && !browser.instances?.length)
|
|
6767
|
+
// vitest injects `instances` in this case later on
|
|
6768
|
+
workspaceNames.push(name ? `${name} (${browser.name})` : browser.name);
|
|
6769
|
+
viteConfig.test?.browser?.instances?.forEach((instance) => {
|
|
6770
|
+
// every instance is a potential project
|
|
6771
|
+
instance.name ??= name ? `${name} (${instance.browser})` : instance.browser;
|
|
6772
|
+
if (isBrowserEnabled) workspaceNames.push(instance.name);
|
|
6773
|
+
});
|
|
6763
6774
|
const filters = project.vitest.config.project;
|
|
6775
|
+
// if there is `--project=...` filter, check if any of the potential projects match
|
|
6776
|
+
// if projects don't match, we ignore the test project altogether
|
|
6777
|
+
// if some of them match, they will later be filtered again by `resolveWorkspace`
|
|
6764
6778
|
if (filters.length) {
|
|
6765
6779
|
const hasProject = workspaceNames.some((name) => {
|
|
6766
6780
|
return project.vitest.matchesProjectFilter(name);
|
|
6767
6781
|
});
|
|
6768
|
-
if (!hasProject)
|
|
6769
|
-
throw new VitestFilteredOutProjectError();
|
|
6770
|
-
}
|
|
6782
|
+
if (!hasProject) throw new VitestFilteredOutProjectError();
|
|
6771
6783
|
}
|
|
6772
6784
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
6773
6785
|
if (classNameStrategy !== "scoped") {
|
|
6774
6786
|
config.css ??= {};
|
|
6775
6787
|
config.css.modules ??= {};
|
|
6776
|
-
if (config.css.modules) {
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
};
|
|
6781
|
-
}
|
|
6788
|
+
if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
6789
|
+
const root = project.config.root;
|
|
6790
|
+
return generateScopedClassName(classNameStrategy, name, relative(root, filename));
|
|
6791
|
+
};
|
|
6782
6792
|
}
|
|
6783
6793
|
config.customLogger = createViteLogger(project.vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
|
|
6784
6794
|
config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
|
|
@@ -6792,9 +6802,9 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
6792
6802
|
},
|
|
6793
6803
|
SsrReplacerPlugin(),
|
|
6794
6804
|
...CSSEnablerPlugin(project),
|
|
6795
|
-
CoverageTransform(project.
|
|
6805
|
+
CoverageTransform(project.vitest),
|
|
6796
6806
|
...MocksPlugins(),
|
|
6797
|
-
VitestProjectResolver(project.
|
|
6807
|
+
VitestProjectResolver(project.vitest),
|
|
6798
6808
|
VitestOptimizer(),
|
|
6799
6809
|
NormalizeURLPlugin()
|
|
6800
6810
|
];
|
|
@@ -6851,9 +6861,7 @@ class TestSpecification {
|
|
|
6851
6861
|
*/
|
|
6852
6862
|
get testModule() {
|
|
6853
6863
|
const task = this.project.vitest.state.idMap.get(this.taskId);
|
|
6854
|
-
if (!task)
|
|
6855
|
-
return undefined;
|
|
6856
|
-
}
|
|
6864
|
+
if (!task) return void 0;
|
|
6857
6865
|
return this.project.vitest.state.getReportedEntity(task);
|
|
6858
6866
|
}
|
|
6859
6867
|
toJSON() {
|
|
@@ -6881,11 +6889,11 @@ class TestSpecification {
|
|
|
6881
6889
|
}
|
|
6882
6890
|
|
|
6883
6891
|
async function createViteServer(inlineConfig) {
|
|
6892
|
+
// Vite prints an error (https://github.com/vitejs/vite/issues/14328)
|
|
6893
|
+
// But Vitest works correctly either way
|
|
6884
6894
|
const error = console.error;
|
|
6885
6895
|
console.error = (...args) => {
|
|
6886
|
-
if (typeof args[0] === "string" && args[0].includes("WebSocket server error:"))
|
|
6887
|
-
return;
|
|
6888
|
-
}
|
|
6896
|
+
if (typeof args[0] === "string" && args[0].includes("WebSocket server error:")) return;
|
|
6889
6897
|
error(...args);
|
|
6890
6898
|
};
|
|
6891
6899
|
const server = await createServer(inlineConfig);
|
|
@@ -6937,11 +6945,11 @@ class TestProject {
|
|
|
6937
6945
|
* It is based on the root of the project (not consistent between OS) and its name.
|
|
6938
6946
|
*/
|
|
6939
6947
|
get hash() {
|
|
6940
|
-
if (!this._hash)
|
|
6941
|
-
throw new Error("The server was not set. It means that `project.hash` was called before the Vite server was established.");
|
|
6942
|
-
}
|
|
6948
|
+
if (!this._hash) throw new Error("The server was not set. It means that `project.hash` was called before the Vite server was established.");
|
|
6943
6949
|
return this._hash;
|
|
6944
6950
|
}
|
|
6951
|
+
// "provide" is a property, not a method to keep the context when destructed in the global setup,
|
|
6952
|
+
// making it a method would be a breaking change, and can be done in Vitest 3 at minimum
|
|
6945
6953
|
/**
|
|
6946
6954
|
* Provide a value to the test context. This value will be available to all tests with `inject`.
|
|
6947
6955
|
*/
|
|
@@ -6951,15 +6959,16 @@ class TestProject {
|
|
|
6951
6959
|
} catch (err) {
|
|
6952
6960
|
throw new Error(`Cannot provide "${key}" because it's not serializable.`, { cause: err });
|
|
6953
6961
|
}
|
|
6962
|
+
// casting `any` because the default type is `never` since `ProvidedContext` is empty
|
|
6954
6963
|
this._provided[key] = value;
|
|
6955
6964
|
};
|
|
6956
6965
|
/**
|
|
6957
6966
|
* Get the provided context. The project context is merged with the global context.
|
|
6958
6967
|
*/
|
|
6959
6968
|
getProvidedContext() {
|
|
6960
|
-
if (this.isRootProject())
|
|
6961
|
-
|
|
6962
|
-
|
|
6969
|
+
if (this.isRootProject()) return this._provided;
|
|
6970
|
+
// globalSetup can run even if core workspace is not part of the test run
|
|
6971
|
+
// so we need to inherit its provided context
|
|
6963
6972
|
return {
|
|
6964
6973
|
...this.vitest.getRootProject().getProvidedContext(),
|
|
6965
6974
|
...this._provided
|
|
@@ -6983,9 +6992,8 @@ class TestProject {
|
|
|
6983
6992
|
* Vite's dev server instance. Every workspace project has its own server.
|
|
6984
6993
|
*/
|
|
6985
6994
|
get vite() {
|
|
6986
|
-
if (!this._vite)
|
|
6987
|
-
|
|
6988
|
-
}
|
|
6995
|
+
if (!this._vite) throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
|
|
6996
|
+
// checking it once should be enough
|
|
6989
6997
|
Object.defineProperty(this, "vite", {
|
|
6990
6998
|
configurable: true,
|
|
6991
6999
|
writable: true,
|
|
@@ -6997,9 +7005,13 @@ class TestProject {
|
|
|
6997
7005
|
* Resolved project configuration.
|
|
6998
7006
|
*/
|
|
6999
7007
|
get config() {
|
|
7000
|
-
if (!this._config)
|
|
7001
|
-
|
|
7002
|
-
|
|
7008
|
+
if (!this._config) throw new Error("The config was not set. It means that `project.config` was called before the Vite server was established.");
|
|
7009
|
+
// checking it once should be enough
|
|
7010
|
+
// Object.defineProperty(this, 'config', {
|
|
7011
|
+
// configurable: true,
|
|
7012
|
+
// writable: true,
|
|
7013
|
+
// value: this._config,
|
|
7014
|
+
// })
|
|
7003
7015
|
return this._config;
|
|
7004
7016
|
}
|
|
7005
7017
|
/**
|
|
@@ -7044,18 +7056,12 @@ class TestProject {
|
|
|
7044
7056
|
}
|
|
7045
7057
|
/** @internal */
|
|
7046
7058
|
async _initializeGlobalSetup() {
|
|
7047
|
-
if (this._globalSetups)
|
|
7048
|
-
return;
|
|
7049
|
-
}
|
|
7059
|
+
if (this._globalSetups) return;
|
|
7050
7060
|
this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup);
|
|
7051
7061
|
for (const globalSetupFile of this._globalSetups) {
|
|
7052
7062
|
const teardown = await globalSetupFile.setup?.(this);
|
|
7053
|
-
if (teardown == null || !!globalSetupFile.teardown)
|
|
7054
|
-
|
|
7055
|
-
}
|
|
7056
|
-
if (typeof teardown !== "function") {
|
|
7057
|
-
throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
|
|
7058
|
-
}
|
|
7063
|
+
if (teardown == null || !!globalSetupFile.teardown) continue;
|
|
7064
|
+
if (typeof teardown !== "function") throw new TypeError(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
|
|
7059
7065
|
globalSetupFile.teardown = teardown;
|
|
7060
7066
|
}
|
|
7061
7067
|
}
|
|
@@ -7068,21 +7074,18 @@ class TestProject {
|
|
|
7068
7074
|
}
|
|
7069
7075
|
/** @internal */
|
|
7070
7076
|
async _teardownGlobalSetup() {
|
|
7071
|
-
if (!this._globalSetups)
|
|
7072
|
-
|
|
7073
|
-
}
|
|
7074
|
-
for (const globalSetupFile of [...this._globalSetups].reverse()) {
|
|
7075
|
-
await globalSetupFile.teardown?.();
|
|
7076
|
-
}
|
|
7077
|
+
if (!this._globalSetups) return;
|
|
7078
|
+
for (const globalSetupFile of [...this._globalSetups].reverse()) await globalSetupFile.teardown?.();
|
|
7077
7079
|
}
|
|
7078
7080
|
/** @deprecated use `vitest.logger` instead */
|
|
7079
7081
|
get logger() {
|
|
7080
7082
|
return this.vitest.logger;
|
|
7081
7083
|
}
|
|
7084
|
+
// it's possible that file path was imported with different queries (?raw, ?url, etc)
|
|
7082
7085
|
/** @deprecated use `.vite` or `.browser.vite` directly */
|
|
7083
7086
|
getModulesByFilepath(file) {
|
|
7084
7087
|
const set = this.server.moduleGraph.getModulesByFile(file) || this.browser?.vite.moduleGraph.getModulesByFile(file);
|
|
7085
|
-
return set || new Set();
|
|
7088
|
+
return set || /* @__PURE__ */ new Set();
|
|
7086
7089
|
}
|
|
7087
7090
|
/** @deprecated use `.vite` or `.browser.vite` directly */
|
|
7088
7091
|
getModuleById(id) {
|
|
@@ -7113,18 +7116,14 @@ class TestProject {
|
|
|
7113
7116
|
};
|
|
7114
7117
|
}
|
|
7115
7118
|
async globAllTestFiles(include, exclude, includeSource, cwd) {
|
|
7116
|
-
if (this.testFilesList)
|
|
7117
|
-
return this.testFilesList;
|
|
7118
|
-
}
|
|
7119
|
+
if (this.testFilesList) return this.testFilesList;
|
|
7119
7120
|
const testFiles = await this.globFiles(include, exclude, cwd);
|
|
7120
7121
|
if (includeSource?.length) {
|
|
7121
7122
|
const files = await this.globFiles(includeSource, exclude, cwd);
|
|
7122
7123
|
await Promise.all(files.map(async (file) => {
|
|
7123
7124
|
try {
|
|
7124
7125
|
const code = await promises.readFile(file, "utf-8");
|
|
7125
|
-
if (this.isInSourceTestCode(code))
|
|
7126
|
-
testFiles.push(file);
|
|
7127
|
-
}
|
|
7126
|
+
if (this.isInSourceTestCode(code)) testFiles.push(file);
|
|
7128
7127
|
} catch {
|
|
7129
7128
|
return null;
|
|
7130
7129
|
}
|
|
@@ -7141,9 +7140,7 @@ class TestProject {
|
|
|
7141
7140
|
}
|
|
7142
7141
|
/** @internal */
|
|
7143
7142
|
_removeCachedTestFile(testPath) {
|
|
7144
|
-
if (this.testFilesList)
|
|
7145
|
-
this.testFilesList = this.testFilesList.filter((file) => file !== testPath);
|
|
7146
|
-
}
|
|
7143
|
+
if (this.testFilesList) this.testFilesList = this.testFilesList.filter((file) => file !== testPath);
|
|
7147
7144
|
}
|
|
7148
7145
|
/**
|
|
7149
7146
|
* Returns if the file is a test file. Requires `.globTestFiles()` to be called first.
|
|
@@ -7172,19 +7169,18 @@ class TestProject {
|
|
|
7172
7169
|
expandDirectories: false
|
|
7173
7170
|
};
|
|
7174
7171
|
const files = await glob(include, globOptions);
|
|
7172
|
+
// keep the slashes consistent with Vite
|
|
7173
|
+
// we are not using the pathe here because it normalizes the drive letter on Windows
|
|
7174
|
+
// and we want to keep it the same as working dir
|
|
7175
7175
|
return files.map((file) => slash(path.resolve(cwd, file)));
|
|
7176
7176
|
}
|
|
7177
7177
|
/**
|
|
7178
7178
|
* Test if a file matches the test globs. This does the actual glob matching if the test is not cached, unlike `isCachedTestFile`.
|
|
7179
7179
|
*/
|
|
7180
7180
|
matchesTestGlob(moduleId, source) {
|
|
7181
|
-
if (this._isCachedTestFile(moduleId))
|
|
7182
|
-
return true;
|
|
7183
|
-
}
|
|
7181
|
+
if (this._isCachedTestFile(moduleId)) return true;
|
|
7184
7182
|
const relativeId = relative(this.config.dir || this.config.root, moduleId);
|
|
7185
|
-
if (pm.isMatch(relativeId, this.config.exclude))
|
|
7186
|
-
return false;
|
|
7187
|
-
}
|
|
7183
|
+
if (pm.isMatch(relativeId, this.config.exclude)) return false;
|
|
7188
7184
|
if (pm.isMatch(relativeId, this.config.include)) {
|
|
7189
7185
|
this.markTestFile(moduleId);
|
|
7190
7186
|
return true;
|
|
@@ -7200,27 +7196,22 @@ class TestProject {
|
|
|
7200
7196
|
}
|
|
7201
7197
|
/** @deprecated use `matchesTestGlob` instead */
|
|
7202
7198
|
async isTargetFile(id, source) {
|
|
7203
|
-
return this.matchesTestGlob(id, source ? () => source :
|
|
7199
|
+
return this.matchesTestGlob(id, source ? () => source : void 0);
|
|
7204
7200
|
}
|
|
7205
7201
|
isInSourceTestCode(code) {
|
|
7206
7202
|
return code.includes("import.meta.vitest");
|
|
7207
7203
|
}
|
|
7208
7204
|
filterFiles(testFiles, filters, dir) {
|
|
7209
|
-
if (filters.length && process.platform === "win32")
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
return true;
|
|
7218
|
-
}
|
|
7219
|
-
const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f);
|
|
7220
|
-
return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase());
|
|
7221
|
-
});
|
|
7205
|
+
if (filters.length && process.platform === "win32") filters = filters.map((f) => slash(f));
|
|
7206
|
+
if (filters.length) return testFiles.filter((t) => {
|
|
7207
|
+
const testFile = relative(dir, t).toLocaleLowerCase();
|
|
7208
|
+
return filters.some((f) => {
|
|
7209
|
+
// if filter is a full file path, we should include it if it's in the same folder
|
|
7210
|
+
if (isAbsolute(f) && t.startsWith(f)) return true;
|
|
7211
|
+
const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f);
|
|
7212
|
+
return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase());
|
|
7222
7213
|
});
|
|
7223
|
-
}
|
|
7214
|
+
});
|
|
7224
7215
|
return testFiles;
|
|
7225
7216
|
}
|
|
7226
7217
|
_parentBrowser;
|
|
@@ -7228,9 +7219,7 @@ class TestProject {
|
|
|
7228
7219
|
_parent;
|
|
7229
7220
|
/** @internal */
|
|
7230
7221
|
_initParentBrowser = deduped(async () => {
|
|
7231
|
-
if (!this.isBrowserEnabled() || this._parentBrowser)
|
|
7232
|
-
return;
|
|
7233
|
-
}
|
|
7222
|
+
if (!this.isBrowserEnabled() || this._parentBrowser) return;
|
|
7234
7223
|
await this.vitest.packageInstaller.ensureInstalled("@vitest/browser", this.config.root, this.vitest.version);
|
|
7235
7224
|
const { createBrowserServer, distRoot } = await import('@vitest/browser');
|
|
7236
7225
|
let cacheDir;
|
|
@@ -7240,15 +7229,11 @@ class TestProject {
|
|
|
7240
7229
|
cacheDir = config.cacheDir;
|
|
7241
7230
|
}
|
|
7242
7231
|
}, ...MocksPlugins({ filter(id) {
|
|
7243
|
-
if (id.includes(distRoot) || id.includes(cacheDir))
|
|
7244
|
-
return false;
|
|
7245
|
-
}
|
|
7232
|
+
if (id.includes(distRoot) || id.includes(cacheDir)) return false;
|
|
7246
7233
|
return true;
|
|
7247
7234
|
} })], [CoverageTransform(this.vitest)]);
|
|
7248
7235
|
this._parentBrowser = browser;
|
|
7249
|
-
if (this.config.browser.ui)
|
|
7250
|
-
setup(this.vitest, browser.vite);
|
|
7251
|
-
}
|
|
7236
|
+
if (this.config.browser.ui) setup(this.vitest, browser.vite);
|
|
7252
7237
|
});
|
|
7253
7238
|
/** @internal */
|
|
7254
7239
|
_initBrowserServer = deduped(async () => {
|
|
@@ -7263,17 +7248,15 @@ class TestProject {
|
|
|
7263
7248
|
* If the resources are needed again, create a new project.
|
|
7264
7249
|
*/
|
|
7265
7250
|
close() {
|
|
7266
|
-
if (!this.closingPromise)
|
|
7267
|
-
this.
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
});
|
|
7276
|
-
}
|
|
7251
|
+
if (!this.closingPromise) this.closingPromise = Promise.all([
|
|
7252
|
+
this.vite?.close(),
|
|
7253
|
+
this.typechecker?.stop(),
|
|
7254
|
+
this.browser?.close(),
|
|
7255
|
+
this.clearTmpDir()
|
|
7256
|
+
].filter(Boolean)).then(() => {
|
|
7257
|
+
this._provided = {};
|
|
7258
|
+
this._vite = void 0;
|
|
7259
|
+
});
|
|
7277
7260
|
return this.closingPromise;
|
|
7278
7261
|
}
|
|
7279
7262
|
/**
|
|
@@ -7303,9 +7286,10 @@ class TestProject {
|
|
|
7303
7286
|
this._setHash();
|
|
7304
7287
|
for (const _providedKey in this.config.provide) {
|
|
7305
7288
|
const providedKey = _providedKey;
|
|
7289
|
+
// type is very strict here, so we cast it to any
|
|
7306
7290
|
this.provide(providedKey, this.config.provide[providedKey]);
|
|
7307
7291
|
}
|
|
7308
|
-
this.closingPromise =
|
|
7292
|
+
this.closingPromise = void 0;
|
|
7309
7293
|
this._vite = server;
|
|
7310
7294
|
this.vitenode = new ViteNodeServer(server, this.config.server);
|
|
7311
7295
|
const node = this.vitenode;
|
|
@@ -7321,10 +7305,9 @@ class TestProject {
|
|
|
7321
7305
|
});
|
|
7322
7306
|
}
|
|
7323
7307
|
_serializeOverriddenConfig() {
|
|
7308
|
+
// TODO: serialize the config _once_ or when needed
|
|
7324
7309
|
const config = serializeConfig(this.config, this.vitest.config, this.vite.config);
|
|
7325
|
-
if (!this.vitest.configOverride)
|
|
7326
|
-
return config;
|
|
7327
|
-
}
|
|
7310
|
+
if (!this.vitest.configOverride) return config;
|
|
7328
7311
|
return deepMerge(config, this.vitest.configOverride);
|
|
7329
7312
|
}
|
|
7330
7313
|
async clearTmpDir() {
|
|
@@ -7338,18 +7321,15 @@ class TestProject {
|
|
|
7338
7321
|
}
|
|
7339
7322
|
/** @internal */
|
|
7340
7323
|
_initBrowserProvider = deduped(async () => {
|
|
7341
|
-
if (!this.isBrowserEnabled() || this.browser?.provider)
|
|
7342
|
-
|
|
7343
|
-
}
|
|
7344
|
-
if (!this.browser) {
|
|
7345
|
-
await this._initBrowserServer();
|
|
7346
|
-
}
|
|
7324
|
+
if (!this.isBrowserEnabled() || this.browser?.provider) return;
|
|
7325
|
+
if (!this.browser) await this._initBrowserServer();
|
|
7347
7326
|
await this.browser?.initBrowserProvider(this);
|
|
7348
7327
|
});
|
|
7349
7328
|
/** @internal */
|
|
7350
7329
|
_provideObject(context) {
|
|
7351
7330
|
for (const _providedKey in context) {
|
|
7352
7331
|
const providedKey = _providedKey;
|
|
7332
|
+
// type is very strict here, so we cast it to any
|
|
7353
7333
|
this.provide(providedKey, context[providedKey]);
|
|
7354
7334
|
}
|
|
7355
7335
|
}
|
|
@@ -7380,11 +7360,9 @@ class TestProject {
|
|
|
7380
7360
|
function deduped(cb) {
|
|
7381
7361
|
let _promise;
|
|
7382
7362
|
return (...args) => {
|
|
7383
|
-
if (!_promise) {
|
|
7384
|
-
_promise =
|
|
7385
|
-
|
|
7386
|
-
});
|
|
7387
|
-
}
|
|
7363
|
+
if (!_promise) _promise = cb(...args).finally(() => {
|
|
7364
|
+
_promise = void 0;
|
|
7365
|
+
});
|
|
7388
7366
|
return _promise;
|
|
7389
7367
|
};
|
|
7390
7368
|
}
|
|
@@ -7406,9 +7384,7 @@ async function initializeProject(workspacePath, ctx, options) {
|
|
|
7406
7384
|
}
|
|
7407
7385
|
function generateHash(str) {
|
|
7408
7386
|
let hash = 0;
|
|
7409
|
-
if (str.length === 0) {
|
|
7410
|
-
return `${hash}`;
|
|
7411
|
-
}
|
|
7387
|
+
if (str.length === 0) return `${hash}`;
|
|
7412
7388
|
for (let i = 0; i < str.length; i++) {
|
|
7413
7389
|
const char = str.charCodeAt(i);
|
|
7414
7390
|
hash = (hash << 5) - hash + char;
|
|
@@ -7419,6 +7395,8 @@ function generateHash(str) {
|
|
|
7419
7395
|
|
|
7420
7396
|
async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projectsDefinition, names) {
|
|
7421
7397
|
const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition);
|
|
7398
|
+
// cli options that affect the project config,
|
|
7399
|
+
// not all options are allowed to be overridden
|
|
7422
7400
|
const overridesOptions = [
|
|
7423
7401
|
"logHeapUsage",
|
|
7424
7402
|
"allowOnly",
|
|
@@ -7440,9 +7418,7 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7440
7418
|
"fileParallelism"
|
|
7441
7419
|
];
|
|
7442
7420
|
const cliOverrides = overridesOptions.reduce((acc, name) => {
|
|
7443
|
-
if (name in cliOptions)
|
|
7444
|
-
acc[name] = cliOptions[name];
|
|
7445
|
-
}
|
|
7421
|
+
if (name in cliOptions) acc[name] = cliOptions[name];
|
|
7446
7422
|
return acc;
|
|
7447
7423
|
}, {});
|
|
7448
7424
|
const projectPromises = [];
|
|
@@ -7450,7 +7426,10 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7450
7426
|
const concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5);
|
|
7451
7427
|
projectConfigs.forEach((options, index) => {
|
|
7452
7428
|
const configRoot = workspaceConfigPath ? dirname(workspaceConfigPath) : vitest.config.root;
|
|
7429
|
+
// if extends a config file, resolve the file path
|
|
7453
7430
|
const configFile = typeof options.extends === "string" ? resolve(configRoot, options.extends) : options.extends === true ? vitest.vite.config.configFile || false : false;
|
|
7431
|
+
// if `root` is configured, resolve it relative to the workspace file or vite root (like other options)
|
|
7432
|
+
// if `root` is not specified, inline configs use the same root as the root project
|
|
7454
7433
|
const root = options.root ? resolve(configRoot, options.root) : vitest.config.root;
|
|
7455
7434
|
projectPromises.push(concurrent(() => initializeProject(index, vitest, {
|
|
7456
7435
|
...options,
|
|
@@ -7463,11 +7442,10 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7463
7442
|
})));
|
|
7464
7443
|
});
|
|
7465
7444
|
for (const path of fileProjects) {
|
|
7445
|
+
// if file leads to the root config, then we can just reuse it because we already initialized it
|
|
7466
7446
|
if (vitest.vite.config.configFile === path) {
|
|
7467
7447
|
const project = getDefaultTestProject(vitest);
|
|
7468
|
-
if (project)
|
|
7469
|
-
projectPromises.push(Promise.resolve(project));
|
|
7470
|
-
}
|
|
7448
|
+
if (project) projectPromises.push(Promise.resolve(project));
|
|
7471
7449
|
continue;
|
|
7472
7450
|
}
|
|
7473
7451
|
const configFile = path.endsWith("/") ? false : path;
|
|
@@ -7478,29 +7456,23 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7478
7456
|
test: cliOverrides
|
|
7479
7457
|
})));
|
|
7480
7458
|
}
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
}
|
|
7459
|
+
// pretty rare case - the glob didn't match anything and there are no inline configs
|
|
7460
|
+
if (!projectPromises.length) throw new Error([
|
|
7461
|
+
"No projects were found. Make sure your configuration is correct. ",
|
|
7462
|
+
vitest.config.project.length ? `The filter matched no projects: ${vitest.config.project.join(", ")}. ` : "",
|
|
7463
|
+
`The projects definition: ${JSON.stringify(projectsDefinition, null, 4)}.`
|
|
7464
|
+
].join(""));
|
|
7488
7465
|
const resolvedProjectsPromises = await Promise.allSettled(projectPromises);
|
|
7489
7466
|
const errors = [];
|
|
7490
7467
|
const resolvedProjects = [];
|
|
7491
|
-
for (const result of resolvedProjectsPromises) {
|
|
7492
|
-
if (result.
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
}
|
|
7500
|
-
}
|
|
7501
|
-
if (errors.length) {
|
|
7502
|
-
throw new AggregateError(errors, "Failed to initialize projects. There were errors during projects setup. See below for more details.");
|
|
7503
|
-
}
|
|
7468
|
+
for (const result of resolvedProjectsPromises) if (result.status === "rejected") {
|
|
7469
|
+
if (result.reason instanceof VitestFilteredOutProjectError)
|
|
7470
|
+
// filter out filtered out projects
|
|
7471
|
+
continue;
|
|
7472
|
+
errors.push(result.reason);
|
|
7473
|
+
} else resolvedProjects.push(result.value);
|
|
7474
|
+
if (errors.length) throw new AggregateError(errors, "Failed to initialize projects. There were errors during projects setup. See below for more details.");
|
|
7475
|
+
// project names are guaranteed to be unique
|
|
7504
7476
|
for (const project of resolvedProjects) {
|
|
7505
7477
|
const name = project.name;
|
|
7506
7478
|
if (names.has(name)) {
|
|
@@ -7524,11 +7496,9 @@ async function resolveProjects(vitest, cliOptions, workspaceConfigPath, projects
|
|
|
7524
7496
|
return resolveBrowserProjects(vitest, names, resolvedProjects);
|
|
7525
7497
|
}
|
|
7526
7498
|
async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
7527
|
-
const removeProjects = new Set();
|
|
7499
|
+
const removeProjects = /* @__PURE__ */ new Set();
|
|
7528
7500
|
resolvedProjects.forEach((project) => {
|
|
7529
|
-
if (!project.config.browser.enabled)
|
|
7530
|
-
return;
|
|
7531
|
-
}
|
|
7501
|
+
if (!project.config.browser.enabled) return;
|
|
7532
7502
|
const instances = project.config.browser.instances || [];
|
|
7533
7503
|
const browser = project.config.browser.name;
|
|
7534
7504
|
if (instances.length === 0 && browser) {
|
|
@@ -7545,17 +7515,17 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7545
7515
|
].filter(Boolean).join("")));
|
|
7546
7516
|
}
|
|
7547
7517
|
const originalName = project.config.name;
|
|
7518
|
+
// if original name is in the --project=name filter, keep all instances
|
|
7548
7519
|
const filteredInstances = vitest.matchesProjectFilter(originalName) ? instances : instances.filter((instance) => {
|
|
7549
7520
|
const newName = instance.name;
|
|
7550
7521
|
return vitest.matchesProjectFilter(newName);
|
|
7551
7522
|
});
|
|
7523
|
+
// every project was filtered out
|
|
7552
7524
|
if (!filteredInstances.length) {
|
|
7553
7525
|
removeProjects.add(project);
|
|
7554
7526
|
return;
|
|
7555
7527
|
}
|
|
7556
|
-
if (project.config.browser.providerOptions) {
|
|
7557
|
-
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.`));
|
|
7558
|
-
}
|
|
7528
|
+
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.`));
|
|
7559
7529
|
filteredInstances.forEach((config, index) => {
|
|
7560
7530
|
const browser = config.browser;
|
|
7561
7531
|
if (!browser) {
|
|
@@ -7564,16 +7534,12 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7564
7534
|
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.`);
|
|
7565
7535
|
}
|
|
7566
7536
|
const name = config.name;
|
|
7567
|
-
if (name == null)
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
"If you have multiple instances for the same browser, make sure to define a custom \"name\". ",
|
|
7574
|
-
"All projects should have unique names. Make sure your configuration is correct."
|
|
7575
|
-
].join(""));
|
|
7576
|
-
}
|
|
7537
|
+
if (name == null) throw new Error(`The browser configuration must have a "name" property. This is a bug in Vitest. Please, open a new issue with reproduction`);
|
|
7538
|
+
if (names.has(name)) throw new Error([
|
|
7539
|
+
`Cannot define a nested project for a ${browser} browser. The project name "${name}" was already defined. `,
|
|
7540
|
+
"If you have multiple instances for the same browser, make sure to define a custom \"name\". ",
|
|
7541
|
+
"All projects should have unique names. Make sure your configuration is correct."
|
|
7542
|
+
].join(""));
|
|
7577
7543
|
names.add(name);
|
|
7578
7544
|
const clonedConfig = cloneConfig(project, config);
|
|
7579
7545
|
clonedConfig.name = name;
|
|
@@ -7588,9 +7554,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7588
7554
|
});
|
|
7589
7555
|
if (headedBrowserProjects.length > 1) {
|
|
7590
7556
|
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("");
|
|
7591
|
-
if (!isTTY) {
|
|
7592
|
-
throw new Error(`${message} Please, filter projects with --browser=name or --project=name flag or run tests with "headless: true" option.`);
|
|
7593
|
-
}
|
|
7557
|
+
if (!isTTY) throw new Error(`${message} Please, filter projects with --browser=name or --project=name flag or run tests with "headless: true" option.`);
|
|
7594
7558
|
const prompts = await import('./index.X0nbfr6-.js').then(function (n) { return n.i; });
|
|
7595
7559
|
const { projectName } = await prompts.default({
|
|
7596
7560
|
type: "select",
|
|
@@ -7601,9 +7565,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
7601
7565
|
})),
|
|
7602
7566
|
message: `${message} Select a single project to run or cancel and run tests with "headless: true" option. Note that you can also start tests with --browser=name or --project=name flag.`
|
|
7603
7567
|
});
|
|
7604
|
-
if (!projectName)
|
|
7605
|
-
throw new Error("The test run was aborted.");
|
|
7606
|
-
}
|
|
7568
|
+
if (!projectName) throw new Error("The test run was aborted.");
|
|
7607
7569
|
return resolvedProjects.filter((project) => project.name === projectName);
|
|
7608
7570
|
}
|
|
7609
7571
|
return resolvedProjects;
|
|
@@ -7623,53 +7585,51 @@ function cloneConfig(project, { browser,...config }) {
|
|
|
7623
7585
|
headless: headless ?? currentConfig.headless,
|
|
7624
7586
|
name: browser,
|
|
7625
7587
|
providerOptions: config,
|
|
7626
|
-
instances:
|
|
7588
|
+
instances: void 0
|
|
7627
7589
|
}
|
|
7628
7590
|
}, overrideConfig);
|
|
7629
7591
|
}
|
|
7630
7592
|
async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDefinition) {
|
|
7593
|
+
// project configurations that were specified directly
|
|
7631
7594
|
const projectsOptions = [];
|
|
7595
|
+
// custom config files that were specified directly or resolved from a directory
|
|
7632
7596
|
const projectsConfigFiles = [];
|
|
7597
|
+
// custom glob matches that should be resolved as directories or config files
|
|
7633
7598
|
const projectsGlobMatches = [];
|
|
7599
|
+
// directories that don't have a config file inside, but should be treated as projects
|
|
7634
7600
|
const nonConfigProjectDirectories = [];
|
|
7635
|
-
for (const definition of projectsDefinition) {
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
}
|
|
7645
|
-
const stats = await promises.stat(file);
|
|
7646
|
-
if (stats.isFile()) {
|
|
7647
|
-
projectsConfigFiles.push(file);
|
|
7648
|
-
} else if (stats.isDirectory()) {
|
|
7649
|
-
const configFile = await resolveDirectoryConfig(file);
|
|
7650
|
-
if (configFile) {
|
|
7651
|
-
projectsConfigFiles.push(configFile);
|
|
7652
|
-
} else {
|
|
7653
|
-
const directory = file[file.length - 1] === "/" ? file : `${file}/`;
|
|
7654
|
-
nonConfigProjectDirectories.push(directory);
|
|
7655
|
-
}
|
|
7656
|
-
} else {
|
|
7657
|
-
throw new TypeError(`Unexpected file type: ${file}`);
|
|
7658
|
-
}
|
|
7659
|
-
} else {
|
|
7660
|
-
projectsGlobMatches.push(stringOption);
|
|
7601
|
+
for (const definition of projectsDefinition) if (typeof definition === "string") {
|
|
7602
|
+
const stringOption = definition.replace("<rootDir>", vitest.config.root);
|
|
7603
|
+
// if the string doesn't contain a glob, we can resolve it directly
|
|
7604
|
+
// ['./vitest.config.js']
|
|
7605
|
+
if (!isDynamicPattern(stringOption)) {
|
|
7606
|
+
const file = resolve(vitest.config.root, stringOption);
|
|
7607
|
+
if (!existsSync(file)) {
|
|
7608
|
+
const relativeWorkspaceConfigPath = workspaceConfigPath ? relative(vitest.config.root, workspaceConfigPath) : void 0;
|
|
7609
|
+
const note = workspaceConfigPath ? `Workspace config file "${relativeWorkspaceConfigPath}"` : "Projects definition";
|
|
7610
|
+
throw new Error(`${note} references a non-existing file or a directory: ${file}`);
|
|
7661
7611
|
}
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7612
|
+
const stats = await promises.stat(file);
|
|
7613
|
+
// user can specify a config file directly
|
|
7614
|
+
if (stats.isFile()) projectsConfigFiles.push(file);
|
|
7615
|
+
else if (stats.isDirectory()) {
|
|
7616
|
+
const configFile = await resolveDirectoryConfig(file);
|
|
7617
|
+
if (configFile) projectsConfigFiles.push(configFile);
|
|
7618
|
+
else {
|
|
7619
|
+
const directory = file[file.length - 1] === "/" ? file : `${file}/`;
|
|
7620
|
+
nonConfigProjectDirectories.push(directory);
|
|
7621
|
+
}
|
|
7622
|
+
} else
|
|
7623
|
+
// should never happen
|
|
7624
|
+
throw new TypeError(`Unexpected file type: ${file}`);
|
|
7625
|
+
} else projectsGlobMatches.push(stringOption);
|
|
7626
|
+
} else if (typeof definition === "function") projectsOptions.push(await definition({
|
|
7627
|
+
command: vitest.vite.config.command,
|
|
7628
|
+
mode: vitest.vite.config.mode,
|
|
7629
|
+
isPreview: false,
|
|
7630
|
+
isSsrBuild: false
|
|
7631
|
+
}));
|
|
7632
|
+
else projectsOptions.push(await definition);
|
|
7673
7633
|
if (projectsGlobMatches.length) {
|
|
7674
7634
|
const globOptions = {
|
|
7675
7635
|
absolute: true,
|
|
@@ -7685,16 +7645,13 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7685
7645
|
};
|
|
7686
7646
|
const projectsFs = await glob(projectsGlobMatches, globOptions);
|
|
7687
7647
|
await Promise.all(projectsFs.map(async (path) => {
|
|
7648
|
+
// directories are allowed with a glob like `packages/*`
|
|
7649
|
+
// in this case every directory is treated as a project
|
|
7688
7650
|
if (path.endsWith("/")) {
|
|
7689
7651
|
const configFile = await resolveDirectoryConfig(path);
|
|
7690
|
-
if (configFile)
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
nonConfigProjectDirectories.push(path);
|
|
7694
|
-
}
|
|
7695
|
-
} else {
|
|
7696
|
-
projectsConfigFiles.push(path);
|
|
7697
|
-
}
|
|
7652
|
+
if (configFile) projectsConfigFiles.push(configFile);
|
|
7653
|
+
else nonConfigProjectDirectories.push(path);
|
|
7654
|
+
} else projectsConfigFiles.push(path);
|
|
7698
7655
|
}));
|
|
7699
7656
|
}
|
|
7700
7657
|
const projectConfigFiles = Array.from(new Set(projectsConfigFiles));
|
|
@@ -7706,31 +7663,25 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, projectsDe
|
|
|
7706
7663
|
}
|
|
7707
7664
|
async function resolveDirectoryConfig(directory) {
|
|
7708
7665
|
const files = new Set(await promises.readdir(directory));
|
|
7666
|
+
// default resolution looks for vitest.config.* or vite.config.* files
|
|
7667
|
+
// this simulates how `findUp` works in packages/vitest/src/node/create.ts:29
|
|
7709
7668
|
const configFile = configFiles.find((file) => files.has(file));
|
|
7710
|
-
if (configFile)
|
|
7711
|
-
return resolve(directory, configFile);
|
|
7712
|
-
}
|
|
7669
|
+
if (configFile) return resolve(directory, configFile);
|
|
7713
7670
|
return null;
|
|
7714
7671
|
}
|
|
7715
7672
|
function getDefaultTestProject(vitest) {
|
|
7716
7673
|
const filter = vitest.config.project;
|
|
7717
7674
|
const project = vitest._ensureRootProject();
|
|
7718
|
-
if (!filter.length)
|
|
7719
|
-
|
|
7720
|
-
}
|
|
7675
|
+
if (!filter.length) return project;
|
|
7676
|
+
// check for the project name and browser names
|
|
7721
7677
|
const hasProjects = getPotentialProjectNames(project).some((p) => vitest.matchesProjectFilter(p));
|
|
7722
|
-
if (hasProjects)
|
|
7723
|
-
return project;
|
|
7724
|
-
}
|
|
7678
|
+
if (hasProjects) return project;
|
|
7725
7679
|
return null;
|
|
7726
7680
|
}
|
|
7727
7681
|
function getPotentialProjectNames(project) {
|
|
7728
7682
|
const names = [project.name];
|
|
7729
|
-
if (project.config.browser.instances)
|
|
7730
|
-
|
|
7731
|
-
} else if (project.config.browser.name) {
|
|
7732
|
-
names.push(project.config.browser.name);
|
|
7733
|
-
}
|
|
7683
|
+
if (project.config.browser.instances) names.push(...project.config.browser.instances.map((i) => i.name));
|
|
7684
|
+
else if (project.config.browser.name) names.push(project.config.browser.name);
|
|
7734
7685
|
return names;
|
|
7735
7686
|
}
|
|
7736
7687
|
|
|
@@ -7741,9 +7692,7 @@ async function loadCustomReporterModule(path, runner) {
|
|
|
7741
7692
|
} catch (customReporterModuleError) {
|
|
7742
7693
|
throw new Error(`Failed to load custom Reporter from ${path}`, { cause: customReporterModuleError });
|
|
7743
7694
|
}
|
|
7744
|
-
if (customReporterModule.default === null || customReporterModule.default ===
|
|
7745
|
-
throw new Error(`Custom reporter loaded from ${path} was not the default export`);
|
|
7746
|
-
}
|
|
7695
|
+
if (customReporterModule.default === null || customReporterModule.default === void 0) throw new Error(`Custom reporter loaded from ${path} was not the default export`);
|
|
7747
7696
|
return customReporterModule.default;
|
|
7748
7697
|
}
|
|
7749
7698
|
function createReporters(reporterReferences, ctx) {
|
|
@@ -7769,14 +7718,12 @@ function createReporters(reporterReferences, ctx) {
|
|
|
7769
7718
|
}
|
|
7770
7719
|
function createBenchmarkReporters(reporterReferences, runner) {
|
|
7771
7720
|
const promisedReporters = reporterReferences.map(async (referenceOrInstance) => {
|
|
7772
|
-
if (typeof referenceOrInstance === "string") {
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
return new CustomReporter();
|
|
7779
|
-
}
|
|
7721
|
+
if (typeof referenceOrInstance === "string") if (referenceOrInstance in BenchmarkReportsMap) {
|
|
7722
|
+
const BuiltinReporter = BenchmarkReportsMap[referenceOrInstance];
|
|
7723
|
+
return new BuiltinReporter();
|
|
7724
|
+
} else {
|
|
7725
|
+
const CustomReporter = await loadCustomReporterModule(referenceOrInstance, runner);
|
|
7726
|
+
return new CustomReporter();
|
|
7780
7727
|
}
|
|
7781
7728
|
return referenceOrInstance;
|
|
7782
7729
|
});
|
|
@@ -7785,49 +7732,37 @@ function createBenchmarkReporters(reporterReferences, runner) {
|
|
|
7785
7732
|
|
|
7786
7733
|
function parseFilter(filter) {
|
|
7787
7734
|
const colonIndex = filter.lastIndexOf(":");
|
|
7788
|
-
if (colonIndex === -1) {
|
|
7789
|
-
return { filename: filter };
|
|
7790
|
-
}
|
|
7735
|
+
if (colonIndex === -1) return { filename: filter };
|
|
7791
7736
|
const [parsedFilename, lineNumber] = [filter.substring(0, colonIndex), filter.substring(colonIndex + 1)];
|
|
7792
|
-
if (lineNumber.match(/^\d+$/)) {
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
throw new RangeLocationFilterProvidedError(filter);
|
|
7799
|
-
} else {
|
|
7800
|
-
return { filename: filter };
|
|
7801
|
-
}
|
|
7737
|
+
if (lineNumber.match(/^\d+$/)) return {
|
|
7738
|
+
filename: parsedFilename,
|
|
7739
|
+
lineNumber: Number.parseInt(lineNumber)
|
|
7740
|
+
};
|
|
7741
|
+
else if (lineNumber.match(/^\d+-\d+$/)) throw new RangeLocationFilterProvidedError(filter);
|
|
7742
|
+
else return { filename: filter };
|
|
7802
7743
|
}
|
|
7803
7744
|
function groupFilters(filters) {
|
|
7804
7745
|
const groupedFilters_ = groupBy(filters, (f) => f.filename);
|
|
7805
7746
|
const groupedFilters = Object.fromEntries(Object.entries(groupedFilters_).map((entry) => {
|
|
7806
7747
|
const [filename, filters] = entry;
|
|
7807
7748
|
const testLocations = filters.map((f) => f.lineNumber);
|
|
7808
|
-
return [filename, testLocations.filter((l) => l !==
|
|
7749
|
+
return [filename, testLocations.filter((l) => l !== void 0)];
|
|
7809
7750
|
}));
|
|
7810
7751
|
return groupedFilters;
|
|
7811
7752
|
}
|
|
7812
7753
|
|
|
7813
7754
|
class VitestSpecifications {
|
|
7814
|
-
_cachedSpecs = new Map();
|
|
7755
|
+
_cachedSpecs = /* @__PURE__ */ new Map();
|
|
7815
7756
|
constructor(vitest) {
|
|
7816
7757
|
this.vitest = vitest;
|
|
7817
7758
|
}
|
|
7818
7759
|
getModuleSpecifications(moduleId) {
|
|
7819
7760
|
const _cached = this.getCachedSpecifications(moduleId);
|
|
7820
|
-
if (_cached)
|
|
7821
|
-
return _cached;
|
|
7822
|
-
}
|
|
7761
|
+
if (_cached) return _cached;
|
|
7823
7762
|
const specs = [];
|
|
7824
7763
|
for (const project of this.vitest.projects) {
|
|
7825
|
-
if (project._isCachedTestFile(moduleId))
|
|
7826
|
-
|
|
7827
|
-
}
|
|
7828
|
-
if (project._isCachedTypecheckFile(moduleId)) {
|
|
7829
|
-
specs.push(project.createSpecification(moduleId, [], "typescript"));
|
|
7830
|
-
}
|
|
7764
|
+
if (project._isCachedTestFile(moduleId)) specs.push(project.createSpecification(moduleId));
|
|
7765
|
+
if (project._isCachedTypecheckFile(moduleId)) specs.push(project.createSpecification(moduleId, [], "typescript"));
|
|
7831
7766
|
}
|
|
7832
7767
|
specs.forEach((spec) => this.ensureSpecificationCached(spec));
|
|
7833
7768
|
return specs;
|
|
@@ -7839,13 +7774,13 @@ class VitestSpecifications {
|
|
|
7839
7774
|
const files = [];
|
|
7840
7775
|
const dir = process.cwd();
|
|
7841
7776
|
const parsedFilters = filters.map((f) => parseFilter(f));
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
}
|
|
7777
|
+
// Require includeTaskLocation when a location filter is passed
|
|
7778
|
+
if (!this.vitest.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) throw new IncludeTaskLocationDisabledError();
|
|
7845
7779
|
const testLines = groupFilters(parsedFilters.map((f) => ({
|
|
7846
7780
|
...f,
|
|
7847
7781
|
filename: resolve(dir, f.filename)
|
|
7848
7782
|
})));
|
|
7783
|
+
// Key is file and val specifies whether we have matched this file with testLocation
|
|
7849
7784
|
const testLocHasMatch = {};
|
|
7850
7785
|
await Promise.all(this.vitest.projects.map(async (project) => {
|
|
7851
7786
|
const { testFiles, typecheckTestFiles } = await project.globTestFiles(parsedFilters.map((f) => f.filename));
|
|
@@ -7865,18 +7800,13 @@ class VitestSpecifications {
|
|
|
7865
7800
|
});
|
|
7866
7801
|
}));
|
|
7867
7802
|
Object.entries(testLines).forEach(([filepath, loc]) => {
|
|
7868
|
-
if (loc.length !== 0 && !testLocHasMatch[filepath])
|
|
7869
|
-
throw new LocationFilterFileNotFoundError(relative(dir, filepath));
|
|
7870
|
-
}
|
|
7803
|
+
if (loc.length !== 0 && !testLocHasMatch[filepath]) throw new LocationFilterFileNotFoundError(relative(dir, filepath));
|
|
7871
7804
|
});
|
|
7872
7805
|
return files;
|
|
7873
7806
|
}
|
|
7874
7807
|
clearCache(moduleId) {
|
|
7875
|
-
if (moduleId)
|
|
7876
|
-
|
|
7877
|
-
} else {
|
|
7878
|
-
this._cachedSpecs.clear();
|
|
7879
|
-
}
|
|
7808
|
+
if (moduleId) this._cachedSpecs.delete(moduleId);
|
|
7809
|
+
else this._cachedSpecs.clear();
|
|
7880
7810
|
}
|
|
7881
7811
|
getCachedSpecifications(moduleId) {
|
|
7882
7812
|
return this._cachedSpecs.get(moduleId);
|
|
@@ -7888,14 +7818,12 @@ class VitestSpecifications {
|
|
|
7888
7818
|
if (index === -1) {
|
|
7889
7819
|
specs.push(spec);
|
|
7890
7820
|
this._cachedSpecs.set(file, specs);
|
|
7891
|
-
} else
|
|
7892
|
-
specs.splice(index, 1, spec);
|
|
7893
|
-
}
|
|
7821
|
+
} else specs.splice(index, 1, spec);
|
|
7894
7822
|
return specs;
|
|
7895
7823
|
}
|
|
7896
7824
|
async filterTestsBySource(specs) {
|
|
7897
7825
|
if (this.vitest.config.changed && !this.vitest.config.related) {
|
|
7898
|
-
const { VitestGit } = await import('./git.
|
|
7826
|
+
const { VitestGit } = await import('./git.BVQ8w_Sw.js');
|
|
7899
7827
|
const vitestGit = new VitestGit(this.vitest.config.root);
|
|
7900
7828
|
const related = await vitestGit.findChangedFiles({ changedSince: this.vitest.config.changed });
|
|
7901
7829
|
if (!related) {
|
|
@@ -7905,46 +7833,34 @@ class VitestSpecifications {
|
|
|
7905
7833
|
this.vitest.config.related = Array.from(new Set(related));
|
|
7906
7834
|
}
|
|
7907
7835
|
const related = this.vitest.config.related;
|
|
7908
|
-
if (!related)
|
|
7909
|
-
return specs;
|
|
7910
|
-
}
|
|
7836
|
+
if (!related) return specs;
|
|
7911
7837
|
const forceRerunTriggers = this.vitest.config.forceRerunTriggers;
|
|
7912
|
-
const matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) :
|
|
7913
|
-
if (matcher && related.some((file) => matcher(file)))
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
if (!this.vitest.config.watch && !related.length)
|
|
7917
|
-
return [];
|
|
7918
|
-
}
|
|
7838
|
+
const matcher = forceRerunTriggers.length ? pm(forceRerunTriggers) : void 0;
|
|
7839
|
+
if (matcher && related.some((file) => matcher(file))) return specs;
|
|
7840
|
+
// don't run anything if no related sources are found
|
|
7841
|
+
// if we are in watch mode, we want to process all tests
|
|
7842
|
+
if (!this.vitest.config.watch && !related.length) return [];
|
|
7919
7843
|
const testGraphs = await Promise.all(specs.map(async (spec) => {
|
|
7920
7844
|
const deps = await this.getTestDependencies(spec);
|
|
7921
7845
|
return [spec, deps];
|
|
7922
7846
|
}));
|
|
7923
7847
|
const runningTests = [];
|
|
7924
|
-
for (const [specification, deps] of testGraphs)
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
}
|
|
7928
|
-
}
|
|
7848
|
+
for (const [specification, deps] of testGraphs)
|
|
7849
|
+
// if deps or the test itself were changed
|
|
7850
|
+
if (related.some((path) => path === specification.moduleId || deps.has(path))) runningTests.push(specification);
|
|
7929
7851
|
return runningTests;
|
|
7930
7852
|
}
|
|
7931
|
-
async getTestDependencies(spec, deps = new Set()) {
|
|
7853
|
+
async getTestDependencies(spec, deps = /* @__PURE__ */ new Set()) {
|
|
7932
7854
|
const addImports = async (project, filepath) => {
|
|
7933
|
-
if (deps.has(filepath))
|
|
7934
|
-
return;
|
|
7935
|
-
}
|
|
7855
|
+
if (deps.has(filepath)) return;
|
|
7936
7856
|
deps.add(filepath);
|
|
7937
7857
|
const mod = project.vite.moduleGraph.getModuleById(filepath);
|
|
7938
7858
|
const transformed = mod?.ssrTransformResult || await project.vitenode.transformRequest(filepath);
|
|
7939
|
-
if (!transformed)
|
|
7940
|
-
return;
|
|
7941
|
-
}
|
|
7859
|
+
if (!transformed) return;
|
|
7942
7860
|
const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
|
|
7943
7861
|
await Promise.all(dependencies.map(async (dep) => {
|
|
7944
7862
|
const fsPath = dep.startsWith("/@fs/") ? dep.slice(isWindows ? 5 : 4) : join(project.config.root, dep);
|
|
7945
|
-
if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath))
|
|
7946
|
-
await addImports(project, fsPath);
|
|
7947
|
-
}
|
|
7863
|
+
if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) await addImports(project, fsPath);
|
|
7948
7864
|
}));
|
|
7949
7865
|
};
|
|
7950
7866
|
await addImports(spec.project, spec.moduleId);
|
|
@@ -8029,24 +7945,16 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8029
7945
|
this.name = task.name;
|
|
8030
7946
|
this.module = getReportedTask(project, task.file);
|
|
8031
7947
|
const suite = this.task.suite;
|
|
8032
|
-
if (suite)
|
|
8033
|
-
|
|
8034
|
-
} else {
|
|
8035
|
-
this.parent = this.module;
|
|
8036
|
-
}
|
|
7948
|
+
if (suite) this.parent = getReportedTask(project, suite);
|
|
7949
|
+
else this.parent = this.module;
|
|
8037
7950
|
this.options = buildOptions(task);
|
|
8038
7951
|
}
|
|
8039
7952
|
/**
|
|
8040
7953
|
* Full name of the test including all parent suites separated with `>`.
|
|
8041
7954
|
*/
|
|
8042
7955
|
get fullName() {
|
|
8043
|
-
if (this.#fullName ===
|
|
8044
|
-
|
|
8045
|
-
this.#fullName = `${this.parent.fullName} > ${this.name}`;
|
|
8046
|
-
} else {
|
|
8047
|
-
this.#fullName = this.name;
|
|
8048
|
-
}
|
|
8049
|
-
}
|
|
7956
|
+
if (this.#fullName === void 0) if (this.parent.type !== "module") this.#fullName = `${this.parent.fullName} > ${this.name}`;
|
|
7957
|
+
else this.#fullName = this.name;
|
|
8050
7958
|
return this.#fullName;
|
|
8051
7959
|
}
|
|
8052
7960
|
/**
|
|
@@ -8059,47 +7967,44 @@ class TestCase extends ReportedTaskImplementation {
|
|
|
8059
7967
|
result() {
|
|
8060
7968
|
const result = this.task.result;
|
|
8061
7969
|
const mode = result?.state || this.task.mode;
|
|
8062
|
-
if (!result && (mode === "skip" || mode === "todo")) {
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
state: "pending",
|
|
8072
|
-
errors: undefined
|
|
8073
|
-
};
|
|
8074
|
-
}
|
|
7970
|
+
if (!result && (mode === "skip" || mode === "todo")) return {
|
|
7971
|
+
state: "skipped",
|
|
7972
|
+
note: void 0,
|
|
7973
|
+
errors: void 0
|
|
7974
|
+
};
|
|
7975
|
+
if (!result || result.state === "run" || result.state === "queued") return {
|
|
7976
|
+
state: "pending",
|
|
7977
|
+
errors: void 0
|
|
7978
|
+
};
|
|
8075
7979
|
const state = result.state === "fail" ? "failed" : result.state === "pass" ? "passed" : "skipped";
|
|
8076
|
-
if (state === "skipped") {
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
state,
|
|
8086
|
-
errors: result.errors
|
|
8087
|
-
};
|
|
8088
|
-
}
|
|
7980
|
+
if (state === "skipped") return {
|
|
7981
|
+
state,
|
|
7982
|
+
note: result.note,
|
|
7983
|
+
errors: void 0
|
|
7984
|
+
};
|
|
7985
|
+
if (state === "passed") return {
|
|
7986
|
+
state,
|
|
7987
|
+
errors: result.errors
|
|
7988
|
+
};
|
|
8089
7989
|
return {
|
|
8090
7990
|
state,
|
|
8091
7991
|
errors: result.errors || []
|
|
8092
7992
|
};
|
|
8093
7993
|
}
|
|
8094
7994
|
/**
|
|
7995
|
+
* Test annotations added via the `task.annotate` API during the test execution.
|
|
7996
|
+
*/
|
|
7997
|
+
annotations() {
|
|
7998
|
+
return [...this.task.annotations];
|
|
7999
|
+
}
|
|
8000
|
+
/**
|
|
8095
8001
|
* Useful information about the test like duration, memory usage, etc.
|
|
8096
8002
|
* Diagnostic is only available after the test has finished.
|
|
8097
8003
|
*/
|
|
8098
8004
|
diagnostic() {
|
|
8099
8005
|
const result = this.task.result;
|
|
8100
|
-
if
|
|
8101
|
-
|
|
8102
|
-
}
|
|
8006
|
+
// startTime should always be available if the test has properly finished
|
|
8007
|
+
if (!result || !result.startTime) return void 0;
|
|
8103
8008
|
const duration = result.duration || 0;
|
|
8104
8009
|
const slow = duration > this.project.globalConfig.slowTestThreshold;
|
|
8105
8010
|
return {
|
|
@@ -8124,9 +8029,7 @@ class TestCollection {
|
|
|
8124
8029
|
* Returns the test or suite at a specific index.
|
|
8125
8030
|
*/
|
|
8126
8031
|
at(index) {
|
|
8127
|
-
if (index < 0)
|
|
8128
|
-
index = this.size + index;
|
|
8129
|
-
}
|
|
8032
|
+
if (index < 0) index = this.size + index;
|
|
8130
8033
|
return getReportedTask(this.#project, this.#task.tasks[index]);
|
|
8131
8034
|
}
|
|
8132
8035
|
/**
|
|
@@ -8145,62 +8048,41 @@ class TestCollection {
|
|
|
8145
8048
|
* Filters all tests that are part of this collection and its children.
|
|
8146
8049
|
*/
|
|
8147
8050
|
*allTests(state) {
|
|
8148
|
-
for (const child of this)
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
if (state === testState) {
|
|
8154
|
-
yield child;
|
|
8155
|
-
}
|
|
8156
|
-
} else {
|
|
8157
|
-
yield child;
|
|
8158
|
-
}
|
|
8159
|
-
}
|
|
8051
|
+
for (const child of this) if (child.type === "suite") yield* child.children.allTests(state);
|
|
8052
|
+
else if (state) {
|
|
8053
|
+
const testState = child.result().state;
|
|
8054
|
+
if (state === testState) yield child;
|
|
8055
|
+
} else yield child;
|
|
8160
8056
|
}
|
|
8161
8057
|
/**
|
|
8162
8058
|
* Filters only the tests that are part of this collection.
|
|
8163
8059
|
*/
|
|
8164
8060
|
*tests(state) {
|
|
8165
8061
|
for (const child of this) {
|
|
8166
|
-
if (child.type !== "test")
|
|
8167
|
-
continue;
|
|
8168
|
-
}
|
|
8062
|
+
if (child.type !== "test") continue;
|
|
8169
8063
|
if (state) {
|
|
8170
8064
|
const testState = child.result().state;
|
|
8171
|
-
if (state === testState)
|
|
8172
|
-
|
|
8173
|
-
}
|
|
8174
|
-
} else {
|
|
8175
|
-
yield child;
|
|
8176
|
-
}
|
|
8065
|
+
if (state === testState) yield child;
|
|
8066
|
+
} else yield child;
|
|
8177
8067
|
}
|
|
8178
8068
|
}
|
|
8179
8069
|
/**
|
|
8180
8070
|
* Filters only the suites that are part of this collection.
|
|
8181
8071
|
*/
|
|
8182
8072
|
*suites() {
|
|
8183
|
-
for (const child of this)
|
|
8184
|
-
if (child.type === "suite") {
|
|
8185
|
-
yield child;
|
|
8186
|
-
}
|
|
8187
|
-
}
|
|
8073
|
+
for (const child of this) if (child.type === "suite") yield child;
|
|
8188
8074
|
}
|
|
8189
8075
|
/**
|
|
8190
8076
|
* Filters all suites that are part of this collection and its children.
|
|
8191
8077
|
*/
|
|
8192
8078
|
*allSuites() {
|
|
8193
|
-
for (const child of this) {
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
yield* child.children.allSuites();
|
|
8197
|
-
}
|
|
8079
|
+
for (const child of this) if (child.type === "suite") {
|
|
8080
|
+
yield child;
|
|
8081
|
+
yield* child.children.allSuites();
|
|
8198
8082
|
}
|
|
8199
8083
|
}
|
|
8200
8084
|
*[Symbol.iterator]() {
|
|
8201
|
-
for (const task of this.#task.tasks)
|
|
8202
|
-
yield getReportedTask(this.#project, task);
|
|
8203
|
-
}
|
|
8085
|
+
for (const task of this.#task.tasks) yield getReportedTask(this.#project, task);
|
|
8204
8086
|
}
|
|
8205
8087
|
}
|
|
8206
8088
|
class SuiteImplementation extends ReportedTaskImplementation {
|
|
@@ -8245,11 +8127,8 @@ class TestSuite extends SuiteImplementation {
|
|
|
8245
8127
|
this.name = task.name;
|
|
8246
8128
|
this.module = getReportedTask(project, task.file);
|
|
8247
8129
|
const suite = this.task.suite;
|
|
8248
|
-
if (suite)
|
|
8249
|
-
|
|
8250
|
-
} else {
|
|
8251
|
-
this.parent = this.module;
|
|
8252
|
-
}
|
|
8130
|
+
if (suite) this.parent = getReportedTask(project, suite);
|
|
8131
|
+
else this.parent = this.module;
|
|
8253
8132
|
this.options = buildOptions(task);
|
|
8254
8133
|
}
|
|
8255
8134
|
/**
|
|
@@ -8262,13 +8141,8 @@ class TestSuite extends SuiteImplementation {
|
|
|
8262
8141
|
* Full name of the suite including all parent suites separated with `>`.
|
|
8263
8142
|
*/
|
|
8264
8143
|
get fullName() {
|
|
8265
|
-
if (this.#fullName ===
|
|
8266
|
-
|
|
8267
|
-
this.#fullName = `${this.parent.fullName} > ${this.name}`;
|
|
8268
|
-
} else {
|
|
8269
|
-
this.#fullName = this.name;
|
|
8270
|
-
}
|
|
8271
|
-
}
|
|
8144
|
+
if (this.#fullName === void 0) if (this.parent.type !== "module") this.#fullName = `${this.parent.fullName} > ${this.name}`;
|
|
8145
|
+
else this.#fullName = this.name;
|
|
8272
8146
|
return this.#fullName;
|
|
8273
8147
|
}
|
|
8274
8148
|
}
|
|
@@ -8290,9 +8164,7 @@ class TestModule extends SuiteImplementation {
|
|
|
8290
8164
|
*/
|
|
8291
8165
|
state() {
|
|
8292
8166
|
const state = this.task.result?.state;
|
|
8293
|
-
if (state === "queued")
|
|
8294
|
-
return "queued";
|
|
8295
|
-
}
|
|
8167
|
+
if (state === "queued") return "queued";
|
|
8296
8168
|
return getSuiteState(this.task);
|
|
8297
8169
|
}
|
|
8298
8170
|
/**
|
|
@@ -8306,13 +8178,15 @@ class TestModule extends SuiteImplementation {
|
|
|
8306
8178
|
const environmentSetupDuration = this.task.environmentLoad || 0;
|
|
8307
8179
|
const duration = this.task.result?.duration || 0;
|
|
8308
8180
|
const heap = this.task.result?.heap;
|
|
8181
|
+
const importDurations = this.task.importDurations ?? {};
|
|
8309
8182
|
return {
|
|
8310
8183
|
environmentSetupDuration,
|
|
8311
8184
|
prepareDuration,
|
|
8312
8185
|
collectDuration,
|
|
8313
8186
|
setupDuration,
|
|
8314
8187
|
duration,
|
|
8315
|
-
heap
|
|
8188
|
+
heap,
|
|
8189
|
+
importDurations
|
|
8316
8190
|
};
|
|
8317
8191
|
}
|
|
8318
8192
|
}
|
|
@@ -8332,56 +8206,39 @@ function storeTask(project, runnerTask, reportedTask) {
|
|
|
8332
8206
|
}
|
|
8333
8207
|
function getReportedTask(project, runnerTask) {
|
|
8334
8208
|
const reportedTask = project.vitest.state.getReportedEntity(runnerTask);
|
|
8335
|
-
if (!reportedTask) {
|
|
8336
|
-
throw new Error(`Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`);
|
|
8337
|
-
}
|
|
8209
|
+
if (!reportedTask) throw new Error(`Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`);
|
|
8338
8210
|
return reportedTask;
|
|
8339
8211
|
}
|
|
8340
8212
|
function getSuiteState(task) {
|
|
8341
8213
|
const mode = task.mode;
|
|
8342
8214
|
const state = task.result?.state;
|
|
8343
|
-
if (mode === "skip" || mode === "todo" || state === "skip" || state === "todo")
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
if (state
|
|
8347
|
-
return "pending";
|
|
8348
|
-
}
|
|
8349
|
-
if (state === "fail") {
|
|
8350
|
-
return "failed";
|
|
8351
|
-
}
|
|
8352
|
-
if (state === "pass") {
|
|
8353
|
-
return "passed";
|
|
8354
|
-
}
|
|
8215
|
+
if (mode === "skip" || mode === "todo" || state === "skip" || state === "todo") return "skipped";
|
|
8216
|
+
if (state == null || state === "run" || state === "only") return "pending";
|
|
8217
|
+
if (state === "fail") return "failed";
|
|
8218
|
+
if (state === "pass") return "passed";
|
|
8355
8219
|
throw new Error(`Unknown suite state: ${state}`);
|
|
8356
8220
|
}
|
|
8357
8221
|
|
|
8358
8222
|
function isAggregateError(err) {
|
|
8359
|
-
if (typeof AggregateError !== "undefined" && err instanceof AggregateError)
|
|
8360
|
-
return true;
|
|
8361
|
-
}
|
|
8223
|
+
if (typeof AggregateError !== "undefined" && err instanceof AggregateError) return true;
|
|
8362
8224
|
return err instanceof Error && "errors" in err;
|
|
8363
8225
|
}
|
|
8364
8226
|
class StateManager {
|
|
8365
|
-
filesMap = new Map();
|
|
8366
|
-
pathsSet = new Set();
|
|
8367
|
-
idMap = new Map();
|
|
8368
|
-
taskFileMap = new WeakMap();
|
|
8369
|
-
errorsSet = new Set();
|
|
8370
|
-
processTimeoutCauses = new Set();
|
|
8371
|
-
reportedTasksMap = new WeakMap();
|
|
8227
|
+
filesMap = /* @__PURE__ */ new Map();
|
|
8228
|
+
pathsSet = /* @__PURE__ */ new Set();
|
|
8229
|
+
idMap = /* @__PURE__ */ new Map();
|
|
8230
|
+
taskFileMap = /* @__PURE__ */ new WeakMap();
|
|
8231
|
+
errorsSet = /* @__PURE__ */ new Set();
|
|
8232
|
+
processTimeoutCauses = /* @__PURE__ */ new Set();
|
|
8233
|
+
reportedTasksMap = /* @__PURE__ */ new WeakMap();
|
|
8372
8234
|
blobs;
|
|
8373
8235
|
catchError(err, type) {
|
|
8374
|
-
if (isAggregateError(err))
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
err
|
|
8379
|
-
}
|
|
8380
|
-
err = {
|
|
8381
|
-
type,
|
|
8382
|
-
message: err
|
|
8383
|
-
};
|
|
8384
|
-
}
|
|
8236
|
+
if (isAggregateError(err)) return err.errors.forEach((error) => this.catchError(error, type));
|
|
8237
|
+
if (err === Object(err)) err.type = type;
|
|
8238
|
+
else err = {
|
|
8239
|
+
type,
|
|
8240
|
+
message: err
|
|
8241
|
+
};
|
|
8385
8242
|
const _err = err;
|
|
8386
8243
|
if (_err && typeof _err === "object" && _err.code === "VITEST_PENDING") {
|
|
8387
8244
|
const task = this.idMap.get(_err.taskId);
|
|
@@ -8414,16 +8271,11 @@ class StateManager {
|
|
|
8414
8271
|
* Return files that were running or collected.
|
|
8415
8272
|
*/
|
|
8416
8273
|
getFiles(keys) {
|
|
8417
|
-
if (keys)
|
|
8418
|
-
return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local);
|
|
8419
|
-
}
|
|
8274
|
+
if (keys) return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local);
|
|
8420
8275
|
return Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
if (f1.meta?.typecheck) {
|
|
8425
|
-
return -1;
|
|
8426
|
-
}
|
|
8276
|
+
// print typecheck files first
|
|
8277
|
+
if (f1.meta?.typecheck && f2.meta?.typecheck) return 0;
|
|
8278
|
+
if (f1.meta?.typecheck) return -1;
|
|
8427
8279
|
return 1;
|
|
8428
8280
|
});
|
|
8429
8281
|
}
|
|
@@ -8446,9 +8298,9 @@ class StateManager {
|
|
|
8446
8298
|
const existing = this.filesMap.get(file.filepath) || [];
|
|
8447
8299
|
const otherFiles = existing.filter((i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck);
|
|
8448
8300
|
const currentFile = existing.find((i) => i.projectName === file.projectName);
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8301
|
+
// keep logs for the previous file because it should always be initiated before the collections phase
|
|
8302
|
+
// which means that all logs are collected during the collection and not inside tests
|
|
8303
|
+
if (currentFile) file.logs = currentFile.logs;
|
|
8452
8304
|
otherFiles.push(file);
|
|
8453
8305
|
this.filesMap.set(file.filepath, otherFiles);
|
|
8454
8306
|
this.updateId(file, project);
|
|
@@ -8466,30 +8318,20 @@ class StateManager {
|
|
|
8466
8318
|
return;
|
|
8467
8319
|
}
|
|
8468
8320
|
const filtered = files.filter((file) => file.projectName !== project.config.name);
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
this.filesMap.set(path, [...filtered, fileTask]);
|
|
8473
|
-
}
|
|
8321
|
+
// always keep a File task, so we can associate logs with it
|
|
8322
|
+
if (!filtered.length) this.filesMap.set(path, [fileTask]);
|
|
8323
|
+
else this.filesMap.set(path, [...filtered, fileTask]);
|
|
8474
8324
|
});
|
|
8475
8325
|
}
|
|
8476
8326
|
updateId(task, project) {
|
|
8477
|
-
if (this.idMap.get(task.id) === task)
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
TestModule.register(task, project);
|
|
8482
|
-
} else if (task.type === "suite") {
|
|
8483
|
-
TestSuite.register(task, project);
|
|
8484
|
-
} else {
|
|
8485
|
-
TestCase.register(task, project);
|
|
8486
|
-
}
|
|
8327
|
+
if (this.idMap.get(task.id) === task) return;
|
|
8328
|
+
if (task.type === "suite" && "filepath" in task) TestModule.register(task, project);
|
|
8329
|
+
else if (task.type === "suite") TestSuite.register(task, project);
|
|
8330
|
+
else TestCase.register(task, project);
|
|
8487
8331
|
this.idMap.set(task.id, task);
|
|
8488
|
-
if (task.type === "suite") {
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
});
|
|
8492
|
-
}
|
|
8332
|
+
if (task.type === "suite") task.tasks.forEach((task) => {
|
|
8333
|
+
this.updateId(task, project);
|
|
8334
|
+
});
|
|
8493
8335
|
}
|
|
8494
8336
|
getReportedEntity(task) {
|
|
8495
8337
|
return this.reportedTasksMap.get(task);
|
|
@@ -8500,18 +8342,15 @@ class StateManager {
|
|
|
8500
8342
|
if (task) {
|
|
8501
8343
|
task.result = result;
|
|
8502
8344
|
task.meta = meta;
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
}
|
|
8345
|
+
// skipped with new PendingError
|
|
8346
|
+
if (result?.state === "skip") task.mode = "skip";
|
|
8506
8347
|
}
|
|
8507
8348
|
}
|
|
8508
8349
|
}
|
|
8509
8350
|
updateUserLog(log) {
|
|
8510
8351
|
const task = log.taskId && this.idMap.get(log.taskId);
|
|
8511
8352
|
if (task) {
|
|
8512
|
-
if (!task.logs)
|
|
8513
|
-
task.logs = [];
|
|
8514
|
-
}
|
|
8353
|
+
if (!task.logs) task.logs = [];
|
|
8515
8354
|
task.logs.push(log);
|
|
8516
8355
|
}
|
|
8517
8356
|
}
|
|
@@ -8523,6 +8362,458 @@ class StateManager {
|
|
|
8523
8362
|
}
|
|
8524
8363
|
}
|
|
8525
8364
|
|
|
8365
|
+
const types = {
|
|
8366
|
+
'application/andrew-inset': ['ez'],
|
|
8367
|
+
'application/appinstaller': ['appinstaller'],
|
|
8368
|
+
'application/applixware': ['aw'],
|
|
8369
|
+
'application/appx': ['appx'],
|
|
8370
|
+
'application/appxbundle': ['appxbundle'],
|
|
8371
|
+
'application/atom+xml': ['atom'],
|
|
8372
|
+
'application/atomcat+xml': ['atomcat'],
|
|
8373
|
+
'application/atomdeleted+xml': ['atomdeleted'],
|
|
8374
|
+
'application/atomsvc+xml': ['atomsvc'],
|
|
8375
|
+
'application/atsc-dwd+xml': ['dwd'],
|
|
8376
|
+
'application/atsc-held+xml': ['held'],
|
|
8377
|
+
'application/atsc-rsat+xml': ['rsat'],
|
|
8378
|
+
'application/automationml-aml+xml': ['aml'],
|
|
8379
|
+
'application/automationml-amlx+zip': ['amlx'],
|
|
8380
|
+
'application/bdoc': ['bdoc'],
|
|
8381
|
+
'application/calendar+xml': ['xcs'],
|
|
8382
|
+
'application/ccxml+xml': ['ccxml'],
|
|
8383
|
+
'application/cdfx+xml': ['cdfx'],
|
|
8384
|
+
'application/cdmi-capability': ['cdmia'],
|
|
8385
|
+
'application/cdmi-container': ['cdmic'],
|
|
8386
|
+
'application/cdmi-domain': ['cdmid'],
|
|
8387
|
+
'application/cdmi-object': ['cdmio'],
|
|
8388
|
+
'application/cdmi-queue': ['cdmiq'],
|
|
8389
|
+
'application/cpl+xml': ['cpl'],
|
|
8390
|
+
'application/cu-seeme': ['cu'],
|
|
8391
|
+
'application/cwl': ['cwl'],
|
|
8392
|
+
'application/dash+xml': ['mpd'],
|
|
8393
|
+
'application/dash-patch+xml': ['mpp'],
|
|
8394
|
+
'application/davmount+xml': ['davmount'],
|
|
8395
|
+
'application/dicom': ['dcm'],
|
|
8396
|
+
'application/docbook+xml': ['dbk'],
|
|
8397
|
+
'application/dssc+der': ['dssc'],
|
|
8398
|
+
'application/dssc+xml': ['xdssc'],
|
|
8399
|
+
'application/ecmascript': ['ecma'],
|
|
8400
|
+
'application/emma+xml': ['emma'],
|
|
8401
|
+
'application/emotionml+xml': ['emotionml'],
|
|
8402
|
+
'application/epub+zip': ['epub'],
|
|
8403
|
+
'application/exi': ['exi'],
|
|
8404
|
+
'application/express': ['exp'],
|
|
8405
|
+
'application/fdf': ['fdf'],
|
|
8406
|
+
'application/fdt+xml': ['fdt'],
|
|
8407
|
+
'application/font-tdpfr': ['pfr'],
|
|
8408
|
+
'application/geo+json': ['geojson'],
|
|
8409
|
+
'application/gml+xml': ['gml'],
|
|
8410
|
+
'application/gpx+xml': ['gpx'],
|
|
8411
|
+
'application/gxf': ['gxf'],
|
|
8412
|
+
'application/gzip': ['gz'],
|
|
8413
|
+
'application/hjson': ['hjson'],
|
|
8414
|
+
'application/hyperstudio': ['stk'],
|
|
8415
|
+
'application/inkml+xml': ['ink', 'inkml'],
|
|
8416
|
+
'application/ipfix': ['ipfix'],
|
|
8417
|
+
'application/its+xml': ['its'],
|
|
8418
|
+
'application/java-archive': ['jar', 'war', 'ear'],
|
|
8419
|
+
'application/java-serialized-object': ['ser'],
|
|
8420
|
+
'application/java-vm': ['class'],
|
|
8421
|
+
'application/javascript': ['*js'],
|
|
8422
|
+
'application/json': ['json', 'map'],
|
|
8423
|
+
'application/json5': ['json5'],
|
|
8424
|
+
'application/jsonml+json': ['jsonml'],
|
|
8425
|
+
'application/ld+json': ['jsonld'],
|
|
8426
|
+
'application/lgr+xml': ['lgr'],
|
|
8427
|
+
'application/lost+xml': ['lostxml'],
|
|
8428
|
+
'application/mac-binhex40': ['hqx'],
|
|
8429
|
+
'application/mac-compactpro': ['cpt'],
|
|
8430
|
+
'application/mads+xml': ['mads'],
|
|
8431
|
+
'application/manifest+json': ['webmanifest'],
|
|
8432
|
+
'application/marc': ['mrc'],
|
|
8433
|
+
'application/marcxml+xml': ['mrcx'],
|
|
8434
|
+
'application/mathematica': ['ma', 'nb', 'mb'],
|
|
8435
|
+
'application/mathml+xml': ['mathml'],
|
|
8436
|
+
'application/mbox': ['mbox'],
|
|
8437
|
+
'application/media-policy-dataset+xml': ['mpf'],
|
|
8438
|
+
'application/mediaservercontrol+xml': ['mscml'],
|
|
8439
|
+
'application/metalink+xml': ['metalink'],
|
|
8440
|
+
'application/metalink4+xml': ['meta4'],
|
|
8441
|
+
'application/mets+xml': ['mets'],
|
|
8442
|
+
'application/mmt-aei+xml': ['maei'],
|
|
8443
|
+
'application/mmt-usd+xml': ['musd'],
|
|
8444
|
+
'application/mods+xml': ['mods'],
|
|
8445
|
+
'application/mp21': ['m21', 'mp21'],
|
|
8446
|
+
'application/mp4': ['*mp4', '*mpg4', 'mp4s', 'm4p'],
|
|
8447
|
+
'application/msix': ['msix'],
|
|
8448
|
+
'application/msixbundle': ['msixbundle'],
|
|
8449
|
+
'application/msword': ['doc', 'dot'],
|
|
8450
|
+
'application/mxf': ['mxf'],
|
|
8451
|
+
'application/n-quads': ['nq'],
|
|
8452
|
+
'application/n-triples': ['nt'],
|
|
8453
|
+
'application/node': ['cjs'],
|
|
8454
|
+
'application/octet-stream': [
|
|
8455
|
+
'bin',
|
|
8456
|
+
'dms',
|
|
8457
|
+
'lrf',
|
|
8458
|
+
'mar',
|
|
8459
|
+
'so',
|
|
8460
|
+
'dist',
|
|
8461
|
+
'distz',
|
|
8462
|
+
'pkg',
|
|
8463
|
+
'bpk',
|
|
8464
|
+
'dump',
|
|
8465
|
+
'elc',
|
|
8466
|
+
'deploy',
|
|
8467
|
+
'exe',
|
|
8468
|
+
'dll',
|
|
8469
|
+
'deb',
|
|
8470
|
+
'dmg',
|
|
8471
|
+
'iso',
|
|
8472
|
+
'img',
|
|
8473
|
+
'msi',
|
|
8474
|
+
'msp',
|
|
8475
|
+
'msm',
|
|
8476
|
+
'buffer',
|
|
8477
|
+
],
|
|
8478
|
+
'application/oda': ['oda'],
|
|
8479
|
+
'application/oebps-package+xml': ['opf'],
|
|
8480
|
+
'application/ogg': ['ogx'],
|
|
8481
|
+
'application/omdoc+xml': ['omdoc'],
|
|
8482
|
+
'application/onenote': [
|
|
8483
|
+
'onetoc',
|
|
8484
|
+
'onetoc2',
|
|
8485
|
+
'onetmp',
|
|
8486
|
+
'onepkg',
|
|
8487
|
+
'one',
|
|
8488
|
+
'onea',
|
|
8489
|
+
],
|
|
8490
|
+
'application/oxps': ['oxps'],
|
|
8491
|
+
'application/p2p-overlay+xml': ['relo'],
|
|
8492
|
+
'application/patch-ops-error+xml': ['xer'],
|
|
8493
|
+
'application/pdf': ['pdf'],
|
|
8494
|
+
'application/pgp-encrypted': ['pgp'],
|
|
8495
|
+
'application/pgp-keys': ['asc'],
|
|
8496
|
+
'application/pgp-signature': ['sig', '*asc'],
|
|
8497
|
+
'application/pics-rules': ['prf'],
|
|
8498
|
+
'application/pkcs10': ['p10'],
|
|
8499
|
+
'application/pkcs7-mime': ['p7m', 'p7c'],
|
|
8500
|
+
'application/pkcs7-signature': ['p7s'],
|
|
8501
|
+
'application/pkcs8': ['p8'],
|
|
8502
|
+
'application/pkix-attr-cert': ['ac'],
|
|
8503
|
+
'application/pkix-cert': ['cer'],
|
|
8504
|
+
'application/pkix-crl': ['crl'],
|
|
8505
|
+
'application/pkix-pkipath': ['pkipath'],
|
|
8506
|
+
'application/pkixcmp': ['pki'],
|
|
8507
|
+
'application/pls+xml': ['pls'],
|
|
8508
|
+
'application/postscript': ['ai', 'eps', 'ps'],
|
|
8509
|
+
'application/provenance+xml': ['provx'],
|
|
8510
|
+
'application/pskc+xml': ['pskcxml'],
|
|
8511
|
+
'application/raml+yaml': ['raml'],
|
|
8512
|
+
'application/rdf+xml': ['rdf', 'owl'],
|
|
8513
|
+
'application/reginfo+xml': ['rif'],
|
|
8514
|
+
'application/relax-ng-compact-syntax': ['rnc'],
|
|
8515
|
+
'application/resource-lists+xml': ['rl'],
|
|
8516
|
+
'application/resource-lists-diff+xml': ['rld'],
|
|
8517
|
+
'application/rls-services+xml': ['rs'],
|
|
8518
|
+
'application/route-apd+xml': ['rapd'],
|
|
8519
|
+
'application/route-s-tsid+xml': ['sls'],
|
|
8520
|
+
'application/route-usd+xml': ['rusd'],
|
|
8521
|
+
'application/rpki-ghostbusters': ['gbr'],
|
|
8522
|
+
'application/rpki-manifest': ['mft'],
|
|
8523
|
+
'application/rpki-roa': ['roa'],
|
|
8524
|
+
'application/rsd+xml': ['rsd'],
|
|
8525
|
+
'application/rss+xml': ['rss'],
|
|
8526
|
+
'application/rtf': ['rtf'],
|
|
8527
|
+
'application/sbml+xml': ['sbml'],
|
|
8528
|
+
'application/scvp-cv-request': ['scq'],
|
|
8529
|
+
'application/scvp-cv-response': ['scs'],
|
|
8530
|
+
'application/scvp-vp-request': ['spq'],
|
|
8531
|
+
'application/scvp-vp-response': ['spp'],
|
|
8532
|
+
'application/sdp': ['sdp'],
|
|
8533
|
+
'application/senml+xml': ['senmlx'],
|
|
8534
|
+
'application/sensml+xml': ['sensmlx'],
|
|
8535
|
+
'application/set-payment-initiation': ['setpay'],
|
|
8536
|
+
'application/set-registration-initiation': ['setreg'],
|
|
8537
|
+
'application/shf+xml': ['shf'],
|
|
8538
|
+
'application/sieve': ['siv', 'sieve'],
|
|
8539
|
+
'application/smil+xml': ['smi', 'smil'],
|
|
8540
|
+
'application/sparql-query': ['rq'],
|
|
8541
|
+
'application/sparql-results+xml': ['srx'],
|
|
8542
|
+
'application/sql': ['sql'],
|
|
8543
|
+
'application/srgs': ['gram'],
|
|
8544
|
+
'application/srgs+xml': ['grxml'],
|
|
8545
|
+
'application/sru+xml': ['sru'],
|
|
8546
|
+
'application/ssdl+xml': ['ssdl'],
|
|
8547
|
+
'application/ssml+xml': ['ssml'],
|
|
8548
|
+
'application/swid+xml': ['swidtag'],
|
|
8549
|
+
'application/tei+xml': ['tei', 'teicorpus'],
|
|
8550
|
+
'application/thraud+xml': ['tfi'],
|
|
8551
|
+
'application/timestamped-data': ['tsd'],
|
|
8552
|
+
'application/toml': ['toml'],
|
|
8553
|
+
'application/trig': ['trig'],
|
|
8554
|
+
'application/ttml+xml': ['ttml'],
|
|
8555
|
+
'application/ubjson': ['ubj'],
|
|
8556
|
+
'application/urc-ressheet+xml': ['rsheet'],
|
|
8557
|
+
'application/urc-targetdesc+xml': ['td'],
|
|
8558
|
+
'application/voicexml+xml': ['vxml'],
|
|
8559
|
+
'application/wasm': ['wasm'],
|
|
8560
|
+
'application/watcherinfo+xml': ['wif'],
|
|
8561
|
+
'application/widget': ['wgt'],
|
|
8562
|
+
'application/winhlp': ['hlp'],
|
|
8563
|
+
'application/wsdl+xml': ['wsdl'],
|
|
8564
|
+
'application/wspolicy+xml': ['wspolicy'],
|
|
8565
|
+
'application/xaml+xml': ['xaml'],
|
|
8566
|
+
'application/xcap-att+xml': ['xav'],
|
|
8567
|
+
'application/xcap-caps+xml': ['xca'],
|
|
8568
|
+
'application/xcap-diff+xml': ['xdf'],
|
|
8569
|
+
'application/xcap-el+xml': ['xel'],
|
|
8570
|
+
'application/xcap-ns+xml': ['xns'],
|
|
8571
|
+
'application/xenc+xml': ['xenc'],
|
|
8572
|
+
'application/xfdf': ['xfdf'],
|
|
8573
|
+
'application/xhtml+xml': ['xhtml', 'xht'],
|
|
8574
|
+
'application/xliff+xml': ['xlf'],
|
|
8575
|
+
'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
|
|
8576
|
+
'application/xml-dtd': ['dtd'],
|
|
8577
|
+
'application/xop+xml': ['xop'],
|
|
8578
|
+
'application/xproc+xml': ['xpl'],
|
|
8579
|
+
'application/xslt+xml': ['*xsl', 'xslt'],
|
|
8580
|
+
'application/xspf+xml': ['xspf'],
|
|
8581
|
+
'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
|
|
8582
|
+
'application/yang': ['yang'],
|
|
8583
|
+
'application/yin+xml': ['yin'],
|
|
8584
|
+
'application/zip': ['zip'],
|
|
8585
|
+
'application/zip+dotlottie': ['lottie'],
|
|
8586
|
+
'audio/3gpp': ['*3gpp'],
|
|
8587
|
+
'audio/aac': ['adts', 'aac'],
|
|
8588
|
+
'audio/adpcm': ['adp'],
|
|
8589
|
+
'audio/amr': ['amr'],
|
|
8590
|
+
'audio/basic': ['au', 'snd'],
|
|
8591
|
+
'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
|
|
8592
|
+
'audio/mobile-xmf': ['mxmf'],
|
|
8593
|
+
'audio/mp3': ['*mp3'],
|
|
8594
|
+
'audio/mp4': ['m4a', 'mp4a', 'm4b'],
|
|
8595
|
+
'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
|
|
8596
|
+
'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
|
|
8597
|
+
'audio/s3m': ['s3m'],
|
|
8598
|
+
'audio/silk': ['sil'],
|
|
8599
|
+
'audio/wav': ['wav'],
|
|
8600
|
+
'audio/wave': ['*wav'],
|
|
8601
|
+
'audio/webm': ['weba'],
|
|
8602
|
+
'audio/xm': ['xm'],
|
|
8603
|
+
'font/collection': ['ttc'],
|
|
8604
|
+
'font/otf': ['otf'],
|
|
8605
|
+
'font/ttf': ['ttf'],
|
|
8606
|
+
'font/woff': ['woff'],
|
|
8607
|
+
'font/woff2': ['woff2'],
|
|
8608
|
+
'image/aces': ['exr'],
|
|
8609
|
+
'image/apng': ['apng'],
|
|
8610
|
+
'image/avci': ['avci'],
|
|
8611
|
+
'image/avcs': ['avcs'],
|
|
8612
|
+
'image/avif': ['avif'],
|
|
8613
|
+
'image/bmp': ['bmp', 'dib'],
|
|
8614
|
+
'image/cgm': ['cgm'],
|
|
8615
|
+
'image/dicom-rle': ['drle'],
|
|
8616
|
+
'image/dpx': ['dpx'],
|
|
8617
|
+
'image/emf': ['emf'],
|
|
8618
|
+
'image/fits': ['fits'],
|
|
8619
|
+
'image/g3fax': ['g3'],
|
|
8620
|
+
'image/gif': ['gif'],
|
|
8621
|
+
'image/heic': ['heic'],
|
|
8622
|
+
'image/heic-sequence': ['heics'],
|
|
8623
|
+
'image/heif': ['heif'],
|
|
8624
|
+
'image/heif-sequence': ['heifs'],
|
|
8625
|
+
'image/hej2k': ['hej2'],
|
|
8626
|
+
'image/ief': ['ief'],
|
|
8627
|
+
'image/jaii': ['jaii'],
|
|
8628
|
+
'image/jais': ['jais'],
|
|
8629
|
+
'image/jls': ['jls'],
|
|
8630
|
+
'image/jp2': ['jp2', 'jpg2'],
|
|
8631
|
+
'image/jpeg': ['jpg', 'jpeg', 'jpe'],
|
|
8632
|
+
'image/jph': ['jph'],
|
|
8633
|
+
'image/jphc': ['jhc'],
|
|
8634
|
+
'image/jpm': ['jpm', 'jpgm'],
|
|
8635
|
+
'image/jpx': ['jpx', 'jpf'],
|
|
8636
|
+
'image/jxl': ['jxl'],
|
|
8637
|
+
'image/jxr': ['jxr'],
|
|
8638
|
+
'image/jxra': ['jxra'],
|
|
8639
|
+
'image/jxrs': ['jxrs'],
|
|
8640
|
+
'image/jxs': ['jxs'],
|
|
8641
|
+
'image/jxsc': ['jxsc'],
|
|
8642
|
+
'image/jxsi': ['jxsi'],
|
|
8643
|
+
'image/jxss': ['jxss'],
|
|
8644
|
+
'image/ktx': ['ktx'],
|
|
8645
|
+
'image/ktx2': ['ktx2'],
|
|
8646
|
+
'image/pjpeg': ['jfif'],
|
|
8647
|
+
'image/png': ['png'],
|
|
8648
|
+
'image/sgi': ['sgi'],
|
|
8649
|
+
'image/svg+xml': ['svg', 'svgz'],
|
|
8650
|
+
'image/t38': ['t38'],
|
|
8651
|
+
'image/tiff': ['tif', 'tiff'],
|
|
8652
|
+
'image/tiff-fx': ['tfx'],
|
|
8653
|
+
'image/webp': ['webp'],
|
|
8654
|
+
'image/wmf': ['wmf'],
|
|
8655
|
+
'message/disposition-notification': ['disposition-notification'],
|
|
8656
|
+
'message/global': ['u8msg'],
|
|
8657
|
+
'message/global-delivery-status': ['u8dsn'],
|
|
8658
|
+
'message/global-disposition-notification': ['u8mdn'],
|
|
8659
|
+
'message/global-headers': ['u8hdr'],
|
|
8660
|
+
'message/rfc822': ['eml', 'mime', 'mht', 'mhtml'],
|
|
8661
|
+
'model/3mf': ['3mf'],
|
|
8662
|
+
'model/gltf+json': ['gltf'],
|
|
8663
|
+
'model/gltf-binary': ['glb'],
|
|
8664
|
+
'model/iges': ['igs', 'iges'],
|
|
8665
|
+
'model/jt': ['jt'],
|
|
8666
|
+
'model/mesh': ['msh', 'mesh', 'silo'],
|
|
8667
|
+
'model/mtl': ['mtl'],
|
|
8668
|
+
'model/obj': ['obj'],
|
|
8669
|
+
'model/prc': ['prc'],
|
|
8670
|
+
'model/step': ['step', 'stp', 'stpnc', 'p21', '210'],
|
|
8671
|
+
'model/step+xml': ['stpx'],
|
|
8672
|
+
'model/step+zip': ['stpz'],
|
|
8673
|
+
'model/step-xml+zip': ['stpxz'],
|
|
8674
|
+
'model/stl': ['stl'],
|
|
8675
|
+
'model/u3d': ['u3d'],
|
|
8676
|
+
'model/vrml': ['wrl', 'vrml'],
|
|
8677
|
+
'model/x3d+binary': ['*x3db', 'x3dbz'],
|
|
8678
|
+
'model/x3d+fastinfoset': ['x3db'],
|
|
8679
|
+
'model/x3d+vrml': ['*x3dv', 'x3dvz'],
|
|
8680
|
+
'model/x3d+xml': ['x3d', 'x3dz'],
|
|
8681
|
+
'model/x3d-vrml': ['x3dv'],
|
|
8682
|
+
'text/cache-manifest': ['appcache', 'manifest'],
|
|
8683
|
+
'text/calendar': ['ics', 'ifb'],
|
|
8684
|
+
'text/coffeescript': ['coffee', 'litcoffee'],
|
|
8685
|
+
'text/css': ['css'],
|
|
8686
|
+
'text/csv': ['csv'],
|
|
8687
|
+
'text/html': ['html', 'htm', 'shtml'],
|
|
8688
|
+
'text/jade': ['jade'],
|
|
8689
|
+
'text/javascript': ['js', 'mjs'],
|
|
8690
|
+
'text/jsx': ['jsx'],
|
|
8691
|
+
'text/less': ['less'],
|
|
8692
|
+
'text/markdown': ['md', 'markdown'],
|
|
8693
|
+
'text/mathml': ['mml'],
|
|
8694
|
+
'text/mdx': ['mdx'],
|
|
8695
|
+
'text/n3': ['n3'],
|
|
8696
|
+
'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
|
|
8697
|
+
'text/richtext': ['rtx'],
|
|
8698
|
+
'text/rtf': ['*rtf'],
|
|
8699
|
+
'text/sgml': ['sgml', 'sgm'],
|
|
8700
|
+
'text/shex': ['shex'],
|
|
8701
|
+
'text/slim': ['slim', 'slm'],
|
|
8702
|
+
'text/spdx': ['spdx'],
|
|
8703
|
+
'text/stylus': ['stylus', 'styl'],
|
|
8704
|
+
'text/tab-separated-values': ['tsv'],
|
|
8705
|
+
'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
|
|
8706
|
+
'text/turtle': ['ttl'],
|
|
8707
|
+
'text/uri-list': ['uri', 'uris', 'urls'],
|
|
8708
|
+
'text/vcard': ['vcard'],
|
|
8709
|
+
'text/vtt': ['vtt'],
|
|
8710
|
+
'text/wgsl': ['wgsl'],
|
|
8711
|
+
'text/xml': ['*xml'],
|
|
8712
|
+
'text/yaml': ['yaml', 'yml'],
|
|
8713
|
+
'video/3gpp': ['3gp', '3gpp'],
|
|
8714
|
+
'video/3gpp2': ['3g2'],
|
|
8715
|
+
'video/h261': ['h261'],
|
|
8716
|
+
'video/h263': ['h263'],
|
|
8717
|
+
'video/h264': ['h264'],
|
|
8718
|
+
'video/iso.segment': ['m4s'],
|
|
8719
|
+
'video/jpeg': ['jpgv'],
|
|
8720
|
+
'video/jpm': ['*jpm', '*jpgm'],
|
|
8721
|
+
'video/mj2': ['mj2', 'mjp2'],
|
|
8722
|
+
'video/mp2t': ['ts', 'm2t', 'm2ts', 'mts'],
|
|
8723
|
+
'video/mp4': ['mp4', 'mp4v', 'mpg4'],
|
|
8724
|
+
'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
|
|
8725
|
+
'video/ogg': ['ogv'],
|
|
8726
|
+
'video/quicktime': ['qt', 'mov'],
|
|
8727
|
+
'video/webm': ['webm'],
|
|
8728
|
+
};
|
|
8729
|
+
Object.freeze(types);
|
|
8730
|
+
|
|
8731
|
+
var __classPrivateFieldGet = ({} && {}.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8732
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
8733
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
8734
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
8735
|
+
};
|
|
8736
|
+
var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
|
|
8737
|
+
class Mime {
|
|
8738
|
+
constructor(...args) {
|
|
8739
|
+
_Mime_extensionToType.set(this, new Map());
|
|
8740
|
+
_Mime_typeToExtension.set(this, new Map());
|
|
8741
|
+
_Mime_typeToExtensions.set(this, new Map());
|
|
8742
|
+
for (const arg of args) {
|
|
8743
|
+
this.define(arg);
|
|
8744
|
+
}
|
|
8745
|
+
}
|
|
8746
|
+
define(typeMap, force = false) {
|
|
8747
|
+
for (let [type, extensions] of Object.entries(typeMap)) {
|
|
8748
|
+
type = type.toLowerCase();
|
|
8749
|
+
extensions = extensions.map((ext) => ext.toLowerCase());
|
|
8750
|
+
if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
|
|
8751
|
+
__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, new Set());
|
|
8752
|
+
}
|
|
8753
|
+
const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
|
|
8754
|
+
let first = true;
|
|
8755
|
+
for (let extension of extensions) {
|
|
8756
|
+
const starred = extension.startsWith('*');
|
|
8757
|
+
extension = starred ? extension.slice(1) : extension;
|
|
8758
|
+
allExtensions?.add(extension);
|
|
8759
|
+
if (first) {
|
|
8760
|
+
__classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
|
|
8761
|
+
}
|
|
8762
|
+
first = false;
|
|
8763
|
+
if (starred)
|
|
8764
|
+
continue;
|
|
8765
|
+
const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
|
|
8766
|
+
if (currentType && currentType != type && !force) {
|
|
8767
|
+
throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
|
|
8768
|
+
}
|
|
8769
|
+
__classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
return this;
|
|
8773
|
+
}
|
|
8774
|
+
getType(path) {
|
|
8775
|
+
if (typeof path !== 'string')
|
|
8776
|
+
return null;
|
|
8777
|
+
const last = path.replace(/^.*[/\\]/s, '').toLowerCase();
|
|
8778
|
+
const ext = last.replace(/^.*\./s, '').toLowerCase();
|
|
8779
|
+
const hasPath = last.length < path.length;
|
|
8780
|
+
const hasDot = ext.length < last.length - 1;
|
|
8781
|
+
if (!hasDot && hasPath)
|
|
8782
|
+
return null;
|
|
8783
|
+
return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
|
|
8784
|
+
}
|
|
8785
|
+
getExtension(type) {
|
|
8786
|
+
if (typeof type !== 'string')
|
|
8787
|
+
return null;
|
|
8788
|
+
type = type?.split?.(';')[0];
|
|
8789
|
+
return ((type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null);
|
|
8790
|
+
}
|
|
8791
|
+
getAllExtensions(type) {
|
|
8792
|
+
if (typeof type !== 'string')
|
|
8793
|
+
return null;
|
|
8794
|
+
return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
|
|
8795
|
+
}
|
|
8796
|
+
_freeze() {
|
|
8797
|
+
this.define = () => {
|
|
8798
|
+
throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
|
|
8799
|
+
};
|
|
8800
|
+
Object.freeze(this);
|
|
8801
|
+
for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
|
|
8802
|
+
Object.freeze(extensions);
|
|
8803
|
+
}
|
|
8804
|
+
return this;
|
|
8805
|
+
}
|
|
8806
|
+
_getTestState() {
|
|
8807
|
+
return {
|
|
8808
|
+
types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
|
|
8809
|
+
extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
|
|
8810
|
+
};
|
|
8811
|
+
}
|
|
8812
|
+
}
|
|
8813
|
+
_Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
|
|
8814
|
+
|
|
8815
|
+
var mime = new Mime(types)._freeze();
|
|
8816
|
+
|
|
8526
8817
|
class TestRun {
|
|
8527
8818
|
constructor(vitest) {
|
|
8528
8819
|
this.vitest = vitest;
|
|
@@ -8550,55 +8841,61 @@ class TestRun {
|
|
|
8550
8841
|
this.vitest.state.updateUserLog(log);
|
|
8551
8842
|
await this.vitest.report("onUserConsoleLog", log);
|
|
8552
8843
|
}
|
|
8844
|
+
async annotate(testId, annotation) {
|
|
8845
|
+
const task = this.vitest.state.idMap.get(testId);
|
|
8846
|
+
const entity = task && this.vitest.state.getReportedEntity(task);
|
|
8847
|
+
assert$1(task && entity, `Entity must be found for task ${task?.name || testId}`);
|
|
8848
|
+
assert$1(entity.type === "test", `Annotation can only be added to a test, instead got ${entity.type}`);
|
|
8849
|
+
await this.resolveTestAttachment(entity, annotation);
|
|
8850
|
+
entity.task.annotations.push(annotation);
|
|
8851
|
+
await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
8852
|
+
return annotation;
|
|
8853
|
+
}
|
|
8553
8854
|
async updated(update, events) {
|
|
8554
8855
|
this.vitest.state.updateTasks(update);
|
|
8555
|
-
await this.
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8856
|
+
for (const [id, event, data] of events) await this.reportEvent(id, event, data).catch((error) => {
|
|
8857
|
+
this.vitest.state.catchError(serializeError(error), "Unhandled Reporter Error");
|
|
8858
|
+
});
|
|
8859
|
+
// TODO: what is the order or reports here?
|
|
8860
|
+
// "onTaskUpdate" in parallel with others or before all or after all?
|
|
8861
|
+
// TODO: error handling - what happens if custom reporter throws an error?
|
|
8862
|
+
await this.vitest.report("onTaskUpdate", update, events);
|
|
8561
8863
|
}
|
|
8562
8864
|
async end(specifications, errors, coverage) {
|
|
8865
|
+
// specification won't have the File task if they were filtered by the --shard command
|
|
8563
8866
|
const modules = specifications.map((spec) => spec.testModule).filter((s) => s != null);
|
|
8564
8867
|
const files = modules.map((m) => m.task);
|
|
8565
|
-
const state = this.vitest.isCancelling ? "interrupted" :
|
|
8868
|
+
const state = this.vitest.isCancelling ? "interrupted" : this.hasFailed(modules) ? "failed" : "passed";
|
|
8869
|
+
if (state !== "passed") process.exitCode = 1;
|
|
8566
8870
|
try {
|
|
8567
8871
|
await Promise.all([this.vitest.report("onTestRunEnd", modules, [...errors], state), this.vitest.report("onFinished", files, errors, coverage)]);
|
|
8568
8872
|
} finally {
|
|
8569
|
-
if (coverage)
|
|
8570
|
-
await this.vitest.report("onCoverage", coverage);
|
|
8571
|
-
}
|
|
8873
|
+
if (coverage) await this.vitest.report("onCoverage", coverage);
|
|
8572
8874
|
}
|
|
8573
8875
|
}
|
|
8574
|
-
|
|
8876
|
+
hasFailed(modules) {
|
|
8877
|
+
if (!modules.length) return !this.vitest.config.passWithNoTests;
|
|
8878
|
+
return modules.some((m) => !m.ok());
|
|
8879
|
+
}
|
|
8880
|
+
async reportEvent(id, event, data) {
|
|
8575
8881
|
const task = this.vitest.state.idMap.get(id);
|
|
8576
8882
|
const entity = task && this.vitest.state.getReportedEntity(task);
|
|
8577
8883
|
assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
|
|
8578
|
-
if (event === "suite-prepare" && entity.type === "suite")
|
|
8579
|
-
|
|
8580
|
-
}
|
|
8581
|
-
if (event === "suite-prepare" && entity.type === "module") {
|
|
8582
|
-
return await this.vitest.report("onTestModuleStart", entity);
|
|
8583
|
-
}
|
|
8884
|
+
if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
|
|
8885
|
+
if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
|
|
8584
8886
|
if (event === "suite-finished") {
|
|
8585
8887
|
assert$1(entity.type === "suite" || entity.type === "module", "Entity type must be suite or module");
|
|
8586
|
-
if (entity.state() === "skipped")
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
}
|
|
8888
|
+
if (entity.state() === "skipped")
|
|
8889
|
+
// everything inside suite or a module is skipped,
|
|
8890
|
+
// so we won't get any children events
|
|
8891
|
+
// we need to report everything manually
|
|
8892
|
+
await this.reportChildren(entity.children);
|
|
8893
|
+
if (entity.type === "module") await this.vitest.report("onTestModuleEnd", entity);
|
|
8894
|
+
else await this.vitest.report("onTestSuiteResult", entity);
|
|
8594
8895
|
return;
|
|
8595
8896
|
}
|
|
8596
|
-
if (event === "test-prepare" && entity.type === "test")
|
|
8597
|
-
|
|
8598
|
-
}
|
|
8599
|
-
if (event === "test-finished" && entity.type === "test") {
|
|
8600
|
-
return await this.vitest.report("onTestCaseResult", entity);
|
|
8601
|
-
}
|
|
8897
|
+
if (event === "test-prepare" && entity.type === "test") return await this.vitest.report("onTestCaseReady", entity);
|
|
8898
|
+
if (event === "test-finished" && entity.type === "test") return await this.vitest.report("onTestCaseResult", entity);
|
|
8602
8899
|
if (event.startsWith("before-hook") || event.startsWith("after-hook")) {
|
|
8603
8900
|
const isBefore = event.startsWith("before-hook");
|
|
8604
8901
|
const hook = entity.type === "test" ? {
|
|
@@ -8608,36 +8905,58 @@ class TestRun {
|
|
|
8608
8905
|
name: isBefore ? "beforeAll" : "afterAll",
|
|
8609
8906
|
entity
|
|
8610
8907
|
};
|
|
8611
|
-
if (event.endsWith("-start"))
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8908
|
+
if (event.endsWith("-start")) await this.vitest.report("onHookStart", hook);
|
|
8909
|
+
else await this.vitest.report("onHookEnd", hook);
|
|
8910
|
+
// this can only happen in --merge-reports, and annotation is already resolved
|
|
8911
|
+
if (event === "test-annotation") {
|
|
8912
|
+
const annotation = data?.annotation;
|
|
8913
|
+
assert$1(annotation && entity.type === "test");
|
|
8914
|
+
await this.vitest.report("onTestCaseAnnotate", entity, annotation);
|
|
8615
8915
|
}
|
|
8616
8916
|
}
|
|
8617
8917
|
}
|
|
8918
|
+
async resolveTestAttachment(test, annotation) {
|
|
8919
|
+
const project = test.project;
|
|
8920
|
+
const attachment = annotation.attachment;
|
|
8921
|
+
if (!attachment) return attachment;
|
|
8922
|
+
const path = attachment.path;
|
|
8923
|
+
if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
|
|
8924
|
+
const currentPath = resolve(project.config.root, path);
|
|
8925
|
+
const hash = createHash("sha1").update(currentPath).digest("hex");
|
|
8926
|
+
const newPath = resolve(project.config.attachmentsDir, `${sanitizeFilePath(annotation.message)}-${hash}${extname(currentPath)}`);
|
|
8927
|
+
await mkdir(dirname(newPath), { recursive: true });
|
|
8928
|
+
await copyFile(currentPath, newPath);
|
|
8929
|
+
attachment.path = newPath;
|
|
8930
|
+
const contentType = attachment.contentType ?? mime.getType(basename(currentPath));
|
|
8931
|
+
attachment.contentType = contentType || void 0;
|
|
8932
|
+
}
|
|
8933
|
+
return attachment;
|
|
8934
|
+
}
|
|
8618
8935
|
async reportChildren(children) {
|
|
8619
|
-
for (const child of children) {
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
await this.vitest.report("onTestSuiteResult", child);
|
|
8627
|
-
}
|
|
8936
|
+
for (const child of children) if (child.type === "test") {
|
|
8937
|
+
await this.vitest.report("onTestCaseReady", child);
|
|
8938
|
+
await this.vitest.report("onTestCaseResult", child);
|
|
8939
|
+
} else {
|
|
8940
|
+
await this.vitest.report("onTestSuiteReady", child);
|
|
8941
|
+
await this.reportChildren(child.children);
|
|
8942
|
+
await this.vitest.report("onTestSuiteResult", child);
|
|
8628
8943
|
}
|
|
8629
8944
|
}
|
|
8630
8945
|
}
|
|
8946
|
+
function sanitizeFilePath(s) {
|
|
8947
|
+
// eslint-disable-next-line no-control-regex
|
|
8948
|
+
return s.replace(/[\x00-\x2C\x2E\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-");
|
|
8949
|
+
}
|
|
8631
8950
|
|
|
8632
8951
|
class VitestWatcher {
|
|
8633
8952
|
/**
|
|
8634
8953
|
* Modules that will be invalidated on the next run.
|
|
8635
8954
|
*/
|
|
8636
|
-
invalidates = new Set();
|
|
8955
|
+
invalidates = /* @__PURE__ */ new Set();
|
|
8637
8956
|
/**
|
|
8638
8957
|
* Test files that have changed and need to be rerun.
|
|
8639
8958
|
*/
|
|
8640
|
-
changedTests = new Set();
|
|
8959
|
+
changedTests = /* @__PURE__ */ new Set();
|
|
8641
8960
|
_onRerun = [];
|
|
8642
8961
|
constructor(vitest) {
|
|
8643
8962
|
this.vitest = vitest;
|
|
@@ -8655,9 +8974,7 @@ class VitestWatcher {
|
|
|
8655
8974
|
unregisterWatcher = noop;
|
|
8656
8975
|
registerWatcher() {
|
|
8657
8976
|
const watcher = this.vitest.vite.watcher;
|
|
8658
|
-
if (this.vitest.config.forceRerunTriggers.length)
|
|
8659
|
-
watcher.add(this.vitest.config.forceRerunTriggers);
|
|
8660
|
-
}
|
|
8977
|
+
if (this.vitest.config.forceRerunTriggers.length) watcher.add(this.vitest.config.forceRerunTriggers);
|
|
8661
8978
|
watcher.on("change", this.onChange);
|
|
8662
8979
|
watcher.on("unlink", this.onUnlink);
|
|
8663
8980
|
watcher.on("add", this.onAdd);
|
|
@@ -8673,9 +8990,7 @@ class VitestWatcher {
|
|
|
8673
8990
|
this._onRerun.forEach((cb) => cb(file));
|
|
8674
8991
|
}
|
|
8675
8992
|
getTestFilesFromWatcherTrigger(id) {
|
|
8676
|
-
if (!this.vitest.config.watchTriggerPatterns)
|
|
8677
|
-
return false;
|
|
8678
|
-
}
|
|
8993
|
+
if (!this.vitest.config.watchTriggerPatterns) return false;
|
|
8679
8994
|
let triggered = false;
|
|
8680
8995
|
this.vitest.config.watchTriggerPatterns.forEach((definition) => {
|
|
8681
8996
|
const exec = definition.pattern.exec(id);
|
|
@@ -8697,13 +9012,10 @@ class VitestWatcher {
|
|
|
8697
9012
|
this.vitest.logger.clearHighlightCache(id);
|
|
8698
9013
|
this.vitest.invalidateFile(id);
|
|
8699
9014
|
const testFiles = this.getTestFilesFromWatcherTrigger(id);
|
|
8700
|
-
if (testFiles)
|
|
8701
|
-
|
|
8702
|
-
} else {
|
|
9015
|
+
if (testFiles) this.scheduleRerun(id);
|
|
9016
|
+
else {
|
|
8703
9017
|
const needsRerun = this.handleFileChanged(id);
|
|
8704
|
-
if (needsRerun)
|
|
8705
|
-
this.scheduleRerun(id);
|
|
8706
|
-
}
|
|
9018
|
+
if (needsRerun) this.scheduleRerun(id);
|
|
8707
9019
|
}
|
|
8708
9020
|
};
|
|
8709
9021
|
onUnlink = (id) => {
|
|
@@ -8730,27 +9042,22 @@ class VitestWatcher {
|
|
|
8730
9042
|
let fileContent;
|
|
8731
9043
|
const matchingProjects = [];
|
|
8732
9044
|
this.vitest.projects.forEach((project) => {
|
|
8733
|
-
if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8")))
|
|
8734
|
-
matchingProjects.push(project);
|
|
8735
|
-
}
|
|
9045
|
+
if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8"))) matchingProjects.push(project);
|
|
8736
9046
|
});
|
|
8737
9047
|
if (matchingProjects.length > 0) {
|
|
8738
9048
|
this.changedTests.add(id);
|
|
8739
9049
|
this.scheduleRerun(id);
|
|
8740
9050
|
} else {
|
|
9051
|
+
// it's possible that file was already there but watcher triggered "add" event instead
|
|
8741
9052
|
const needsRerun = this.handleFileChanged(id);
|
|
8742
|
-
if (needsRerun)
|
|
8743
|
-
this.scheduleRerun(id);
|
|
8744
|
-
}
|
|
9053
|
+
if (needsRerun) this.scheduleRerun(id);
|
|
8745
9054
|
}
|
|
8746
9055
|
};
|
|
8747
9056
|
/**
|
|
8748
9057
|
* @returns A value indicating whether rerun is needed (changedTests was mutated)
|
|
8749
9058
|
*/
|
|
8750
9059
|
handleFileChanged(filepath) {
|
|
8751
|
-
if (this.changedTests.has(filepath) || this.invalidates.has(filepath))
|
|
8752
|
-
return false;
|
|
8753
|
-
}
|
|
9060
|
+
if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) return false;
|
|
8754
9061
|
if (pm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) {
|
|
8755
9062
|
this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file));
|
|
8756
9063
|
return true;
|
|
@@ -8760,6 +9067,8 @@ class VitestWatcher {
|
|
|
8760
9067
|
return moduleGraph.getModulesByFile(filepath)?.size;
|
|
8761
9068
|
});
|
|
8762
9069
|
if (!projects.length) {
|
|
9070
|
+
// if there are no modules it's possible that server was restarted
|
|
9071
|
+
// we don't have information about importers anymore, so let's check if the file is a test file at least
|
|
8763
9072
|
if (this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project._isCachedTestFile(filepath))) {
|
|
8764
9073
|
this.changedTests.add(filepath);
|
|
8765
9074
|
return true;
|
|
@@ -8769,30 +9078,21 @@ class VitestWatcher {
|
|
|
8769
9078
|
const files = [];
|
|
8770
9079
|
for (const project of projects) {
|
|
8771
9080
|
const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath) || project.vite.moduleGraph.getModulesByFile(filepath);
|
|
8772
|
-
if (!mods || !mods.size)
|
|
8773
|
-
continue;
|
|
8774
|
-
}
|
|
9081
|
+
if (!mods || !mods.size) continue;
|
|
8775
9082
|
this.invalidates.add(filepath);
|
|
9083
|
+
// one of test files that we already run, or one of test files that we can run
|
|
8776
9084
|
if (this.vitest.state.filesMap.has(filepath) || project._isCachedTestFile(filepath)) {
|
|
8777
9085
|
this.changedTests.add(filepath);
|
|
8778
9086
|
files.push(filepath);
|
|
8779
9087
|
continue;
|
|
8780
9088
|
}
|
|
8781
9089
|
let rerun = false;
|
|
8782
|
-
for (const mod of mods) {
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
if (needsRerun) {
|
|
8789
|
-
rerun = true;
|
|
8790
|
-
}
|
|
8791
|
-
});
|
|
8792
|
-
}
|
|
8793
|
-
if (rerun) {
|
|
8794
|
-
files.push(filepath);
|
|
8795
|
-
}
|
|
9090
|
+
for (const mod of mods) mod.importers.forEach((i) => {
|
|
9091
|
+
if (!i.file) return;
|
|
9092
|
+
const needsRerun = this.handleFileChanged(i.file);
|
|
9093
|
+
if (needsRerun) rerun = true;
|
|
9094
|
+
});
|
|
9095
|
+
if (rerun) files.push(filepath);
|
|
8796
9096
|
}
|
|
8797
9097
|
return !!files.length;
|
|
8798
9098
|
}
|
|
@@ -8844,11 +9144,11 @@ class Vitest {
|
|
|
8844
9144
|
resolvedProjects = [];
|
|
8845
9145
|
/** @internal */ _browserLastPort = defaultBrowserPort;
|
|
8846
9146
|
/** @internal */ _browserSessions = new BrowserSessions();
|
|
8847
|
-
/** @internal */
|
|
9147
|
+
/** @internal */ _cliOptions = {};
|
|
8848
9148
|
/** @internal */ reporters = [];
|
|
8849
|
-
/** @internal */ vitenode =
|
|
8850
|
-
/** @internal */ runner =
|
|
8851
|
-
/** @internal */ _testRun =
|
|
9149
|
+
/** @internal */ vitenode = void 0;
|
|
9150
|
+
/** @internal */ runner = void 0;
|
|
9151
|
+
/** @internal */ _testRun = void 0;
|
|
8852
9152
|
isFirstRun = true;
|
|
8853
9153
|
restartsCount = 0;
|
|
8854
9154
|
specifications;
|
|
@@ -8860,8 +9160,9 @@ class Vitest {
|
|
|
8860
9160
|
_cache;
|
|
8861
9161
|
_snapshot;
|
|
8862
9162
|
_workspaceConfigPath;
|
|
8863
|
-
constructor(mode, options = {}) {
|
|
9163
|
+
constructor(mode, cliOptions, options = {}) {
|
|
8864
9164
|
this.mode = mode;
|
|
9165
|
+
this._cliOptions = cliOptions;
|
|
8865
9166
|
this.logger = new Logger(this, options.stdout, options.stderr);
|
|
8866
9167
|
this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
|
|
8867
9168
|
this.specifications = new VitestSpecifications(this);
|
|
@@ -8922,25 +9223,24 @@ class Vitest {
|
|
|
8922
9223
|
return this._cache;
|
|
8923
9224
|
}
|
|
8924
9225
|
/** @deprecated internal */
|
|
8925
|
-
setServer(options, server
|
|
8926
|
-
return this._setServer(options, server
|
|
9226
|
+
setServer(options, server) {
|
|
9227
|
+
return this._setServer(options, server);
|
|
8927
9228
|
}
|
|
8928
9229
|
/** @internal */
|
|
8929
|
-
async _setServer(options, server
|
|
8930
|
-
this._options = options;
|
|
9230
|
+
async _setServer(options, server) {
|
|
8931
9231
|
this.watcher.unregisterWatcher();
|
|
8932
9232
|
clearTimeout(this._rerunTimer);
|
|
8933
9233
|
this.restartsCount += 1;
|
|
8934
9234
|
this._browserLastPort = defaultBrowserPort;
|
|
8935
9235
|
this.pool?.close?.();
|
|
8936
|
-
this.pool =
|
|
8937
|
-
this.closingPromise =
|
|
9236
|
+
this.pool = void 0;
|
|
9237
|
+
this.closingPromise = void 0;
|
|
8938
9238
|
this.projects = [];
|
|
8939
9239
|
this.resolvedProjects = [];
|
|
8940
|
-
this._workspaceConfigPath =
|
|
8941
|
-
this.coverageProvider =
|
|
8942
|
-
this.runningPromise =
|
|
8943
|
-
this.coreWorkspaceProject =
|
|
9240
|
+
this._workspaceConfigPath = void 0;
|
|
9241
|
+
this.coverageProvider = void 0;
|
|
9242
|
+
this.runningPromise = void 0;
|
|
9243
|
+
this.coreWorkspaceProject = void 0;
|
|
8944
9244
|
this.specifications.clearCache();
|
|
8945
9245
|
this._onUserTestsRerun = [];
|
|
8946
9246
|
this._vite = server;
|
|
@@ -8950,9 +9250,7 @@ class Vitest {
|
|
|
8950
9250
|
this._cache = new VitestCache(this.version);
|
|
8951
9251
|
this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions });
|
|
8952
9252
|
this._testRun = new TestRun(this);
|
|
8953
|
-
if (this.config.watch)
|
|
8954
|
-
this.watcher.registerWatcher();
|
|
8955
|
-
}
|
|
9253
|
+
if (this.config.watch) this.watcher.registerWatcher();
|
|
8956
9254
|
this.vitenode = new ViteNodeServer(server, this.config.server);
|
|
8957
9255
|
const node = this.vitenode;
|
|
8958
9256
|
this.runner = new ViteNodeRunner({
|
|
@@ -8966,6 +9264,7 @@ class Vitest {
|
|
|
8966
9264
|
}
|
|
8967
9265
|
});
|
|
8968
9266
|
if (this.config.watch) {
|
|
9267
|
+
// hijack server restart
|
|
8969
9268
|
const serverRestart = server.restart;
|
|
8970
9269
|
server.restart = async (...args) => {
|
|
8971
9270
|
await Promise.all(this._onRestartListeners.map((fn) => fn()));
|
|
@@ -8973,6 +9272,7 @@ class Vitest {
|
|
|
8973
9272
|
await this.close();
|
|
8974
9273
|
await serverRestart(...args);
|
|
8975
9274
|
};
|
|
9275
|
+
// since we set `server.hmr: false`, Vite does not auto restart itself
|
|
8976
9276
|
server.watcher.on("change", async (file) => {
|
|
8977
9277
|
file = normalize(file);
|
|
8978
9278
|
const isConfig = file === server.config.configFile || this.projects.some((p) => p.vite.config.configFile === file) || file === this._workspaceConfigPath;
|
|
@@ -8988,7 +9288,7 @@ class Vitest {
|
|
|
8988
9288
|
try {
|
|
8989
9289
|
await this.cache.results.readFromCache();
|
|
8990
9290
|
} catch {}
|
|
8991
|
-
const projects = await this.resolveProjects(
|
|
9291
|
+
const projects = await this.resolveProjects(this._cliOptions);
|
|
8992
9292
|
this.resolvedProjects = projects;
|
|
8993
9293
|
this.projects = projects;
|
|
8994
9294
|
await Promise.all(projects.flatMap((project) => {
|
|
@@ -8999,26 +9299,17 @@ class Vitest {
|
|
|
8999
9299
|
injectTestProjects: this.injectTestProject
|
|
9000
9300
|
}));
|
|
9001
9301
|
}));
|
|
9002
|
-
if (
|
|
9302
|
+
if (this._cliOptions.browser?.enabled) {
|
|
9003
9303
|
const browserProjects = this.projects.filter((p) => p.config.browser.enabled);
|
|
9004
|
-
if (!browserProjects.length)
|
|
9005
|
-
throw new Error(`Vitest received --browser flag, but no project had a browser configuration.`);
|
|
9006
|
-
}
|
|
9304
|
+
if (!browserProjects.length) throw new Error(`Vitest received --browser flag, but no project had a browser configuration.`);
|
|
9007
9305
|
}
|
|
9008
9306
|
if (!this.projects.length) {
|
|
9009
9307
|
const filter = toArray(resolved.project).join("\", \"");
|
|
9010
|
-
if (filter) {
|
|
9011
|
-
|
|
9012
|
-
} else {
|
|
9013
|
-
throw new Error(`Vitest wasn't able to resolve any project.`);
|
|
9014
|
-
}
|
|
9015
|
-
}
|
|
9016
|
-
if (!this.coreWorkspaceProject) {
|
|
9017
|
-
this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9018
|
-
}
|
|
9019
|
-
if (this.config.testNamePattern) {
|
|
9020
|
-
this.configOverride.testNamePattern = this.config.testNamePattern;
|
|
9308
|
+
if (filter) throw new Error(`No projects matched the filter "${filter}".`);
|
|
9309
|
+
else throw new Error(`Vitest wasn't able to resolve any project.`);
|
|
9021
9310
|
}
|
|
9311
|
+
if (!this.coreWorkspaceProject) this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9312
|
+
if (this.config.testNamePattern) this.configOverride.testNamePattern = this.config.testNamePattern;
|
|
9022
9313
|
this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
|
|
9023
9314
|
await Promise.all(this._onSetServer.map((fn) => fn()));
|
|
9024
9315
|
}
|
|
@@ -9029,7 +9320,7 @@ class Vitest {
|
|
|
9029
9320
|
*/
|
|
9030
9321
|
injectTestProject = async (config) => {
|
|
9031
9322
|
const currentNames = new Set(this.projects.map((p) => p.name));
|
|
9032
|
-
const projects = await resolveProjects(this, this.
|
|
9323
|
+
const projects = await resolveProjects(this, this._cliOptions, void 0, Array.isArray(config) ? config : [config], currentNames);
|
|
9033
9324
|
this.projects.push(...projects);
|
|
9034
9325
|
return projects;
|
|
9035
9326
|
};
|
|
@@ -9047,9 +9338,7 @@ class Vitest {
|
|
|
9047
9338
|
}
|
|
9048
9339
|
/** @internal */
|
|
9049
9340
|
_ensureRootProject() {
|
|
9050
|
-
if (this.coreWorkspaceProject)
|
|
9051
|
-
return this.coreWorkspaceProject;
|
|
9052
|
-
}
|
|
9341
|
+
if (this.coreWorkspaceProject) return this.coreWorkspaceProject;
|
|
9053
9342
|
this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
9054
9343
|
return this.coreWorkspaceProject;
|
|
9055
9344
|
}
|
|
@@ -9061,9 +9350,7 @@ class Vitest {
|
|
|
9061
9350
|
* Return project that has the root (or "global") config.
|
|
9062
9351
|
*/
|
|
9063
9352
|
getRootProject() {
|
|
9064
|
-
if (!this.coreWorkspaceProject)
|
|
9065
|
-
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.`);
|
|
9066
|
-
}
|
|
9353
|
+
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.`);
|
|
9067
9354
|
return this.coreWorkspaceProject;
|
|
9068
9355
|
}
|
|
9069
9356
|
/**
|
|
@@ -9076,9 +9363,7 @@ class Vitest {
|
|
|
9076
9363
|
}
|
|
9077
9364
|
getProjectByName(name) {
|
|
9078
9365
|
const project = this.projects.find((p) => p.name === name) || this.coreWorkspaceProject || this.projects[0];
|
|
9079
|
-
if (!project) {
|
|
9080
|
-
throw new Error(`Project "${name}" was not found.`);
|
|
9081
|
-
}
|
|
9366
|
+
if (!project) throw new Error(`Project "${name}" was not found.`);
|
|
9082
9367
|
return project;
|
|
9083
9368
|
}
|
|
9084
9369
|
/**
|
|
@@ -9089,46 +9374,39 @@ class Vitest {
|
|
|
9089
9374
|
return this.runner.executeId(moduleId);
|
|
9090
9375
|
}
|
|
9091
9376
|
async resolveWorkspaceConfigPath() {
|
|
9092
|
-
if (typeof this.config.workspace === "string")
|
|
9093
|
-
return this.config.workspace;
|
|
9094
|
-
}
|
|
9377
|
+
if (typeof this.config.workspace === "string") return this.config.workspace;
|
|
9095
9378
|
const configDir = this.vite.config.configFile ? dirname(this.vite.config.configFile) : this.config.root;
|
|
9096
9379
|
const rootFiles = await promises.readdir(configDir);
|
|
9097
9380
|
const workspaceConfigName = workspacesFiles.find((configFile) => {
|
|
9098
9381
|
return rootFiles.includes(configFile);
|
|
9099
9382
|
});
|
|
9100
|
-
if (!workspaceConfigName)
|
|
9101
|
-
return undefined;
|
|
9102
|
-
}
|
|
9383
|
+
if (!workspaceConfigName) return void 0;
|
|
9103
9384
|
return join(configDir, workspaceConfigName);
|
|
9104
9385
|
}
|
|
9105
9386
|
async resolveProjects(cliOptions) {
|
|
9106
|
-
const names = new Set();
|
|
9387
|
+
const names = /* @__PURE__ */ new Set();
|
|
9107
9388
|
if (this.config.projects) {
|
|
9108
|
-
if (typeof this.config.workspace !== "undefined")
|
|
9109
|
-
|
|
9110
|
-
}
|
|
9111
|
-
return resolveProjects(this, cliOptions, undefined, this.config.projects, names);
|
|
9389
|
+
if (typeof this.config.workspace !== "undefined") this.logger.warn("Both `config.projects` and `config.workspace` are defined. Ignoring the `workspace` option.");
|
|
9390
|
+
return resolveProjects(this, cliOptions, void 0, this.config.projects, names);
|
|
9112
9391
|
}
|
|
9113
9392
|
if (Array.isArray(this.config.workspace)) {
|
|
9114
9393
|
this.logger.deprecate("The `workspace` option is deprecated and will be removed in the next major. To hide this warning, rename `workspace` option to `projects`.");
|
|
9115
|
-
return resolveProjects(this, cliOptions,
|
|
9394
|
+
return resolveProjects(this, cliOptions, void 0, this.config.workspace, names);
|
|
9116
9395
|
}
|
|
9117
9396
|
const workspaceConfigPath = await this.resolveWorkspaceConfigPath();
|
|
9118
9397
|
this._workspaceConfigPath = workspaceConfigPath;
|
|
9398
|
+
// user doesn't have a workspace config, return default project
|
|
9119
9399
|
if (!workspaceConfigPath) {
|
|
9400
|
+
// user can filter projects with --project flag, `getDefaultTestProject`
|
|
9401
|
+
// returns the project only if it matches the filter
|
|
9120
9402
|
const project = getDefaultTestProject(this);
|
|
9121
|
-
if (!project)
|
|
9122
|
-
return [];
|
|
9123
|
-
}
|
|
9403
|
+
if (!project) return [];
|
|
9124
9404
|
return resolveBrowserProjects(this, new Set([project.name]), [project]);
|
|
9125
9405
|
}
|
|
9126
9406
|
const configFile = this.vite.config.configFile ? resolve(this.vite.config.root, this.vite.config.configFile) : "the root config file";
|
|
9127
9407
|
this.logger.deprecate(`The workspace file is deprecated and will be removed in the next major. Please, use the \`projects\` field in ${configFile} instead.`);
|
|
9128
9408
|
const workspaceModule = await this.import(workspaceConfigPath);
|
|
9129
|
-
if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) {
|
|
9130
|
-
throw new TypeError(`Workspace config file "${workspaceConfigPath}" must export a default array of project paths.`);
|
|
9131
|
-
}
|
|
9409
|
+
if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) throw new TypeError(`Workspace config file "${workspaceConfigPath}" must export a default array of project paths.`);
|
|
9132
9410
|
return resolveProjects(this, cliOptions, workspaceConfigPath, workspaceModule.default, names);
|
|
9133
9411
|
}
|
|
9134
9412
|
/**
|
|
@@ -9139,9 +9417,7 @@ class Vitest {
|
|
|
9139
9417
|
return this.specifications.globTestSpecifications(filters);
|
|
9140
9418
|
}
|
|
9141
9419
|
async initCoverageProvider() {
|
|
9142
|
-
if (this.coverageProvider !==
|
|
9143
|
-
return;
|
|
9144
|
-
}
|
|
9420
|
+
if (this.coverageProvider !== void 0) return;
|
|
9145
9421
|
this.coverageProvider = await getCoverageProvider(this.config.coverage, this.runner);
|
|
9146
9422
|
if (this.coverageProvider) {
|
|
9147
9423
|
await this.coverageProvider.initialize(this);
|
|
@@ -9153,9 +9429,7 @@ class Vitest {
|
|
|
9153
9429
|
* Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
|
|
9154
9430
|
*/
|
|
9155
9431
|
async mergeReports(directory) {
|
|
9156
|
-
if (this.reporters.some((r) => r instanceof BlobReporter))
|
|
9157
|
-
throw new Error("Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first.");
|
|
9158
|
-
}
|
|
9432
|
+
if (this.reporters.some((r) => r instanceof BlobReporter)) throw new Error("Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first.");
|
|
9159
9433
|
const { files, errors, coverages, executionTimes } = await readBlobs(this.version, directory || this.config.mergeReports, this.projects);
|
|
9160
9434
|
this.state.blobs = {
|
|
9161
9435
|
files,
|
|
@@ -9168,17 +9442,12 @@ class Vitest {
|
|
|
9168
9442
|
const specifications = [];
|
|
9169
9443
|
for (const file of files) {
|
|
9170
9444
|
const project = this.getProjectByName(file.projectName || "");
|
|
9171
|
-
const specification = project.createSpecification(file.filepath,
|
|
9445
|
+
const specification = project.createSpecification(file.filepath, void 0, file.pool);
|
|
9172
9446
|
specifications.push(specification);
|
|
9173
9447
|
}
|
|
9174
9448
|
await this.report("onSpecsCollected", specifications.map((spec) => spec.toJSON()));
|
|
9175
9449
|
await this._testRun.start(specifications).catch(noop);
|
|
9176
|
-
for (const file of files)
|
|
9177
|
-
await this._reportFileTask(file);
|
|
9178
|
-
}
|
|
9179
|
-
if (hasFailed(files)) {
|
|
9180
|
-
process.exitCode = 1;
|
|
9181
|
-
}
|
|
9450
|
+
for (const file of files) await this._reportFileTask(file);
|
|
9182
9451
|
this._checkUnhandledErrors(errors);
|
|
9183
9452
|
await this._testRun.end(specifications, errors).catch(noop);
|
|
9184
9453
|
await this.initCoverageProvider();
|
|
@@ -9195,24 +9464,19 @@ class Vitest {
|
|
|
9195
9464
|
await this._testRun.collected(project, [file]).catch(noop);
|
|
9196
9465
|
const logs = [];
|
|
9197
9466
|
const { packs, events } = convertTasksToEvents(file, (task) => {
|
|
9198
|
-
if (task.logs)
|
|
9199
|
-
logs.push(...task.logs);
|
|
9200
|
-
}
|
|
9467
|
+
if (task.logs) logs.push(...task.logs);
|
|
9201
9468
|
});
|
|
9202
9469
|
logs.sort((log1, log2) => log1.time - log2.time);
|
|
9203
|
-
for (const log of logs)
|
|
9204
|
-
await this._testRun.log(log).catch(noop);
|
|
9205
|
-
}
|
|
9470
|
+
for (const log of logs) await this._testRun.log(log).catch(noop);
|
|
9206
9471
|
await this._testRun.updated(packs, events).catch(noop);
|
|
9207
9472
|
}
|
|
9208
9473
|
async collect(filters) {
|
|
9209
9474
|
const files = await this.specifications.getRelevantTestSpecifications(filters);
|
|
9210
|
-
if
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
}
|
|
9475
|
+
// if run with --changed, don't exit if no tests are found
|
|
9476
|
+
if (!files.length) return {
|
|
9477
|
+
testModules: [],
|
|
9478
|
+
unhandledErrors: []
|
|
9479
|
+
};
|
|
9216
9480
|
return this.collectTests(files);
|
|
9217
9481
|
}
|
|
9218
9482
|
/** @deprecated use `getRelevantTestSpecifications` instead */
|
|
@@ -9241,33 +9505,27 @@ class Vitest {
|
|
|
9241
9505
|
} finally {
|
|
9242
9506
|
await this.report("onInit", this);
|
|
9243
9507
|
}
|
|
9244
|
-
this.filenamePattern = filters && filters?.length > 0 ? filters :
|
|
9508
|
+
this.filenamePattern = filters && filters?.length > 0 ? filters : void 0;
|
|
9245
9509
|
const files = await this.specifications.getRelevantTestSpecifications(filters);
|
|
9510
|
+
// if run with --changed, don't exit if no tests are found
|
|
9246
9511
|
if (!files.length) {
|
|
9247
|
-
const throwAnError = !this.config.watch || !(this.config.changed || this.config.related?.length);
|
|
9248
9512
|
await this._testRun.start([]);
|
|
9249
9513
|
const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
|
|
9250
|
-
if (throwAnError) {
|
|
9251
|
-
const exitCode = this.config.passWithNoTests ? 0 : 1;
|
|
9252
|
-
process.exitCode = exitCode;
|
|
9253
|
-
}
|
|
9254
9514
|
await this._testRun.end([], [], coverage);
|
|
9515
|
+
// Report coverage for uncovered files
|
|
9255
9516
|
await this.reportCoverage(coverage, true);
|
|
9256
|
-
if (
|
|
9257
|
-
throw new FilesNotFoundError(this.mode);
|
|
9258
|
-
}
|
|
9517
|
+
if (!this.config.watch || !(this.config.changed || this.config.related?.length)) throw new FilesNotFoundError(this.mode);
|
|
9259
9518
|
}
|
|
9260
9519
|
let testModules = {
|
|
9261
9520
|
testModules: [],
|
|
9262
9521
|
unhandledErrors: []
|
|
9263
9522
|
};
|
|
9264
9523
|
if (files.length) {
|
|
9524
|
+
// populate once, update cache on watch
|
|
9265
9525
|
await this.cache.stats.populateStats(this.config.root, files);
|
|
9266
9526
|
testModules = await this.runFiles(files, true);
|
|
9267
9527
|
}
|
|
9268
|
-
if (this.config.watch)
|
|
9269
|
-
await this.report("onWatcherStart");
|
|
9270
|
-
}
|
|
9528
|
+
if (this.config.watch) await this.report("onWatcherStart");
|
|
9271
9529
|
return testModules;
|
|
9272
9530
|
}
|
|
9273
9531
|
/**
|
|
@@ -9281,10 +9539,9 @@ class Vitest {
|
|
|
9281
9539
|
} finally {
|
|
9282
9540
|
await this.report("onInit", this);
|
|
9283
9541
|
}
|
|
9542
|
+
// populate test files cache so watch mode can trigger a file rerun
|
|
9284
9543
|
await this.globTestSpecifications();
|
|
9285
|
-
if (this.config.watch)
|
|
9286
|
-
await this.report("onWatcherStart");
|
|
9287
|
-
}
|
|
9544
|
+
if (this.config.watch) await this.report("onWatcherStart");
|
|
9288
9545
|
}
|
|
9289
9546
|
/**
|
|
9290
9547
|
* @deprecated remove when vscode extension supports "getModuleSpecifications"
|
|
@@ -9326,7 +9583,7 @@ class Vitest {
|
|
|
9326
9583
|
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
9327
9584
|
*/
|
|
9328
9585
|
async rerunTestSpecifications(specifications, allTestsRun = false) {
|
|
9329
|
-
this.configOverride.testNamePattern =
|
|
9586
|
+
this.configOverride.testNamePattern = void 0;
|
|
9330
9587
|
const files = specifications.map((spec) => spec.moduleId);
|
|
9331
9588
|
await Promise.all([this.report("onWatcherRerun", files, "rerun test"), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
9332
9589
|
const result = await this.runTestSpecifications(specifications, allTestsRun);
|
|
@@ -9335,21 +9592,19 @@ class Vitest {
|
|
|
9335
9592
|
}
|
|
9336
9593
|
async runFiles(specs, allTestsRun) {
|
|
9337
9594
|
await this._testRun.start(specs);
|
|
9595
|
+
// previous run
|
|
9338
9596
|
await this.runningPromise;
|
|
9339
9597
|
this._onCancelListeners = [];
|
|
9340
9598
|
this.isCancelling = false;
|
|
9599
|
+
// schedule the new run
|
|
9341
9600
|
this.runningPromise = (async () => {
|
|
9342
9601
|
try {
|
|
9343
|
-
if (!this.pool)
|
|
9344
|
-
this.pool = createPool(this);
|
|
9345
|
-
}
|
|
9602
|
+
if (!this.pool) this.pool = createPool(this);
|
|
9346
9603
|
const invalidates = Array.from(this.watcher.invalidates);
|
|
9347
9604
|
this.watcher.invalidates.clear();
|
|
9348
9605
|
this.snapshot.clear();
|
|
9349
9606
|
this.state.clearErrors();
|
|
9350
|
-
if (!this.isFirstRun && this.config.coverage.cleanOnRerun)
|
|
9351
|
-
await this.coverageProvider?.clean();
|
|
9352
|
-
}
|
|
9607
|
+
if (!this.isFirstRun && this.config.coverage.cleanOnRerun) await this.coverageProvider?.clean();
|
|
9353
9608
|
await this.initializeGlobalSetup(specs);
|
|
9354
9609
|
try {
|
|
9355
9610
|
await this.pool.runTests(specs, invalidates);
|
|
@@ -9357,9 +9612,6 @@ class Vitest {
|
|
|
9357
9612
|
this.state.catchError(err, "Unhandled Error");
|
|
9358
9613
|
}
|
|
9359
9614
|
const files = this.state.getFiles();
|
|
9360
|
-
if (hasFailed(files)) {
|
|
9361
|
-
process.exitCode = 1;
|
|
9362
|
-
}
|
|
9363
9615
|
this.cache.results.updateResults(files);
|
|
9364
9616
|
try {
|
|
9365
9617
|
await this.cache.results.writeToCache();
|
|
@@ -9369,6 +9621,7 @@ class Vitest {
|
|
|
9369
9621
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9370
9622
|
};
|
|
9371
9623
|
} finally {
|
|
9624
|
+
// TODO: wait for coverage only if `onFinished` is defined
|
|
9372
9625
|
const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun });
|
|
9373
9626
|
const errors = this.state.getUnhandledErrors();
|
|
9374
9627
|
this._checkUnhandledErrors(errors);
|
|
@@ -9376,10 +9629,11 @@ class Vitest {
|
|
|
9376
9629
|
await this.reportCoverage(coverage, allTestsRun);
|
|
9377
9630
|
}
|
|
9378
9631
|
})().finally(() => {
|
|
9379
|
-
this.runningPromise =
|
|
9632
|
+
this.runningPromise = void 0;
|
|
9380
9633
|
this.isFirstRun = false;
|
|
9634
|
+
// all subsequent runs will treat this as a fresh run
|
|
9381
9635
|
this.config.changed = false;
|
|
9382
|
-
this.config.related =
|
|
9636
|
+
this.config.related = void 0;
|
|
9383
9637
|
});
|
|
9384
9638
|
return await this.runningPromise;
|
|
9385
9639
|
}
|
|
@@ -9390,13 +9644,13 @@ class Vitest {
|
|
|
9390
9644
|
async collectTests(specifications) {
|
|
9391
9645
|
const filepaths = specifications.map((spec) => spec.moduleId);
|
|
9392
9646
|
this.state.collectPaths(filepaths);
|
|
9647
|
+
// previous run
|
|
9393
9648
|
await this.runningPromise;
|
|
9394
9649
|
this._onCancelListeners = [];
|
|
9395
9650
|
this.isCancelling = false;
|
|
9651
|
+
// schedule the new run
|
|
9396
9652
|
this.runningPromise = (async () => {
|
|
9397
|
-
if (!this.pool)
|
|
9398
|
-
this.pool = createPool(this);
|
|
9399
|
-
}
|
|
9653
|
+
if (!this.pool) this.pool = createPool(this);
|
|
9400
9654
|
const invalidates = Array.from(this.watcher.invalidates);
|
|
9401
9655
|
this.watcher.invalidates.clear();
|
|
9402
9656
|
this.snapshot.clear();
|
|
@@ -9408,17 +9662,18 @@ class Vitest {
|
|
|
9408
9662
|
this.state.catchError(err, "Unhandled Error");
|
|
9409
9663
|
}
|
|
9410
9664
|
const files = this.state.getFiles();
|
|
9411
|
-
if
|
|
9412
|
-
|
|
9413
|
-
|
|
9665
|
+
// can only happen if there was a syntax error in describe block
|
|
9666
|
+
// or there was an error importing a file
|
|
9667
|
+
if (hasFailed(files)) process.exitCode = 1;
|
|
9414
9668
|
return {
|
|
9415
9669
|
testModules: this.state.getTestModules(),
|
|
9416
9670
|
unhandledErrors: this.state.getUnhandledErrors()
|
|
9417
9671
|
};
|
|
9418
9672
|
})().finally(() => {
|
|
9419
|
-
this.runningPromise =
|
|
9673
|
+
this.runningPromise = void 0;
|
|
9674
|
+
// all subsequent runs will treat this as a fresh run
|
|
9420
9675
|
this.config.changed = false;
|
|
9421
|
-
this.config.related =
|
|
9676
|
+
this.config.related = void 0;
|
|
9422
9677
|
});
|
|
9423
9678
|
return await this.runningPromise;
|
|
9424
9679
|
}
|
|
@@ -9437,18 +9692,12 @@ class Vitest {
|
|
|
9437
9692
|
async initializeGlobalSetup(paths) {
|
|
9438
9693
|
const projects = new Set(paths.map((spec) => spec.project));
|
|
9439
9694
|
const coreProject = this.getRootProject();
|
|
9440
|
-
if (!projects.has(coreProject))
|
|
9441
|
-
|
|
9442
|
-
}
|
|
9443
|
-
for (const project of projects) {
|
|
9444
|
-
await project._initializeGlobalSetup();
|
|
9445
|
-
}
|
|
9695
|
+
if (!projects.has(coreProject)) projects.add(coreProject);
|
|
9696
|
+
for (const project of projects) await project._initializeGlobalSetup();
|
|
9446
9697
|
}
|
|
9447
9698
|
/** @internal */
|
|
9448
9699
|
async rerunFiles(files = this.state.getFilepaths(), trigger, allTestsRun = true, resetTestNamePattern = false) {
|
|
9449
|
-
if (resetTestNamePattern)
|
|
9450
|
-
this.configOverride.testNamePattern = undefined;
|
|
9451
|
-
}
|
|
9700
|
+
if (resetTestNamePattern) this.configOverride.testNamePattern = void 0;
|
|
9452
9701
|
if (this.filenamePattern) {
|
|
9453
9702
|
const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
|
|
9454
9703
|
files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
|
|
@@ -9462,37 +9711,30 @@ class Vitest {
|
|
|
9462
9711
|
/** @internal */
|
|
9463
9712
|
async rerunTask(id) {
|
|
9464
9713
|
const task = this.state.idMap.get(id);
|
|
9465
|
-
if (!task) {
|
|
9466
|
-
throw new Error(`Task ${id} was not found`);
|
|
9467
|
-
}
|
|
9714
|
+
if (!task) throw new Error(`Task ${id} was not found`);
|
|
9468
9715
|
const taskNamePattern = task.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9469
9716
|
await this.changeNamePattern(taskNamePattern, [task.file.filepath], "tasks" in task ? "rerun suite" : "rerun test");
|
|
9470
9717
|
}
|
|
9471
9718
|
/** @internal */
|
|
9472
9719
|
async changeProjectName(pattern) {
|
|
9473
|
-
if (pattern === "")
|
|
9474
|
-
|
|
9475
|
-
} else {
|
|
9476
|
-
this.configOverride.project = [pattern];
|
|
9477
|
-
}
|
|
9720
|
+
if (pattern === "") this.configOverride.project = void 0;
|
|
9721
|
+
else this.configOverride.project = [pattern];
|
|
9478
9722
|
await this.vite.restart();
|
|
9479
9723
|
}
|
|
9480
9724
|
/** @internal */
|
|
9481
9725
|
async changeNamePattern(pattern, files = this.state.getFilepaths(), trigger) {
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
const testNamePattern = pattern ? new RegExp(pattern) : undefined;
|
|
9726
|
+
// Empty test name pattern should reset filename pattern as well
|
|
9727
|
+
if (pattern === "") this.filenamePattern = void 0;
|
|
9728
|
+
const testNamePattern = pattern ? new RegExp(pattern) : void 0;
|
|
9486
9729
|
this.configOverride.testNamePattern = testNamePattern;
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
|
|
9490
|
-
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
});
|
|
9730
|
+
// filter only test files that have tests matching the pattern
|
|
9731
|
+
if (testNamePattern) files = files.filter((filepath) => {
|
|
9732
|
+
const files = this.state.getFiles([filepath]);
|
|
9733
|
+
return !files.length || files.some((file) => {
|
|
9734
|
+
const tasks = getTasks(file);
|
|
9735
|
+
return !tasks.length || tasks.some((task) => testNamePattern.test(task.name));
|
|
9494
9736
|
});
|
|
9495
|
-
}
|
|
9737
|
+
});
|
|
9496
9738
|
await this.rerunFiles(files, trigger, pattern === "");
|
|
9497
9739
|
}
|
|
9498
9740
|
/** @internal */
|
|
@@ -9510,6 +9752,7 @@ class Vitest {
|
|
|
9510
9752
|
* @param files The list of files on the file system
|
|
9511
9753
|
*/
|
|
9512
9754
|
async updateSnapshot(files) {
|
|
9755
|
+
// default to failed files
|
|
9513
9756
|
files = files || [...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)];
|
|
9514
9757
|
this.enableSnapshotUpdate();
|
|
9515
9758
|
try {
|
|
@@ -9544,52 +9787,46 @@ class Vitest {
|
|
|
9544
9787
|
* This method doesn't run any tests.
|
|
9545
9788
|
*/
|
|
9546
9789
|
setGlobalTestNamePattern(pattern) {
|
|
9547
|
-
if (pattern instanceof RegExp)
|
|
9548
|
-
|
|
9549
|
-
} else {
|
|
9550
|
-
this.configOverride.testNamePattern = pattern ? new RegExp(pattern) : undefined;
|
|
9551
|
-
}
|
|
9790
|
+
if (pattern instanceof RegExp) this.configOverride.testNamePattern = pattern;
|
|
9791
|
+
else this.configOverride.testNamePattern = pattern ? new RegExp(pattern) : void 0;
|
|
9552
9792
|
}
|
|
9553
9793
|
/**
|
|
9554
9794
|
* Resets the global test name pattern. This method doesn't run any tests.
|
|
9555
9795
|
*/
|
|
9556
9796
|
resetGlobalTestNamePattern() {
|
|
9557
|
-
this.configOverride.testNamePattern =
|
|
9797
|
+
this.configOverride.testNamePattern = void 0;
|
|
9558
9798
|
}
|
|
9559
9799
|
_rerunTimer;
|
|
9800
|
+
// we can't use a single `triggerId` yet because vscode extension relies on this
|
|
9560
9801
|
async scheduleRerun(triggerId) {
|
|
9561
9802
|
const currentCount = this.restartsCount;
|
|
9562
9803
|
clearTimeout(this._rerunTimer);
|
|
9563
9804
|
await this.runningPromise;
|
|
9564
9805
|
clearTimeout(this._rerunTimer);
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
}
|
|
9806
|
+
// server restarted
|
|
9807
|
+
if (this.restartsCount !== currentCount) return;
|
|
9568
9808
|
this._rerunTimer = setTimeout(async () => {
|
|
9569
9809
|
if (this.watcher.changedTests.size === 0) {
|
|
9570
9810
|
this.watcher.invalidates.clear();
|
|
9571
9811
|
return;
|
|
9572
9812
|
}
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
}
|
|
9813
|
+
// server restarted
|
|
9814
|
+
if (this.restartsCount !== currentCount) return;
|
|
9576
9815
|
this.isFirstRun = false;
|
|
9577
9816
|
this.snapshot.clear();
|
|
9578
9817
|
let files = Array.from(this.watcher.changedTests);
|
|
9579
9818
|
if (this.filenamePattern) {
|
|
9580
9819
|
const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
|
|
9581
9820
|
files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
}
|
|
9821
|
+
// A file that does not match the current filename pattern was changed
|
|
9822
|
+
if (files.length === 0) return;
|
|
9585
9823
|
}
|
|
9586
9824
|
this.watcher.changedTests.clear();
|
|
9587
9825
|
const triggerIds = new Set(triggerId.map((id) => relative(this.config.root, id)));
|
|
9588
9826
|
const triggerLabel = Array.from(triggerIds).join(", ");
|
|
9827
|
+
// get file specifications and filter them if needed
|
|
9589
9828
|
const specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
|
|
9590
|
-
if (this._onFilterWatchedSpecification.length === 0)
|
|
9591
|
-
return true;
|
|
9592
|
-
}
|
|
9829
|
+
if (this._onFilterWatchedSpecification.length === 0) return true;
|
|
9593
9830
|
return this._onFilterWatchedSpecification.every((fn) => fn(specification));
|
|
9594
9831
|
});
|
|
9595
9832
|
await Promise.all([this.report("onWatcherRerun", files, triggerLabel), ...this._onUserTestsRerun.map((fn) => fn(specifications))]);
|
|
@@ -9616,24 +9853,17 @@ class Vitest {
|
|
|
9616
9853
|
}
|
|
9617
9854
|
/** @internal */
|
|
9618
9855
|
_checkUnhandledErrors(errors) {
|
|
9619
|
-
if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors)
|
|
9620
|
-
process.exitCode = 1;
|
|
9621
|
-
}
|
|
9856
|
+
if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) process.exitCode = 1;
|
|
9622
9857
|
}
|
|
9623
9858
|
async reportCoverage(coverage, allTestsRun) {
|
|
9624
9859
|
if (this.state.getCountOfFailedTests() > 0) {
|
|
9625
9860
|
await this.coverageProvider?.onTestFailure?.();
|
|
9626
|
-
if (!this.config.coverage.reportOnFailure)
|
|
9627
|
-
return;
|
|
9628
|
-
}
|
|
9861
|
+
if (!this.config.coverage.reportOnFailure) return;
|
|
9629
9862
|
}
|
|
9630
9863
|
if (this.coverageProvider) {
|
|
9631
9864
|
await this.coverageProvider.reportCoverage(coverage, { allTestsRun });
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
reporter.onFinishedReportCoverage();
|
|
9635
|
-
}
|
|
9636
|
-
}
|
|
9865
|
+
// notify coverage iframe reload
|
|
9866
|
+
for (const reporter of this.reporters) if (reporter instanceof WebSocketReporter) reporter.onFinishedReportCoverage();
|
|
9637
9867
|
}
|
|
9638
9868
|
}
|
|
9639
9869
|
/**
|
|
@@ -9641,35 +9871,26 @@ class Vitest {
|
|
|
9641
9871
|
* This can only be called once; the closing promise is cached until the server restarts.
|
|
9642
9872
|
*/
|
|
9643
9873
|
async close() {
|
|
9644
|
-
if (!this.closingPromise) {
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
})());
|
|
9662
|
-
}
|
|
9663
|
-
closePromises.push(...this._onClose.map((fn) => fn()));
|
|
9664
|
-
return Promise.allSettled(closePromises).then((results) => {
|
|
9665
|
-
results.forEach((r) => {
|
|
9666
|
-
if (r.status === "rejected") {
|
|
9667
|
-
this.logger.error("error during close", r.reason);
|
|
9668
|
-
}
|
|
9669
|
-
});
|
|
9874
|
+
if (!this.closingPromise) this.closingPromise = (async () => {
|
|
9875
|
+
const teardownProjects = [...this.projects];
|
|
9876
|
+
if (this.coreWorkspaceProject && !teardownProjects.includes(this.coreWorkspaceProject)) teardownProjects.push(this.coreWorkspaceProject);
|
|
9877
|
+
// do teardown before closing the server
|
|
9878
|
+
for (const project of teardownProjects.reverse()) await project._teardownGlobalSetup();
|
|
9879
|
+
const closePromises = this.projects.map((w) => w.close());
|
|
9880
|
+
// close the core workspace server only once
|
|
9881
|
+
// it's possible that it's not initialized at all because it's not running any tests
|
|
9882
|
+
if (this.coreWorkspaceProject && !this.projects.includes(this.coreWorkspaceProject)) closePromises.push(this.coreWorkspaceProject.close().then(() => this._vite = void 0));
|
|
9883
|
+
if (this.pool) closePromises.push((async () => {
|
|
9884
|
+
await this.pool?.close?.();
|
|
9885
|
+
this.pool = void 0;
|
|
9886
|
+
})());
|
|
9887
|
+
closePromises.push(...this._onClose.map((fn) => fn()));
|
|
9888
|
+
return Promise.allSettled(closePromises).then((results) => {
|
|
9889
|
+
results.forEach((r) => {
|
|
9890
|
+
if (r.status === "rejected") this.logger.error("error during close", r.reason);
|
|
9670
9891
|
});
|
|
9671
|
-
})
|
|
9672
|
-
}
|
|
9892
|
+
});
|
|
9893
|
+
})();
|
|
9673
9894
|
return this.closingPromise;
|
|
9674
9895
|
}
|
|
9675
9896
|
/**
|
|
@@ -9683,31 +9904,23 @@ class Vitest {
|
|
|
9683
9904
|
this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause));
|
|
9684
9905
|
if (!this.pool) {
|
|
9685
9906
|
const runningServers = [this._vite, ...this.projects.map((p) => p._vite)].filter(Boolean).length;
|
|
9686
|
-
if (runningServers === 1)
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
} else {
|
|
9691
|
-
console.warn("Tests closed successfully but something prevents the main process from exiting");
|
|
9692
|
-
}
|
|
9693
|
-
if (!this.reporters.some((r) => r instanceof HangingProcessReporter)) {
|
|
9694
|
-
console.warn("You can try to identify the cause by enabling \"hanging-process\" reporter. See https://vitest.dev/config/#reporters");
|
|
9695
|
-
}
|
|
9907
|
+
if (runningServers === 1) console.warn("Tests closed successfully but something prevents Vite server from exiting");
|
|
9908
|
+
else if (runningServers > 1) console.warn(`Tests closed successfully but something prevents ${runningServers} Vite servers from exiting`);
|
|
9909
|
+
else console.warn("Tests closed successfully but something prevents the main process from exiting");
|
|
9910
|
+
if (!this.reporters.some((r) => r instanceof HangingProcessReporter)) console.warn("You can try to identify the cause by enabling \"hanging-process\" reporter. See https://vitest.dev/config/#reporters");
|
|
9696
9911
|
}
|
|
9697
9912
|
process.exit();
|
|
9698
9913
|
});
|
|
9699
9914
|
}, this.config.teardownTimeout).unref();
|
|
9700
9915
|
await this.close();
|
|
9701
|
-
if (force)
|
|
9702
|
-
process.exit();
|
|
9703
|
-
}
|
|
9916
|
+
if (force) process.exit();
|
|
9704
9917
|
}
|
|
9705
9918
|
/** @internal */
|
|
9706
9919
|
async report(name, ...args) {
|
|
9707
9920
|
await Promise.all(this.reporters.map((r) => r[name]?.(
|
|
9708
9921
|
// @ts-expect-error let me go
|
|
9709
9922
|
...args
|
|
9710
|
-
)));
|
|
9923
|
+
)));
|
|
9711
9924
|
}
|
|
9712
9925
|
/** @internal */
|
|
9713
9926
|
async _globTestFilepaths() {
|
|
@@ -9730,6 +9943,7 @@ class Vitest {
|
|
|
9730
9943
|
getModuleProjects(filepath) {
|
|
9731
9944
|
return this.projects.filter((project) => {
|
|
9732
9945
|
return project.getModulesByFilepath(filepath).size;
|
|
9946
|
+
// TODO: reevaluate || project.browser?.moduleGraph.getModulesByFile(id)?.size
|
|
9733
9947
|
});
|
|
9734
9948
|
}
|
|
9735
9949
|
/**
|
|
@@ -9780,10 +9994,9 @@ class Vitest {
|
|
|
9780
9994
|
* Check if the project with a given name should be included.
|
|
9781
9995
|
*/
|
|
9782
9996
|
matchesProjectFilter(name) {
|
|
9783
|
-
const projects = this._config?.project || this.
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
}
|
|
9997
|
+
const projects = this._config?.project || this._cliOptions?.project;
|
|
9998
|
+
// no filters applied, any project can be included
|
|
9999
|
+
if (!projects || !projects.length) return true;
|
|
9787
10000
|
return toArray(projects).some((project) => {
|
|
9788
10001
|
const regexp = wildcardPatternToRegExp(project);
|
|
9789
10002
|
return regexp.test(name);
|
|
@@ -9791,16 +10004,14 @@ class Vitest {
|
|
|
9791
10004
|
}
|
|
9792
10005
|
}
|
|
9793
10006
|
function assert(condition, property, name = property) {
|
|
9794
|
-
if (!condition) {
|
|
9795
|
-
throw new Error(`The ${name} was not set. It means that \`vitest.${property}\` was called before the Vite server was established. Await the Vitest promise before accessing \`vitest.${property}\`.`);
|
|
9796
|
-
}
|
|
10007
|
+
if (!condition) throw new Error(`The ${name} was not set. It means that \`vitest.${property}\` was called before the Vite server was established. Await the Vitest promise before accessing \`vitest.${property}\`.`);
|
|
9797
10008
|
}
|
|
9798
10009
|
|
|
9799
|
-
async function VitestPlugin(options = {},
|
|
10010
|
+
async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(options))) {
|
|
9800
10011
|
const userConfig = deepMerge({}, options);
|
|
9801
10012
|
async function UIPlugin() {
|
|
9802
|
-
await
|
|
9803
|
-
return (await import('@vitest/ui')).default(
|
|
10013
|
+
await vitest.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), vitest.version);
|
|
10014
|
+
return (await import('@vitest/ui')).default(vitest);
|
|
9804
10015
|
}
|
|
9805
10016
|
return [
|
|
9806
10017
|
{
|
|
@@ -9810,17 +10021,21 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
9810
10021
|
this.meta.watchMode = false;
|
|
9811
10022
|
},
|
|
9812
10023
|
async config(viteConfig) {
|
|
9813
|
-
if (options.watch)
|
|
9814
|
-
|
|
9815
|
-
|
|
10024
|
+
if (options.watch)
|
|
10025
|
+
// Earlier runs have overwritten values of the `options`.
|
|
10026
|
+
// Reset it back to initial user config before setting up the server again.
|
|
10027
|
+
options = deepMerge({}, userConfig);
|
|
10028
|
+
// preliminary merge of options to be able to create server options for vite
|
|
10029
|
+
// however to allow vitest plugins to modify vitest config values
|
|
10030
|
+
// this is repeated in configResolved where the config is final
|
|
9816
10031
|
const testConfig = deepMerge({}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options);
|
|
9817
10032
|
testConfig.api = resolveApiServerConfig(testConfig, defaultPort);
|
|
10033
|
+
// store defines for globalThis to make them
|
|
10034
|
+
// reassignable when running in worker in src/runtime/setup.ts
|
|
9818
10035
|
const defines = deleteDefineConfig(viteConfig);
|
|
9819
10036
|
options.defines = defines;
|
|
9820
10037
|
let open = false;
|
|
9821
|
-
if (testConfig.ui && testConfig.open)
|
|
9822
|
-
open = testConfig.uiBase ?? "/__vitest__/";
|
|
9823
|
-
}
|
|
10038
|
+
if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
|
|
9824
10039
|
const resolveOptions = getDefaultResolveOptions();
|
|
9825
10040
|
const config = {
|
|
9826
10041
|
root: viteConfig.test?.root || options.root,
|
|
@@ -9838,7 +10053,7 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
9838
10053
|
...testConfig.api,
|
|
9839
10054
|
open,
|
|
9840
10055
|
hmr: false,
|
|
9841
|
-
ws: testConfig.api?.middlewareMode ? false :
|
|
10056
|
+
ws: testConfig.api?.middlewareMode ? false : void 0,
|
|
9842
10057
|
preTransformRequests: false,
|
|
9843
10058
|
fs: { allow: resolveFsAllow(options.root || process.cwd(), testConfig.config) }
|
|
9844
10059
|
},
|
|
@@ -9856,95 +10071,81 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
9856
10071
|
deps: testConfig.deps ?? viteConfig.test?.deps
|
|
9857
10072
|
}
|
|
9858
10073
|
};
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9862
|
-
|
|
10074
|
+
// inherit so it's available in VitestOptimizer
|
|
10075
|
+
// I cannot wait to rewrite all of this in Vitest 4
|
|
10076
|
+
if (options.cache != null) config.test.cache = options.cache;
|
|
10077
|
+
if (vitest.configOverride.project)
|
|
10078
|
+
// project filter was set by the user, so we need to filter the project
|
|
10079
|
+
options.project = vitest.configOverride.project;
|
|
10080
|
+
config.customLogger = createViteLogger(vitest.logger, viteConfig.logLevel || "warn", { allowClearScreen: false });
|
|
9863
10081
|
config.customLogger = silenceImportViteIgnoreWarning(config.customLogger);
|
|
10082
|
+
// we want inline dependencies to be resolved by analyser plugin so module graph is populated correctly
|
|
9864
10083
|
if (viteConfig.ssr?.noExternal !== true) {
|
|
9865
10084
|
const inline = testConfig.server?.deps?.inline;
|
|
9866
|
-
if (inline === true) {
|
|
9867
|
-
|
|
9868
|
-
} else {
|
|
10085
|
+
if (inline === true) config.ssr = { noExternal: true };
|
|
10086
|
+
else {
|
|
9869
10087
|
const noExternal = viteConfig.ssr?.noExternal;
|
|
9870
|
-
const noExternalArray = typeof noExternal !== "undefined" ? toArray(noExternal) :
|
|
10088
|
+
const noExternalArray = typeof noExternal !== "undefined" ? toArray(noExternal) : void 0;
|
|
10089
|
+
// filter the same packages
|
|
9871
10090
|
const uniqueInline = inline && noExternalArray ? inline.filter((dep) => !noExternalArray.includes(dep)) : inline;
|
|
9872
10091
|
config.ssr = { noExternal: uniqueInline };
|
|
9873
10092
|
}
|
|
9874
10093
|
}
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
if (watch) {
|
|
9878
|
-
watch.useFsEvents = false;
|
|
9879
|
-
watch.usePolling = false;
|
|
9880
|
-
}
|
|
9881
|
-
}
|
|
10094
|
+
// chokidar fsevents is unstable on macos when emitting "ready" event
|
|
10095
|
+
if (process.platform === "darwin" && false);
|
|
9882
10096
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
9883
10097
|
if (classNameStrategy !== "scoped") {
|
|
9884
10098
|
config.css ??= {};
|
|
9885
10099
|
config.css.modules ??= {};
|
|
9886
|
-
if (config.css.modules) {
|
|
9887
|
-
config.
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
};
|
|
9891
|
-
}
|
|
10100
|
+
if (config.css.modules) config.css.modules.generateScopedName = (name, filename) => {
|
|
10101
|
+
const root = vitest.config.root || options.root || process.cwd();
|
|
10102
|
+
return generateScopedClassName(classNameStrategy, name, relative(root, filename));
|
|
10103
|
+
};
|
|
9892
10104
|
}
|
|
9893
10105
|
return config;
|
|
9894
10106
|
},
|
|
9895
10107
|
async configResolved(viteConfig) {
|
|
9896
10108
|
const viteConfigTest = viteConfig.test || {};
|
|
9897
|
-
if (viteConfigTest.watch === false)
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
if ("alias" in viteConfigTest) {
|
|
9901
|
-
delete viteConfigTest.alias;
|
|
9902
|
-
}
|
|
10109
|
+
if (viteConfigTest.watch === false) viteConfigTest.run = true;
|
|
10110
|
+
if ("alias" in viteConfigTest) delete viteConfigTest.alias;
|
|
10111
|
+
// viteConfig.test is final now, merge it for real
|
|
9903
10112
|
options = deepMerge({}, configDefaults, viteConfigTest, options);
|
|
9904
10113
|
options.api = resolveApiServerConfig(options, defaultPort);
|
|
10114
|
+
// we replace every "import.meta.env" with "process.env"
|
|
10115
|
+
// to allow reassigning, so we need to put all envs on process.env
|
|
9905
10116
|
const { PROD, DEV,...envs } = viteConfig.env;
|
|
10117
|
+
// process.env can have only string values and will cast string on it if we pass other type,
|
|
10118
|
+
// so we are making them truthy
|
|
9906
10119
|
process.env.PROD ??= PROD ? "1" : "";
|
|
9907
10120
|
process.env.DEV ??= DEV ? "1" : "";
|
|
9908
|
-
for (const name in envs)
|
|
9909
|
-
|
|
9910
|
-
|
|
9911
|
-
if (!options.watch) {
|
|
9912
|
-
viteConfig.server.watch = null;
|
|
9913
|
-
}
|
|
10121
|
+
for (const name in envs) process.env[name] ??= envs[name];
|
|
10122
|
+
// don't watch files in run mode
|
|
10123
|
+
if (!options.watch) viteConfig.server.watch = null;
|
|
9914
10124
|
Object.defineProperty(viteConfig, "_vitest", {
|
|
9915
10125
|
value: options,
|
|
9916
10126
|
enumerable: false,
|
|
9917
10127
|
configurable: true
|
|
9918
10128
|
});
|
|
9919
10129
|
const originalName = options.name;
|
|
9920
|
-
if (options.browser?.
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
});
|
|
9924
|
-
}
|
|
10130
|
+
if (options.browser?.instances) options.browser.instances.forEach((instance) => {
|
|
10131
|
+
instance.name ??= originalName ? `${originalName} (${instance.browser})` : instance.browser;
|
|
10132
|
+
});
|
|
9925
10133
|
},
|
|
9926
10134
|
configureServer: {
|
|
9927
10135
|
order: "post",
|
|
9928
10136
|
async handler(server) {
|
|
9929
|
-
if (options.watch &&
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
await ctx._setServer(options, server, userConfig);
|
|
9935
|
-
if (options.api && options.watch) {
|
|
9936
|
-
(await Promise.resolve().then(function () { return setup$1; })).setup(ctx);
|
|
9937
|
-
}
|
|
9938
|
-
if (!options.watch) {
|
|
9939
|
-
await server.watcher.close();
|
|
9940
|
-
}
|
|
10137
|
+
if (options.watch && false);
|
|
10138
|
+
await vitest._setServer(options, server);
|
|
10139
|
+
if (options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(vitest);
|
|
10140
|
+
// #415, in run mode we don't need the watcher, close it would improve the performance
|
|
10141
|
+
if (!options.watch) await server.watcher.close();
|
|
9941
10142
|
}
|
|
9942
10143
|
}
|
|
9943
10144
|
},
|
|
9944
10145
|
SsrReplacerPlugin(),
|
|
9945
|
-
...CSSEnablerPlugin(
|
|
9946
|
-
CoverageTransform(
|
|
9947
|
-
VitestCoreResolver(
|
|
10146
|
+
...CSSEnablerPlugin(vitest),
|
|
10147
|
+
CoverageTransform(vitest),
|
|
10148
|
+
VitestCoreResolver(vitest),
|
|
9948
10149
|
options.ui ? await UIPlugin() : null,
|
|
9949
10150
|
...MocksPlugins(),
|
|
9950
10151
|
VitestOptimizer(),
|
|
@@ -9952,29 +10153,24 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
9952
10153
|
].filter(notNullish);
|
|
9953
10154
|
}
|
|
9954
10155
|
function removeUndefinedValues(obj) {
|
|
9955
|
-
for (const key in Object.keys(obj))
|
|
9956
|
-
if (obj[key] === undefined) {
|
|
9957
|
-
delete obj[key];
|
|
9958
|
-
}
|
|
9959
|
-
}
|
|
10156
|
+
for (const key in Object.keys(obj)) if (obj[key] === void 0) delete obj[key];
|
|
9960
10157
|
return obj;
|
|
9961
10158
|
}
|
|
9962
10159
|
|
|
9963
10160
|
async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) {
|
|
9964
|
-
const ctx = new Vitest(mode, vitestOptions);
|
|
10161
|
+
const ctx = new Vitest(mode, deepClone(options), vitestOptions);
|
|
9965
10162
|
const root = slash(resolve$1(options.root || process.cwd()));
|
|
9966
10163
|
const configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root });
|
|
9967
10164
|
options.config = configPath;
|
|
10165
|
+
const { browser: _removeBrowser,...restOptions } = options;
|
|
9968
10166
|
const config = {
|
|
9969
10167
|
configFile: configPath,
|
|
9970
10168
|
configLoader: options.configLoader,
|
|
9971
10169
|
mode: options.mode || mode,
|
|
9972
|
-
plugins: await VitestPlugin(
|
|
10170
|
+
plugins: await VitestPlugin(restOptions, ctx)
|
|
9973
10171
|
};
|
|
9974
10172
|
const server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })));
|
|
9975
|
-
if (ctx.config.api?.port)
|
|
9976
|
-
await server.listen();
|
|
9977
|
-
}
|
|
10173
|
+
if (ctx.config.api?.port) await server.listen();
|
|
9978
10174
|
return ctx;
|
|
9979
10175
|
}
|
|
9980
10176
|
|
|
@@ -9983,7 +10179,7 @@ const SELECTION_MAX_INDEX = 7;
|
|
|
9983
10179
|
const ESC = "\x1B[";
|
|
9984
10180
|
class WatchFilter {
|
|
9985
10181
|
filterRL;
|
|
9986
|
-
currentKeyword =
|
|
10182
|
+
currentKeyword = void 0;
|
|
9987
10183
|
message;
|
|
9988
10184
|
results = [];
|
|
9989
10185
|
selectionIndex = -1;
|
|
@@ -9999,9 +10195,7 @@ class WatchFilter {
|
|
|
9999
10195
|
escapeCodeTimeout: 50
|
|
10000
10196
|
});
|
|
10001
10197
|
readline.emitKeypressEvents(this.stdin, this.filterRL);
|
|
10002
|
-
if (this.stdin.isTTY)
|
|
10003
|
-
this.stdin.setRawMode(true);
|
|
10004
|
-
}
|
|
10198
|
+
if (this.stdin.isTTY) this.stdin.setRawMode(true);
|
|
10005
10199
|
}
|
|
10006
10200
|
async filter(filterFunc) {
|
|
10007
10201
|
this.write(this.promptLine());
|
|
@@ -10020,57 +10214,41 @@ class WatchFilter {
|
|
|
10020
10214
|
return async (str, key) => {
|
|
10021
10215
|
switch (true) {
|
|
10022
10216
|
case key.sequence === "":
|
|
10023
|
-
if (this.currentKeyword && this.currentKeyword?.length > 1)
|
|
10024
|
-
|
|
10025
|
-
} else {
|
|
10026
|
-
this.currentKeyword = undefined;
|
|
10027
|
-
}
|
|
10217
|
+
if (this.currentKeyword && this.currentKeyword?.length > 1) this.currentKeyword = this.currentKeyword?.slice(0, -1);
|
|
10218
|
+
else this.currentKeyword = void 0;
|
|
10028
10219
|
break;
|
|
10029
10220
|
case key?.ctrl && key?.name === "c":
|
|
10030
10221
|
case key?.name === "escape":
|
|
10031
10222
|
this.write(`${ESC}1G${ESC}0J`);
|
|
10032
|
-
onSubmit(
|
|
10223
|
+
onSubmit(void 0);
|
|
10033
10224
|
return;
|
|
10034
10225
|
case key?.name === "enter":
|
|
10035
10226
|
case key?.name === "return":
|
|
10036
10227
|
onSubmit(this.results[this.selectionIndex] || this.currentKeyword || "");
|
|
10037
|
-
this.currentKeyword =
|
|
10228
|
+
this.currentKeyword = void 0;
|
|
10038
10229
|
break;
|
|
10039
10230
|
case key?.name === "up":
|
|
10040
|
-
if (this.selectionIndex && this.selectionIndex > 0)
|
|
10041
|
-
|
|
10042
|
-
} else {
|
|
10043
|
-
this.selectionIndex = -1;
|
|
10044
|
-
}
|
|
10231
|
+
if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--;
|
|
10232
|
+
else this.selectionIndex = -1;
|
|
10045
10233
|
break;
|
|
10046
10234
|
case key?.name === "down":
|
|
10047
|
-
if (this.selectionIndex < this.results.length - 1)
|
|
10048
|
-
|
|
10049
|
-
} else if (this.selectionIndex >= this.results.length - 1) {
|
|
10050
|
-
this.selectionIndex = this.results.length - 1;
|
|
10051
|
-
}
|
|
10235
|
+
if (this.selectionIndex < this.results.length - 1) this.selectionIndex++;
|
|
10236
|
+
else if (this.selectionIndex >= this.results.length - 1) this.selectionIndex = this.results.length - 1;
|
|
10052
10237
|
break;
|
|
10053
10238
|
case !key?.ctrl && !key?.meta:
|
|
10054
|
-
if (this.currentKeyword ===
|
|
10055
|
-
|
|
10056
|
-
} else {
|
|
10057
|
-
this.currentKeyword += str || "";
|
|
10058
|
-
}
|
|
10239
|
+
if (this.currentKeyword === void 0) this.currentKeyword = str;
|
|
10240
|
+
else this.currentKeyword += str || "";
|
|
10059
10241
|
break;
|
|
10060
10242
|
}
|
|
10061
|
-
if (this.currentKeyword)
|
|
10062
|
-
this.results = await filterFunc(this.currentKeyword);
|
|
10063
|
-
}
|
|
10243
|
+
if (this.currentKeyword) this.results = await filterFunc(this.currentKeyword);
|
|
10064
10244
|
this.render();
|
|
10065
10245
|
};
|
|
10066
10246
|
}
|
|
10067
10247
|
render() {
|
|
10068
10248
|
let printStr = this.promptLine();
|
|
10069
|
-
if (!this.currentKeyword)
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
printStr += "\nPattern matches no results";
|
|
10073
|
-
} else {
|
|
10249
|
+
if (!this.currentKeyword) printStr += "\nPlease input filter pattern";
|
|
10250
|
+
else if (this.currentKeyword && this.results.length === 0) printStr += "\nPattern matches no results";
|
|
10251
|
+
else {
|
|
10074
10252
|
const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`;
|
|
10075
10253
|
let resultBody = "";
|
|
10076
10254
|
if (this.results.length > MAX_RESULT_COUNT) {
|
|
@@ -10078,12 +10256,9 @@ class WatchFilter {
|
|
|
10078
10256
|
const displayResults = this.results.slice(offset, MAX_RESULT_COUNT + offset);
|
|
10079
10257
|
const remainingResultCount = this.results.length - offset - displayResults.length;
|
|
10080
10258
|
resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n")}`;
|
|
10081
|
-
if (remainingResultCount > 0)
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
} else {
|
|
10085
|
-
resultBody = this.results.map((result, index) => index === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n");
|
|
10086
|
-
}
|
|
10259
|
+
if (remainingResultCount > 0) resultBody += `
|
|
10260
|
+
${c.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}`)}`;
|
|
10261
|
+
} else resultBody = this.results.map((result, index) => index === this.selectionIndex ? c.green(` › ${result}`) : c.dim(` › ${result}`)).join("\n");
|
|
10087
10262
|
printStr += `\n${resultCountLine}\n${resultBody}`;
|
|
10088
10263
|
}
|
|
10089
10264
|
this.eraseAndPrint(printStr);
|
|
@@ -10100,6 +10275,7 @@ class WatchFilter {
|
|
|
10100
10275
|
const lines = str.split(/\r?\n/);
|
|
10101
10276
|
for (const line of lines) {
|
|
10102
10277
|
const columns = "columns" in this.stdout ? this.stdout.columns : 80;
|
|
10278
|
+
// We have to take care of screen width in case of long lines
|
|
10103
10279
|
rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns);
|
|
10104
10280
|
}
|
|
10105
10281
|
this.write(`${ESC}1G`);
|
|
@@ -10109,12 +10285,8 @@ class WatchFilter {
|
|
|
10109
10285
|
}
|
|
10110
10286
|
close() {
|
|
10111
10287
|
this.filterRL.close();
|
|
10112
|
-
if (this.onKeyPress)
|
|
10113
|
-
|
|
10114
|
-
}
|
|
10115
|
-
if (this.stdin.isTTY) {
|
|
10116
|
-
this.stdin.setRawMode(false);
|
|
10117
|
-
}
|
|
10288
|
+
if (this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress);
|
|
10289
|
+
if (this.stdin.isTTY) this.stdin.setRawMode(false);
|
|
10118
10290
|
}
|
|
10119
10291
|
restoreCursor() {
|
|
10120
10292
|
const cursortPos = this.keywordOffset() + (this.currentKeyword?.length || 0);
|
|
@@ -10154,6 +10326,8 @@ ${keys.map((i) => c.dim(" press ") + c.reset([i[0]].flat().map(c.bold).join(",
|
|
|
10154
10326
|
function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
10155
10327
|
let latestFilename = "";
|
|
10156
10328
|
async function _keypressHandler(str, key) {
|
|
10329
|
+
// Cancel run and exit when ctrl-c or esc is pressed.
|
|
10330
|
+
// If cancelling takes long and key is pressed multiple times, exit forcefully.
|
|
10157
10331
|
if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") {
|
|
10158
10332
|
if (!ctx.isCancelling) {
|
|
10159
10333
|
ctx.logger.log(c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n"));
|
|
@@ -10162,6 +10336,7 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10162
10336
|
}
|
|
10163
10337
|
return ctx.exit(true);
|
|
10164
10338
|
}
|
|
10339
|
+
// window not support suspend
|
|
10165
10340
|
if (!isWindows && key && key.ctrl && key.name === "z") {
|
|
10166
10341
|
process.kill(process.ppid, "SIGTSTP");
|
|
10167
10342
|
process.kill(process.pid, "SIGTSTP");
|
|
@@ -10169,39 +10344,30 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10169
10344
|
}
|
|
10170
10345
|
const name = key?.name;
|
|
10171
10346
|
if (ctx.runningPromise) {
|
|
10172
|
-
if (cancelKeys.includes(name))
|
|
10173
|
-
await ctx.cancelCurrentRun("keyboard-input");
|
|
10174
|
-
}
|
|
10347
|
+
if (cancelKeys.includes(name)) await ctx.cancelCurrentRun("keyboard-input");
|
|
10175
10348
|
return;
|
|
10176
10349
|
}
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
if (name === "h")
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
return ctx.updateSnapshot();
|
|
10185
|
-
}
|
|
10350
|
+
// quit
|
|
10351
|
+
if (name === "q") return ctx.exit(true);
|
|
10352
|
+
// help
|
|
10353
|
+
if (name === "h") return printShortcutsHelp();
|
|
10354
|
+
// update snapshot
|
|
10355
|
+
if (name === "u") return ctx.updateSnapshot();
|
|
10356
|
+
// rerun all tests
|
|
10186
10357
|
if (name === "a" || name === "return") {
|
|
10187
10358
|
const files = await ctx._globTestFilepaths();
|
|
10188
10359
|
return ctx.changeNamePattern("", files, "rerun all tests");
|
|
10189
10360
|
}
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10193
|
-
if (name === "f")
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
if (name === "
|
|
10200
|
-
return inputNamePattern();
|
|
10201
|
-
}
|
|
10202
|
-
if (name === "p") {
|
|
10203
|
-
return inputFilePattern();
|
|
10204
|
-
}
|
|
10361
|
+
// rerun current pattern tests
|
|
10362
|
+
if (name === "r") return ctx.rerunFiles();
|
|
10363
|
+
// rerun only failed tests
|
|
10364
|
+
if (name === "f") return ctx.rerunFailed();
|
|
10365
|
+
// change project filter
|
|
10366
|
+
if (name === "w") return inputProjectName();
|
|
10367
|
+
// change testNamePattern
|
|
10368
|
+
if (name === "t") return inputNamePattern();
|
|
10369
|
+
// change fileNamePattern
|
|
10370
|
+
if (name === "p") return inputFilePattern();
|
|
10205
10371
|
if (name === "b") {
|
|
10206
10372
|
await ctx._initBrowserServers();
|
|
10207
10373
|
ctx.projects.forEach((project) => {
|
|
@@ -10224,15 +10390,15 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10224
10390
|
const reg = new RegExp(str);
|
|
10225
10391
|
return tests.map((test) => test.name).filter((testName) => testName.match(reg));
|
|
10226
10392
|
} catch {
|
|
10393
|
+
// `new RegExp` may throw error when input is invalid regexp
|
|
10227
10394
|
return [];
|
|
10228
10395
|
}
|
|
10229
10396
|
});
|
|
10230
10397
|
on();
|
|
10231
|
-
if (typeof filter === "undefined")
|
|
10232
|
-
return;
|
|
10233
|
-
}
|
|
10398
|
+
if (typeof filter === "undefined") return;
|
|
10234
10399
|
const files = ctx.state.getFilepaths();
|
|
10235
|
-
|
|
10400
|
+
// if running in standalone mode, Vitest instance doesn't know about any test file
|
|
10401
|
+
const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
|
|
10236
10402
|
await ctx.changeNamePattern(filter?.trim() || "", cliFiles, "change pattern");
|
|
10237
10403
|
}
|
|
10238
10404
|
async function inputProjectName() {
|
|
@@ -10254,12 +10420,10 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10254
10420
|
return files.map((file) => relative(ctx.config.root, file[1]));
|
|
10255
10421
|
});
|
|
10256
10422
|
on();
|
|
10257
|
-
if (typeof filter === "undefined")
|
|
10258
|
-
return;
|
|
10259
|
-
}
|
|
10423
|
+
if (typeof filter === "undefined") return;
|
|
10260
10424
|
latestFilename = filter?.trim() || "";
|
|
10261
10425
|
const lastResults = watchFilter.getLastResults();
|
|
10262
|
-
await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) :
|
|
10426
|
+
await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0);
|
|
10263
10427
|
}
|
|
10264
10428
|
let rl;
|
|
10265
10429
|
function on() {
|
|
@@ -10269,18 +10433,14 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) {
|
|
|
10269
10433
|
escapeCodeTimeout: 50
|
|
10270
10434
|
});
|
|
10271
10435
|
readline.emitKeypressEvents(stdin, rl);
|
|
10272
|
-
if (stdin.isTTY)
|
|
10273
|
-
stdin.setRawMode(true);
|
|
10274
|
-
}
|
|
10436
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
10275
10437
|
stdin.on("keypress", keypressHandler);
|
|
10276
10438
|
}
|
|
10277
10439
|
function off() {
|
|
10278
10440
|
rl?.close();
|
|
10279
|
-
rl =
|
|
10441
|
+
rl = void 0;
|
|
10280
10442
|
stdin.removeListener("keypress", keypressHandler);
|
|
10281
|
-
if (stdin.isTTY)
|
|
10282
|
-
stdin.setRawMode(false);
|
|
10283
|
-
}
|
|
10443
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
10284
10444
|
}
|
|
10285
10445
|
on();
|
|
10286
10446
|
return function cleanup() {
|
|
@@ -10309,28 +10469,17 @@ async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, v
|
|
|
10309
10469
|
const stdin = vitestOptions?.stdin || process.stdin;
|
|
10310
10470
|
const stdout = vitestOptions?.stdout || process.stdout;
|
|
10311
10471
|
let stdinCleanup;
|
|
10312
|
-
if (stdin.isTTY && ctx.config.watch)
|
|
10313
|
-
stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout);
|
|
10314
|
-
}
|
|
10472
|
+
if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout);
|
|
10315
10473
|
ctx.onAfterSetServer(() => {
|
|
10316
|
-
if (ctx.config.standalone)
|
|
10317
|
-
|
|
10318
|
-
} else {
|
|
10319
|
-
ctx.start(cliFilters);
|
|
10320
|
-
}
|
|
10474
|
+
if (ctx.config.standalone) ctx.init();
|
|
10475
|
+
else ctx.start(cliFilters);
|
|
10321
10476
|
});
|
|
10322
10477
|
try {
|
|
10323
|
-
if (ctx.config.mergeReports)
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
await ctx.init();
|
|
10327
|
-
} else {
|
|
10328
|
-
await ctx.start(cliFilters);
|
|
10329
|
-
}
|
|
10478
|
+
if (ctx.config.mergeReports) await ctx.mergeReports();
|
|
10479
|
+
else if (ctx.config.standalone) await ctx.init();
|
|
10480
|
+
else await ctx.start(cliFilters);
|
|
10330
10481
|
} catch (e) {
|
|
10331
|
-
if (e instanceof FilesNotFoundError)
|
|
10332
|
-
return ctx;
|
|
10333
|
-
}
|
|
10482
|
+
if (e instanceof FilesNotFoundError) return ctx;
|
|
10334
10483
|
if (e instanceof GitNotFoundError) {
|
|
10335
10484
|
ctx.logger.error(e.message);
|
|
10336
10485
|
return ctx;
|
|
@@ -10347,9 +10496,7 @@ async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, v
|
|
|
10347
10496
|
ctx.logger.error("\n\n");
|
|
10348
10497
|
return ctx;
|
|
10349
10498
|
}
|
|
10350
|
-
if (ctx.shouldKeepServer())
|
|
10351
|
-
return ctx;
|
|
10352
|
-
}
|
|
10499
|
+
if (ctx.shouldKeepServer()) return ctx;
|
|
10353
10500
|
stdinCleanup?.();
|
|
10354
10501
|
await ctx.close();
|
|
10355
10502
|
return ctx;
|
|
@@ -10358,9 +10505,8 @@ async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions) {
|
|
|
10358
10505
|
process.env.TEST = "true";
|
|
10359
10506
|
process.env.VITEST = "true";
|
|
10360
10507
|
process.env.NODE_ENV ??= "test";
|
|
10361
|
-
if (options.run)
|
|
10362
|
-
|
|
10363
|
-
}
|
|
10508
|
+
if (options.run) options.watch = false;
|
|
10509
|
+
// this shouldn't affect _application root_ that can be changed inside config
|
|
10364
10510
|
const root = resolve(options.root || process.cwd());
|
|
10365
10511
|
const ctx = await createVitest(mode, options, viteOverrides, vitestOptions);
|
|
10366
10512
|
const environmentPackage = getEnvPackageName(ctx.config.environment);
|
|
@@ -10378,24 +10524,16 @@ function processCollected(ctx, files, options) {
|
|
|
10378
10524
|
ctx.logger.printError(error, { project: suite.project });
|
|
10379
10525
|
});
|
|
10380
10526
|
});
|
|
10381
|
-
if (errorsPrinted)
|
|
10382
|
-
|
|
10383
|
-
}
|
|
10384
|
-
if (typeof options.json !== "undefined") {
|
|
10385
|
-
return processJsonOutput(files, options);
|
|
10386
|
-
}
|
|
10527
|
+
if (errorsPrinted) return;
|
|
10528
|
+
if (typeof options.json !== "undefined") return processJsonOutput(files, options);
|
|
10387
10529
|
return formatCollectedAsString(files).forEach((test) => console.log(test));
|
|
10388
10530
|
}
|
|
10389
10531
|
function outputFileList(files, options) {
|
|
10390
|
-
if (typeof options.json !== "undefined")
|
|
10391
|
-
return outputJsonFileList(files, options);
|
|
10392
|
-
}
|
|
10532
|
+
if (typeof options.json !== "undefined") return outputJsonFileList(files, options);
|
|
10393
10533
|
formatFilesAsString(files, options).map((file) => console.log(file));
|
|
10394
10534
|
}
|
|
10395
10535
|
function outputJsonFileList(files, options) {
|
|
10396
|
-
if (typeof options.json === "boolean")
|
|
10397
|
-
return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10398
|
-
}
|
|
10536
|
+
if (typeof options.json === "boolean") return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2));
|
|
10399
10537
|
if (typeof options.json === "string") {
|
|
10400
10538
|
const jsonPath = resolve(options.root || process.cwd(), options.json);
|
|
10401
10539
|
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
@@ -10405,25 +10543,19 @@ function outputJsonFileList(files, options) {
|
|
|
10405
10543
|
function formatFilesAsJSON(files) {
|
|
10406
10544
|
return files.map((file) => {
|
|
10407
10545
|
const result = { file: file.moduleId };
|
|
10408
|
-
if (file.project.name)
|
|
10409
|
-
result.projectName = file.project.name;
|
|
10410
|
-
}
|
|
10546
|
+
if (file.project.name) result.projectName = file.project.name;
|
|
10411
10547
|
return result;
|
|
10412
10548
|
});
|
|
10413
10549
|
}
|
|
10414
10550
|
function formatFilesAsString(files, options) {
|
|
10415
10551
|
return files.map((file) => {
|
|
10416
10552
|
let name = relative(options.root || process.cwd(), file.moduleId);
|
|
10417
|
-
if (file.project.name) {
|
|
10418
|
-
name = `[${file.project.name}] ${name}`;
|
|
10419
|
-
}
|
|
10553
|
+
if (file.project.name) name = `[${file.project.name}] ${name}`;
|
|
10420
10554
|
return name;
|
|
10421
10555
|
});
|
|
10422
10556
|
}
|
|
10423
10557
|
function processJsonOutput(files, options) {
|
|
10424
|
-
if (typeof options.json === "boolean")
|
|
10425
|
-
return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10426
|
-
}
|
|
10558
|
+
if (typeof options.json === "boolean") return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
10427
10559
|
if (typeof options.json === "string") {
|
|
10428
10560
|
const jsonPath = resolve(options.root || process.cwd(), options.json);
|
|
10429
10561
|
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
@@ -10433,28 +10565,20 @@ function processJsonOutput(files, options) {
|
|
|
10433
10565
|
function forEachSuite(modules, callback) {
|
|
10434
10566
|
modules.forEach((testModule) => {
|
|
10435
10567
|
callback(testModule);
|
|
10436
|
-
for (const suite of testModule.children.allSuites())
|
|
10437
|
-
callback(suite);
|
|
10438
|
-
}
|
|
10568
|
+
for (const suite of testModule.children.allSuites()) callback(suite);
|
|
10439
10569
|
});
|
|
10440
10570
|
}
|
|
10441
10571
|
function formatCollectedAsJSON(files) {
|
|
10442
10572
|
const results = [];
|
|
10443
10573
|
files.forEach((file) => {
|
|
10444
10574
|
for (const test of file.children.allTests()) {
|
|
10445
|
-
if (test.result().state === "skipped")
|
|
10446
|
-
continue;
|
|
10447
|
-
}
|
|
10575
|
+
if (test.result().state === "skipped") continue;
|
|
10448
10576
|
const result = {
|
|
10449
10577
|
name: test.fullName,
|
|
10450
10578
|
file: test.module.moduleId
|
|
10451
10579
|
};
|
|
10452
|
-
if (test.project.name)
|
|
10453
|
-
|
|
10454
|
-
}
|
|
10455
|
-
if (test.location) {
|
|
10456
|
-
result.location = test.location;
|
|
10457
|
-
}
|
|
10580
|
+
if (test.project.name) result.projectName = test.project.name;
|
|
10581
|
+
if (test.location) result.location = test.location;
|
|
10458
10582
|
results.push(result);
|
|
10459
10583
|
}
|
|
10460
10584
|
});
|
|
@@ -10464,9 +10588,7 @@ function formatCollectedAsString(testModules) {
|
|
|
10464
10588
|
const results = [];
|
|
10465
10589
|
testModules.forEach((testModule) => {
|
|
10466
10590
|
for (const test of testModule.children.allTests()) {
|
|
10467
|
-
if (test.result().state === "skipped")
|
|
10468
|
-
continue;
|
|
10469
|
-
}
|
|
10591
|
+
if (test.result().state === "skipped") continue;
|
|
10470
10592
|
const fullName = `${test.module.task.name} > ${test.fullName}`;
|
|
10471
10593
|
results.push((test.project.name ? `[${test.project.name}] ` : "") + fullName);
|
|
10472
10594
|
}
|
|
@@ -10479,15 +10601,9 @@ const envPackageNames = {
|
|
|
10479
10601
|
"edge-runtime": "@edge-runtime/vm"
|
|
10480
10602
|
};
|
|
10481
10603
|
function getEnvPackageName(env) {
|
|
10482
|
-
if (env === "node")
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
if (env in envPackageNames) {
|
|
10486
|
-
return envPackageNames[env];
|
|
10487
|
-
}
|
|
10488
|
-
if (env[0] === "." || env[0] === "/") {
|
|
10489
|
-
return null;
|
|
10490
|
-
}
|
|
10604
|
+
if (env === "node") return null;
|
|
10605
|
+
if (env in envPackageNames) return envPackageNames[env];
|
|
10606
|
+
if (env[0] === "." || env[0] === "/") return null;
|
|
10491
10607
|
return `vitest-environment-${env}`;
|
|
10492
10608
|
}
|
|
10493
10609
|
|