vitest 3.0.0-beta.1 → 3.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +12 -9
- package/dist/browser.js +2 -2
- package/dist/chunks/{RandomSequencer.gisBJ77r.js → RandomSequencer.C6x84bNN.js} +4 -3
- package/dist/chunks/{base.CkcgFVQd.js → base.CQ2VEtuH.js} +1 -1
- package/dist/chunks/{cac.CWCZimpS.js → cac.e7qW4xLT.js} +34 -18
- package/dist/chunks/{cli-api.BKUOv0Nc.js → cli-api.CWDlED-m.js} +1126 -537
- package/dist/chunks/{coverage.BoMDb1ip.js → coverage.BWeNbfBa.js} +4 -4
- package/dist/chunks/{creator.DcAcUhMD.js → creator.Ot9GlSGw.js} +16 -14
- package/dist/chunks/{environment.CT0jpO-1.d.ts → environment.d8YfPkTm.d.ts} +1 -3
- package/dist/chunks/{globals.DJTzb7B3.js → globals.BFncSRNA.js} +2 -2
- package/dist/chunks/{index.CkOJwybT.js → index.BBoOXW-l.js} +7 -2
- package/dist/chunks/{index.BqHViJW9.js → index.CkWmZCXU.js} +1 -1
- package/dist/chunks/{index.DKe7vK-G.js → index.CzkCSFCy.js} +670 -628
- package/dist/chunks/{reporters.BZbwTvrM.d.ts → reporters.DCiyjXOg.d.ts} +634 -532
- package/dist/chunks/{resolveConfig.3rGGWga5.js → resolveConfig.C1d7TK-U.js} +5560 -5541
- package/dist/chunks/{runBaseTests.C6huCAng.js → runBaseTests.qNWRkgHj.js} +11 -10
- package/dist/chunks/{setup-common.B5ClyS48.js → setup-common.Cp_bu5q3.js} +1 -1
- package/dist/chunks/types.BOjykUpq.d.ts +27 -0
- package/dist/chunks/{utils.CMUTX-p8.js → utils.Coei4Wlj.js} +1 -1
- package/dist/chunks/{vi.CZKezqeD.js → vi.S4Fq8wSo.js} +2 -1
- package/dist/chunks/{vite.DIfmneq0.d.ts → vite.CRSMFy31.d.ts} +1 -1
- package/dist/chunks/{worker.umPNbBNk.d.ts → worker.R-PA7DpW.d.ts} +1 -1
- package/dist/chunks/{worker.CmzGeuVD.d.ts → worker.XbtCXEXv.d.ts} +4 -3
- package/dist/cli.js +1 -1
- package/dist/config.cjs +1 -0
- package/dist/config.d.ts +6 -8
- package/dist/config.js +1 -0
- package/dist/coverage.d.ts +4 -6
- package/dist/coverage.js +33 -8
- package/dist/environments.d.ts +2 -2
- package/dist/execute.d.ts +2 -2
- package/dist/index.d.ts +11 -14
- package/dist/index.js +2 -2
- package/dist/node.d.ts +22 -17
- package/dist/node.js +66 -32
- package/dist/reporters.d.ts +4 -6
- package/dist/reporters.js +3 -3
- package/dist/runners.d.ts +2 -2
- package/dist/runners.js +3 -3
- package/dist/suite.d.ts +1 -1
- package/dist/workers/forks.js +1 -1
- package/dist/workers/runVmTests.js +7 -7
- package/dist/workers/threads.js +1 -1
- package/dist/workers.d.ts +3 -3
- package/dist/workers.js +1 -1
- package/package.json +15 -15
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { existsSync, promises, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { createFileTask, limitConcurrency, getTasks, hasFailed, getTests, getNames } from '@vitest/runner/utils';
|
|
3
2
|
import { normalize, relative, dirname, resolve, join, basename, isAbsolute } from 'pathe';
|
|
4
|
-
import { g as getCoverageProvider, C as CoverageProviderMap } from './coverage.
|
|
3
|
+
import { g as getCoverageProvider, C as CoverageProviderMap } from './coverage.BWeNbfBa.js';
|
|
5
4
|
import a, { resolve as resolve$1 } from 'node:path';
|
|
6
|
-
import { noop, isPrimitive, toArray, deepMerge, nanoid, slash,
|
|
5
|
+
import { noop, isPrimitive, createDefer, toArray, deepMerge, nanoid, slash, deepClone, notNullish } from '@vitest/utils';
|
|
7
6
|
import { f as findUp, p as prompt } from './index.BJDntFik.js';
|
|
8
7
|
import { searchForWorkspaceRoot, version, createServer, mergeConfig } from 'vite';
|
|
9
8
|
import { A as API_PATH, c as configFiles, a as defaultBrowserPort, w as workspacesFiles, d as defaultPort } from './constants.fzPh7AOq.js';
|
|
9
|
+
import { createFileTask, limitConcurrency, getTasks, hasFailed, getTests } from '@vitest/runner/utils';
|
|
10
10
|
import { SnapshotManager } from '@vitest/snapshot/manager';
|
|
11
|
-
import { e as groupBy, i as isPackageExists, f as requireMicromatch, V as VitestCache, h as configDefaults, g as getFilePoolName, j as isBrowserEnabled, m as mm, b as resolveConfig, w as wildcardPatternToRegExp, k as createPool, a as resolveApiServerConfig, c as coverageConfigDefaults, s as stdout } from './resolveConfig.3rGGWga5.js';
|
|
12
11
|
import { ViteNodeRunner } from 'vite-node/client';
|
|
13
12
|
import { ViteNodeServer } from 'vite-node/server';
|
|
14
|
-
import { v as version$1 } from './cac.
|
|
13
|
+
import { v as version$1 } from './cac.e7qW4xLT.js';
|
|
15
14
|
import { c as createBirpc } from './index.68735LiX.js';
|
|
16
|
-
import { s as stringify, p as parse, i as generateCodeFrame, R as ReportersMap, h as BenchmarkReportsMap, f as TestModule, g as TestSuite, e as TestCase, L as Logger, j as BlobReporter, r as readBlobs } from './index.
|
|
15
|
+
import { s as stringify, p as parse, i as generateCodeFrame, R as ReportersMap, h as BenchmarkReportsMap, f as TestModule, g as TestSuite, e as TestCase, L as Logger, j as BlobReporter, r as readBlobs } from './index.CzkCSFCy.js';
|
|
17
16
|
import require$$0$2 from 'stream';
|
|
18
17
|
import require$$0 from 'zlib';
|
|
19
18
|
import require$$0$1 from 'buffer';
|
|
@@ -27,11 +26,11 @@ import require$$7 from 'url';
|
|
|
27
26
|
import { g as getDefaultExportFromCjs, c as commonjsGlobal } from './_commonjsHelpers.BFTU3MAI.js';
|
|
28
27
|
import { parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
29
28
|
import { distDir, rootDir } from '../path.js';
|
|
29
|
+
import { i as isPackageExists, e as requireMicromatch, V as VitestCache, f as configDefaults, g as getFilePoolName, h as isBrowserEnabled, m as mm, a as resolveConfig, j as groupBy, w as wildcardPatternToRegExp, k as createPool, b as resolveApiServerConfig, c as coverageConfigDefaults, s as stdout } from './resolveConfig.C1d7TK-U.js';
|
|
30
30
|
import { createRequire } from 'node:module';
|
|
31
31
|
import url from 'node:url';
|
|
32
32
|
import c from 'tinyrainbow';
|
|
33
|
-
import { h as hash, i as isWindows } from './RandomSequencer.
|
|
34
|
-
import { isCI } from 'std-env';
|
|
33
|
+
import { b as isTTY, h as hash, i as isWindows } from './RandomSequencer.C6x84bNN.js';
|
|
35
34
|
import { rm } from 'node:fs/promises';
|
|
36
35
|
import nodeos__default, { tmpdir } from 'node:os';
|
|
37
36
|
import require$$0$4 from 'os';
|
|
@@ -40,6 +39,7 @@ import require$$0$6 from 'fs';
|
|
|
40
39
|
import { normalizeRequestId, cleanUrl } from 'vite-node/utils';
|
|
41
40
|
import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node';
|
|
42
41
|
import MagicString from 'magic-string';
|
|
42
|
+
import { w as withLabel } from './utils.Coei4Wlj.js';
|
|
43
43
|
import readline from 'node:readline';
|
|
44
44
|
import { stripVTControlCharacters } from 'node:util';
|
|
45
45
|
|
|
@@ -4931,7 +4931,7 @@ function setup(ctx, _server) {
|
|
|
4931
4931
|
await ctx.rerunTask(id);
|
|
4932
4932
|
},
|
|
4933
4933
|
getConfig() {
|
|
4934
|
-
return ctx.
|
|
4934
|
+
return ctx.getRootProject().serializedConfig;
|
|
4935
4935
|
},
|
|
4936
4936
|
async getTransformResult(projectName, id, browser = false) {
|
|
4937
4937
|
const project = ctx.getProjectByName(projectName);
|
|
@@ -4947,17 +4947,18 @@ function setup(ctx, _server) {
|
|
|
4947
4947
|
async getModuleGraph(project, id, browser) {
|
|
4948
4948
|
return getModuleGraph(ctx, project, id, browser);
|
|
4949
4949
|
},
|
|
4950
|
-
updateSnapshot(file) {
|
|
4950
|
+
async updateSnapshot(file) {
|
|
4951
4951
|
if (!file) {
|
|
4952
|
-
|
|
4952
|
+
await ctx.updateSnapshot();
|
|
4953
|
+
} else {
|
|
4954
|
+
await ctx.updateSnapshot([file.filepath]);
|
|
4953
4955
|
}
|
|
4954
|
-
return ctx.updateSnapshot([file.filepath]);
|
|
4955
4956
|
},
|
|
4956
4957
|
getUnhandledErrors() {
|
|
4957
4958
|
return ctx.state.getUnhandledErrors();
|
|
4958
4959
|
},
|
|
4959
4960
|
async getTestFiles() {
|
|
4960
|
-
const spec = await ctx.
|
|
4961
|
+
const spec = await ctx.globTestSpecifications();
|
|
4961
4962
|
return spec.map((spec2) => [
|
|
4962
4963
|
{
|
|
4963
4964
|
name: spec2.project.config.name,
|
|
@@ -5019,15 +5020,18 @@ class WebSocketReporter {
|
|
|
5019
5020
|
return;
|
|
5020
5021
|
}
|
|
5021
5022
|
packs.forEach(([taskId, result]) => {
|
|
5022
|
-
const project = this.ctx.getProjectByTaskId(taskId);
|
|
5023
5023
|
const task = this.ctx.state.idMap.get(taskId);
|
|
5024
5024
|
const isBrowser = task && task.file.pool === "browser";
|
|
5025
5025
|
result?.errors?.forEach((error) => {
|
|
5026
5026
|
if (isPrimitive(error)) {
|
|
5027
5027
|
return;
|
|
5028
5028
|
}
|
|
5029
|
-
|
|
5030
|
-
|
|
5029
|
+
if (isBrowser) {
|
|
5030
|
+
const project = this.ctx.getProjectByName(task.file.projectName || "");
|
|
5031
|
+
error.stacks = project.browser?.parseErrorStacktrace(error);
|
|
5032
|
+
} else {
|
|
5033
|
+
error.stacks = parseErrorStacktrace(error);
|
|
5034
|
+
}
|
|
5031
5035
|
});
|
|
5032
5036
|
});
|
|
5033
5037
|
this.clients.forEach((client) => {
|
|
@@ -5057,6 +5061,33 @@ var setup$1 = /*#__PURE__*/Object.freeze({
|
|
|
5057
5061
|
setup: setup
|
|
5058
5062
|
});
|
|
5059
5063
|
|
|
5064
|
+
class BrowserSessions {
|
|
5065
|
+
sessions = /* @__PURE__ */ new Map();
|
|
5066
|
+
getSession(sessionId) {
|
|
5067
|
+
return this.sessions.get(sessionId);
|
|
5068
|
+
}
|
|
5069
|
+
createAsyncSession(method, sessionId, files, project) {
|
|
5070
|
+
const defer = createDefer();
|
|
5071
|
+
const timeout = setTimeout(() => {
|
|
5072
|
+
defer.reject(new Error(`Failed to connect to the browser session "${sessionId}" within the timeout.`));
|
|
5073
|
+
}, project.vitest.config.browser.connectTimeout ?? 6e4).unref();
|
|
5074
|
+
this.sessions.set(sessionId, {
|
|
5075
|
+
files,
|
|
5076
|
+
method,
|
|
5077
|
+
project,
|
|
5078
|
+
connected: () => {
|
|
5079
|
+
clearTimeout(timeout);
|
|
5080
|
+
},
|
|
5081
|
+
resolve: () => {
|
|
5082
|
+
defer.resolve();
|
|
5083
|
+
this.sessions.delete(sessionId);
|
|
5084
|
+
},
|
|
5085
|
+
reject: defer.reject
|
|
5086
|
+
});
|
|
5087
|
+
return defer;
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
|
|
5060
5091
|
class FilesNotFoundError extends Error {
|
|
5061
5092
|
code = "VITEST_FILES_NOT_FOUND";
|
|
5062
5093
|
constructor(mode) {
|
|
@@ -5088,41 +5119,6 @@ class RangeLocationFilterProvidedError extends Error {
|
|
|
5088
5119
|
}
|
|
5089
5120
|
}
|
|
5090
5121
|
|
|
5091
|
-
function parseFilter(filter) {
|
|
5092
|
-
const colonIndex = filter.lastIndexOf(":");
|
|
5093
|
-
if (colonIndex === -1) {
|
|
5094
|
-
return { filename: filter };
|
|
5095
|
-
}
|
|
5096
|
-
const [parsedFilename, lineNumber] = [
|
|
5097
|
-
filter.substring(0, colonIndex),
|
|
5098
|
-
filter.substring(colonIndex + 1)
|
|
5099
|
-
];
|
|
5100
|
-
if (lineNumber.match(/^\d+$/)) {
|
|
5101
|
-
return {
|
|
5102
|
-
filename: parsedFilename,
|
|
5103
|
-
lineNumber: Number.parseInt(lineNumber)
|
|
5104
|
-
};
|
|
5105
|
-
} else if (lineNumber.match(/^\d+-\d+$/)) {
|
|
5106
|
-
throw new RangeLocationFilterProvidedError(filter);
|
|
5107
|
-
} else {
|
|
5108
|
-
return { filename: filter };
|
|
5109
|
-
}
|
|
5110
|
-
}
|
|
5111
|
-
function groupFilters(filters) {
|
|
5112
|
-
const groupedFilters_ = groupBy(filters, (f) => f.filename);
|
|
5113
|
-
const groupedFilters = Object.fromEntries(
|
|
5114
|
-
Object.entries(groupedFilters_).map((entry) => {
|
|
5115
|
-
const [filename, filters2] = entry;
|
|
5116
|
-
const testLocations = filters2.map((f) => f.lineNumber);
|
|
5117
|
-
return [
|
|
5118
|
-
filename,
|
|
5119
|
-
testLocations.filter((l) => l !== void 0)
|
|
5120
|
-
];
|
|
5121
|
-
})
|
|
5122
|
-
);
|
|
5123
|
-
return groupedFilters;
|
|
5124
|
-
}
|
|
5125
|
-
|
|
5126
5122
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
5127
5123
|
class VitestPackageInstaller {
|
|
5128
5124
|
isPackageExists(name, options) {
|
|
@@ -5143,7 +5139,6 @@ class VitestPackageInstaller {
|
|
|
5143
5139
|
if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] })) {
|
|
5144
5140
|
return true;
|
|
5145
5141
|
}
|
|
5146
|
-
const promptInstall = !isCI && process.stdout.isTTY;
|
|
5147
5142
|
process.stderr.write(
|
|
5148
5143
|
c.red(
|
|
5149
5144
|
`${c.inverse(
|
|
@@ -5153,11 +5148,11 @@ class VitestPackageInstaller {
|
|
|
5153
5148
|
`
|
|
5154
5149
|
)
|
|
5155
5150
|
);
|
|
5156
|
-
if (!
|
|
5151
|
+
if (!isTTY) {
|
|
5157
5152
|
return false;
|
|
5158
5153
|
}
|
|
5159
5154
|
const prompts = await import('./index.BJDntFik.js').then(function (n) { return n.i; });
|
|
5160
|
-
const { install } = await prompts.
|
|
5155
|
+
const { install } = await prompts.default({
|
|
5161
5156
|
type: "confirm",
|
|
5162
5157
|
name: "install",
|
|
5163
5158
|
message: c.reset(`Do you want to install ${c.green(dependency)}?`)
|
|
@@ -9514,8 +9509,8 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
9514
9509
|
middlewareMode: true,
|
|
9515
9510
|
fs: {
|
|
9516
9511
|
allow: resolveFsAllow(
|
|
9517
|
-
project.
|
|
9518
|
-
project.
|
|
9512
|
+
project.vitest.config.root,
|
|
9513
|
+
project.vitest.server.config.configFile
|
|
9519
9514
|
)
|
|
9520
9515
|
}
|
|
9521
9516
|
},
|
|
@@ -9593,20 +9588,31 @@ class TestSpecification {
|
|
|
9593
9588
|
* @deprecated use `pool` instead
|
|
9594
9589
|
*/
|
|
9595
9590
|
2;
|
|
9591
|
+
/**
|
|
9592
|
+
* The test project that the module belongs to.
|
|
9593
|
+
*/
|
|
9596
9594
|
project;
|
|
9595
|
+
/**
|
|
9596
|
+
* The ID of the module in the Vite module graph. It is usually an absolute file path.
|
|
9597
|
+
*/
|
|
9597
9598
|
moduleId;
|
|
9599
|
+
/**
|
|
9600
|
+
* The current test pool. It's possible to have multiple pools in a single test project with `poolMatchGlob` and `typecheck.enabled`.
|
|
9601
|
+
* @experimental In Vitest 4, the project will only support a single pool and this property will be removed.
|
|
9602
|
+
*/
|
|
9598
9603
|
pool;
|
|
9599
|
-
/**
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9604
|
+
/**
|
|
9605
|
+
* Line numbers of the test locations to run.
|
|
9606
|
+
*/
|
|
9607
|
+
testLines;
|
|
9608
|
+
constructor(project, moduleId, pool, testLines) {
|
|
9603
9609
|
this[0] = project;
|
|
9604
9610
|
this[1] = moduleId;
|
|
9605
9611
|
this[2] = { pool };
|
|
9606
9612
|
this.project = project;
|
|
9607
9613
|
this.moduleId = moduleId;
|
|
9608
9614
|
this.pool = pool;
|
|
9609
|
-
this.
|
|
9615
|
+
this.testLines = testLines;
|
|
9610
9616
|
}
|
|
9611
9617
|
toJSON() {
|
|
9612
9618
|
return [
|
|
@@ -9615,7 +9621,7 @@ class TestSpecification {
|
|
|
9615
9621
|
root: this.project.config.root
|
|
9616
9622
|
},
|
|
9617
9623
|
this.moduleId,
|
|
9618
|
-
{ pool: this.pool }
|
|
9624
|
+
{ pool: this.pool, testLines: this.testLines }
|
|
9619
9625
|
];
|
|
9620
9626
|
}
|
|
9621
9627
|
/**
|
|
@@ -9669,15 +9675,18 @@ class TestProject {
|
|
|
9669
9675
|
* Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
|
|
9670
9676
|
*/
|
|
9671
9677
|
tmpDir = join(tmpdir(), nanoid());
|
|
9678
|
+
/** @internal */
|
|
9672
9679
|
vitenode;
|
|
9673
|
-
|
|
9680
|
+
/** @internal */
|
|
9674
9681
|
typechecker;
|
|
9682
|
+
/** @internal */
|
|
9683
|
+
_config;
|
|
9684
|
+
runner;
|
|
9675
9685
|
closingPromise;
|
|
9676
9686
|
testFilesList = null;
|
|
9677
9687
|
typecheckFilesList = null;
|
|
9678
9688
|
_globalSetups;
|
|
9679
9689
|
_provided = {};
|
|
9680
|
-
_config;
|
|
9681
9690
|
_vite;
|
|
9682
9691
|
// "provide" is a property, not a method to keep the context when destructed in the global setup,
|
|
9683
9692
|
// making it a method would be a breaking change, and can be done in Vitest 3 at minimum
|
|
@@ -9705,7 +9714,7 @@ class TestProject {
|
|
|
9705
9714
|
return this._provided;
|
|
9706
9715
|
}
|
|
9707
9716
|
return {
|
|
9708
|
-
...this.vitest.
|
|
9717
|
+
...this.vitest.getRootProject().getProvidedContext(),
|
|
9709
9718
|
...this._provided
|
|
9710
9719
|
};
|
|
9711
9720
|
}
|
|
@@ -9713,12 +9722,12 @@ class TestProject {
|
|
|
9713
9722
|
* Creates a new test specification. Specifications describe how to run tests.
|
|
9714
9723
|
* @param moduleId The file path
|
|
9715
9724
|
*/
|
|
9716
|
-
createSpecification(moduleId,
|
|
9725
|
+
createSpecification(moduleId, locations, pool) {
|
|
9717
9726
|
return new TestSpecification(
|
|
9718
9727
|
this,
|
|
9719
9728
|
moduleId,
|
|
9720
9729
|
pool || getFilePoolName(this, moduleId),
|
|
9721
|
-
|
|
9730
|
+
locations
|
|
9722
9731
|
);
|
|
9723
9732
|
}
|
|
9724
9733
|
toJSON() {
|
|
@@ -9735,6 +9744,11 @@ class TestProject {
|
|
|
9735
9744
|
if (!this._vite) {
|
|
9736
9745
|
throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
|
|
9737
9746
|
}
|
|
9747
|
+
Object.defineProperty(this, "vite", {
|
|
9748
|
+
configurable: true,
|
|
9749
|
+
writable: true,
|
|
9750
|
+
value: this._vite
|
|
9751
|
+
});
|
|
9738
9752
|
return this._vite;
|
|
9739
9753
|
}
|
|
9740
9754
|
/**
|
|
@@ -9766,7 +9780,7 @@ class TestProject {
|
|
|
9766
9780
|
* Check if this is the root project. The root project is the one that has the root config.
|
|
9767
9781
|
*/
|
|
9768
9782
|
isRootProject() {
|
|
9769
|
-
return this.vitest.
|
|
9783
|
+
return this.vitest.getRootProject() === this;
|
|
9770
9784
|
}
|
|
9771
9785
|
/** @deprecated use `isRootProject` instead */
|
|
9772
9786
|
isCore() {
|
|
@@ -9893,22 +9907,21 @@ class TestProject {
|
|
|
9893
9907
|
isBrowserEnabled() {
|
|
9894
9908
|
return isBrowserEnabled(this.config);
|
|
9895
9909
|
}
|
|
9896
|
-
|
|
9897
|
-
_markTestFile(testPath) {
|
|
9910
|
+
markTestFile(testPath) {
|
|
9898
9911
|
this.testFilesList?.push(testPath);
|
|
9899
9912
|
}
|
|
9900
9913
|
/**
|
|
9901
9914
|
* Returns if the file is a test file. Requires `.globTestFiles()` to be called first.
|
|
9902
9915
|
* @internal
|
|
9903
9916
|
*/
|
|
9904
|
-
|
|
9917
|
+
isCachedTestFile(testPath) {
|
|
9905
9918
|
return !!this.testFilesList && this.testFilesList.includes(testPath);
|
|
9906
9919
|
}
|
|
9907
9920
|
/**
|
|
9908
9921
|
* Returns if the file is a typecheck test file. Requires `.globTestFiles()` to be called first.
|
|
9909
9922
|
* @internal
|
|
9910
9923
|
*/
|
|
9911
|
-
|
|
9924
|
+
isCachedTypecheckFile(testPath) {
|
|
9912
9925
|
return !!this.typecheckFilesList && this.typecheckFilesList.includes(testPath);
|
|
9913
9926
|
}
|
|
9914
9927
|
/** @deprecated use `serializedConfig` instead */
|
|
@@ -9926,25 +9939,32 @@ class TestProject {
|
|
|
9926
9939
|
return files.map((file) => slash(a.resolve(cwd, file)));
|
|
9927
9940
|
}
|
|
9928
9941
|
/**
|
|
9929
|
-
* Test if a file matches the test globs. This does the actual glob matching unlike `
|
|
9942
|
+
* Test if a file matches the test globs. This does the actual glob matching if the test is not cached, unlike `isCachedTestFile`.
|
|
9930
9943
|
*/
|
|
9931
|
-
matchesTestGlob(
|
|
9932
|
-
|
|
9944
|
+
matchesTestGlob(moduleId, source) {
|
|
9945
|
+
if (this.isCachedTestFile(moduleId)) {
|
|
9946
|
+
return true;
|
|
9947
|
+
}
|
|
9948
|
+
const relativeId = relative(this.config.dir || this.config.root, moduleId);
|
|
9933
9949
|
if (mm.isMatch(relativeId, this.config.exclude)) {
|
|
9934
9950
|
return false;
|
|
9935
9951
|
}
|
|
9936
9952
|
if (mm.isMatch(relativeId, this.config.include)) {
|
|
9953
|
+
this.markTestFile(moduleId);
|
|
9937
9954
|
return true;
|
|
9938
9955
|
}
|
|
9939
9956
|
if (this.config.includeSource?.length && mm.isMatch(relativeId, this.config.includeSource)) {
|
|
9940
|
-
const code = source || readFileSync(
|
|
9941
|
-
|
|
9957
|
+
const code = source?.() || readFileSync(moduleId, "utf-8");
|
|
9958
|
+
if (this.isInSourceTestCode(code)) {
|
|
9959
|
+
this.markTestFile(moduleId);
|
|
9960
|
+
return true;
|
|
9961
|
+
}
|
|
9942
9962
|
}
|
|
9943
9963
|
return false;
|
|
9944
9964
|
}
|
|
9945
9965
|
/** @deprecated use `matchesTestGlob` instead */
|
|
9946
9966
|
async isTargetFile(id, source) {
|
|
9947
|
-
return this.matchesTestGlob(id, source);
|
|
9967
|
+
return this.matchesTestGlob(id, source ? () => source : void 0);
|
|
9948
9968
|
}
|
|
9949
9969
|
isInSourceTestCode(code) {
|
|
9950
9970
|
return code.includes("import.meta.vitest");
|
|
@@ -9968,11 +9988,19 @@ class TestProject {
|
|
|
9968
9988
|
return testFiles;
|
|
9969
9989
|
}
|
|
9970
9990
|
/** @internal */
|
|
9971
|
-
|
|
9972
|
-
|
|
9991
|
+
_parentBrowser;
|
|
9992
|
+
/** @internal */
|
|
9993
|
+
_parent;
|
|
9994
|
+
/** @internal */
|
|
9995
|
+
_initParentBrowser = deduped(async () => {
|
|
9996
|
+
if (!this.isBrowserEnabled() || this._parentBrowser) {
|
|
9973
9997
|
return;
|
|
9974
9998
|
}
|
|
9975
|
-
await this.vitest.packageInstaller.ensureInstalled(
|
|
9999
|
+
await this.vitest.packageInstaller.ensureInstalled(
|
|
10000
|
+
"@vitest/browser",
|
|
10001
|
+
this.config.root,
|
|
10002
|
+
this.vitest.version
|
|
10003
|
+
);
|
|
9976
10004
|
const { createBrowserServer, distRoot } = await import('@vitest/browser');
|
|
9977
10005
|
const browser = await createBrowserServer(
|
|
9978
10006
|
this,
|
|
@@ -9987,13 +10015,20 @@ class TestProject {
|
|
|
9987
10015
|
}
|
|
9988
10016
|
})
|
|
9989
10017
|
],
|
|
9990
|
-
[CoverageTransform(this.
|
|
10018
|
+
[CoverageTransform(this.vitest)]
|
|
9991
10019
|
);
|
|
9992
|
-
this.
|
|
10020
|
+
this._parentBrowser = browser;
|
|
9993
10021
|
if (this.config.browser.ui) {
|
|
9994
10022
|
setup(this.vitest, browser.vite);
|
|
9995
10023
|
}
|
|
9996
|
-
}
|
|
10024
|
+
});
|
|
10025
|
+
/** @internal */
|
|
10026
|
+
_initBrowserServer = deduped(async () => {
|
|
10027
|
+
await this._parent?._initParentBrowser();
|
|
10028
|
+
if (!this.browser && this._parent?._parentBrowser) {
|
|
10029
|
+
this.browser = this._parent._parentBrowser.spawn(this);
|
|
10030
|
+
}
|
|
10031
|
+
});
|
|
9997
10032
|
/**
|
|
9998
10033
|
* Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
|
|
9999
10034
|
* If the resources are needed again, create a new project.
|
|
@@ -10014,6 +10049,13 @@ class TestProject {
|
|
|
10014
10049
|
}
|
|
10015
10050
|
return this.closingPromise;
|
|
10016
10051
|
}
|
|
10052
|
+
/**
|
|
10053
|
+
* Import a file using Vite module runner.
|
|
10054
|
+
* @param moduleId The ID of the module in Vite module graph
|
|
10055
|
+
*/
|
|
10056
|
+
import(moduleId) {
|
|
10057
|
+
return this.runner.executeId(moduleId);
|
|
10058
|
+
}
|
|
10017
10059
|
/** @deprecated use `name` instead */
|
|
10018
10060
|
getName() {
|
|
10019
10061
|
return this.config.name || "";
|
|
@@ -10080,14 +10122,24 @@ class TestProject {
|
|
|
10080
10122
|
return this._initBrowserProvider();
|
|
10081
10123
|
}
|
|
10082
10124
|
/** @internal */
|
|
10083
|
-
async
|
|
10125
|
+
_initBrowserProvider = deduped(async () => {
|
|
10084
10126
|
if (!this.isBrowserEnabled() || this.browser?.provider) {
|
|
10085
10127
|
return;
|
|
10086
10128
|
}
|
|
10087
10129
|
if (!this.browser) {
|
|
10088
10130
|
await this._initBrowserServer();
|
|
10089
10131
|
}
|
|
10090
|
-
await this.browser?.initBrowserProvider();
|
|
10132
|
+
await this.browser?.initBrowserProvider(this);
|
|
10133
|
+
});
|
|
10134
|
+
/** @internal */
|
|
10135
|
+
_provideObject(context) {
|
|
10136
|
+
for (const _providedKey in context) {
|
|
10137
|
+
const providedKey = _providedKey;
|
|
10138
|
+
this.provide(
|
|
10139
|
+
providedKey,
|
|
10140
|
+
context[providedKey]
|
|
10141
|
+
);
|
|
10142
|
+
}
|
|
10091
10143
|
}
|
|
10092
10144
|
/** @internal */
|
|
10093
10145
|
static _createBasicProject(vitest) {
|
|
@@ -10099,15 +10151,34 @@ class TestProject {
|
|
|
10099
10151
|
project.runner = vitest.runner;
|
|
10100
10152
|
project._vite = vitest.server;
|
|
10101
10153
|
project._config = vitest.config;
|
|
10102
|
-
|
|
10103
|
-
const providedKey = _providedKey;
|
|
10104
|
-
project.provide(
|
|
10105
|
-
providedKey,
|
|
10106
|
-
vitest.config.provide[providedKey]
|
|
10107
|
-
);
|
|
10108
|
-
}
|
|
10154
|
+
project._provideObject(vitest.config.provide);
|
|
10109
10155
|
return project;
|
|
10110
10156
|
}
|
|
10157
|
+
/** @internal */
|
|
10158
|
+
static _cloneBrowserProject(parent, config) {
|
|
10159
|
+
const clone = new TestProject(
|
|
10160
|
+
parent.path,
|
|
10161
|
+
parent.vitest
|
|
10162
|
+
);
|
|
10163
|
+
clone.vitenode = parent.vitenode;
|
|
10164
|
+
clone.runner = parent.runner;
|
|
10165
|
+
clone._vite = parent._vite;
|
|
10166
|
+
clone._config = config;
|
|
10167
|
+
clone._parent = parent;
|
|
10168
|
+
clone._provideObject(config.provide);
|
|
10169
|
+
return clone;
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
function deduped(cb) {
|
|
10173
|
+
let _promise;
|
|
10174
|
+
return (...args) => {
|
|
10175
|
+
if (!_promise) {
|
|
10176
|
+
_promise = cb(...args).finally(() => {
|
|
10177
|
+
_promise = void 0;
|
|
10178
|
+
});
|
|
10179
|
+
}
|
|
10180
|
+
return _promise;
|
|
10181
|
+
};
|
|
10111
10182
|
}
|
|
10112
10183
|
async function initializeProject(workspacePath, ctx, options) {
|
|
10113
10184
|
const project = new TestProject(workspacePath, ctx, options);
|
|
@@ -10192,6 +10263,192 @@ function createBenchmarkReporters(reporterReferences, runner) {
|
|
|
10192
10263
|
return Promise.all(promisedReporters);
|
|
10193
10264
|
}
|
|
10194
10265
|
|
|
10266
|
+
function parseFilter(filter) {
|
|
10267
|
+
const colonIndex = filter.lastIndexOf(":");
|
|
10268
|
+
if (colonIndex === -1) {
|
|
10269
|
+
return { filename: filter };
|
|
10270
|
+
}
|
|
10271
|
+
const [parsedFilename, lineNumber] = [
|
|
10272
|
+
filter.substring(0, colonIndex),
|
|
10273
|
+
filter.substring(colonIndex + 1)
|
|
10274
|
+
];
|
|
10275
|
+
if (lineNumber.match(/^\d+$/)) {
|
|
10276
|
+
return {
|
|
10277
|
+
filename: parsedFilename,
|
|
10278
|
+
lineNumber: Number.parseInt(lineNumber)
|
|
10279
|
+
};
|
|
10280
|
+
} else if (lineNumber.match(/^\d+-\d+$/)) {
|
|
10281
|
+
throw new RangeLocationFilterProvidedError(filter);
|
|
10282
|
+
} else {
|
|
10283
|
+
return { filename: filter };
|
|
10284
|
+
}
|
|
10285
|
+
}
|
|
10286
|
+
function groupFilters(filters) {
|
|
10287
|
+
const groupedFilters_ = groupBy(filters, (f) => f.filename);
|
|
10288
|
+
const groupedFilters = Object.fromEntries(
|
|
10289
|
+
Object.entries(groupedFilters_).map((entry) => {
|
|
10290
|
+
const [filename, filters2] = entry;
|
|
10291
|
+
const testLocations = filters2.map((f) => f.lineNumber);
|
|
10292
|
+
return [
|
|
10293
|
+
filename,
|
|
10294
|
+
testLocations.filter((l) => l !== void 0)
|
|
10295
|
+
];
|
|
10296
|
+
})
|
|
10297
|
+
);
|
|
10298
|
+
return groupedFilters;
|
|
10299
|
+
}
|
|
10300
|
+
|
|
10301
|
+
class VitestSpecifications {
|
|
10302
|
+
constructor(vitest) {
|
|
10303
|
+
this.vitest = vitest;
|
|
10304
|
+
}
|
|
10305
|
+
_cachedSpecs = /* @__PURE__ */ new Map();
|
|
10306
|
+
getModuleSpecifications(moduleId) {
|
|
10307
|
+
const _cached = this.getCachedSpecifications(moduleId);
|
|
10308
|
+
if (_cached) {
|
|
10309
|
+
return _cached;
|
|
10310
|
+
}
|
|
10311
|
+
const specs = [];
|
|
10312
|
+
for (const project of this.vitest.projects) {
|
|
10313
|
+
if (project.isCachedTestFile(moduleId)) {
|
|
10314
|
+
specs.push(project.createSpecification(moduleId));
|
|
10315
|
+
}
|
|
10316
|
+
if (project.isCachedTypecheckFile(moduleId)) {
|
|
10317
|
+
specs.push(project.createSpecification(moduleId, [], "typescript"));
|
|
10318
|
+
}
|
|
10319
|
+
}
|
|
10320
|
+
specs.forEach((spec) => this.ensureSpecificationCached(spec));
|
|
10321
|
+
return specs;
|
|
10322
|
+
}
|
|
10323
|
+
async getRelevantTestSpecifications(filters = []) {
|
|
10324
|
+
return this.filterTestsBySource(
|
|
10325
|
+
await this.globTestSpecifications(filters)
|
|
10326
|
+
);
|
|
10327
|
+
}
|
|
10328
|
+
async globTestSpecifications(filters = []) {
|
|
10329
|
+
const files = [];
|
|
10330
|
+
const dir = process.cwd();
|
|
10331
|
+
const parsedFilters = filters.map((f) => parseFilter(f));
|
|
10332
|
+
if (!this.vitest.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) {
|
|
10333
|
+
throw new IncludeTaskLocationDisabledError();
|
|
10334
|
+
}
|
|
10335
|
+
const testLines = groupFilters(parsedFilters.map(
|
|
10336
|
+
(f) => ({ ...f, filename: resolve(dir, f.filename) })
|
|
10337
|
+
));
|
|
10338
|
+
const testLocHasMatch = {};
|
|
10339
|
+
await Promise.all(this.vitest.projects.map(async (project) => {
|
|
10340
|
+
const { testFiles, typecheckTestFiles } = await project.globTestFiles(
|
|
10341
|
+
parsedFilters.map((f) => f.filename)
|
|
10342
|
+
);
|
|
10343
|
+
testFiles.forEach((file) => {
|
|
10344
|
+
const lines = testLines[file];
|
|
10345
|
+
testLocHasMatch[file] = true;
|
|
10346
|
+
const spec = project.createSpecification(file, lines);
|
|
10347
|
+
this.ensureSpecificationCached(spec);
|
|
10348
|
+
files.push(spec);
|
|
10349
|
+
});
|
|
10350
|
+
typecheckTestFiles.forEach((file) => {
|
|
10351
|
+
const lines = testLines[file];
|
|
10352
|
+
testLocHasMatch[file] = true;
|
|
10353
|
+
const spec = project.createSpecification(file, lines, "typescript");
|
|
10354
|
+
this.ensureSpecificationCached(spec);
|
|
10355
|
+
files.push(spec);
|
|
10356
|
+
});
|
|
10357
|
+
}));
|
|
10358
|
+
Object.entries(testLines).forEach(([filepath, loc]) => {
|
|
10359
|
+
if (loc.length !== 0 && !testLocHasMatch[filepath]) {
|
|
10360
|
+
throw new LocationFilterFileNotFoundError(
|
|
10361
|
+
relative(dir, filepath)
|
|
10362
|
+
);
|
|
10363
|
+
}
|
|
10364
|
+
});
|
|
10365
|
+
return files;
|
|
10366
|
+
}
|
|
10367
|
+
clearCache(moduleId) {
|
|
10368
|
+
if (moduleId) {
|
|
10369
|
+
this._cachedSpecs.delete(moduleId);
|
|
10370
|
+
} else {
|
|
10371
|
+
this._cachedSpecs.clear();
|
|
10372
|
+
}
|
|
10373
|
+
}
|
|
10374
|
+
getCachedSpecifications(moduleId) {
|
|
10375
|
+
return this._cachedSpecs.get(moduleId);
|
|
10376
|
+
}
|
|
10377
|
+
ensureSpecificationCached(spec) {
|
|
10378
|
+
const file = spec.moduleId;
|
|
10379
|
+
const specs = this._cachedSpecs.get(file) || [];
|
|
10380
|
+
const index = specs.findIndex((_s) => _s.project === spec.project && _s.pool === spec.pool);
|
|
10381
|
+
if (index === -1) {
|
|
10382
|
+
specs.push(spec);
|
|
10383
|
+
this._cachedSpecs.set(file, specs);
|
|
10384
|
+
} else {
|
|
10385
|
+
specs.splice(index, 1, spec);
|
|
10386
|
+
}
|
|
10387
|
+
return specs;
|
|
10388
|
+
}
|
|
10389
|
+
async filterTestsBySource(specs) {
|
|
10390
|
+
if (this.vitest.config.changed && !this.vitest.config.related) {
|
|
10391
|
+
const { VitestGit } = await import('./git.B5SDxu-n.js');
|
|
10392
|
+
const vitestGit = new VitestGit(this.vitest.config.root);
|
|
10393
|
+
const related2 = await vitestGit.findChangedFiles({
|
|
10394
|
+
changedSince: this.vitest.config.changed
|
|
10395
|
+
});
|
|
10396
|
+
if (!related2) {
|
|
10397
|
+
process.exitCode = 1;
|
|
10398
|
+
throw new GitNotFoundError();
|
|
10399
|
+
}
|
|
10400
|
+
this.vitest.config.related = Array.from(new Set(related2));
|
|
10401
|
+
}
|
|
10402
|
+
const related = this.vitest.config.related;
|
|
10403
|
+
if (!related) {
|
|
10404
|
+
return specs;
|
|
10405
|
+
}
|
|
10406
|
+
const forceRerunTriggers = this.vitest.config.forceRerunTriggers;
|
|
10407
|
+
if (forceRerunTriggers.length && mm(related, forceRerunTriggers).length) {
|
|
10408
|
+
return specs;
|
|
10409
|
+
}
|
|
10410
|
+
if (!this.vitest.config.watch && !related.length) {
|
|
10411
|
+
return [];
|
|
10412
|
+
}
|
|
10413
|
+
const testGraphs = await Promise.all(
|
|
10414
|
+
specs.map(async (spec) => {
|
|
10415
|
+
const deps = await this.getTestDependencies(spec);
|
|
10416
|
+
return [spec, deps];
|
|
10417
|
+
})
|
|
10418
|
+
);
|
|
10419
|
+
const runningTests = [];
|
|
10420
|
+
for (const [specification, deps] of testGraphs) {
|
|
10421
|
+
if (related.some((path) => path === specification.moduleId || deps.has(path))) {
|
|
10422
|
+
runningTests.push(specification);
|
|
10423
|
+
}
|
|
10424
|
+
}
|
|
10425
|
+
return runningTests;
|
|
10426
|
+
}
|
|
10427
|
+
async getTestDependencies(spec, deps = /* @__PURE__ */ new Set()) {
|
|
10428
|
+
const addImports = async (project, filepath) => {
|
|
10429
|
+
if (deps.has(filepath)) {
|
|
10430
|
+
return;
|
|
10431
|
+
}
|
|
10432
|
+
deps.add(filepath);
|
|
10433
|
+
const mod = project.vite.moduleGraph.getModuleById(filepath);
|
|
10434
|
+
const transformed = mod?.ssrTransformResult || await project.vitenode.transformRequest(filepath);
|
|
10435
|
+
if (!transformed) {
|
|
10436
|
+
return;
|
|
10437
|
+
}
|
|
10438
|
+
const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
|
|
10439
|
+
await Promise.all(dependencies.map(async (dep) => {
|
|
10440
|
+
const fsPath = dep.startsWith("/@fs/") ? dep.slice(isWindows ? 5 : 4) : join(project.config.root, dep);
|
|
10441
|
+
if (!fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) {
|
|
10442
|
+
await addImports(project, fsPath);
|
|
10443
|
+
}
|
|
10444
|
+
}));
|
|
10445
|
+
};
|
|
10446
|
+
await addImports(spec.project, spec.moduleId);
|
|
10447
|
+
deps.delete(spec.moduleId);
|
|
10448
|
+
return deps;
|
|
10449
|
+
}
|
|
10450
|
+
}
|
|
10451
|
+
|
|
10195
10452
|
function isAggregateError(err) {
|
|
10196
10453
|
if (typeof AggregateError !== "undefined" && err instanceof AggregateError) {
|
|
10197
10454
|
return true;
|
|
@@ -10373,23 +10630,161 @@ class StateManager {
|
|
|
10373
10630
|
}
|
|
10374
10631
|
}
|
|
10375
10632
|
|
|
10376
|
-
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
const REGEX_GROUP_SYMBOLS_RE = /(?:^|[^!*+?@])\([^(]*\|[^|]*\)/;
|
|
10380
|
-
const GLOB_EXTENSION_SYMBOLS_RE = /[!*+?@]\([^(]*\)/;
|
|
10381
|
-
const BRACE_EXPANSION_SEPARATORS_RE = /,|\.\./;
|
|
10382
|
-
function isDynamicPattern(pattern, options = {}) {
|
|
10383
|
-
if (pattern === "") {
|
|
10384
|
-
return false;
|
|
10385
|
-
}
|
|
10386
|
-
if (options.caseSensitiveMatch === false || pattern.includes(ESCAPE_SYMBOL)) {
|
|
10387
|
-
return true;
|
|
10633
|
+
class VitestWatcher {
|
|
10634
|
+
constructor(vitest) {
|
|
10635
|
+
this.vitest = vitest;
|
|
10388
10636
|
}
|
|
10389
|
-
|
|
10390
|
-
|
|
10637
|
+
/**
|
|
10638
|
+
* Modules that will be invalidated on the next run.
|
|
10639
|
+
*/
|
|
10640
|
+
invalidates = /* @__PURE__ */ new Set();
|
|
10641
|
+
/**
|
|
10642
|
+
* Test files that have changed and need to be rerun.
|
|
10643
|
+
*/
|
|
10644
|
+
changedTests = /* @__PURE__ */ new Set();
|
|
10645
|
+
_onRerun = [];
|
|
10646
|
+
/**
|
|
10647
|
+
* Register a handler that will be called when test files need to be rerun.
|
|
10648
|
+
* The callback can receive several files in case the changed file is imported by several test files.
|
|
10649
|
+
* Several invocations of this method will add multiple handlers.
|
|
10650
|
+
* @internal
|
|
10651
|
+
*/
|
|
10652
|
+
onWatcherRerun(cb) {
|
|
10653
|
+
this._onRerun.push(cb);
|
|
10654
|
+
return this;
|
|
10391
10655
|
}
|
|
10392
|
-
|
|
10656
|
+
unregisterWatcher = noop;
|
|
10657
|
+
registerWatcher() {
|
|
10658
|
+
const watcher = this.vitest.vite.watcher;
|
|
10659
|
+
if (this.vitest.config.forceRerunTriggers.length) {
|
|
10660
|
+
watcher.add(this.vitest.config.forceRerunTriggers);
|
|
10661
|
+
}
|
|
10662
|
+
watcher.on("change", this.onChange);
|
|
10663
|
+
watcher.on("unlink", this.onUnlink);
|
|
10664
|
+
watcher.on("add", this.onAdd);
|
|
10665
|
+
this.unregisterWatcher = () => {
|
|
10666
|
+
watcher.off("change", this.onChange);
|
|
10667
|
+
watcher.off("unlink", this.onUnlink);
|
|
10668
|
+
watcher.off("add", this.onAdd);
|
|
10669
|
+
this.unregisterWatcher = noop;
|
|
10670
|
+
};
|
|
10671
|
+
return this;
|
|
10672
|
+
}
|
|
10673
|
+
scheduleRerun(file) {
|
|
10674
|
+
this._onRerun.forEach((cb) => cb(file));
|
|
10675
|
+
}
|
|
10676
|
+
onChange = (id) => {
|
|
10677
|
+
id = slash(id);
|
|
10678
|
+
this.vitest.logger.clearHighlightCache(id);
|
|
10679
|
+
this.vitest.invalidateFile(id);
|
|
10680
|
+
const needsRerun = this.handleFileChanged(id);
|
|
10681
|
+
if (needsRerun) {
|
|
10682
|
+
this.scheduleRerun(id);
|
|
10683
|
+
}
|
|
10684
|
+
};
|
|
10685
|
+
onUnlink = (id) => {
|
|
10686
|
+
id = slash(id);
|
|
10687
|
+
this.vitest.logger.clearHighlightCache(id);
|
|
10688
|
+
this.invalidates.add(id);
|
|
10689
|
+
if (this.vitest.state.filesMap.has(id)) {
|
|
10690
|
+
this.vitest.state.filesMap.delete(id);
|
|
10691
|
+
this.vitest.cache.results.removeFromCache(id);
|
|
10692
|
+
this.vitest.cache.stats.removeStats(id);
|
|
10693
|
+
this.changedTests.delete(id);
|
|
10694
|
+
this.vitest.report("onTestRemoved", id);
|
|
10695
|
+
}
|
|
10696
|
+
};
|
|
10697
|
+
onAdd = (id) => {
|
|
10698
|
+
id = slash(id);
|
|
10699
|
+
this.vitest.invalidateFile(id);
|
|
10700
|
+
let fileContent;
|
|
10701
|
+
const matchingProjects = [];
|
|
10702
|
+
this.vitest.projects.forEach((project) => {
|
|
10703
|
+
if (project.matchesTestGlob(id, () => fileContent ??= readFileSync(id, "utf-8"))) {
|
|
10704
|
+
matchingProjects.push(project);
|
|
10705
|
+
}
|
|
10706
|
+
});
|
|
10707
|
+
if (matchingProjects.length > 0) {
|
|
10708
|
+
this.changedTests.add(id);
|
|
10709
|
+
this.scheduleRerun(id);
|
|
10710
|
+
} else {
|
|
10711
|
+
const needsRerun = this.handleFileChanged(id);
|
|
10712
|
+
if (needsRerun) {
|
|
10713
|
+
this.scheduleRerun(id);
|
|
10714
|
+
}
|
|
10715
|
+
}
|
|
10716
|
+
};
|
|
10717
|
+
/**
|
|
10718
|
+
* @returns A value indicating whether rerun is needed (changedTests was mutated)
|
|
10719
|
+
*/
|
|
10720
|
+
handleFileChanged(filepath) {
|
|
10721
|
+
if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) {
|
|
10722
|
+
return false;
|
|
10723
|
+
}
|
|
10724
|
+
if (mm.isMatch(filepath, this.vitest.config.forceRerunTriggers)) {
|
|
10725
|
+
this.vitest.state.getFilepaths().forEach((file) => this.changedTests.add(file));
|
|
10726
|
+
return true;
|
|
10727
|
+
}
|
|
10728
|
+
const projects = this.vitest.projects.filter((project) => {
|
|
10729
|
+
const moduleGraph = project.browser?.vite.moduleGraph || project.vite.moduleGraph;
|
|
10730
|
+
return moduleGraph.getModulesByFile(filepath)?.size;
|
|
10731
|
+
});
|
|
10732
|
+
if (!projects.length) {
|
|
10733
|
+
if (this.vitest.state.filesMap.has(filepath) || this.vitest.projects.some((project) => project.isCachedTestFile(filepath))) {
|
|
10734
|
+
this.changedTests.add(filepath);
|
|
10735
|
+
return true;
|
|
10736
|
+
}
|
|
10737
|
+
return false;
|
|
10738
|
+
}
|
|
10739
|
+
const files = [];
|
|
10740
|
+
for (const project of projects) {
|
|
10741
|
+
const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath) || project.vite.moduleGraph.getModulesByFile(filepath);
|
|
10742
|
+
if (!mods || !mods.size) {
|
|
10743
|
+
continue;
|
|
10744
|
+
}
|
|
10745
|
+
this.invalidates.add(filepath);
|
|
10746
|
+
if (this.vitest.state.filesMap.has(filepath) || project.isCachedTestFile(filepath)) {
|
|
10747
|
+
this.changedTests.add(filepath);
|
|
10748
|
+
files.push(filepath);
|
|
10749
|
+
continue;
|
|
10750
|
+
}
|
|
10751
|
+
let rerun = false;
|
|
10752
|
+
for (const mod of mods) {
|
|
10753
|
+
mod.importers.forEach((i) => {
|
|
10754
|
+
if (!i.file) {
|
|
10755
|
+
return;
|
|
10756
|
+
}
|
|
10757
|
+
const needsRerun = this.handleFileChanged(i.file);
|
|
10758
|
+
if (needsRerun) {
|
|
10759
|
+
rerun = true;
|
|
10760
|
+
}
|
|
10761
|
+
});
|
|
10762
|
+
}
|
|
10763
|
+
if (rerun) {
|
|
10764
|
+
files.push(filepath);
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
return !!files.length;
|
|
10768
|
+
}
|
|
10769
|
+
}
|
|
10770
|
+
|
|
10771
|
+
const ESCAPE_SYMBOL = "\\";
|
|
10772
|
+
const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/;
|
|
10773
|
+
const REGEX_CHARACTER_CLASS_SYMBOLS_RE = /\[[^[]*\]/;
|
|
10774
|
+
const REGEX_GROUP_SYMBOLS_RE = /(?:^|[^!*+?@])\([^(]*\|[^|]*\)/;
|
|
10775
|
+
const GLOB_EXTENSION_SYMBOLS_RE = /[!*+?@]\([^(]*\)/;
|
|
10776
|
+
const BRACE_EXPANSION_SEPARATORS_RE = /,|\.\./;
|
|
10777
|
+
function isDynamicPattern(pattern, options = {}) {
|
|
10778
|
+
if (pattern === "") {
|
|
10779
|
+
return false;
|
|
10780
|
+
}
|
|
10781
|
+
if (options.caseSensitiveMatch === false || pattern.includes(ESCAPE_SYMBOL)) {
|
|
10782
|
+
return true;
|
|
10783
|
+
}
|
|
10784
|
+
if (COMMON_GLOB_SYMBOLS_RE.test(pattern) || REGEX_CHARACTER_CLASS_SYMBOLS_RE.test(pattern) || REGEX_GROUP_SYMBOLS_RE.test(pattern)) {
|
|
10785
|
+
return true;
|
|
10786
|
+
}
|
|
10787
|
+
if (options.extglob !== false && GLOB_EXTENSION_SYMBOLS_RE.test(pattern)) {
|
|
10393
10788
|
return true;
|
|
10394
10789
|
}
|
|
10395
10790
|
if (options.braceExpansion !== false && hasBraceExpansion(pattern)) {
|
|
@@ -10454,8 +10849,8 @@ async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspa
|
|
|
10454
10849
|
)));
|
|
10455
10850
|
});
|
|
10456
10851
|
for (const path of fileProjects) {
|
|
10457
|
-
if (vitest.
|
|
10458
|
-
projectPromises.push(Promise.resolve(vitest.
|
|
10852
|
+
if (vitest.vite.config.configFile === path) {
|
|
10853
|
+
projectPromises.push(Promise.resolve(vitest._ensureRootProject()));
|
|
10459
10854
|
continue;
|
|
10460
10855
|
}
|
|
10461
10856
|
const configFile = path.endsWith("/") ? false : path;
|
|
@@ -10469,7 +10864,7 @@ async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspa
|
|
|
10469
10864
|
);
|
|
10470
10865
|
}
|
|
10471
10866
|
if (!projectPromises.length) {
|
|
10472
|
-
return [vitest.
|
|
10867
|
+
return resolveBrowserWorkspace(vitest, /* @__PURE__ */ new Set(), [vitest._ensureRootProject()]);
|
|
10473
10868
|
}
|
|
10474
10869
|
const resolvedProjects = await Promise.all(projectPromises);
|
|
10475
10870
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -10493,8 +10888,136 @@ async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspa
|
|
|
10493
10888
|
}
|
|
10494
10889
|
names.add(name);
|
|
10495
10890
|
}
|
|
10891
|
+
return resolveBrowserWorkspace(vitest, names, resolvedProjects);
|
|
10892
|
+
}
|
|
10893
|
+
async function resolveBrowserWorkspace(vitest, names, resolvedProjects) {
|
|
10894
|
+
const filters = toArray(vitest.config.project).map((s) => wildcardPatternToRegExp(s));
|
|
10895
|
+
const removeProjects = /* @__PURE__ */ new Set();
|
|
10896
|
+
resolvedProjects.forEach((project) => {
|
|
10897
|
+
if (!project.config.browser.enabled) {
|
|
10898
|
+
return;
|
|
10899
|
+
}
|
|
10900
|
+
const configs = project.config.browser.instances || [];
|
|
10901
|
+
if (configs.length === 0) {
|
|
10902
|
+
configs.push({ browser: project.config.browser.name });
|
|
10903
|
+
console.warn(
|
|
10904
|
+
withLabel(
|
|
10905
|
+
"yellow",
|
|
10906
|
+
"Vitest",
|
|
10907
|
+
[
|
|
10908
|
+
`No browser "instances" were defined`,
|
|
10909
|
+
project.name ? ` for the "${project.name}" project. ` : ". ",
|
|
10910
|
+
`Running tests in "${project.config.browser.name}" browser. `,
|
|
10911
|
+
'The "browser.name" field is deprecated since Vitest 3. ',
|
|
10912
|
+
"Read more: https://vitest.dev/guide/browser/config#browser-instances"
|
|
10913
|
+
].filter(Boolean).join("")
|
|
10914
|
+
)
|
|
10915
|
+
);
|
|
10916
|
+
}
|
|
10917
|
+
const originalName = project.config.name;
|
|
10918
|
+
const filteredConfigs = !filters.length ? configs : configs.filter((config) => {
|
|
10919
|
+
const browser = config.browser;
|
|
10920
|
+
const newName = config.name || (originalName ? `${originalName} (${browser})` : browser);
|
|
10921
|
+
return filters.some((pattern) => pattern.test(newName));
|
|
10922
|
+
});
|
|
10923
|
+
if (!filteredConfigs.length) {
|
|
10924
|
+
return;
|
|
10925
|
+
}
|
|
10926
|
+
if (project.config.browser.providerOptions) {
|
|
10927
|
+
vitest.logger.warn(
|
|
10928
|
+
withLabel("yellow", "Vitest", `"providerOptions"${originalName ? ` in "${originalName}" project` : ""} is ignored because it's overriden by the configs. To hide this warning, remove the "providerOptions" property from the browser configuration.`)
|
|
10929
|
+
);
|
|
10930
|
+
}
|
|
10931
|
+
filteredConfigs.forEach((config, index) => {
|
|
10932
|
+
const browser = config.browser;
|
|
10933
|
+
if (!browser) {
|
|
10934
|
+
const nth = index + 1;
|
|
10935
|
+
const ending = nth === 2 ? "nd" : nth === 3 ? "rd" : "th";
|
|
10936
|
+
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.`);
|
|
10937
|
+
}
|
|
10938
|
+
const name = config.name;
|
|
10939
|
+
const newName = name || (originalName ? `${originalName} (${browser})` : browser);
|
|
10940
|
+
if (names.has(newName)) {
|
|
10941
|
+
throw new Error(
|
|
10942
|
+
[
|
|
10943
|
+
`Cannot define a nested project for a ${browser} browser. The project name "${newName}" was already defined. `,
|
|
10944
|
+
'If you have multiple instances for the same browser, make sure to define a custom "name". ',
|
|
10945
|
+
"All projects in a workspace should have unique names. Make sure your configuration is correct."
|
|
10946
|
+
].join("")
|
|
10947
|
+
);
|
|
10948
|
+
}
|
|
10949
|
+
names.add(newName);
|
|
10950
|
+
const clonedConfig = cloneConfig(project, config);
|
|
10951
|
+
clonedConfig.name = newName;
|
|
10952
|
+
const clone = TestProject._cloneBrowserProject(project, clonedConfig);
|
|
10953
|
+
resolvedProjects.push(clone);
|
|
10954
|
+
});
|
|
10955
|
+
removeProjects.add(project);
|
|
10956
|
+
});
|
|
10957
|
+
resolvedProjects = resolvedProjects.filter((project) => !removeProjects.has(project));
|
|
10958
|
+
const headedBrowserProjects = resolvedProjects.filter((project) => {
|
|
10959
|
+
return project.config.browser.enabled && !project.config.browser.headless;
|
|
10960
|
+
});
|
|
10961
|
+
if (headedBrowserProjects.length > 1) {
|
|
10962
|
+
const message = [
|
|
10963
|
+
`Found multiple projects that run browser tests in headed mode: "${headedBrowserProjects.map((p) => p.name).join('", "')}".`,
|
|
10964
|
+
` Vitest cannot run multiple headed browsers at the same time.`
|
|
10965
|
+
].join("");
|
|
10966
|
+
if (!isTTY) {
|
|
10967
|
+
throw new Error(`${message} Please, filter projects with --browser=name or --project=name flag or run tests with "headless: true" option.`);
|
|
10968
|
+
}
|
|
10969
|
+
const prompts = await import('./index.BJDntFik.js').then(function (n) { return n.i; });
|
|
10970
|
+
const { projectName } = await prompts.default({
|
|
10971
|
+
type: "select",
|
|
10972
|
+
name: "projectName",
|
|
10973
|
+
choices: headedBrowserProjects.map((project) => ({
|
|
10974
|
+
title: project.name,
|
|
10975
|
+
value: project.name
|
|
10976
|
+
})),
|
|
10977
|
+
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.`
|
|
10978
|
+
});
|
|
10979
|
+
if (!projectName) {
|
|
10980
|
+
throw new Error("The test run was aborted.");
|
|
10981
|
+
}
|
|
10982
|
+
return resolvedProjects.filter((project) => project.name === projectName);
|
|
10983
|
+
}
|
|
10496
10984
|
return resolvedProjects;
|
|
10497
10985
|
}
|
|
10986
|
+
function cloneConfig(project, { browser, ...config }) {
|
|
10987
|
+
const {
|
|
10988
|
+
locators,
|
|
10989
|
+
viewport,
|
|
10990
|
+
testerHtmlPath,
|
|
10991
|
+
headless,
|
|
10992
|
+
screenshotDirectory,
|
|
10993
|
+
screenshotFailures,
|
|
10994
|
+
// @ts-expect-error remove just in case
|
|
10995
|
+
browser: _browser,
|
|
10996
|
+
name,
|
|
10997
|
+
...overrideConfig
|
|
10998
|
+
} = config;
|
|
10999
|
+
const currentConfig = project.config.browser;
|
|
11000
|
+
return mergeConfig({
|
|
11001
|
+
...deepClone(project.config),
|
|
11002
|
+
browser: {
|
|
11003
|
+
...project.config.browser,
|
|
11004
|
+
locators: locators ? {
|
|
11005
|
+
testIdAttribute: locators.testIdAttribute ?? currentConfig.locators.testIdAttribute
|
|
11006
|
+
} : project.config.browser.locators,
|
|
11007
|
+
viewport: viewport ?? currentConfig.viewport,
|
|
11008
|
+
testerHtmlPath: testerHtmlPath ?? currentConfig.testerHtmlPath,
|
|
11009
|
+
screenshotDirectory: screenshotDirectory ?? currentConfig.screenshotDirectory,
|
|
11010
|
+
screenshotFailures: screenshotFailures ?? currentConfig.screenshotFailures,
|
|
11011
|
+
// TODO: test that CLI arg is preferred over the local config
|
|
11012
|
+
headless: project.vitest._options?.browser?.headless ?? headless ?? currentConfig.headless,
|
|
11013
|
+
name: browser,
|
|
11014
|
+
providerOptions: config,
|
|
11015
|
+
instances: void 0
|
|
11016
|
+
// projects cannot spawn more configs
|
|
11017
|
+
}
|
|
11018
|
+
// TODO: should resolve, not merge/override
|
|
11019
|
+
}, overrideConfig);
|
|
11020
|
+
}
|
|
10498
11021
|
async function resolveTestProjectConfigs(vitest, workspaceConfigPath, workspaceDefinition) {
|
|
10499
11022
|
const projectsOptions = [];
|
|
10500
11023
|
const workspaceConfigFiles = [];
|
|
@@ -10529,8 +11052,8 @@ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, workspaceD
|
|
|
10529
11052
|
}
|
|
10530
11053
|
} else if (typeof definition === "function") {
|
|
10531
11054
|
projectsOptions.push(await definition({
|
|
10532
|
-
command: vitest.
|
|
10533
|
-
mode: vitest.
|
|
11055
|
+
command: vitest.vite.config.command,
|
|
11056
|
+
mode: vitest.vite.config.mode,
|
|
10534
11057
|
isPreview: false,
|
|
10535
11058
|
isSsrBuild: false
|
|
10536
11059
|
}));
|
|
@@ -10591,53 +11114,143 @@ class Vitest {
|
|
|
10591
11114
|
this.mode = mode;
|
|
10592
11115
|
this.logger = new Logger(this, options.stdout, options.stderr);
|
|
10593
11116
|
this.packageInstaller = options.packageInstaller || new VitestPackageInstaller();
|
|
11117
|
+
this.specifications = new VitestSpecifications(this);
|
|
11118
|
+
this.watcher = new VitestWatcher(this).onWatcherRerun(
|
|
11119
|
+
(file) => this.scheduleRerun([file])
|
|
11120
|
+
// TODO: error handling
|
|
11121
|
+
);
|
|
10594
11122
|
}
|
|
11123
|
+
/**
|
|
11124
|
+
* Current Vitest version.
|
|
11125
|
+
* @example '2.0.0'
|
|
11126
|
+
*/
|
|
10595
11127
|
version = version$1;
|
|
10596
|
-
|
|
11128
|
+
static version = version$1;
|
|
11129
|
+
/**
|
|
11130
|
+
* The logger instance used to log messages. It's recommended to use this logger instead of `console`.
|
|
11131
|
+
* It's possible to override stdout and stderr streams when initiating Vitest.
|
|
11132
|
+
* @example
|
|
11133
|
+
* new Vitest('test', {
|
|
11134
|
+
* stdout: new Writable(),
|
|
11135
|
+
* })
|
|
11136
|
+
*/
|
|
11137
|
+
logger;
|
|
11138
|
+
/**
|
|
11139
|
+
* The package installer instance used to install Vitest packages.
|
|
11140
|
+
* @example
|
|
11141
|
+
* await vitest.packageInstaller.ensureInstalled('@vitest/browser', process.cwd())
|
|
11142
|
+
*/
|
|
11143
|
+
packageInstaller;
|
|
11144
|
+
/**
|
|
11145
|
+
* A path to the built Vitest directory. This is usually a folder in `node_modules`.
|
|
11146
|
+
*/
|
|
11147
|
+
distPath = distDir;
|
|
11148
|
+
/**
|
|
11149
|
+
* A list of projects that are currently running.
|
|
11150
|
+
* If projects were filtered with `--project` flag, they won't appear here.
|
|
11151
|
+
*/
|
|
11152
|
+
projects = [];
|
|
11153
|
+
/** @internal */
|
|
10597
11154
|
configOverride = {};
|
|
10598
|
-
|
|
10599
|
-
state = void 0;
|
|
10600
|
-
snapshot = void 0;
|
|
10601
|
-
cache = void 0;
|
|
10602
|
-
reporters = void 0;
|
|
11155
|
+
/** @internal */
|
|
10603
11156
|
coverageProvider;
|
|
10604
|
-
|
|
10605
|
-
pool;
|
|
10606
|
-
vitenode = void 0;
|
|
10607
|
-
invalidates = /* @__PURE__ */ new Set();
|
|
10608
|
-
changedTests = /* @__PURE__ */ new Set();
|
|
10609
|
-
watchedTests = /* @__PURE__ */ new Set();
|
|
11157
|
+
/** @internal */
|
|
10610
11158
|
filenamePattern;
|
|
11159
|
+
/** @internal */
|
|
10611
11160
|
runningPromise;
|
|
11161
|
+
/** @internal */
|
|
10612
11162
|
closingPromise;
|
|
11163
|
+
/** @internal */
|
|
10613
11164
|
isCancelling = false;
|
|
10614
|
-
isFirstRun = true;
|
|
10615
|
-
restartsCount = 0;
|
|
10616
|
-
runner = void 0;
|
|
10617
|
-
packageInstaller;
|
|
10618
|
-
/** TODO: rename to `_coreRootProject` */
|
|
10619
11165
|
/** @internal */
|
|
10620
11166
|
coreWorkspaceProject;
|
|
10621
|
-
/** @
|
|
11167
|
+
/** @internal */
|
|
10622
11168
|
resolvedProjects = [];
|
|
10623
|
-
projects = [];
|
|
10624
|
-
distPath = distDir;
|
|
10625
|
-
_cachedSpecs = /* @__PURE__ */ new Map();
|
|
10626
|
-
_workspaceConfigPath;
|
|
10627
|
-
/** @deprecated use `_cachedSpecs` */
|
|
10628
|
-
projectTestFiles = this._cachedSpecs;
|
|
10629
11169
|
/** @internal */
|
|
10630
11170
|
_browserLastPort = defaultBrowserPort;
|
|
10631
11171
|
/** @internal */
|
|
11172
|
+
_browserSessions = new BrowserSessions();
|
|
11173
|
+
/** @internal */
|
|
10632
11174
|
_options = {};
|
|
11175
|
+
/** @internal */
|
|
11176
|
+
reporters = void 0;
|
|
11177
|
+
/** @internal */
|
|
11178
|
+
vitenode = void 0;
|
|
11179
|
+
/** @internal */
|
|
11180
|
+
runner = void 0;
|
|
11181
|
+
isFirstRun = true;
|
|
11182
|
+
restartsCount = 0;
|
|
11183
|
+
specifications;
|
|
11184
|
+
watcher;
|
|
11185
|
+
pool;
|
|
11186
|
+
_config;
|
|
11187
|
+
_vite;
|
|
11188
|
+
_state;
|
|
11189
|
+
_cache;
|
|
11190
|
+
_snapshot;
|
|
11191
|
+
_workspaceConfigPath;
|
|
10633
11192
|
_onRestartListeners = [];
|
|
10634
11193
|
_onClose = [];
|
|
10635
11194
|
_onSetServer = [];
|
|
10636
11195
|
_onCancelListeners = [];
|
|
10637
11196
|
_onUserTestsRerun = [];
|
|
10638
|
-
|
|
11197
|
+
_onFilterWatchedSpecification = [];
|
|
11198
|
+
/** @deprecated will be removed in 4.0, use `onFilterWatchedSpecification` instead */
|
|
11199
|
+
get invalidates() {
|
|
11200
|
+
return this.watcher.invalidates;
|
|
11201
|
+
}
|
|
11202
|
+
/** @deprecated will be removed in 4.0, use `onFilterWatchedSpecification` instead */
|
|
11203
|
+
get changedTests() {
|
|
11204
|
+
return this.watcher.changedTests;
|
|
11205
|
+
}
|
|
11206
|
+
/**
|
|
11207
|
+
* The global config.
|
|
11208
|
+
*/
|
|
11209
|
+
get config() {
|
|
11210
|
+
assert(this._config, "config");
|
|
11211
|
+
return this._config;
|
|
11212
|
+
}
|
|
11213
|
+
/** @deprecated use `vitest.vite` instead */
|
|
11214
|
+
get server() {
|
|
11215
|
+
return this._vite;
|
|
11216
|
+
}
|
|
11217
|
+
/**
|
|
11218
|
+
* Global Vite's dev server instance.
|
|
11219
|
+
*/
|
|
11220
|
+
get vite() {
|
|
11221
|
+
assert(this._vite, "vite", "server");
|
|
11222
|
+
return this._vite;
|
|
11223
|
+
}
|
|
11224
|
+
/**
|
|
11225
|
+
* The global test state manager.
|
|
11226
|
+
* @experimental The State API is experimental and not subject to semver.
|
|
11227
|
+
*/
|
|
11228
|
+
get state() {
|
|
11229
|
+
assert(this._state, "state");
|
|
11230
|
+
return this._state;
|
|
11231
|
+
}
|
|
11232
|
+
/**
|
|
11233
|
+
* The global snapshot manager. You can access the current state on `snapshot.summary`.
|
|
11234
|
+
*/
|
|
11235
|
+
get snapshot() {
|
|
11236
|
+
assert(this._snapshot, "snapshot", "snapshot manager");
|
|
11237
|
+
return this._snapshot;
|
|
11238
|
+
}
|
|
11239
|
+
/**
|
|
11240
|
+
* Test results and test file stats cache. Primarily used by the sequencer to sort tests.
|
|
11241
|
+
*/
|
|
11242
|
+
get cache() {
|
|
11243
|
+
assert(this._cache, "cache");
|
|
11244
|
+
return this._cache;
|
|
11245
|
+
}
|
|
11246
|
+
/** @deprecated internal */
|
|
11247
|
+
setServer(options, server, cliOptions) {
|
|
11248
|
+
return this._setServer(options, server, cliOptions);
|
|
11249
|
+
}
|
|
11250
|
+
/** @internal */
|
|
11251
|
+
async _setServer(options, server, cliOptions) {
|
|
10639
11252
|
this._options = options;
|
|
10640
|
-
this.unregisterWatcher
|
|
11253
|
+
this.watcher.unregisterWatcher();
|
|
10641
11254
|
clearTimeout(this._rerunTimer);
|
|
10642
11255
|
this.restartsCount += 1;
|
|
10643
11256
|
this._browserLastPort = defaultBrowserPort;
|
|
@@ -10649,16 +11262,16 @@ class Vitest {
|
|
|
10649
11262
|
this._workspaceConfigPath = void 0;
|
|
10650
11263
|
this.coverageProvider = void 0;
|
|
10651
11264
|
this.runningPromise = void 0;
|
|
10652
|
-
this.
|
|
11265
|
+
this.specifications.clearCache();
|
|
10653
11266
|
this._onUserTestsRerun = [];
|
|
10654
11267
|
const resolved = resolveConfig(this.mode, options, server.config, this.logger);
|
|
10655
|
-
this.
|
|
10656
|
-
this.
|
|
10657
|
-
this.
|
|
10658
|
-
this.
|
|
10659
|
-
this.
|
|
11268
|
+
this._vite = server;
|
|
11269
|
+
this._config = resolved;
|
|
11270
|
+
this._state = new StateManager();
|
|
11271
|
+
this._cache = new VitestCache(this.version);
|
|
11272
|
+
this._snapshot = new SnapshotManager({ ...resolved.snapshotOptions });
|
|
10660
11273
|
if (this.config.watch) {
|
|
10661
|
-
this.registerWatcher();
|
|
11274
|
+
this.watcher.registerWatcher();
|
|
10662
11275
|
}
|
|
10663
11276
|
this.vitenode = new ViteNodeServer(server, this.config.server);
|
|
10664
11277
|
const node = this.vitenode;
|
|
@@ -10691,7 +11304,6 @@ class Vitest {
|
|
|
10691
11304
|
}
|
|
10692
11305
|
});
|
|
10693
11306
|
}
|
|
10694
|
-
this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
|
|
10695
11307
|
this.cache.results.setConfig(resolved.root, resolved.cache);
|
|
10696
11308
|
try {
|
|
10697
11309
|
await this.cache.results.readFromCache();
|
|
@@ -10705,6 +11317,9 @@ class Vitest {
|
|
|
10705
11317
|
this.projects = this.projects.filter(
|
|
10706
11318
|
(p) => filters.some((pattern) => pattern.test(p.name))
|
|
10707
11319
|
);
|
|
11320
|
+
if (!this.projects.length) {
|
|
11321
|
+
throw new Error(`No projects matched the filter "${toArray(resolved.project).join('", "')}".`);
|
|
11322
|
+
}
|
|
10708
11323
|
}
|
|
10709
11324
|
if (!this.coreWorkspaceProject) {
|
|
10710
11325
|
this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
@@ -10712,19 +11327,37 @@ class Vitest {
|
|
|
10712
11327
|
if (this.config.testNamePattern) {
|
|
10713
11328
|
this.configOverride.testNamePattern = this.config.testNamePattern;
|
|
10714
11329
|
}
|
|
11330
|
+
this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this);
|
|
10715
11331
|
await Promise.all(this._onSetServer.map((fn) => fn()));
|
|
10716
11332
|
}
|
|
10717
|
-
provide(key, value) {
|
|
10718
|
-
this.getRootTestProject().provide(key, value);
|
|
10719
|
-
}
|
|
10720
11333
|
/**
|
|
10721
|
-
*
|
|
11334
|
+
* Provide a value to the test context. This value will be available to all tests with `inject`.
|
|
10722
11335
|
*/
|
|
10723
|
-
|
|
11336
|
+
provide = (key, value) => {
|
|
11337
|
+
this.getRootProject().provide(key, value);
|
|
11338
|
+
};
|
|
11339
|
+
/**
|
|
11340
|
+
* Get global provided context.
|
|
11341
|
+
*/
|
|
11342
|
+
getProvidedContext() {
|
|
11343
|
+
return this.getRootProject().getProvidedContext();
|
|
11344
|
+
}
|
|
11345
|
+
/** @internal */
|
|
11346
|
+
_ensureRootProject() {
|
|
11347
|
+
if (this.coreWorkspaceProject) {
|
|
11348
|
+
return this.coreWorkspaceProject;
|
|
11349
|
+
}
|
|
10724
11350
|
this.coreWorkspaceProject = TestProject._createBasicProject(this);
|
|
10725
11351
|
return this.coreWorkspaceProject;
|
|
10726
11352
|
}
|
|
10727
|
-
|
|
11353
|
+
/** @deprecated use `getRootProject` instead */
|
|
11354
|
+
getCoreWorkspaceProject() {
|
|
11355
|
+
return this.getRootProject();
|
|
11356
|
+
}
|
|
11357
|
+
/**
|
|
11358
|
+
* Return project that has the root (or "global") config.
|
|
11359
|
+
*/
|
|
11360
|
+
getRootProject() {
|
|
10728
11361
|
if (!this.coreWorkspaceProject) {
|
|
10729
11362
|
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.`);
|
|
10730
11363
|
}
|
|
@@ -10736,16 +11369,27 @@ class Vitest {
|
|
|
10736
11369
|
getProjectByTaskId(taskId) {
|
|
10737
11370
|
const task = this.state.idMap.get(taskId);
|
|
10738
11371
|
const projectName = task.projectName || task?.file?.projectName || "";
|
|
10739
|
-
return this.
|
|
11372
|
+
return this.getProjectByName(projectName);
|
|
10740
11373
|
}
|
|
10741
|
-
getProjectByName(name
|
|
10742
|
-
|
|
11374
|
+
getProjectByName(name) {
|
|
11375
|
+
const project = this.projects.find((p) => p.name === name) || this.coreWorkspaceProject || this.projects[0];
|
|
11376
|
+
if (!project) {
|
|
11377
|
+
throw new Error(`Project "${name}" was not found.`);
|
|
11378
|
+
}
|
|
11379
|
+
return project;
|
|
11380
|
+
}
|
|
11381
|
+
/**
|
|
11382
|
+
* Import a file using Vite module runner. The file will be transformed by Vite and executed in a separate context.
|
|
11383
|
+
* @param moduleId The ID of the module in Vite module graph
|
|
11384
|
+
*/
|
|
11385
|
+
import(moduleId) {
|
|
11386
|
+
return this.runner.executeId(moduleId);
|
|
10743
11387
|
}
|
|
10744
11388
|
async resolveWorkspaceConfigPath() {
|
|
10745
11389
|
if (typeof this.config.workspace === "string") {
|
|
10746
11390
|
return this.config.workspace;
|
|
10747
11391
|
}
|
|
10748
|
-
const configDir = this.
|
|
11392
|
+
const configDir = this.vite.config.configFile ? dirname(this.vite.config.configFile) : this.config.root;
|
|
10749
11393
|
const rootFiles = await promises.readdir(configDir);
|
|
10750
11394
|
const workspaceConfigName = workspacesFiles.find((configFile) => {
|
|
10751
11395
|
return rootFiles.includes(configFile);
|
|
@@ -10767,9 +11411,9 @@ class Vitest {
|
|
|
10767
11411
|
const workspaceConfigPath = await this.resolveWorkspaceConfigPath();
|
|
10768
11412
|
this._workspaceConfigPath = workspaceConfigPath;
|
|
10769
11413
|
if (!workspaceConfigPath) {
|
|
10770
|
-
return [this.
|
|
11414
|
+
return resolveBrowserWorkspace(this, /* @__PURE__ */ new Set(), [this._ensureRootProject()]);
|
|
10771
11415
|
}
|
|
10772
|
-
const workspaceModule = await this.
|
|
11416
|
+
const workspaceModule = await this.import(workspaceConfigPath);
|
|
10773
11417
|
if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) {
|
|
10774
11418
|
throw new TypeError(`Workspace config file "${workspaceConfigPath}" must export a default array of project paths.`);
|
|
10775
11419
|
}
|
|
@@ -10780,6 +11424,13 @@ class Vitest {
|
|
|
10780
11424
|
workspaceModule.default
|
|
10781
11425
|
);
|
|
10782
11426
|
}
|
|
11427
|
+
/**
|
|
11428
|
+
* Glob test files in every project and create a TestSpecification for each file and pool.
|
|
11429
|
+
* @param filters String filters to match the test files.
|
|
11430
|
+
*/
|
|
11431
|
+
async globTestSpecifications(filters = []) {
|
|
11432
|
+
return this.specifications.globTestSpecifications(filters);
|
|
11433
|
+
}
|
|
10783
11434
|
async initCoverageProvider() {
|
|
10784
11435
|
if (this.coverageProvider !== void 0) {
|
|
10785
11436
|
return;
|
|
@@ -10794,16 +11445,19 @@ class Vitest {
|
|
|
10794
11445
|
}
|
|
10795
11446
|
return this.coverageProvider;
|
|
10796
11447
|
}
|
|
10797
|
-
|
|
11448
|
+
/**
|
|
11449
|
+
* Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified).
|
|
11450
|
+
*/
|
|
11451
|
+
async mergeReports(directory) {
|
|
10798
11452
|
if (this.reporters.some((r) => r instanceof BlobReporter)) {
|
|
10799
11453
|
throw new Error("Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first.");
|
|
10800
11454
|
}
|
|
10801
|
-
const { files, errors, coverages } = await readBlobs(this.version, this.config.mergeReports, this.projects);
|
|
11455
|
+
const { files, errors, coverages } = await readBlobs(this.version, directory || this.config.mergeReports, this.projects);
|
|
10802
11456
|
await this.report("onInit", this);
|
|
10803
11457
|
await this.report("onPathsCollected", files.flatMap((f) => f.filepath));
|
|
10804
11458
|
const workspaceSpecs = /* @__PURE__ */ new Map();
|
|
10805
11459
|
for (const file of files) {
|
|
10806
|
-
const project = this.getProjectByName(file.projectName);
|
|
11460
|
+
const project = this.getProjectByName(file.projectName || "");
|
|
10807
11461
|
const specs = workspaceSpecs.get(project) || [];
|
|
10808
11462
|
specs.push(file);
|
|
10809
11463
|
workspaceSpecs.set(project, specs);
|
|
@@ -10836,31 +11490,42 @@ class Vitest {
|
|
|
10836
11490
|
if (hasFailed(files)) {
|
|
10837
11491
|
process.exitCode = 1;
|
|
10838
11492
|
}
|
|
10839
|
-
this.
|
|
11493
|
+
this._checkUnhandledErrors(errors);
|
|
10840
11494
|
await this.report("onFinished", files, errors);
|
|
10841
11495
|
await this.initCoverageProvider();
|
|
10842
11496
|
await this.coverageProvider?.mergeReports?.(coverages);
|
|
11497
|
+
return {
|
|
11498
|
+
testModules: this.state.getTestModules(),
|
|
11499
|
+
unhandledErrors: this.state.getUnhandledErrors()
|
|
11500
|
+
};
|
|
10843
11501
|
}
|
|
10844
11502
|
async collect(filters) {
|
|
10845
11503
|
this._onClose = [];
|
|
10846
|
-
const files = await this.
|
|
10847
|
-
await this.globTestFiles(filters)
|
|
10848
|
-
);
|
|
11504
|
+
const files = await this.specifications.getRelevantTestSpecifications(filters);
|
|
10849
11505
|
if (!files.length) {
|
|
10850
|
-
return {
|
|
11506
|
+
return { testModules: [], unhandledErrors: [] };
|
|
10851
11507
|
}
|
|
10852
|
-
|
|
10853
|
-
return {
|
|
10854
|
-
tests: this.state.getFiles(),
|
|
10855
|
-
errors: this.state.getUnhandledErrors()
|
|
10856
|
-
};
|
|
11508
|
+
return this.collectTests(files);
|
|
10857
11509
|
}
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
);
|
|
10862
|
-
return files;
|
|
11510
|
+
/** @deprecated use `getRelevantTestSpecifications` instead */
|
|
11511
|
+
listFiles(filters) {
|
|
11512
|
+
return this.getRelevantTestSpecifications(filters);
|
|
10863
11513
|
}
|
|
11514
|
+
/**
|
|
11515
|
+
* Returns the list of test files that match the config and filters.
|
|
11516
|
+
* @param filters String filters to match the test files
|
|
11517
|
+
*/
|
|
11518
|
+
getRelevantTestSpecifications(filters) {
|
|
11519
|
+
return this.specifications.getRelevantTestSpecifications(filters);
|
|
11520
|
+
}
|
|
11521
|
+
/**
|
|
11522
|
+
* Initialize reporters, the coverage provider, and run tests.
|
|
11523
|
+
* This method can throw an error:
|
|
11524
|
+
* - `FilesNotFoundError` if no tests are found
|
|
11525
|
+
* - `GitNotFoundError` if `--related` flag is used, but git repository is not initialized
|
|
11526
|
+
* - `Error` from the user reporters
|
|
11527
|
+
* @param filters String filters to match the test files
|
|
11528
|
+
*/
|
|
10864
11529
|
async start(filters) {
|
|
10865
11530
|
this._onClose = [];
|
|
10866
11531
|
try {
|
|
@@ -10869,9 +11534,8 @@ class Vitest {
|
|
|
10869
11534
|
} finally {
|
|
10870
11535
|
await this.report("onInit", this);
|
|
10871
11536
|
}
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
);
|
|
11537
|
+
this.filenamePattern = filters && filters?.length > 0 ? filters : void 0;
|
|
11538
|
+
const files = await this.specifications.getRelevantTestSpecifications(filters);
|
|
10875
11539
|
if (!files.length) {
|
|
10876
11540
|
const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
|
|
10877
11541
|
await this.reportCoverage(coverage, true);
|
|
@@ -10882,14 +11546,23 @@ class Vitest {
|
|
|
10882
11546
|
throw new FilesNotFoundError(this.mode);
|
|
10883
11547
|
}
|
|
10884
11548
|
}
|
|
11549
|
+
let testModules = {
|
|
11550
|
+
testModules: [],
|
|
11551
|
+
unhandledErrors: []
|
|
11552
|
+
};
|
|
10885
11553
|
if (files.length) {
|
|
10886
11554
|
await this.cache.stats.populateStats(this.config.root, files);
|
|
10887
|
-
await this.runFiles(files, true);
|
|
11555
|
+
testModules = await this.runFiles(files, true);
|
|
10888
11556
|
}
|
|
10889
11557
|
if (this.config.watch) {
|
|
10890
11558
|
await this.report("onWatcherStart");
|
|
10891
11559
|
}
|
|
11560
|
+
return testModules;
|
|
10892
11561
|
}
|
|
11562
|
+
/**
|
|
11563
|
+
* Initialize reporters and the coverage provider. This method doesn't run any tests.
|
|
11564
|
+
* If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called.
|
|
11565
|
+
*/
|
|
10893
11566
|
async init() {
|
|
10894
11567
|
this._onClose = [];
|
|
10895
11568
|
try {
|
|
@@ -10898,105 +11571,60 @@ class Vitest {
|
|
|
10898
11571
|
} finally {
|
|
10899
11572
|
await this.report("onInit", this);
|
|
10900
11573
|
}
|
|
10901
|
-
await this.
|
|
10902
|
-
if (this.config.watch) {
|
|
10903
|
-
await this.report("onWatcherStart");
|
|
10904
|
-
}
|
|
10905
|
-
}
|
|
10906
|
-
async getTestDependencies(spec, deps = /* @__PURE__ */ new Set()) {
|
|
10907
|
-
const addImports = async (project, filepath) => {
|
|
10908
|
-
if (deps.has(filepath)) {
|
|
10909
|
-
return;
|
|
10910
|
-
}
|
|
10911
|
-
deps.add(filepath);
|
|
10912
|
-
const mod = project.vite.moduleGraph.getModuleById(filepath);
|
|
10913
|
-
const transformed = mod?.ssrTransformResult || await project.vitenode.transformRequest(filepath);
|
|
10914
|
-
if (!transformed) {
|
|
10915
|
-
return;
|
|
10916
|
-
}
|
|
10917
|
-
const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
|
|
10918
|
-
await Promise.all(dependencies.map(async (dep) => {
|
|
10919
|
-
const path = await project.vite.pluginContainer.resolveId(dep, filepath, { ssr: true });
|
|
10920
|
-
const fsPath = path && !path.external && path.id.split("?")[0];
|
|
10921
|
-
if (fsPath && !fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) {
|
|
10922
|
-
await addImports(project, fsPath);
|
|
10923
|
-
}
|
|
10924
|
-
}));
|
|
10925
|
-
};
|
|
10926
|
-
await addImports(spec.project, spec.moduleId);
|
|
10927
|
-
deps.delete(spec.moduleId);
|
|
10928
|
-
return deps;
|
|
10929
|
-
}
|
|
10930
|
-
async filterTestsBySource(specs) {
|
|
10931
|
-
if (this.config.changed && !this.config.related) {
|
|
10932
|
-
const { VitestGit } = await import('./git.B5SDxu-n.js');
|
|
10933
|
-
const vitestGit = new VitestGit(this.config.root);
|
|
10934
|
-
const related2 = await vitestGit.findChangedFiles({
|
|
10935
|
-
changedSince: this.config.changed
|
|
10936
|
-
});
|
|
10937
|
-
if (!related2) {
|
|
10938
|
-
process.exitCode = 1;
|
|
10939
|
-
throw new GitNotFoundError();
|
|
10940
|
-
}
|
|
10941
|
-
this.config.related = Array.from(new Set(related2));
|
|
10942
|
-
}
|
|
10943
|
-
const related = this.config.related;
|
|
10944
|
-
if (!related) {
|
|
10945
|
-
return specs;
|
|
10946
|
-
}
|
|
10947
|
-
const forceRerunTriggers = this.config.forceRerunTriggers;
|
|
10948
|
-
if (forceRerunTriggers.length && mm(related, forceRerunTriggers).length) {
|
|
10949
|
-
return specs;
|
|
10950
|
-
}
|
|
10951
|
-
if (!this.config.watch && !related.length) {
|
|
10952
|
-
return [];
|
|
10953
|
-
}
|
|
10954
|
-
const testGraphs = await Promise.all(
|
|
10955
|
-
specs.map(async (spec) => {
|
|
10956
|
-
const deps = await this.getTestDependencies(spec);
|
|
10957
|
-
return [spec, deps];
|
|
10958
|
-
})
|
|
10959
|
-
);
|
|
10960
|
-
const runningTests = [];
|
|
10961
|
-
for (const [filepath, deps] of testGraphs) {
|
|
10962
|
-
if (related.some((path) => path === filepath[1] || deps.has(path))) {
|
|
10963
|
-
runningTests.push(filepath);
|
|
10964
|
-
}
|
|
11574
|
+
await this.globTestSpecifications();
|
|
11575
|
+
if (this.config.watch) {
|
|
11576
|
+
await this.report("onWatcherStart");
|
|
10965
11577
|
}
|
|
10966
|
-
return runningTests;
|
|
10967
11578
|
}
|
|
10968
11579
|
/**
|
|
10969
|
-
* @deprecated remove when vscode extension supports "
|
|
11580
|
+
* @deprecated remove when vscode extension supports "getModuleSpecifications"
|
|
10970
11581
|
*/
|
|
10971
11582
|
getProjectsByTestFile(file) {
|
|
10972
|
-
return this.
|
|
11583
|
+
return this.getModuleSpecifications(file);
|
|
10973
11584
|
}
|
|
11585
|
+
/** @deprecated */
|
|
10974
11586
|
getFileWorkspaceSpecs(file) {
|
|
10975
|
-
|
|
10976
|
-
if (_cached) {
|
|
10977
|
-
return _cached;
|
|
10978
|
-
}
|
|
10979
|
-
const specs = [];
|
|
10980
|
-
for (const project of this.projects) {
|
|
10981
|
-
if (project.isTestFile(file)) {
|
|
10982
|
-
specs.push(project.createSpecification(file));
|
|
10983
|
-
}
|
|
10984
|
-
if (project.isTypecheckFile(file)) {
|
|
10985
|
-
specs.push(project.createSpecification(file, "typescript"));
|
|
10986
|
-
}
|
|
10987
|
-
}
|
|
10988
|
-
specs.forEach((spec) => this.ensureSpecCached(spec));
|
|
10989
|
-
return specs;
|
|
11587
|
+
return this.getModuleSpecifications(file);
|
|
10990
11588
|
}
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11589
|
+
/**
|
|
11590
|
+
* Get test specifications assosiated with the given module. If module is not a test file, an empty array is returned.
|
|
11591
|
+
*
|
|
11592
|
+
* **Note:** this method relies on a cache generated by `globTestSpecifications`. If the file was not processed yet, use `project.matchesGlobPattern` instead.
|
|
11593
|
+
* @param moduleId The module ID to get test specifications for.
|
|
11594
|
+
*/
|
|
11595
|
+
getModuleSpecifications(moduleId) {
|
|
11596
|
+
return this.specifications.getModuleSpecifications(moduleId);
|
|
11597
|
+
}
|
|
11598
|
+
/**
|
|
11599
|
+
* Vitest automatically caches test specifications for each file. This method clears the cache for the given file or the whole cache alltogether.
|
|
11600
|
+
*/
|
|
11601
|
+
clearSpecificationsCache(moduleId) {
|
|
11602
|
+
this.specifications.clearCache(moduleId);
|
|
11603
|
+
}
|
|
11604
|
+
/**
|
|
11605
|
+
* Run tests for the given test specifications. This does not trigger `onWatcher*` events.
|
|
11606
|
+
* @param specifications A list of specifications to run.
|
|
11607
|
+
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
11608
|
+
*/
|
|
11609
|
+
runTestSpecifications(specifications, allTestsRun = false) {
|
|
11610
|
+
specifications.forEach((spec) => this.specifications.ensureSpecificationCached(spec));
|
|
11611
|
+
return this.runFiles(specifications, allTestsRun);
|
|
11612
|
+
}
|
|
11613
|
+
/**
|
|
11614
|
+
* Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
|
|
11615
|
+
* @param specifications A list of specifications to run.
|
|
11616
|
+
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
11617
|
+
*/
|
|
11618
|
+
async rerunTestSpecifications(specifications, allTestsRun = false) {
|
|
11619
|
+
this.configOverride.testNamePattern = void 0;
|
|
11620
|
+
const files = specifications.map((spec) => spec.moduleId);
|
|
11621
|
+
await Promise.all([
|
|
11622
|
+
this.report("onWatcherRerun", files, "rerun test"),
|
|
11623
|
+
...this._onUserTestsRerun.map((fn) => fn(specifications))
|
|
11624
|
+
]);
|
|
11625
|
+
const result = await this.runTestSpecifications(specifications, allTestsRun);
|
|
11626
|
+
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
11627
|
+
return result;
|
|
11000
11628
|
}
|
|
11001
11629
|
async runFiles(specs, allTestsRun) {
|
|
11002
11630
|
const filepaths = specs.map((spec) => spec.moduleId);
|
|
@@ -11011,8 +11639,8 @@ class Vitest {
|
|
|
11011
11639
|
if (!this.pool) {
|
|
11012
11640
|
this.pool = createPool(this);
|
|
11013
11641
|
}
|
|
11014
|
-
const invalidates = Array.from(this.invalidates);
|
|
11015
|
-
this.invalidates.clear();
|
|
11642
|
+
const invalidates = Array.from(this.watcher.invalidates);
|
|
11643
|
+
this.watcher.invalidates.clear();
|
|
11016
11644
|
this.snapshot.clear();
|
|
11017
11645
|
this.state.clearErrors();
|
|
11018
11646
|
if (!this.isFirstRun && this.config.coverage.cleanOnRerun) {
|
|
@@ -11030,11 +11658,15 @@ class Vitest {
|
|
|
11030
11658
|
}
|
|
11031
11659
|
this.cache.results.updateResults(files);
|
|
11032
11660
|
await this.cache.results.writeToCache();
|
|
11661
|
+
return {
|
|
11662
|
+
testModules: this.state.getTestModules(),
|
|
11663
|
+
unhandledErrors: this.state.getUnhandledErrors()
|
|
11664
|
+
};
|
|
11033
11665
|
} finally {
|
|
11034
11666
|
const files = Array.from(new Set(specs.map((spec) => spec.moduleId)));
|
|
11035
11667
|
const errors = this.state.getUnhandledErrors();
|
|
11036
11668
|
const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun });
|
|
11037
|
-
this.
|
|
11669
|
+
this._checkUnhandledErrors(errors);
|
|
11038
11670
|
await this.report("onFinished", this.state.getFiles(files), errors, coverage);
|
|
11039
11671
|
await this.reportCoverage(coverage, allTestsRun);
|
|
11040
11672
|
}
|
|
@@ -11046,8 +11678,12 @@ class Vitest {
|
|
|
11046
11678
|
});
|
|
11047
11679
|
return await this.runningPromise;
|
|
11048
11680
|
}
|
|
11049
|
-
|
|
11050
|
-
|
|
11681
|
+
/**
|
|
11682
|
+
* Collect tests in specified modules. Vitest will run the files to collect tests.
|
|
11683
|
+
* @param specifications A list of specifications to run.
|
|
11684
|
+
*/
|
|
11685
|
+
async collectTests(specifications) {
|
|
11686
|
+
const filepaths = specifications.map((spec) => spec.moduleId);
|
|
11051
11687
|
this.state.collectPaths(filepaths);
|
|
11052
11688
|
await this.runningPromise;
|
|
11053
11689
|
this._onCancelListeners = [];
|
|
@@ -11056,13 +11692,13 @@ class Vitest {
|
|
|
11056
11692
|
if (!this.pool) {
|
|
11057
11693
|
this.pool = createPool(this);
|
|
11058
11694
|
}
|
|
11059
|
-
const invalidates = Array.from(this.invalidates);
|
|
11060
|
-
this.invalidates.clear();
|
|
11695
|
+
const invalidates = Array.from(this.watcher.invalidates);
|
|
11696
|
+
this.watcher.invalidates.clear();
|
|
11061
11697
|
this.snapshot.clear();
|
|
11062
11698
|
this.state.clearErrors();
|
|
11063
|
-
await this.initializeGlobalSetup(
|
|
11699
|
+
await this.initializeGlobalSetup(specifications);
|
|
11064
11700
|
try {
|
|
11065
|
-
await this.pool.collectTests(
|
|
11701
|
+
await this.pool.collectTests(specifications, invalidates);
|
|
11066
11702
|
} catch (err) {
|
|
11067
11703
|
this.state.catchError(err, "Unhandled Error");
|
|
11068
11704
|
}
|
|
@@ -11070,6 +11706,10 @@ class Vitest {
|
|
|
11070
11706
|
if (hasFailed(files)) {
|
|
11071
11707
|
process.exitCode = 1;
|
|
11072
11708
|
}
|
|
11709
|
+
return {
|
|
11710
|
+
testModules: this.state.getTestModules(),
|
|
11711
|
+
unhandledErrors: this.state.getUnhandledErrors()
|
|
11712
|
+
};
|
|
11073
11713
|
})().finally(() => {
|
|
11074
11714
|
this.runningPromise = void 0;
|
|
11075
11715
|
this.config.changed = false;
|
|
@@ -11077,31 +11717,46 @@ class Vitest {
|
|
|
11077
11717
|
});
|
|
11078
11718
|
return await this.runningPromise;
|
|
11079
11719
|
}
|
|
11720
|
+
/**
|
|
11721
|
+
* Gracefully cancel the current test run. Vitest will wait until all running tests are finished before cancelling.
|
|
11722
|
+
*/
|
|
11080
11723
|
async cancelCurrentRun(reason) {
|
|
11081
11724
|
this.isCancelling = true;
|
|
11082
11725
|
await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason)));
|
|
11083
11726
|
}
|
|
11084
|
-
|
|
11727
|
+
/** @internal */
|
|
11728
|
+
async _initBrowserServers() {
|
|
11085
11729
|
await Promise.all(this.projects.map((p) => p._initBrowserServer()));
|
|
11086
11730
|
}
|
|
11731
|
+
async initializeGlobalSetup(paths) {
|
|
11732
|
+
const projects = new Set(paths.map((spec) => spec.project));
|
|
11733
|
+
const coreProject = this.getRootProject();
|
|
11734
|
+
if (!projects.has(coreProject)) {
|
|
11735
|
+
projects.add(coreProject);
|
|
11736
|
+
}
|
|
11737
|
+
for (const project of projects) {
|
|
11738
|
+
await project._initializeGlobalSetup();
|
|
11739
|
+
}
|
|
11740
|
+
}
|
|
11741
|
+
/** @internal */
|
|
11087
11742
|
async rerunFiles(files = this.state.getFilepaths(), trigger, allTestsRun = true, resetTestNamePattern = false) {
|
|
11088
11743
|
if (resetTestNamePattern) {
|
|
11089
11744
|
this.configOverride.testNamePattern = void 0;
|
|
11090
11745
|
}
|
|
11091
11746
|
if (this.filenamePattern) {
|
|
11092
|
-
const filteredFiles = await this.
|
|
11093
|
-
files = files.filter((file) => filteredFiles.some((f) => f
|
|
11747
|
+
const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
|
|
11748
|
+
files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
|
|
11094
11749
|
}
|
|
11750
|
+
const specifications = files.flatMap((file) => this.getModuleSpecifications(file));
|
|
11095
11751
|
await Promise.all([
|
|
11096
11752
|
this.report("onWatcherRerun", files, trigger),
|
|
11097
|
-
...this._onUserTestsRerun.map((fn) => fn(
|
|
11753
|
+
...this._onUserTestsRerun.map((fn) => fn(specifications))
|
|
11098
11754
|
]);
|
|
11099
|
-
await this.runFiles(
|
|
11755
|
+
const testResult = await this.runFiles(specifications, allTestsRun);
|
|
11100
11756
|
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
11757
|
+
return testResult;
|
|
11101
11758
|
}
|
|
11102
|
-
|
|
11103
|
-
return Object.hasOwnProperty.call(task, "tasks");
|
|
11104
|
-
}
|
|
11759
|
+
/** @internal */
|
|
11105
11760
|
async rerunTask(id) {
|
|
11106
11761
|
const task = this.state.idMap.get(id);
|
|
11107
11762
|
if (!task) {
|
|
@@ -11110,9 +11765,10 @@ class Vitest {
|
|
|
11110
11765
|
await this.changeNamePattern(
|
|
11111
11766
|
task.name,
|
|
11112
11767
|
[task.file.filepath],
|
|
11113
|
-
|
|
11768
|
+
"tasks" in task ? "rerun suite" : "rerun test"
|
|
11114
11769
|
);
|
|
11115
11770
|
}
|
|
11771
|
+
/** @internal */
|
|
11116
11772
|
async changeProjectName(pattern) {
|
|
11117
11773
|
if (pattern === "") {
|
|
11118
11774
|
delete this.configOverride.project;
|
|
@@ -11120,9 +11776,10 @@ class Vitest {
|
|
|
11120
11776
|
this.configOverride.project = pattern;
|
|
11121
11777
|
}
|
|
11122
11778
|
this.projects = this.resolvedProjects.filter((p) => p.name === pattern);
|
|
11123
|
-
const files = (await this.
|
|
11779
|
+
const files = (await this.globTestSpecifications()).map((spec) => spec.moduleId);
|
|
11124
11780
|
await this.rerunFiles(files, "change project filter", pattern === "");
|
|
11125
11781
|
}
|
|
11782
|
+
/** @internal */
|
|
11126
11783
|
async changeNamePattern(pattern, files = this.state.getFilepaths(), trigger) {
|
|
11127
11784
|
if (pattern === "") {
|
|
11128
11785
|
this.filenamePattern = void 0;
|
|
@@ -11140,31 +11797,71 @@ class Vitest {
|
|
|
11140
11797
|
}
|
|
11141
11798
|
await this.rerunFiles(files, trigger, pattern === "");
|
|
11142
11799
|
}
|
|
11800
|
+
/** @internal */
|
|
11143
11801
|
async changeFilenamePattern(pattern, files = this.state.getFilepaths()) {
|
|
11144
|
-
this.filenamePattern = pattern;
|
|
11145
|
-
const trigger = this.filenamePattern ? "change filename pattern" : "reset filename pattern";
|
|
11802
|
+
this.filenamePattern = pattern ? [pattern] : [];
|
|
11803
|
+
const trigger = this.filenamePattern.length ? "change filename pattern" : "reset filename pattern";
|
|
11146
11804
|
await this.rerunFiles(files, trigger, pattern === "");
|
|
11147
11805
|
}
|
|
11806
|
+
/** @internal */
|
|
11148
11807
|
async rerunFailed() {
|
|
11149
11808
|
await this.rerunFiles(this.state.getFailedFilepaths(), "rerun failed", false);
|
|
11150
11809
|
}
|
|
11810
|
+
/**
|
|
11811
|
+
* Update snapshots in specified files. If no files are provided, it will update files with failed tests and obsolete snapshots.
|
|
11812
|
+
* @param files The list of files on the file system
|
|
11813
|
+
*/
|
|
11151
11814
|
async updateSnapshot(files) {
|
|
11152
11815
|
files = files || [
|
|
11153
11816
|
...this.state.getFailedFilepaths(),
|
|
11154
11817
|
...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath)
|
|
11155
11818
|
];
|
|
11819
|
+
this.enableSnapshotUpdate();
|
|
11820
|
+
try {
|
|
11821
|
+
return await this.rerunFiles(files, "update snapshot", false);
|
|
11822
|
+
} finally {
|
|
11823
|
+
this.resetSnapshotUpdate();
|
|
11824
|
+
}
|
|
11825
|
+
}
|
|
11826
|
+
/**
|
|
11827
|
+
* Enable the mode that allows updating snapshots when running tests.
|
|
11828
|
+
* This method doesn't run any tests.
|
|
11829
|
+
*
|
|
11830
|
+
* Every test that runs after this method is called will update snapshots.
|
|
11831
|
+
* To disable the mode, call `resetSnapshotUpdate`.
|
|
11832
|
+
*/
|
|
11833
|
+
enableSnapshotUpdate() {
|
|
11156
11834
|
this.configOverride.snapshotOptions = {
|
|
11157
11835
|
updateSnapshot: "all",
|
|
11158
11836
|
// environment is resolved inside a worker thread
|
|
11159
11837
|
snapshotEnvironment: null
|
|
11160
11838
|
};
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11839
|
+
}
|
|
11840
|
+
/**
|
|
11841
|
+
* Disable the mode that allows updating snapshots when running tests.
|
|
11842
|
+
*/
|
|
11843
|
+
resetSnapshotUpdate() {
|
|
11844
|
+
delete this.configOverride.snapshotOptions;
|
|
11845
|
+
}
|
|
11846
|
+
/**
|
|
11847
|
+
* Set the global test name pattern to a regexp.
|
|
11848
|
+
* This method doesn't run any tests.
|
|
11849
|
+
*/
|
|
11850
|
+
setGlobalTestNamePattern(pattern) {
|
|
11851
|
+
if (pattern instanceof RegExp) {
|
|
11852
|
+
this.configOverride.testNamePattern = pattern;
|
|
11853
|
+
} else {
|
|
11854
|
+
this.configOverride.testNamePattern = pattern ? new RegExp(pattern) : void 0;
|
|
11165
11855
|
}
|
|
11166
11856
|
}
|
|
11857
|
+
/**
|
|
11858
|
+
* Resets the global test name pattern. This method doesn't run any tests.
|
|
11859
|
+
*/
|
|
11860
|
+
resetGlobalTestNamePattern() {
|
|
11861
|
+
this.configOverride.testNamePattern = void 0;
|
|
11862
|
+
}
|
|
11167
11863
|
_rerunTimer;
|
|
11864
|
+
// we can't use a single `triggerId` yet because vscode extension relies on this
|
|
11168
11865
|
async scheduleRerun(triggerId) {
|
|
11169
11866
|
const currentCount = this.restartsCount;
|
|
11170
11867
|
clearTimeout(this._rerunTimer);
|
|
@@ -11174,15 +11871,8 @@ class Vitest {
|
|
|
11174
11871
|
return;
|
|
11175
11872
|
}
|
|
11176
11873
|
this._rerunTimer = setTimeout(async () => {
|
|
11177
|
-
if (this.
|
|
11178
|
-
this.
|
|
11179
|
-
if (!this.watchedTests.has(test)) {
|
|
11180
|
-
this.changedTests.delete(test);
|
|
11181
|
-
}
|
|
11182
|
-
});
|
|
11183
|
-
}
|
|
11184
|
-
if (this.changedTests.size === 0) {
|
|
11185
|
-
this.invalidates.clear();
|
|
11874
|
+
if (this.watcher.changedTests.size === 0) {
|
|
11875
|
+
this.watcher.invalidates.clear();
|
|
11186
11876
|
return;
|
|
11187
11877
|
}
|
|
11188
11878
|
if (this.restartsCount !== currentCount) {
|
|
@@ -11190,161 +11880,54 @@ class Vitest {
|
|
|
11190
11880
|
}
|
|
11191
11881
|
this.isFirstRun = false;
|
|
11192
11882
|
this.snapshot.clear();
|
|
11193
|
-
let files = Array.from(this.changedTests);
|
|
11883
|
+
let files = Array.from(this.watcher.changedTests);
|
|
11194
11884
|
if (this.filenamePattern) {
|
|
11195
|
-
const filteredFiles = await this.
|
|
11196
|
-
files = files.filter((file) => filteredFiles.some((f) => f
|
|
11885
|
+
const filteredFiles = await this.globTestSpecifications(this.filenamePattern);
|
|
11886
|
+
files = files.filter((file) => filteredFiles.some((f) => f.moduleId === file));
|
|
11197
11887
|
if (files.length === 0) {
|
|
11198
11888
|
return;
|
|
11199
11889
|
}
|
|
11200
11890
|
}
|
|
11201
|
-
this.changedTests.clear();
|
|
11891
|
+
this.watcher.changedTests.clear();
|
|
11202
11892
|
const triggerIds = new Set(triggerId.map((id) => relative(this.config.root, id)));
|
|
11203
11893
|
const triggerLabel = Array.from(triggerIds).join(", ");
|
|
11894
|
+
const specifications = files.flatMap((file) => this.getModuleSpecifications(file)).filter((specification) => {
|
|
11895
|
+
if (this._onFilterWatchedSpecification.length === 0) {
|
|
11896
|
+
return true;
|
|
11897
|
+
}
|
|
11898
|
+
return this._onFilterWatchedSpecification.every((fn) => fn(specification));
|
|
11899
|
+
});
|
|
11204
11900
|
await Promise.all([
|
|
11205
11901
|
this.report("onWatcherRerun", files, triggerLabel),
|
|
11206
|
-
...this._onUserTestsRerun.map((fn) => fn(
|
|
11902
|
+
...this._onUserTestsRerun.map((fn) => fn(specifications))
|
|
11207
11903
|
]);
|
|
11208
|
-
await this.runFiles(
|
|
11904
|
+
await this.runFiles(specifications, false);
|
|
11209
11905
|
await this.report("onWatcherStart", this.state.getFiles(files));
|
|
11210
11906
|
}, WATCHER_DEBOUNCE);
|
|
11211
11907
|
}
|
|
11212
|
-
getModuleProjects(filepath) {
|
|
11213
|
-
return this.projects.filter((project) => {
|
|
11214
|
-
return project.getModulesByFilepath(filepath).size;
|
|
11215
|
-
});
|
|
11216
|
-
}
|
|
11217
11908
|
/**
|
|
11218
|
-
*
|
|
11909
|
+
* Invalidate a file in all projects.
|
|
11219
11910
|
*/
|
|
11220
|
-
|
|
11221
|
-
this.
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
}
|
|
11225
|
-
updateLastChanged(filepath) {
|
|
11226
|
-
const projects = this.getModuleProjects(filepath);
|
|
11227
|
-
projects.forEach(({ server, browser }) => {
|
|
11228
|
-
const serverMods = server.moduleGraph.getModulesByFile(filepath);
|
|
11229
|
-
serverMods?.forEach((mod) => server.moduleGraph.invalidateModule(mod));
|
|
11911
|
+
invalidateFile(filepath) {
|
|
11912
|
+
this.projects.forEach(({ vite, browser }) => {
|
|
11913
|
+
const serverMods = vite.moduleGraph.getModulesByFile(filepath);
|
|
11914
|
+
serverMods?.forEach((mod) => vite.moduleGraph.invalidateModule(mod));
|
|
11230
11915
|
if (browser) {
|
|
11231
11916
|
const browserMods = browser.vite.moduleGraph.getModulesByFile(filepath);
|
|
11232
11917
|
browserMods?.forEach((mod) => browser.vite.moduleGraph.invalidateModule(mod));
|
|
11233
11918
|
}
|
|
11234
11919
|
});
|
|
11235
11920
|
}
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
this.
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
this.scheduleRerun(needsRerun);
|
|
11243
|
-
}
|
|
11244
|
-
};
|
|
11245
|
-
onUnlink = (id) => {
|
|
11246
|
-
id = slash(id);
|
|
11247
|
-
this.logger.clearHighlightCache(id);
|
|
11248
|
-
this.invalidates.add(id);
|
|
11249
|
-
if (this.state.filesMap.has(id)) {
|
|
11250
|
-
this.state.filesMap.delete(id);
|
|
11251
|
-
this.cache.results.removeFromCache(id);
|
|
11252
|
-
this.cache.stats.removeStats(id);
|
|
11253
|
-
this.changedTests.delete(id);
|
|
11254
|
-
this.report("onTestRemoved", id);
|
|
11255
|
-
}
|
|
11256
|
-
};
|
|
11257
|
-
onAdd = async (id) => {
|
|
11258
|
-
id = slash(id);
|
|
11259
|
-
this.updateLastChanged(id);
|
|
11260
|
-
const fileContent = readFileSync(id, "utf-8");
|
|
11261
|
-
const matchingProjects = [];
|
|
11262
|
-
this.projects.forEach((project) => {
|
|
11263
|
-
if (project.matchesTestGlob(id, fileContent)) {
|
|
11264
|
-
matchingProjects.push(project);
|
|
11265
|
-
project._markTestFile(id);
|
|
11266
|
-
}
|
|
11267
|
-
});
|
|
11268
|
-
if (matchingProjects.length > 0) {
|
|
11269
|
-
this.changedTests.add(id);
|
|
11270
|
-
this.scheduleRerun([id]);
|
|
11271
|
-
} else {
|
|
11272
|
-
const needsRerun = this.handleFileChanged(id);
|
|
11273
|
-
if (needsRerun.length) {
|
|
11274
|
-
this.scheduleRerun(needsRerun);
|
|
11275
|
-
}
|
|
11276
|
-
}
|
|
11277
|
-
};
|
|
11278
|
-
checkUnhandledErrors(errors) {
|
|
11921
|
+
/** @deprecated use `invalidateFile` */
|
|
11922
|
+
updateLastChanged(filepath) {
|
|
11923
|
+
this.invalidateFile(filepath);
|
|
11924
|
+
}
|
|
11925
|
+
/** @internal */
|
|
11926
|
+
_checkUnhandledErrors(errors) {
|
|
11279
11927
|
if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) {
|
|
11280
11928
|
process.exitCode = 1;
|
|
11281
11929
|
}
|
|
11282
11930
|
}
|
|
11283
|
-
unregisterWatcher = noop;
|
|
11284
|
-
registerWatcher() {
|
|
11285
|
-
const watcher = this.server.watcher;
|
|
11286
|
-
if (this.config.forceRerunTriggers.length) {
|
|
11287
|
-
watcher.add(this.config.forceRerunTriggers);
|
|
11288
|
-
}
|
|
11289
|
-
watcher.on("change", this.onChange);
|
|
11290
|
-
watcher.on("unlink", this.onUnlink);
|
|
11291
|
-
watcher.on("add", this.onAdd);
|
|
11292
|
-
this.unregisterWatcher = () => {
|
|
11293
|
-
watcher.off("change", this.onChange);
|
|
11294
|
-
watcher.off("unlink", this.onUnlink);
|
|
11295
|
-
watcher.off("add", this.onAdd);
|
|
11296
|
-
this.unregisterWatcher = noop;
|
|
11297
|
-
};
|
|
11298
|
-
}
|
|
11299
|
-
/**
|
|
11300
|
-
* @returns A value indicating whether rerun is needed (changedTests was mutated)
|
|
11301
|
-
*/
|
|
11302
|
-
handleFileChanged(filepath) {
|
|
11303
|
-
if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) {
|
|
11304
|
-
return [];
|
|
11305
|
-
}
|
|
11306
|
-
if (mm.isMatch(filepath, this.config.forceRerunTriggers)) {
|
|
11307
|
-
this.state.getFilepaths().forEach((file) => this.changedTests.add(file));
|
|
11308
|
-
return [filepath];
|
|
11309
|
-
}
|
|
11310
|
-
const projects = this.getModuleProjects(filepath);
|
|
11311
|
-
if (!projects.length) {
|
|
11312
|
-
if (this.state.filesMap.has(filepath) || this.projects.some((project) => project.isTestFile(filepath))) {
|
|
11313
|
-
this.changedTests.add(filepath);
|
|
11314
|
-
return [filepath];
|
|
11315
|
-
}
|
|
11316
|
-
return [];
|
|
11317
|
-
}
|
|
11318
|
-
const files = [];
|
|
11319
|
-
for (const project of projects) {
|
|
11320
|
-
const mods = project.getModulesByFilepath(filepath);
|
|
11321
|
-
if (!mods.size) {
|
|
11322
|
-
continue;
|
|
11323
|
-
}
|
|
11324
|
-
this.invalidates.add(filepath);
|
|
11325
|
-
if (this.state.filesMap.has(filepath) || project.isTestFile(filepath)) {
|
|
11326
|
-
this.changedTests.add(filepath);
|
|
11327
|
-
files.push(filepath);
|
|
11328
|
-
continue;
|
|
11329
|
-
}
|
|
11330
|
-
let rerun = false;
|
|
11331
|
-
for (const mod of mods) {
|
|
11332
|
-
mod.importers.forEach((i) => {
|
|
11333
|
-
if (!i.file) {
|
|
11334
|
-
return;
|
|
11335
|
-
}
|
|
11336
|
-
const heedsRerun = this.handleFileChanged(i.file);
|
|
11337
|
-
if (heedsRerun.length) {
|
|
11338
|
-
rerun = true;
|
|
11339
|
-
}
|
|
11340
|
-
});
|
|
11341
|
-
}
|
|
11342
|
-
if (rerun) {
|
|
11343
|
-
files.push(filepath);
|
|
11344
|
-
}
|
|
11345
|
-
}
|
|
11346
|
-
return Array.from(new Set(files));
|
|
11347
|
-
}
|
|
11348
11931
|
async reportCoverage(coverage, allTestsRun) {
|
|
11349
11932
|
if (this.state.getCountOfFailedTests() > 0) {
|
|
11350
11933
|
await this.coverageProvider?.onTestFailure?.();
|
|
@@ -11361,19 +11944,23 @@ class Vitest {
|
|
|
11361
11944
|
}
|
|
11362
11945
|
}
|
|
11363
11946
|
}
|
|
11947
|
+
/**
|
|
11948
|
+
* Closes all projects and their associated resources.
|
|
11949
|
+
* This can only be called once; the closing promise is cached until the server restarts.
|
|
11950
|
+
*/
|
|
11364
11951
|
async close() {
|
|
11365
11952
|
if (!this.closingPromise) {
|
|
11366
11953
|
this.closingPromise = (async () => {
|
|
11367
11954
|
const teardownProjects = [...this.projects];
|
|
11368
|
-
if (!teardownProjects.includes(this.coreWorkspaceProject)) {
|
|
11955
|
+
if (this.coreWorkspaceProject && !teardownProjects.includes(this.coreWorkspaceProject)) {
|
|
11369
11956
|
teardownProjects.push(this.coreWorkspaceProject);
|
|
11370
11957
|
}
|
|
11371
11958
|
for (const project of teardownProjects.reverse()) {
|
|
11372
11959
|
await project._teardownGlobalSetup();
|
|
11373
11960
|
}
|
|
11374
11961
|
const closePromises = this.resolvedProjects.map((w) => w.close());
|
|
11375
|
-
if (!this.resolvedProjects.includes(this.coreWorkspaceProject)) {
|
|
11376
|
-
closePromises.push(this.coreWorkspaceProject.close().then(() => this.
|
|
11962
|
+
if (this.coreWorkspaceProject && !this.resolvedProjects.includes(this.coreWorkspaceProject)) {
|
|
11963
|
+
closePromises.push(this.coreWorkspaceProject.close().then(() => this._vite = void 0));
|
|
11377
11964
|
}
|
|
11378
11965
|
if (this.pool) {
|
|
11379
11966
|
closePromises.push((async () => {
|
|
@@ -11395,7 +11982,8 @@ class Vitest {
|
|
|
11395
11982
|
return this.closingPromise;
|
|
11396
11983
|
}
|
|
11397
11984
|
/**
|
|
11398
|
-
*
|
|
11985
|
+
* Closes all projects and exit the process
|
|
11986
|
+
* @param force If true, the process will exit immediately after closing the projects.
|
|
11399
11987
|
*/
|
|
11400
11988
|
async exit(force = false) {
|
|
11401
11989
|
setTimeout(() => {
|
|
@@ -11403,7 +11991,7 @@ class Vitest {
|
|
|
11403
11991
|
console.warn(`close timed out after ${this.config.teardownTimeout}ms`);
|
|
11404
11992
|
this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause));
|
|
11405
11993
|
if (!this.pool) {
|
|
11406
|
-
const runningServers = [this.
|
|
11994
|
+
const runningServers = [this.vite, ...this.resolvedProjects.map((p) => p.vite)].filter(Boolean).length;
|
|
11407
11995
|
if (runningServers === 1) {
|
|
11408
11996
|
console.warn("Tests closed successfully but something prevents Vite server from exiting");
|
|
11409
11997
|
} else if (runningServers > 1) {
|
|
@@ -11421,94 +12009,90 @@ class Vitest {
|
|
|
11421
12009
|
process.exit();
|
|
11422
12010
|
}
|
|
11423
12011
|
}
|
|
12012
|
+
/** @internal */
|
|
11424
12013
|
async report(name, ...args) {
|
|
11425
12014
|
await Promise.all(this.reporters.map((r) => r[name]?.(
|
|
11426
12015
|
...args
|
|
11427
12016
|
)));
|
|
11428
12017
|
}
|
|
11429
|
-
|
|
11430
|
-
|
|
12018
|
+
/** @internal */
|
|
12019
|
+
async _globTestFilepaths() {
|
|
12020
|
+
const specifications = await this.globTestSpecifications();
|
|
12021
|
+
return Array.from(new Set(specifications.map((spec) => spec.moduleId)));
|
|
11431
12022
|
}
|
|
12023
|
+
/**
|
|
12024
|
+
* @deprecated use `globTestSpecifications` instead
|
|
12025
|
+
*/
|
|
11432
12026
|
async globTestSpecs(filters = []) {
|
|
11433
|
-
|
|
11434
|
-
const dir = process.cwd();
|
|
11435
|
-
const parsedFilters = filters.map((f) => parseFilter(f));
|
|
11436
|
-
if (!this.config.includeTaskLocation && parsedFilters.some((f) => f.lineNumber !== void 0)) {
|
|
11437
|
-
throw new IncludeTaskLocationDisabledError();
|
|
11438
|
-
}
|
|
11439
|
-
const testLocations = groupFilters(parsedFilters.map(
|
|
11440
|
-
(f) => ({ ...f, filename: slash(resolve$1(dir, f.filename)) })
|
|
11441
|
-
));
|
|
11442
|
-
const testLocHasMatch = {};
|
|
11443
|
-
await Promise.all(this.projects.map(async (project) => {
|
|
11444
|
-
const { testFiles, typecheckTestFiles } = await project.globTestFiles(
|
|
11445
|
-
parsedFilters.map((f) => f.filename)
|
|
11446
|
-
);
|
|
11447
|
-
testFiles.forEach((file) => {
|
|
11448
|
-
const loc = testLocations[file];
|
|
11449
|
-
testLocHasMatch[file] = true;
|
|
11450
|
-
const spec = project.createSpecification(file, void 0, loc);
|
|
11451
|
-
this.ensureSpecCached(spec);
|
|
11452
|
-
files.push(spec);
|
|
11453
|
-
});
|
|
11454
|
-
typecheckTestFiles.forEach((file) => {
|
|
11455
|
-
const loc = testLocations[file];
|
|
11456
|
-
testLocHasMatch[file] = true;
|
|
11457
|
-
const spec = project.createSpecification(file, "typescript", loc);
|
|
11458
|
-
this.ensureSpecCached(spec);
|
|
11459
|
-
files.push(spec);
|
|
11460
|
-
});
|
|
11461
|
-
}));
|
|
11462
|
-
Object.entries(testLocations).forEach(([filepath, loc]) => {
|
|
11463
|
-
if (loc.length !== 0 && !testLocHasMatch[filepath]) {
|
|
11464
|
-
throw new LocationFilterFileNotFoundError(
|
|
11465
|
-
relative(dir, filepath)
|
|
11466
|
-
);
|
|
11467
|
-
}
|
|
11468
|
-
});
|
|
11469
|
-
return files;
|
|
12027
|
+
return this.globTestSpecifications(filters);
|
|
11470
12028
|
}
|
|
11471
12029
|
/**
|
|
11472
|
-
* @deprecated use `
|
|
12030
|
+
* @deprecated use `globTestSpecifications` instead
|
|
11473
12031
|
*/
|
|
11474
12032
|
async globTestFiles(filters = []) {
|
|
11475
|
-
return this.
|
|
12033
|
+
return this.globTestSpecifications(filters);
|
|
11476
12034
|
}
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
specs.push(spec);
|
|
11483
|
-
this._cachedSpecs.set(file, specs);
|
|
11484
|
-
}
|
|
12035
|
+
/** @deprecated filter by `this.projects` yourself */
|
|
12036
|
+
getModuleProjects(filepath) {
|
|
12037
|
+
return this.projects.filter((project) => {
|
|
12038
|
+
return project.getModulesByFilepath(filepath).size;
|
|
12039
|
+
});
|
|
11485
12040
|
}
|
|
11486
|
-
|
|
12041
|
+
/**
|
|
12042
|
+
* Should the server be kept running after the tests are done.
|
|
12043
|
+
*/
|
|
11487
12044
|
shouldKeepServer() {
|
|
11488
12045
|
return !!this.config?.watch;
|
|
11489
12046
|
}
|
|
12047
|
+
/**
|
|
12048
|
+
* Register a handler that will be called when the server is restarted due to a config change.
|
|
12049
|
+
*/
|
|
11490
12050
|
onServerRestart(fn) {
|
|
11491
12051
|
this._onRestartListeners.push(fn);
|
|
11492
12052
|
}
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
12053
|
+
/**
|
|
12054
|
+
* Register a handler that will be called when the test run is cancelled with `vitest.cancelCurrentRun`.
|
|
12055
|
+
*/
|
|
11496
12056
|
onCancel(fn) {
|
|
11497
12057
|
this._onCancelListeners.push(fn);
|
|
11498
12058
|
}
|
|
12059
|
+
/**
|
|
12060
|
+
* Register a handler that will be called when the server is closed.
|
|
12061
|
+
*/
|
|
11499
12062
|
onClose(fn) {
|
|
11500
12063
|
this._onClose.push(fn);
|
|
11501
12064
|
}
|
|
12065
|
+
/**
|
|
12066
|
+
* Register a handler that will be called when the tests are rerunning.
|
|
12067
|
+
*/
|
|
11502
12068
|
onTestsRerun(fn) {
|
|
11503
12069
|
this._onUserTestsRerun.push(fn);
|
|
11504
12070
|
}
|
|
12071
|
+
/**
|
|
12072
|
+
* Register a handler that will be called when a file is changed.
|
|
12073
|
+
* This callback should return `true` of `false` indicating whether the test file needs to be rerun.
|
|
12074
|
+
* @example
|
|
12075
|
+
* const testsToRun = [resolve('./test.spec.ts')]
|
|
12076
|
+
* vitest.onFilterWatchedSpecification(specification => testsToRun.includes(specification.moduleId))
|
|
12077
|
+
*/
|
|
12078
|
+
onFilterWatchedSpecification(fn) {
|
|
12079
|
+
this._onFilterWatchedSpecification.push(fn);
|
|
12080
|
+
}
|
|
12081
|
+
/** @internal */
|
|
12082
|
+
onAfterSetServer(fn) {
|
|
12083
|
+
this._onSetServer.push(fn);
|
|
12084
|
+
}
|
|
12085
|
+
}
|
|
12086
|
+
function assert(condition, property, name = property) {
|
|
12087
|
+
if (!condition) {
|
|
12088
|
+
throw new Error(`The ${name} was not set. It means that \`vitest.${property}\` was called before the Vite server was established. Either await the Vitest promise or check that it is initialized with \`vitest.ready()\` before accessing \`vitest.${property}\`.`);
|
|
12089
|
+
}
|
|
11505
12090
|
}
|
|
11506
12091
|
|
|
11507
12092
|
async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
11508
12093
|
const userConfig = deepMerge({}, options);
|
|
11509
|
-
const getRoot = () => ctx.config?.root || options.root || process.cwd();
|
|
11510
12094
|
async function UIPlugin() {
|
|
11511
|
-
await ctx.packageInstaller.ensureInstalled("@vitest/ui",
|
|
12095
|
+
await ctx.packageInstaller.ensureInstalled("@vitest/ui", options.root || process.cwd(), ctx.version);
|
|
11512
12096
|
return (await import('@vitest/ui')).default(ctx);
|
|
11513
12097
|
}
|
|
11514
12098
|
return [
|
|
@@ -11558,7 +12142,7 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
11558
12142
|
ws: testConfig.api?.middlewareMode ? false : void 0,
|
|
11559
12143
|
preTransformRequests: false,
|
|
11560
12144
|
fs: {
|
|
11561
|
-
allow: resolveFsAllow(
|
|
12145
|
+
allow: resolveFsAllow(options.root || process.cwd(), testConfig.config)
|
|
11562
12146
|
}
|
|
11563
12147
|
},
|
|
11564
12148
|
build: {
|
|
@@ -11634,7 +12218,7 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
11634
12218
|
config.css.modules ??= {};
|
|
11635
12219
|
if (config.css.modules) {
|
|
11636
12220
|
config.css.modules.generateScopedName = (name, filename) => {
|
|
11637
|
-
const root =
|
|
12221
|
+
const root = ctx.config.root || options.root || process.cwd();
|
|
11638
12222
|
return generateScopedClassName(
|
|
11639
12223
|
classNameStrategy,
|
|
11640
12224
|
name,
|
|
@@ -11665,6 +12249,11 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
11665
12249
|
viteConfig.server.watch = null;
|
|
11666
12250
|
}
|
|
11667
12251
|
hijackVitePluginInject(viteConfig);
|
|
12252
|
+
Object.defineProperty(viteConfig, "_vitest", {
|
|
12253
|
+
value: options,
|
|
12254
|
+
enumerable: false,
|
|
12255
|
+
configurable: true
|
|
12256
|
+
});
|
|
11668
12257
|
},
|
|
11669
12258
|
configureServer: {
|
|
11670
12259
|
// runs after vite:import-analysis as it relies on `server` instance on Vite 5
|
|
@@ -11675,7 +12264,7 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
|
|
|
11675
12264
|
console.log("[debug] watcher is ready");
|
|
11676
12265
|
});
|
|
11677
12266
|
}
|
|
11678
|
-
await ctx.
|
|
12267
|
+
await ctx._setServer(options, server, userConfig);
|
|
11679
12268
|
if (options.api && options.watch) {
|
|
11680
12269
|
(await Promise.resolve().then(function () { return setup$1; })).setup(ctx);
|
|
11681
12270
|
}
|
|
@@ -11947,7 +12536,7 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout2) {
|
|
|
11947
12536
|
return ctx.updateSnapshot();
|
|
11948
12537
|
}
|
|
11949
12538
|
if (name === "a" || name === "return") {
|
|
11950
|
-
const files = await ctx.
|
|
12539
|
+
const files = await ctx._globTestFilepaths();
|
|
11951
12540
|
return ctx.changeNamePattern("", files, "rerun all tests");
|
|
11952
12541
|
}
|
|
11953
12542
|
if (name === "r") {
|
|
@@ -11966,7 +12555,7 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout2) {
|
|
|
11966
12555
|
return inputFilePattern();
|
|
11967
12556
|
}
|
|
11968
12557
|
if (name === "b") {
|
|
11969
|
-
await ctx.
|
|
12558
|
+
await ctx._initBrowserServers();
|
|
11970
12559
|
ctx.projects.forEach((project) => {
|
|
11971
12560
|
ctx.logger.log();
|
|
11972
12561
|
ctx.logger.printBrowserBanner(project);
|
|
@@ -11999,7 +12588,7 @@ function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout2) {
|
|
|
11999
12588
|
return;
|
|
12000
12589
|
}
|
|
12001
12590
|
const files = ctx.state.getFilepaths();
|
|
12002
|
-
const cliFiles = ctx.config.standalone && !files.length ? await ctx.
|
|
12591
|
+
const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0;
|
|
12003
12592
|
await ctx.changeNamePattern(
|
|
12004
12593
|
filter?.trim() || "",
|
|
12005
12594
|
cliFiles,
|
|
@@ -12136,12 +12725,6 @@ async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions) {
|
|
|
12136
12725
|
options.watch = false;
|
|
12137
12726
|
}
|
|
12138
12727
|
const root = resolve(options.root || process.cwd());
|
|
12139
|
-
if (typeof options.browser === "object" && !("enabled" in options.browser)) {
|
|
12140
|
-
options.browser.enabled = true;
|
|
12141
|
-
}
|
|
12142
|
-
if (typeof options.typecheck?.only === "boolean") {
|
|
12143
|
-
options.typecheck.enabled ??= true;
|
|
12144
|
-
}
|
|
12145
12728
|
const ctx = await createVitest(mode, options, viteOverrides, vitestOptions);
|
|
12146
12729
|
const environmentPackage = getEnvPackageName(ctx.config.environment);
|
|
12147
12730
|
if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) {
|
|
@@ -12153,11 +12736,10 @@ async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions) {
|
|
|
12153
12736
|
function processCollected(ctx, files, options) {
|
|
12154
12737
|
let errorsPrinted = false;
|
|
12155
12738
|
forEachSuite(files, (suite) => {
|
|
12156
|
-
|
|
12157
|
-
errors.forEach((error) => {
|
|
12739
|
+
suite.errors().forEach((error) => {
|
|
12158
12740
|
errorsPrinted = true;
|
|
12159
12741
|
ctx.logger.printError(error, {
|
|
12160
|
-
project:
|
|
12742
|
+
project: suite.project
|
|
12161
12743
|
});
|
|
12162
12744
|
});
|
|
12163
12745
|
});
|
|
@@ -12215,43 +12797,50 @@ function processJsonOutput(files, options) {
|
|
|
12215
12797
|
writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2));
|
|
12216
12798
|
}
|
|
12217
12799
|
}
|
|
12218
|
-
function forEachSuite(
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
|
|
12222
|
-
|
|
12800
|
+
function forEachSuite(modules, callback) {
|
|
12801
|
+
modules.forEach((testModule) => {
|
|
12802
|
+
callback(testModule);
|
|
12803
|
+
for (const suite of testModule.children.allSuites()) {
|
|
12804
|
+
callback(suite);
|
|
12223
12805
|
}
|
|
12224
12806
|
});
|
|
12225
12807
|
}
|
|
12226
12808
|
function formatCollectedAsJSON(files) {
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12809
|
+
const results = [];
|
|
12810
|
+
files.forEach((file) => {
|
|
12811
|
+
for (const test of file.children.allTests()) {
|
|
12812
|
+
if (test.skipped()) {
|
|
12813
|
+
continue;
|
|
12814
|
+
}
|
|
12230
12815
|
const result = {
|
|
12231
|
-
name:
|
|
12232
|
-
file:
|
|
12816
|
+
name: test.fullName,
|
|
12817
|
+
file: test.module.moduleId
|
|
12233
12818
|
};
|
|
12234
|
-
if (test.
|
|
12235
|
-
result.projectName = test.
|
|
12819
|
+
if (test.project.name) {
|
|
12820
|
+
result.projectName = test.project.name;
|
|
12236
12821
|
}
|
|
12237
12822
|
if (test.location) {
|
|
12238
12823
|
result.location = test.location;
|
|
12239
12824
|
}
|
|
12240
|
-
|
|
12241
|
-
}
|
|
12242
|
-
})
|
|
12825
|
+
results.push(result);
|
|
12826
|
+
}
|
|
12827
|
+
});
|
|
12828
|
+
return results;
|
|
12243
12829
|
}
|
|
12244
|
-
function formatCollectedAsString(
|
|
12245
|
-
|
|
12246
|
-
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
return `[${test.file.projectName}] ${name}`;
|
|
12830
|
+
function formatCollectedAsString(testModules) {
|
|
12831
|
+
const results = [];
|
|
12832
|
+
testModules.forEach((testModule) => {
|
|
12833
|
+
for (const test of testModule.children.allTests()) {
|
|
12834
|
+
if (test.skipped()) {
|
|
12835
|
+
continue;
|
|
12251
12836
|
}
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12837
|
+
const fullName = `${test.module.task.name} > ${test.fullName}`;
|
|
12838
|
+
results.push(
|
|
12839
|
+
(test.project.name ? `[${test.project.name}] ` : "") + fullName
|
|
12840
|
+
);
|
|
12841
|
+
}
|
|
12842
|
+
});
|
|
12843
|
+
return results;
|
|
12255
12844
|
}
|
|
12256
12845
|
const envPackageNames = {
|
|
12257
12846
|
"jsdom": "jsdom",
|
|
@@ -12281,4 +12870,4 @@ var cliApi = /*#__PURE__*/Object.freeze({
|
|
|
12281
12870
|
startVitest: startVitest
|
|
12282
12871
|
});
|
|
12283
12872
|
|
|
12284
|
-
export { FilesNotFoundError as F, GitNotFoundError as G,
|
|
12873
|
+
export { FilesNotFoundError as F, GitNotFoundError as G, Vitest as V, VitestPlugin as a, VitestPackageInstaller as b, createVitest as c, registerConsoleShortcuts as d, createViteLogger as e, cliApi as f, resolveFsAllow as r, startVitest as s };
|