vitest 2.1.5 → 2.2.0-beta.2

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.
Files changed (45) hide show
  1. package/LICENSE.md +0 -75
  2. package/dist/browser.d.ts +11 -11
  3. package/dist/browser.js +1 -1
  4. package/dist/chunks/{RandomSequencer.CMRlh2v4.js → RandomSequencer.BPedXEug.js} +1 -0
  5. package/dist/chunks/{base.BZZh4cSm.js → base.BS0HhLXd.js} +1 -1
  6. package/dist/chunks/{benchmark.geERunq4.d.ts → benchmark.CFFwLv-O.d.ts} +2 -2
  7. package/dist/chunks/{cac.DWAW3Uh5.js → cac.Cs06pOqp.js} +56 -7
  8. package/dist/chunks/{cli-api.BtqJwSCh.js → cli-api.CB-jIbYQ.js} +585 -407
  9. package/dist/chunks/{config.Cy0C388Z.d.ts → config.CPguQ7J1.d.ts} +2 -1
  10. package/dist/chunks/{environment.LoooBwUu.d.ts → environment.CT0jpO-1.d.ts} +2 -1
  11. package/dist/chunks/{globals.D8ZVAdXd.js → globals.BCGEw6ON.js} +2 -2
  12. package/dist/chunks/{index.nEwtF0bu.js → index.BjjsHdBb.js} +1 -1
  13. package/dist/chunks/{index.ckWaX2gY.js → index.DD5eTY2y.js} +2 -8
  14. package/dist/chunks/{index.DsZFoqi9.js → index.bzFpKeaq.js} +601 -807
  15. package/dist/chunks/{reporters.D7Jzd9GS.d.ts → reporters.F9D2idOT.d.ts} +1429 -1286
  16. package/dist/chunks/{resolveConfig.RxKrDli4.js → resolveConfig.CLnvCvEs.js} +11 -9
  17. package/dist/chunks/{runBaseTests.3qpJUEJM.js → runBaseTests.B7hcVT-s.js} +4 -4
  18. package/dist/chunks/{setup-common.Dj6BZI3u.js → setup-common.BfGt8K-K.js} +4 -1
  19. package/dist/chunks/{suite.B2jumIFP.d.ts → suite.BJU7kdY9.d.ts} +4 -4
  20. package/dist/chunks/{utils.DNoFbBUZ.js → utils.DJONn5B5.js} +15 -21
  21. package/dist/chunks/{vi.DgezovHB.js → vi.BlPttogV.js} +6 -1
  22. package/dist/chunks/{vite.C-N5BBZe.d.ts → vite.DonA4fvH.d.ts} +1 -1
  23. package/dist/chunks/{worker.tN5KGIih.d.ts → worker.9VY11NZs.d.ts} +2 -2
  24. package/dist/chunks/{worker.B9FxPCaC.d.ts → worker.Qz1UB4Fv.d.ts} +1 -1
  25. package/dist/cli.js +1 -1
  26. package/dist/config.d.ts +13 -11
  27. package/dist/coverage.d.ts +9 -112
  28. package/dist/coverage.js +2 -2
  29. package/dist/environments.d.ts +2 -2
  30. package/dist/execute.d.ts +4 -3
  31. package/dist/index.d.ts +14 -13
  32. package/dist/index.js +2 -2
  33. package/dist/node.d.ts +26 -15
  34. package/dist/node.js +9 -9
  35. package/dist/reporters.d.ts +9 -8
  36. package/dist/reporters.js +4 -5
  37. package/dist/runners.d.ts +5 -3
  38. package/dist/runners.js +4 -1
  39. package/dist/suite.d.ts +2 -2
  40. package/dist/workers/forks.js +1 -1
  41. package/dist/workers/runVmTests.js +4 -4
  42. package/dist/workers/threads.js +1 -1
  43. package/dist/workers.d.ts +5 -4
  44. package/dist/workers.js +1 -1
  45. package/package.json +13 -12
@@ -8,12 +8,12 @@ import { f as findUp, p as prompt } from './index.BJDntFik.js';
8
8
  import { searchForWorkspaceRoot, version, createServer, mergeConfig } from 'vite';
9
9
  import { A as API_PATH, c as configFiles, a as defaultBrowserPort, w as workspacesFiles, d as defaultPort } from './constants.fzPh7AOq.js';
10
10
  import { SnapshotManager } from '@vitest/snapshot/manager';
11
- import { i as isPackageExists, e as requireMicromatch, V as VitestCache, f as configDefaults, m as mm, b as resolveConfig, h as isBrowserEnabled, w as wildcardPatternToRegExp, g as getFilePoolName, j as createPool, a as resolveApiServerConfig, c as coverageConfigDefaults, s as stdout } from './resolveConfig.RxKrDli4.js';
11
+ import { i as isPackageExists, e as requireMicromatch, V as VitestCache, f as configDefaults, g as getFilePoolName, h as isBrowserEnabled, m as mm, b as resolveConfig, w as wildcardPatternToRegExp, j as createPool, a as resolveApiServerConfig, c as coverageConfigDefaults, s as stdout } from './resolveConfig.CLnvCvEs.js';
12
12
  import { ViteNodeRunner } from 'vite-node/client';
13
13
  import { ViteNodeServer } from 'vite-node/server';
14
- import { v as version$1 } from './cac.DWAW3Uh5.js';
14
+ import { v as version$1 } from './cac.Cs06pOqp.js';
15
15
  import { c as createBirpc } from './index.68735LiX.js';
16
- import { s as stringify, p as parse, R as ReportersMap, h as BenchmarkReportsMap, f as TestModule, g as TestSuite, e as TestCase, j as generateCodeFrame, i as TestProject, L as Logger, k as BlobReporter, r as readBlobs } from './index.DsZFoqi9.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.bzFpKeaq.js';
17
17
  import require$$0$2 from 'stream';
18
18
  import require$$0 from 'zlib';
19
19
  import require$$0$1 from 'buffer';
@@ -30,7 +30,7 @@ import { distDir, rootDir } from '../path.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.CMRlh2v4.js';
33
+ import { h as hash, i as isWindows } from './RandomSequencer.BPedXEug.js';
34
34
  import { isCI } from 'std-env';
35
35
  import { rm } from 'node:fs/promises';
36
36
  import nodeos__default, { tmpdir } from 'node:os';
@@ -4845,7 +4845,7 @@ async function getModuleGraph(ctx, projectName, id, browser = false) {
4845
4845
  if (browser && project.browser) {
4846
4846
  await get(project.browser.vite.moduleGraph.getModuleById(id));
4847
4847
  } else {
4848
- await get(project.server.moduleGraph.getModuleById(id));
4848
+ await get(project.vite.moduleGraph.getModuleById(id));
4849
4849
  }
4850
4850
  return {
4851
4851
  graph,
@@ -4924,11 +4924,14 @@ function setup(ctx, _server) {
4924
4924
  }
4925
4925
  return promises.writeFile(id, content, "utf-8");
4926
4926
  },
4927
- async rerun(files) {
4928
- await ctx.rerunFiles(files);
4927
+ async rerun(files, resetTestNamePattern) {
4928
+ await ctx.rerunFiles(files, void 0, true, resetTestNamePattern);
4929
+ },
4930
+ async rerunTask(id) {
4931
+ await ctx.rerunTask(id);
4929
4932
  },
4930
4933
  getConfig() {
4931
- return ctx.getCoreWorkspaceProject().getSerializableConfig();
4934
+ return ctx.getRootTestProject().serializedConfig;
4932
4935
  },
4933
4936
  async getTransformResult(projectName, id, browser = false) {
4934
4937
  const project = ctx.getProjectByName(projectName);
@@ -5123,249 +5126,6 @@ Package ${packageName} installed, re-run the command to start.
5123
5126
  }
5124
5127
  }
5125
5128
 
5126
- async function loadCustomReporterModule(path, runner) {
5127
- let customReporterModule;
5128
- try {
5129
- customReporterModule = await runner.executeId(path);
5130
- } catch (customReporterModuleError) {
5131
- throw new Error(`Failed to load custom Reporter from ${path}`, {
5132
- cause: customReporterModuleError
5133
- });
5134
- }
5135
- if (customReporterModule.default === null || customReporterModule.default === void 0) {
5136
- throw new Error(
5137
- `Custom reporter loaded from ${path} was not the default export`
5138
- );
5139
- }
5140
- return customReporterModule.default;
5141
- }
5142
- function createReporters(reporterReferences, ctx) {
5143
- const runner = ctx.runner;
5144
- const promisedReporters = reporterReferences.map(
5145
- async (referenceOrInstance) => {
5146
- if (Array.isArray(referenceOrInstance)) {
5147
- const [reporterName, reporterOptions] = referenceOrInstance;
5148
- if (reporterName === "html") {
5149
- await ctx.packageInstaller.ensureInstalled("@vitest/ui", runner.root, ctx.version);
5150
- const CustomReporter = await loadCustomReporterModule(
5151
- "@vitest/ui/reporter",
5152
- runner
5153
- );
5154
- return new CustomReporter(reporterOptions);
5155
- } else if (reporterName in ReportersMap) {
5156
- const BuiltinReporter = ReportersMap[reporterName];
5157
- return new BuiltinReporter(reporterOptions);
5158
- } else {
5159
- const CustomReporter = await loadCustomReporterModule(
5160
- reporterName,
5161
- runner
5162
- );
5163
- return new CustomReporter(reporterOptions);
5164
- }
5165
- }
5166
- return referenceOrInstance;
5167
- }
5168
- );
5169
- return Promise.all(promisedReporters);
5170
- }
5171
- function createBenchmarkReporters(reporterReferences, runner) {
5172
- const promisedReporters = reporterReferences.map(
5173
- async (referenceOrInstance) => {
5174
- if (typeof referenceOrInstance === "string") {
5175
- if (referenceOrInstance in BenchmarkReportsMap) {
5176
- const BuiltinReporter = BenchmarkReportsMap[referenceOrInstance];
5177
- return new BuiltinReporter();
5178
- } else {
5179
- const CustomReporter = await loadCustomReporterModule(
5180
- referenceOrInstance,
5181
- runner
5182
- );
5183
- return new CustomReporter();
5184
- }
5185
- }
5186
- return referenceOrInstance;
5187
- }
5188
- );
5189
- return Promise.all(promisedReporters);
5190
- }
5191
-
5192
- function isAggregateError(err) {
5193
- if (typeof AggregateError !== "undefined" && err instanceof AggregateError) {
5194
- return true;
5195
- }
5196
- return err instanceof Error && "errors" in err;
5197
- }
5198
- class StateManager {
5199
- filesMap = /* @__PURE__ */ new Map();
5200
- pathsSet = /* @__PURE__ */ new Set();
5201
- idMap = /* @__PURE__ */ new Map();
5202
- taskFileMap = /* @__PURE__ */ new WeakMap();
5203
- errorsSet = /* @__PURE__ */ new Set();
5204
- processTimeoutCauses = /* @__PURE__ */ new Set();
5205
- reportedTasksMap = /* @__PURE__ */ new WeakMap();
5206
- catchError(err, type) {
5207
- if (isAggregateError(err)) {
5208
- return err.errors.forEach((error) => this.catchError(error, type));
5209
- }
5210
- if (err === Object(err)) {
5211
- err.type = type;
5212
- } else {
5213
- err = { type, message: err };
5214
- }
5215
- const _err = err;
5216
- if (_err && typeof _err === "object" && _err.code === "VITEST_PENDING") {
5217
- const task = this.idMap.get(_err.taskId);
5218
- if (task) {
5219
- task.mode = "skip";
5220
- task.result ??= { state: "skip" };
5221
- task.result.state = "skip";
5222
- }
5223
- return;
5224
- }
5225
- this.errorsSet.add(err);
5226
- }
5227
- clearErrors() {
5228
- this.errorsSet.clear();
5229
- }
5230
- getUnhandledErrors() {
5231
- return Array.from(this.errorsSet.values());
5232
- }
5233
- addProcessTimeoutCause(cause) {
5234
- this.processTimeoutCauses.add(cause);
5235
- }
5236
- getProcessTimeoutCauses() {
5237
- return Array.from(this.processTimeoutCauses.values());
5238
- }
5239
- getPaths() {
5240
- return Array.from(this.pathsSet);
5241
- }
5242
- /**
5243
- * Return files that were running or collected.
5244
- */
5245
- getFiles(keys) {
5246
- if (keys) {
5247
- return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local);
5248
- }
5249
- return Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
5250
- if (f1.meta?.typecheck && f2.meta?.typecheck) {
5251
- return 0;
5252
- }
5253
- if (f1.meta?.typecheck) {
5254
- return -1;
5255
- }
5256
- return 1;
5257
- });
5258
- }
5259
- getFilepaths() {
5260
- return Array.from(this.filesMap.keys());
5261
- }
5262
- getFailedFilepaths() {
5263
- return this.getFiles().filter((i) => i.result?.state === "fail").map((i) => i.filepath);
5264
- }
5265
- collectPaths(paths = []) {
5266
- paths.forEach((path) => {
5267
- this.pathsSet.add(path);
5268
- });
5269
- }
5270
- collectFiles(project, files = []) {
5271
- files.forEach((file) => {
5272
- const existing = this.filesMap.get(file.filepath) || [];
5273
- const otherFiles = existing.filter(
5274
- (i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck
5275
- );
5276
- const currentFile = existing.find(
5277
- (i) => i.projectName === file.projectName
5278
- );
5279
- if (currentFile) {
5280
- file.logs = currentFile.logs;
5281
- }
5282
- otherFiles.push(file);
5283
- this.filesMap.set(file.filepath, otherFiles);
5284
- this.updateId(file, project);
5285
- });
5286
- }
5287
- clearFiles(project, paths = []) {
5288
- paths.forEach((path) => {
5289
- const files = this.filesMap.get(path);
5290
- const fileTask = createFileTask(
5291
- path,
5292
- project.config.root,
5293
- project.config.name
5294
- );
5295
- fileTask.local = true;
5296
- TestModule.register(fileTask, project);
5297
- this.idMap.set(fileTask.id, fileTask);
5298
- if (!files) {
5299
- this.filesMap.set(path, [fileTask]);
5300
- return;
5301
- }
5302
- const filtered = files.filter(
5303
- (file) => file.projectName !== project.config.name
5304
- );
5305
- if (!filtered.length) {
5306
- this.filesMap.set(path, [fileTask]);
5307
- } else {
5308
- this.filesMap.set(path, [...filtered, fileTask]);
5309
- }
5310
- });
5311
- }
5312
- updateId(task, project) {
5313
- if (this.idMap.get(task.id) === task) {
5314
- return;
5315
- }
5316
- if (task.type === "suite" && "filepath" in task) {
5317
- TestModule.register(task, project);
5318
- } else if (task.type === "suite") {
5319
- TestSuite.register(task, project);
5320
- } else {
5321
- TestCase.register(task, project);
5322
- }
5323
- this.idMap.set(task.id, task);
5324
- if (task.type === "suite") {
5325
- task.tasks.forEach((task2) => {
5326
- this.updateId(task2, project);
5327
- });
5328
- }
5329
- }
5330
- getReportedEntity(task) {
5331
- return this.reportedTasksMap.get(task);
5332
- }
5333
- updateTasks(packs) {
5334
- for (const [id, result, meta] of packs) {
5335
- const task = this.idMap.get(id);
5336
- if (task) {
5337
- task.result = result;
5338
- task.meta = meta;
5339
- if (result?.state === "skip") {
5340
- task.mode = "skip";
5341
- }
5342
- }
5343
- }
5344
- }
5345
- updateUserLog(log) {
5346
- const task = log.taskId && this.idMap.get(log.taskId);
5347
- if (task) {
5348
- if (!task.logs) {
5349
- task.logs = [];
5350
- }
5351
- task.logs.push(log);
5352
- }
5353
- }
5354
- getCountOfFailedTests() {
5355
- return Array.from(this.idMap.values()).filter(
5356
- (t) => t.result?.state === "fail"
5357
- ).length;
5358
- }
5359
- cancelFiles(files, project) {
5360
- this.collectFiles(
5361
- project,
5362
- files.map(
5363
- (filepath) => createFileTask(filepath, project.config.root, project.config.name)
5364
- )
5365
- );
5366
- }
5367
- }
5368
-
5369
5129
  var tasks = {};
5370
5130
 
5371
5131
  var utils$1 = {};
@@ -8559,6 +8319,7 @@ function serializeConfig(config, coreConfig, viteConfig) {
8559
8319
  pool: config.pool,
8560
8320
  expect: config.expect,
8561
8321
  snapshotSerializers: config.snapshotSerializers,
8322
+ // TODO: non serializable function?
8562
8323
  diff: config.diff,
8563
8324
  retry: config.retry,
8564
8325
  disableConsoleIntercept: config.disableConsoleIntercept,
@@ -9445,7 +9206,7 @@ function NormalizeURLPlugin() {
9445
9206
  };
9446
9207
  }
9447
9208
 
9448
- function resolveOptimizerConfig(_testOptions, viteOptions, testConfig) {
9209
+ function resolveOptimizerConfig(_testOptions, viteOptions, testConfig, viteCacheDir) {
9449
9210
  const testOptions = _testOptions || {};
9450
9211
  const newConfig = {};
9451
9212
  const [major, minor, fix] = version.split(".").map(Number);
@@ -9466,7 +9227,6 @@ function resolveOptimizerConfig(_testOptions, viteOptions, testConfig) {
9466
9227
  };
9467
9228
  } else {
9468
9229
  const root = testConfig.root ?? process.cwd();
9469
- const cacheDir = testConfig.cache !== false ? testConfig.cache?.dir : void 0;
9470
9230
  const currentInclude = testOptions.include || viteOptions?.include || [];
9471
9231
  const exclude = [
9472
9232
  "vitest",
@@ -9482,7 +9242,7 @@ function resolveOptimizerConfig(_testOptions, viteOptions, testConfig) {
9482
9242
  const include = (testOptions.include || viteOptions?.include || []).filter(
9483
9243
  (n) => !exclude.includes(n)
9484
9244
  );
9485
- newConfig.cacheDir = cacheDir ?? VitestCache.resolveCacheDir(root, cacheDir, testConfig.name);
9245
+ newConfig.cacheDir = testConfig.cache !== false && testConfig.cache?.dir || VitestCache.resolveCacheDir(root, viteCacheDir, testConfig.name);
9486
9246
  newConfig.optimizeDeps = {
9487
9247
  ...viteOptions,
9488
9248
  ...testOptions,
@@ -9565,12 +9325,14 @@ function VitestOptimizer() {
9565
9325
  const webOptimizer = resolveOptimizerConfig(
9566
9326
  testConfig.deps?.optimizer?.web,
9567
9327
  viteConfig.optimizeDeps,
9568
- testConfig
9328
+ testConfig,
9329
+ viteConfig.cacheDir
9569
9330
  );
9570
9331
  const ssrOptimizer = resolveOptimizerConfig(
9571
9332
  testConfig.deps?.optimizer?.ssr,
9572
9333
  viteConfig.ssr?.optimizeDeps,
9573
- testConfig
9334
+ testConfig,
9335
+ viteConfig.cacheDir
9574
9336
  );
9575
9337
  viteConfig.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || viteConfig.cacheDir;
9576
9338
  viteConfig.optimizeDeps = webOptimizer.optimizeDeps;
@@ -9751,7 +9513,7 @@ function WorkspaceVitestPlugin(project, options) {
9751
9513
  },
9752
9514
  async configureServer(server) {
9753
9515
  const options2 = deepMerge({}, configDefaults, server.config.test || {});
9754
- await project.setServer(options2, server);
9516
+ await project._configureServer(options2, server);
9755
9517
  await server.watcher.close();
9756
9518
  }
9757
9519
  },
@@ -9782,11 +9544,11 @@ class TestSpecification {
9782
9544
  moduleId;
9783
9545
  pool;
9784
9546
  // public readonly location: WorkspaceSpecLocation | undefined
9785
- constructor(workspaceProject, moduleId, pool) {
9786
- this[0] = workspaceProject;
9547
+ constructor(project, moduleId, pool) {
9548
+ this[0] = project;
9787
9549
  this[1] = moduleId;
9788
9550
  this[2] = { pool };
9789
- this.project = workspaceProject.testProject;
9551
+ this.project = project;
9790
9552
  this.moduleId = moduleId;
9791
9553
  this.pool = pool;
9792
9554
  }
@@ -9805,7 +9567,7 @@ class TestSpecification {
9805
9567
  * @deprecated
9806
9568
  */
9807
9569
  *[Symbol.iterator]() {
9808
- yield this.project.workspaceProject;
9570
+ yield this.project;
9809
9571
  yield this.moduleId;
9810
9572
  yield this.pool;
9811
9573
  }
@@ -9824,51 +9586,46 @@ async function createViteServer(inlineConfig) {
9824
9586
  return server;
9825
9587
  }
9826
9588
 
9827
- async function initializeProject(workspacePath, ctx, options) {
9828
- const project = new WorkspaceProject(workspacePath, ctx, options);
9829
- const root = options.root || (typeof workspacePath === "number" ? void 0 : workspacePath.endsWith("/") ? workspacePath : dirname(workspacePath));
9830
- const configFile = options.extends ? resolve(dirname(options.workspaceConfigPath), options.extends) : typeof workspacePath === "number" || workspacePath.endsWith("/") ? false : workspacePath;
9831
- const config = {
9832
- ...options,
9833
- root,
9834
- configFile,
9835
- // this will make "mode": "test" | "benchmark" inside defineConfig
9836
- mode: options.test?.mode || options.mode || ctx.config.mode,
9837
- plugins: [
9838
- ...options.plugins || [],
9839
- WorkspaceVitestPlugin(project, { ...options, root, workspacePath })
9840
- ]
9841
- };
9842
- await createViteServer(config);
9843
- return project;
9844
- }
9845
- class WorkspaceProject {
9846
- constructor(path2, ctx, options) {
9589
+ class TestProject {
9590
+ constructor(path2, vitest, options) {
9847
9591
  this.path = path2;
9848
- this.ctx = ctx;
9849
9592
  this.options = options;
9593
+ this.vitest = vitest;
9594
+ this.ctx = vitest;
9595
+ this.globalConfig = vitest.config;
9850
9596
  }
9851
- configOverride;
9852
- config;
9853
- server;
9597
+ /**
9598
+ * The global Vitest instance.
9599
+ * @experimental The public Vitest API is experimental and does not follow semver.
9600
+ */
9601
+ vitest;
9602
+ /**
9603
+ * Resolved global configuration. If there are no workspace projects, this will be the same as `config`.
9604
+ */
9605
+ globalConfig;
9606
+ /**
9607
+ * Browser instance if the browser is enabled. This is initialized when the tests run for the first time.
9608
+ */
9609
+ browser;
9610
+ /** @deprecated use `vitest` instead */
9611
+ ctx;
9612
+ /**
9613
+ * Temporary directory for the project. This is unique for each project. Vitest stores transformed content here.
9614
+ */
9615
+ tmpDir = join(tmpdir(), nanoid());
9854
9616
  vitenode;
9855
9617
  runner;
9856
- browser;
9857
9618
  typechecker;
9858
9619
  closingPromise;
9859
9620
  testFilesList = null;
9860
9621
  typecheckFilesList = null;
9861
- testProject;
9862
- id = nanoid();
9863
- tmpDir = join(tmpdir(), this.id);
9864
9622
  _globalSetups;
9865
9623
  _provided = {};
9866
- getName() {
9867
- return this.config.name || "";
9868
- }
9869
- isCore() {
9870
- return this.ctx.getCoreWorkspaceProject() === this;
9871
- }
9624
+ _config;
9625
+ _vite;
9626
+ /**
9627
+ * Provide a value to the test context. This value will be available to all tests with `inject`.
9628
+ */
9872
9629
  provide(key, value) {
9873
9630
  try {
9874
9631
  structuredClone(value);
@@ -9882,19 +9639,90 @@ class WorkspaceProject {
9882
9639
  }
9883
9640
  this._provided[key] = value;
9884
9641
  }
9642
+ /**
9643
+ * Get the provided context. The project context is merged with the global context.
9644
+ */
9885
9645
  getProvidedContext() {
9886
- if (this.isCore()) {
9646
+ if (this.isRootProject()) {
9887
9647
  return this._provided;
9888
9648
  }
9889
9649
  return {
9890
- ...this.ctx.getCoreWorkspaceProject().getProvidedContext(),
9650
+ ...this.vitest.getRootTestProject().getProvidedContext(),
9891
9651
  ...this._provided
9892
9652
  };
9893
9653
  }
9654
+ /**
9655
+ * Creates a new test specification. Specifications describe how to run tests.
9656
+ * @param moduleId The file path
9657
+ */
9658
+ createSpecification(moduleId, pool) {
9659
+ return new TestSpecification(
9660
+ this,
9661
+ moduleId,
9662
+ pool || getFilePoolName(this, moduleId)
9663
+ );
9664
+ }
9665
+ toJSON() {
9666
+ return {
9667
+ name: this.name,
9668
+ serializedConfig: this.serializedConfig,
9669
+ context: this.getProvidedContext()
9670
+ };
9671
+ }
9672
+ /**
9673
+ * Vite's dev server instance. Every workspace project has its own server.
9674
+ */
9675
+ get vite() {
9676
+ if (!this._vite) {
9677
+ throw new Error("The server was not set. It means that `project.vite` was called before the Vite server was established.");
9678
+ }
9679
+ return this._vite;
9680
+ }
9681
+ /**
9682
+ * Resolved project configuration.
9683
+ */
9684
+ get config() {
9685
+ if (!this._config) {
9686
+ throw new Error("The config was not set. It means that `project.config` was called before the Vite server was established.");
9687
+ }
9688
+ return this._config;
9689
+ }
9690
+ /**
9691
+ * The name of the project or an empty string if not set.
9692
+ */
9693
+ get name() {
9694
+ return this.config.name || "";
9695
+ }
9696
+ /**
9697
+ * Serialized project configuration. This is the config that tests receive.
9698
+ */
9699
+ get serializedConfig() {
9700
+ return this._serializeOverridenConfig();
9701
+ }
9702
+ /** @deprecated use `vite` instead */
9703
+ get server() {
9704
+ return this._vite;
9705
+ }
9706
+ /**
9707
+ * Check if this is the root project. The root project is the one that has the root config.
9708
+ */
9709
+ isRootProject() {
9710
+ return this.vitest.getRootTestProject() === this;
9711
+ }
9712
+ /** @deprecated use `isRootProject` instead */
9713
+ isCore() {
9714
+ return this.isRootProject();
9715
+ }
9716
+ /** @deprecated use `createSpecification` instead */
9894
9717
  createSpec(moduleId, pool) {
9895
9718
  return new TestSpecification(this, moduleId, pool);
9896
9719
  }
9897
- async initializeGlobalSetup() {
9720
+ /** @deprecated */
9721
+ initializeGlobalSetup() {
9722
+ return this._initializeGlobalSetup();
9723
+ }
9724
+ /** @internal */
9725
+ async _initializeGlobalSetup() {
9898
9726
  if (this._globalSetups) {
9899
9727
  return;
9900
9728
  }
@@ -9905,7 +9733,8 @@ class WorkspaceProject {
9905
9733
  for (const globalSetupFile of this._globalSetups) {
9906
9734
  const teardown = await globalSetupFile.setup?.({
9907
9735
  provide: (key, value) => this.provide(key, value),
9908
- config: this.config
9736
+ config: this.config,
9737
+ onTestsRerun: (cb) => this.vitest.onTestsRerun(cb)
9909
9738
  });
9910
9739
  if (teardown == null || !!globalSetupFile.teardown) {
9911
9740
  continue;
@@ -9918,7 +9747,12 @@ class WorkspaceProject {
9918
9747
  globalSetupFile.teardown = teardown;
9919
9748
  }
9920
9749
  }
9921
- async teardownGlobalSetup() {
9750
+ /** @deprecated */
9751
+ teardownGlobalSetup() {
9752
+ return this._teardownGlobalSetup();
9753
+ }
9754
+ /** @internal */
9755
+ async _teardownGlobalSetup() {
9922
9756
  if (!this._globalSetups) {
9923
9757
  return;
9924
9758
  }
@@ -9926,24 +9760,33 @@ class WorkspaceProject {
9926
9760
  await globalSetupFile.teardown?.();
9927
9761
  }
9928
9762
  }
9763
+ /** @deprecated use `vitest.logger` instead */
9929
9764
  get logger() {
9930
- return this.ctx.logger;
9765
+ return this.vitest.logger;
9931
9766
  }
9932
9767
  // it's possible that file path was imported with different queries (?raw, ?url, etc)
9768
+ /** @deprecated use `.vite` or `.browser.vite` directly */
9933
9769
  getModulesByFilepath(file) {
9934
9770
  const set = this.server.moduleGraph.getModulesByFile(file) || this.browser?.vite.moduleGraph.getModulesByFile(file);
9935
9771
  return set || /* @__PURE__ */ new Set();
9936
9772
  }
9773
+ /** @deprecated use `.vite` or `.browser.vite` directly */
9937
9774
  getModuleById(id) {
9938
9775
  return this.server.moduleGraph.getModuleById(id) || this.browser?.vite.moduleGraph.getModuleById(id);
9939
9776
  }
9777
+ /** @deprecated use `.vite` or `.browser.vite` directly */
9940
9778
  getSourceMapModuleById(id) {
9941
9779
  const mod = this.server.moduleGraph.getModuleById(id);
9942
9780
  return mod?.ssrTransformResult?.map || mod?.transformResult?.map;
9943
9781
  }
9782
+ /** @deprecated use `vitest.reporters` instead */
9944
9783
  get reporters() {
9945
9784
  return this.ctx.reporters;
9946
9785
  }
9786
+ /**
9787
+ * Get all files in the project that match the globs in the config and the filters.
9788
+ * @param filters String filters to match the test files.
9789
+ */
9947
9790
  async globTestFiles(filters = []) {
9948
9791
  const dir = this.config.dir || this.config.root;
9949
9792
  const { include, exclude, includeSource } = this.config;
@@ -9977,7 +9820,7 @@ class WorkspaceProject {
9977
9820
  files.map(async (file) => {
9978
9821
  try {
9979
9822
  const code = await promises.readFile(file, "utf-8");
9980
- if (this.isInSourceTestFile(code)) {
9823
+ if (this.isInSourceTestCode(code)) {
9981
9824
  testFiles.push(file);
9982
9825
  }
9983
9826
  } catch {
@@ -9989,12 +9832,32 @@ class WorkspaceProject {
9989
9832
  this.testFilesList = testFiles;
9990
9833
  return testFiles;
9991
9834
  }
9992
- isTestFile(id) {
9993
- return this.testFilesList && this.testFilesList.includes(id);
9835
+ isBrowserEnabled() {
9836
+ return isBrowserEnabled(this.config);
9837
+ }
9838
+ /** @internal */
9839
+ _markTestFile(testPath) {
9840
+ this.testFilesList?.push(testPath);
9994
9841
  }
9995
- isTypecheckFile(id) {
9996
- return this.typecheckFilesList && this.typecheckFilesList.includes(id);
9842
+ /**
9843
+ * Returns if the file is a test file. Requires `.globTestFiles()` to be called first.
9844
+ * @internal
9845
+ */
9846
+ isTestFile(testPath) {
9847
+ return !!this.testFilesList && this.testFilesList.includes(testPath);
9997
9848
  }
9849
+ /**
9850
+ * Returns if the file is a typecheck test file. Requires `.globTestFiles()` to be called first.
9851
+ * @internal
9852
+ */
9853
+ isTypecheckFile(testPath) {
9854
+ return !!this.typecheckFilesList && this.typecheckFilesList.includes(testPath);
9855
+ }
9856
+ /** @deprecated use `serializedConfig` instead */
9857
+ getSerializableConfig() {
9858
+ return this._serializeOverridenConfig();
9859
+ }
9860
+ /** @internal */
9998
9861
  async globFiles(include, exclude, cwd) {
9999
9862
  const globOptions = {
10000
9863
  dot: true,
@@ -10004,8 +9867,11 @@ class WorkspaceProject {
10004
9867
  const files = await fg(include, globOptions);
10005
9868
  return files.map((file) => slash(a.resolve(cwd, file)));
10006
9869
  }
10007
- async isTargetFile(id, source) {
10008
- const relativeId = relative(this.config.dir || this.config.root, id);
9870
+ /**
9871
+ * Test if a file matches the test globs. This does the actual glob matching unlike `isTestFile`.
9872
+ */
9873
+ matchesTestGlob(filepath, source) {
9874
+ const relativeId = relative(this.config.dir || this.config.root, filepath);
10009
9875
  if (mm.isMatch(relativeId, this.config.exclude)) {
10010
9876
  return false;
10011
9877
  }
@@ -10013,12 +9879,16 @@ class WorkspaceProject {
10013
9879
  return true;
10014
9880
  }
10015
9881
  if (this.config.includeSource?.length && mm.isMatch(relativeId, this.config.includeSource)) {
10016
- source = source || await promises.readFile(id, "utf-8");
10017
- return this.isInSourceTestFile(source);
9882
+ const code = source || readFileSync(filepath, "utf-8");
9883
+ return this.isInSourceTestCode(code);
10018
9884
  }
10019
9885
  return false;
10020
9886
  }
10021
- isInSourceTestFile(code) {
9887
+ /** @deprecated use `matchesTestGlob` instead */
9888
+ async isTargetFile(id, source) {
9889
+ return this.matchesTestGlob(id, source);
9890
+ }
9891
+ isInSourceTestCode(code) {
10022
9892
  return code.includes("import.meta.vitest");
10023
9893
  }
10024
9894
  filterFiles(testFiles, filters, dir) {
@@ -10039,15 +9909,16 @@ class WorkspaceProject {
10039
9909
  }
10040
9910
  return testFiles;
10041
9911
  }
10042
- async initBrowserServer() {
9912
+ /** @internal */
9913
+ async _initBrowserServer() {
10043
9914
  if (!this.isBrowserEnabled() || this.browser) {
10044
9915
  return;
10045
9916
  }
10046
- await this.ctx.packageInstaller.ensureInstalled("@vitest/browser", this.config.root, this.ctx.version);
9917
+ await this.vitest.packageInstaller.ensureInstalled("@vitest/browser", this.config.root, this.ctx.version);
10047
9918
  const { createBrowserServer, distRoot } = await import('@vitest/browser');
10048
9919
  const browser = await createBrowserServer(
10049
9920
  this,
10050
- this.server.config.configFile,
9921
+ this.vite.config.configFile,
10051
9922
  [
10052
9923
  ...MocksPlugins({
10053
9924
  filter(id) {
@@ -10062,40 +9933,47 @@ class WorkspaceProject {
10062
9933
  );
10063
9934
  this.browser = browser;
10064
9935
  if (this.config.browser.ui) {
10065
- setup(this.ctx, browser.vite);
9936
+ setup(this.vitest, browser.vite);
10066
9937
  }
10067
9938
  }
10068
- static createBasicProject(ctx) {
10069
- const project = new WorkspaceProject(
10070
- ctx.config.name || ctx.config.root,
10071
- ctx
10072
- );
10073
- project.vitenode = ctx.vitenode;
10074
- project.server = ctx.server;
10075
- project.runner = ctx.runner;
10076
- project.config = ctx.config;
10077
- for (const _providedKey in ctx.config.provide) {
10078
- const providedKey = _providedKey;
10079
- project.provide(
10080
- providedKey,
10081
- ctx.config.provide[providedKey]
10082
- );
9939
+ /**
9940
+ * Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts.
9941
+ * If the resources are needed again, create a new project.
9942
+ */
9943
+ close() {
9944
+ if (!this.closingPromise) {
9945
+ this.closingPromise = Promise.all(
9946
+ [
9947
+ this.vite?.close(),
9948
+ this.typechecker?.stop(),
9949
+ this.browser?.close(),
9950
+ this.clearTmpDir()
9951
+ ].filter(Boolean)
9952
+ ).then(() => {
9953
+ this._provided = {};
9954
+ this._vite = void 0;
9955
+ });
10083
9956
  }
10084
- project.testProject = new TestProject(project);
10085
- return project;
9957
+ return this.closingPromise;
9958
+ }
9959
+ /** @deprecated use `name` instead */
9960
+ getName() {
9961
+ return this.config.name || "";
10086
9962
  }
10087
- static async createCoreProject(ctx) {
10088
- return WorkspaceProject.createBasicProject(ctx);
9963
+ /** @deprecated internal */
9964
+ setServer(options, server) {
9965
+ return this._configureServer(options, server);
10089
9966
  }
10090
- async setServer(options, server) {
10091
- this.config = resolveConfig(
10092
- this.ctx.mode,
9967
+ /** @internal */
9968
+ async _configureServer(options, server) {
9969
+ this._config = resolveConfig(
9970
+ this.vitest.mode,
10093
9971
  {
10094
9972
  ...options,
10095
- coverage: this.ctx.config.coverage
9973
+ coverage: this.vitest.config.coverage
10096
9974
  },
10097
9975
  server.config,
10098
- this.ctx.logger
9976
+ this.vitest.logger
10099
9977
  );
10100
9978
  for (const _providedKey in this.config.provide) {
10101
9979
  const providedKey = _providedKey;
@@ -10105,8 +9983,7 @@ class WorkspaceProject {
10105
9983
  );
10106
9984
  }
10107
9985
  this.closingPromise = void 0;
10108
- this.testProject = new TestProject(this);
10109
- this.server = server;
9986
+ this._vite = server;
10110
9987
  this.vitenode = new ViteNodeServer(server, this.config.server);
10111
9988
  const node = this.vitenode;
10112
9989
  this.runner = new ViteNodeRunner({
@@ -10120,51 +9997,325 @@ class WorkspaceProject {
10120
9997
  }
10121
9998
  });
10122
9999
  }
10123
- isBrowserEnabled() {
10124
- return isBrowserEnabled(this.config);
10125
- }
10126
- getSerializableConfig() {
10000
+ _serializeOverridenConfig() {
10127
10001
  const config = serializeConfig(
10128
10002
  this.config,
10129
- this.ctx.config,
10130
- this.server.config
10003
+ this.vitest.config,
10004
+ this.vite.config
10131
10005
  );
10132
- if (!this.ctx.configOverride) {
10006
+ if (!this.vitest.configOverride) {
10133
10007
  return config;
10134
10008
  }
10135
10009
  return deepMerge(
10136
10010
  config,
10137
- this.ctx.configOverride
10011
+ this.vitest.configOverride
10138
10012
  );
10139
10013
  }
10140
- close() {
10141
- if (!this.closingPromise) {
10142
- this.closingPromise = Promise.all(
10143
- [
10144
- this.server?.close(),
10145
- this.typechecker?.stop(),
10146
- this.browser?.close(),
10147
- this.clearTmpDir()
10148
- ].filter(Boolean)
10149
- ).then(() => this._provided = {});
10150
- }
10151
- return this.closingPromise;
10152
- }
10153
10014
  async clearTmpDir() {
10154
10015
  try {
10155
10016
  await rm(this.tmpDir, { recursive: true });
10156
10017
  } catch {
10157
10018
  }
10158
10019
  }
10159
- async initBrowserProvider() {
10020
+ /** @deprecated */
10021
+ initBrowserProvider() {
10022
+ return this._initBrowserProvider();
10023
+ }
10024
+ /** @internal */
10025
+ async _initBrowserProvider() {
10160
10026
  if (!this.isBrowserEnabled() || this.browser?.provider) {
10161
10027
  return;
10162
10028
  }
10163
10029
  if (!this.browser) {
10164
- await this.initBrowserServer();
10030
+ await this._initBrowserServer();
10165
10031
  }
10166
10032
  await this.browser?.initBrowserProvider();
10167
10033
  }
10034
+ /** @internal */
10035
+ static _createBasicProject(vitest) {
10036
+ const project = new TestProject(
10037
+ vitest.config.name || vitest.config.root,
10038
+ vitest
10039
+ );
10040
+ project.vitenode = vitest.vitenode;
10041
+ project.runner = vitest.runner;
10042
+ project._vite = vitest.server;
10043
+ project._config = vitest.config;
10044
+ for (const _providedKey in vitest.config.provide) {
10045
+ const providedKey = _providedKey;
10046
+ project.provide(
10047
+ providedKey,
10048
+ vitest.config.provide[providedKey]
10049
+ );
10050
+ }
10051
+ return project;
10052
+ }
10053
+ }
10054
+ async function initializeProject(workspacePath, ctx, options) {
10055
+ const project = new TestProject(workspacePath, ctx, options);
10056
+ const { extends: extendsConfig, workspaceConfigPath, ...restOptions } = options;
10057
+ const root = options.root || (typeof workspacePath === "number" ? void 0 : workspacePath.endsWith("/") ? workspacePath : dirname(workspacePath));
10058
+ const configFile = extendsConfig ? resolve(dirname(workspaceConfigPath), extendsConfig) : typeof workspacePath === "number" || workspacePath.endsWith("/") ? false : workspacePath;
10059
+ const config = {
10060
+ ...restOptions,
10061
+ root,
10062
+ configFile,
10063
+ // this will make "mode": "test" | "benchmark" inside defineConfig
10064
+ mode: options.test?.mode || options.mode || ctx.config.mode,
10065
+ plugins: [
10066
+ ...options.plugins || [],
10067
+ WorkspaceVitestPlugin(project, { ...options, root, workspacePath })
10068
+ ]
10069
+ };
10070
+ await createViteServer(config);
10071
+ return project;
10072
+ }
10073
+
10074
+ async function loadCustomReporterModule(path, runner) {
10075
+ let customReporterModule;
10076
+ try {
10077
+ customReporterModule = await runner.executeId(path);
10078
+ } catch (customReporterModuleError) {
10079
+ throw new Error(`Failed to load custom Reporter from ${path}`, {
10080
+ cause: customReporterModuleError
10081
+ });
10082
+ }
10083
+ if (customReporterModule.default === null || customReporterModule.default === void 0) {
10084
+ throw new Error(
10085
+ `Custom reporter loaded from ${path} was not the default export`
10086
+ );
10087
+ }
10088
+ return customReporterModule.default;
10089
+ }
10090
+ function createReporters(reporterReferences, ctx) {
10091
+ const runner = ctx.runner;
10092
+ const promisedReporters = reporterReferences.map(
10093
+ async (referenceOrInstance) => {
10094
+ if (Array.isArray(referenceOrInstance)) {
10095
+ const [reporterName, reporterOptions] = referenceOrInstance;
10096
+ if (reporterName === "html") {
10097
+ await ctx.packageInstaller.ensureInstalled("@vitest/ui", runner.root, ctx.version);
10098
+ const CustomReporter = await loadCustomReporterModule(
10099
+ "@vitest/ui/reporter",
10100
+ runner
10101
+ );
10102
+ return new CustomReporter(reporterOptions);
10103
+ } else if (reporterName in ReportersMap) {
10104
+ const BuiltinReporter = ReportersMap[reporterName];
10105
+ return new BuiltinReporter(reporterOptions);
10106
+ } else {
10107
+ const CustomReporter = await loadCustomReporterModule(
10108
+ reporterName,
10109
+ runner
10110
+ );
10111
+ return new CustomReporter(reporterOptions);
10112
+ }
10113
+ }
10114
+ return referenceOrInstance;
10115
+ }
10116
+ );
10117
+ return Promise.all(promisedReporters);
10118
+ }
10119
+ function createBenchmarkReporters(reporterReferences, runner) {
10120
+ const promisedReporters = reporterReferences.map(
10121
+ async (referenceOrInstance) => {
10122
+ if (typeof referenceOrInstance === "string") {
10123
+ if (referenceOrInstance in BenchmarkReportsMap) {
10124
+ const BuiltinReporter = BenchmarkReportsMap[referenceOrInstance];
10125
+ return new BuiltinReporter();
10126
+ } else {
10127
+ const CustomReporter = await loadCustomReporterModule(
10128
+ referenceOrInstance,
10129
+ runner
10130
+ );
10131
+ return new CustomReporter();
10132
+ }
10133
+ }
10134
+ return referenceOrInstance;
10135
+ }
10136
+ );
10137
+ return Promise.all(promisedReporters);
10138
+ }
10139
+
10140
+ function isAggregateError(err) {
10141
+ if (typeof AggregateError !== "undefined" && err instanceof AggregateError) {
10142
+ return true;
10143
+ }
10144
+ return err instanceof Error && "errors" in err;
10145
+ }
10146
+ class StateManager {
10147
+ filesMap = /* @__PURE__ */ new Map();
10148
+ pathsSet = /* @__PURE__ */ new Set();
10149
+ idMap = /* @__PURE__ */ new Map();
10150
+ taskFileMap = /* @__PURE__ */ new WeakMap();
10151
+ errorsSet = /* @__PURE__ */ new Set();
10152
+ processTimeoutCauses = /* @__PURE__ */ new Set();
10153
+ reportedTasksMap = /* @__PURE__ */ new WeakMap();
10154
+ catchError(err, type) {
10155
+ if (isAggregateError(err)) {
10156
+ return err.errors.forEach((error) => this.catchError(error, type));
10157
+ }
10158
+ if (err === Object(err)) {
10159
+ err.type = type;
10160
+ } else {
10161
+ err = { type, message: err };
10162
+ }
10163
+ const _err = err;
10164
+ if (_err && typeof _err === "object" && _err.code === "VITEST_PENDING") {
10165
+ const task = this.idMap.get(_err.taskId);
10166
+ if (task) {
10167
+ task.mode = "skip";
10168
+ task.result ??= { state: "skip" };
10169
+ task.result.state = "skip";
10170
+ task.result.note = _err.note;
10171
+ }
10172
+ return;
10173
+ }
10174
+ this.errorsSet.add(err);
10175
+ }
10176
+ clearErrors() {
10177
+ this.errorsSet.clear();
10178
+ }
10179
+ getUnhandledErrors() {
10180
+ return Array.from(this.errorsSet.values());
10181
+ }
10182
+ addProcessTimeoutCause(cause) {
10183
+ this.processTimeoutCauses.add(cause);
10184
+ }
10185
+ getProcessTimeoutCauses() {
10186
+ return Array.from(this.processTimeoutCauses.values());
10187
+ }
10188
+ getPaths() {
10189
+ return Array.from(this.pathsSet);
10190
+ }
10191
+ /**
10192
+ * Return files that were running or collected.
10193
+ */
10194
+ getFiles(keys) {
10195
+ if (keys) {
10196
+ return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local);
10197
+ }
10198
+ return Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => {
10199
+ if (f1.meta?.typecheck && f2.meta?.typecheck) {
10200
+ return 0;
10201
+ }
10202
+ if (f1.meta?.typecheck) {
10203
+ return -1;
10204
+ }
10205
+ return 1;
10206
+ });
10207
+ }
10208
+ getTestModules(keys) {
10209
+ return this.getFiles(keys).map((file) => this.getReportedEntity(file));
10210
+ }
10211
+ getFilepaths() {
10212
+ return Array.from(this.filesMap.keys());
10213
+ }
10214
+ getFailedFilepaths() {
10215
+ return this.getFiles().filter((i) => i.result?.state === "fail").map((i) => i.filepath);
10216
+ }
10217
+ collectPaths(paths = []) {
10218
+ paths.forEach((path) => {
10219
+ this.pathsSet.add(path);
10220
+ });
10221
+ }
10222
+ collectFiles(project, files = []) {
10223
+ files.forEach((file) => {
10224
+ const existing = this.filesMap.get(file.filepath) || [];
10225
+ const otherFiles = existing.filter(
10226
+ (i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck
10227
+ );
10228
+ const currentFile = existing.find(
10229
+ (i) => i.projectName === file.projectName
10230
+ );
10231
+ if (currentFile) {
10232
+ file.logs = currentFile.logs;
10233
+ }
10234
+ otherFiles.push(file);
10235
+ this.filesMap.set(file.filepath, otherFiles);
10236
+ this.updateId(file, project);
10237
+ });
10238
+ }
10239
+ clearFiles(project, paths = []) {
10240
+ paths.forEach((path) => {
10241
+ const files = this.filesMap.get(path);
10242
+ const fileTask = createFileTask(
10243
+ path,
10244
+ project.config.root,
10245
+ project.config.name
10246
+ );
10247
+ fileTask.local = true;
10248
+ TestModule.register(fileTask, project);
10249
+ this.idMap.set(fileTask.id, fileTask);
10250
+ if (!files) {
10251
+ this.filesMap.set(path, [fileTask]);
10252
+ return;
10253
+ }
10254
+ const filtered = files.filter(
10255
+ (file) => file.projectName !== project.config.name
10256
+ );
10257
+ if (!filtered.length) {
10258
+ this.filesMap.set(path, [fileTask]);
10259
+ } else {
10260
+ this.filesMap.set(path, [...filtered, fileTask]);
10261
+ }
10262
+ });
10263
+ }
10264
+ updateId(task, project) {
10265
+ if (this.idMap.get(task.id) === task) {
10266
+ return;
10267
+ }
10268
+ if (task.type === "suite" && "filepath" in task) {
10269
+ TestModule.register(task, project);
10270
+ } else if (task.type === "suite") {
10271
+ TestSuite.register(task, project);
10272
+ } else {
10273
+ TestCase.register(task, project);
10274
+ }
10275
+ this.idMap.set(task.id, task);
10276
+ if (task.type === "suite") {
10277
+ task.tasks.forEach((task2) => {
10278
+ this.updateId(task2, project);
10279
+ });
10280
+ }
10281
+ }
10282
+ getReportedEntity(task) {
10283
+ return this.reportedTasksMap.get(task);
10284
+ }
10285
+ updateTasks(packs) {
10286
+ for (const [id, result, meta] of packs) {
10287
+ const task = this.idMap.get(id);
10288
+ if (task) {
10289
+ task.result = result;
10290
+ task.meta = meta;
10291
+ if (result?.state === "skip") {
10292
+ task.mode = "skip";
10293
+ }
10294
+ }
10295
+ }
10296
+ }
10297
+ updateUserLog(log) {
10298
+ const task = log.taskId && this.idMap.get(log.taskId);
10299
+ if (task) {
10300
+ if (!task.logs) {
10301
+ task.logs = [];
10302
+ }
10303
+ task.logs.push(log);
10304
+ }
10305
+ }
10306
+ getCountOfFailedTests() {
10307
+ return Array.from(this.idMap.values()).filter(
10308
+ (t) => t.result?.state === "fail"
10309
+ ).length;
10310
+ }
10311
+ cancelFiles(files, project) {
10312
+ this.collectFiles(
10313
+ project,
10314
+ files.map(
10315
+ (filepath) => createFileTask(filepath, project.config.root, project.config.name)
10316
+ )
10317
+ );
10318
+ }
10168
10319
  }
10169
10320
 
10170
10321
  const ESCAPE_SYMBOL = "\\";
@@ -10205,7 +10356,7 @@ function hasBraceExpansion(pattern) {
10205
10356
  }
10206
10357
 
10207
10358
  async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspaceDefinition) {
10208
- const { configFiles, projectConfigs, nonConfigDirectories } = await resolveWorkspaceProjectConfigs(
10359
+ const { configFiles, projectConfigs, nonConfigDirectories } = await resolveTestProjectConfigs(
10209
10360
  vitest,
10210
10361
  workspaceConfigPath,
10211
10362
  workspaceDefinition
@@ -10272,9 +10423,9 @@ async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspa
10272
10423
  ].join("") : [" "];
10273
10424
  throw new Error([
10274
10425
  `Project name "${name}"`,
10275
- project.server.config.configFile ? ` from "${relative(vitest.config.root, project.server.config.configFile)}"` : "",
10426
+ project.vite.config.configFile ? ` from "${relative(vitest.config.root, project.vite.config.configFile)}"` : "",
10276
10427
  " is not unique.",
10277
- duplicate?.server.config.configFile ? ` The project is already defined by "${relative(vitest.config.root, duplicate.server.config.configFile)}".` : "",
10428
+ duplicate?.vite.config.configFile ? ` The project is already defined by "${relative(vitest.config.root, duplicate.vite.config.configFile)}".` : "",
10278
10429
  filesError,
10279
10430
  "All projects in a workspace should have unique names. Make sure your configuration is correct."
10280
10431
  ].join(""));
@@ -10283,7 +10434,7 @@ async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspa
10283
10434
  }
10284
10435
  return resolvedProjects;
10285
10436
  }
10286
- async function resolveWorkspaceProjectConfigs(vitest, workspaceConfigPath, workspaceDefinition) {
10437
+ async function resolveTestProjectConfigs(vitest, workspaceConfigPath, workspaceDefinition) {
10287
10438
  const projectsOptions = [];
10288
10439
  const workspaceConfigFiles = [];
10289
10440
  const workspaceGlobMatches = [];
@@ -10402,6 +10553,7 @@ class Vitest {
10402
10553
  restartsCount = 0;
10403
10554
  runner = void 0;
10404
10555
  packageInstaller;
10556
+ /** @internal */
10405
10557
  coreWorkspaceProject;
10406
10558
  /** @private */
10407
10559
  resolvedProjects = [];
@@ -10417,6 +10569,7 @@ class Vitest {
10417
10569
  _onClose = [];
10418
10570
  _onSetServer = [];
10419
10571
  _onCancelListeners = [];
10572
+ _onUserTestsRerun = [];
10420
10573
  async setServer(options, server, cliOptions) {
10421
10574
  this.unregisterWatcher?.();
10422
10575
  clearTimeout(this._rerunTimer);
@@ -10431,6 +10584,7 @@ class Vitest {
10431
10584
  this.coverageProvider = void 0;
10432
10585
  this.runningPromise = void 0;
10433
10586
  this._cachedSpecs.clear();
10587
+ this._onUserTestsRerun = [];
10434
10588
  const resolved = resolveConfig(this.mode, options, server.config, this.logger);
10435
10589
  this.server = server;
10436
10590
  this.config = resolved;
@@ -10487,7 +10641,7 @@ class Vitest {
10487
10641
  );
10488
10642
  }
10489
10643
  if (!this.coreWorkspaceProject) {
10490
- this.coreWorkspaceProject = WorkspaceProject.createBasicProject(this);
10644
+ this.coreWorkspaceProject = TestProject._createBasicProject(this);
10491
10645
  }
10492
10646
  if (this.config.testNamePattern) {
10493
10647
  this.configOverride.testNamePattern = this.config.testNamePattern;
@@ -10495,22 +10649,19 @@ class Vitest {
10495
10649
  await Promise.all(this._onSetServer.map((fn) => fn()));
10496
10650
  }
10497
10651
  provide(key, value) {
10498
- this.getCoreWorkspaceProject().provide(key, value);
10499
- }
10500
- /**
10501
- * @deprecated internal, use `_createCoreProject` instead
10502
- */
10503
- createCoreProject() {
10504
- return this._createCoreProject();
10652
+ this.getRootTestProject().provide(key, value);
10505
10653
  }
10506
10654
  /**
10507
10655
  * @internal
10508
10656
  */
10509
- async _createCoreProject() {
10510
- this.coreWorkspaceProject = await WorkspaceProject.createCoreProject(this);
10657
+ _createCoreProject() {
10658
+ this.coreWorkspaceProject = TestProject._createBasicProject(this);
10511
10659
  return this.coreWorkspaceProject;
10512
10660
  }
10513
- getCoreWorkspaceProject() {
10661
+ getRootTestProject() {
10662
+ if (!this.coreWorkspaceProject) {
10663
+ 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.`);
10664
+ }
10514
10665
  return this.coreWorkspaceProject;
10515
10666
  }
10516
10667
  /**
@@ -10519,10 +10670,10 @@ class Vitest {
10519
10670
  getProjectByTaskId(taskId) {
10520
10671
  const task = this.state.idMap.get(taskId);
10521
10672
  const projectName = task.projectName || task?.file?.projectName || "";
10522
- return this.projects.find((p) => p.getName() === projectName) || this.getCoreWorkspaceProject() || this.projects[0];
10673
+ return this.projects.find((p) => p.name === projectName) || this.getRootTestProject() || this.projects[0];
10523
10674
  }
10524
10675
  getProjectByName(name = "") {
10525
- return this.projects.find((p) => p.getName() === name) || this.getCoreWorkspaceProject() || this.projects[0];
10676
+ return this.projects.find((p) => p.name === name) || this.coreWorkspaceProject || this.projects[0];
10526
10677
  }
10527
10678
  async getWorkspaceConfigPath() {
10528
10679
  if (this.config.workspace) {
@@ -10542,7 +10693,7 @@ class Vitest {
10542
10693
  const workspaceConfigPath = await this.getWorkspaceConfigPath();
10543
10694
  this._workspaceConfigPath = workspaceConfigPath;
10544
10695
  if (!workspaceConfigPath) {
10545
- return [await this._createCoreProject()];
10696
+ return [this._createCoreProject()];
10546
10697
  }
10547
10698
  const workspaceModule = await this.runner.executeFile(workspaceConfigPath);
10548
10699
  if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) {
@@ -10684,21 +10835,21 @@ class Vitest {
10684
10835
  return;
10685
10836
  }
10686
10837
  deps.add(filepath);
10687
- const mod = project.server.moduleGraph.getModuleById(filepath);
10838
+ const mod = project.vite.moduleGraph.getModuleById(filepath);
10688
10839
  const transformed = mod?.ssrTransformResult || await project.vitenode.transformRequest(filepath);
10689
10840
  if (!transformed) {
10690
10841
  return;
10691
10842
  }
10692
10843
  const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []];
10693
10844
  await Promise.all(dependencies.map(async (dep) => {
10694
- const path = await project.server.pluginContainer.resolveId(dep, filepath, { ssr: true });
10845
+ const path = await project.vite.pluginContainer.resolveId(dep, filepath, { ssr: true });
10695
10846
  const fsPath = path && !path.external && path.id.split("?")[0];
10696
10847
  if (fsPath && !fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) {
10697
10848
  await addImports(project, fsPath);
10698
10849
  }
10699
10850
  }));
10700
10851
  };
10701
- await addImports(spec.project.workspaceProject, spec.moduleId);
10852
+ await addImports(spec.project, spec.moduleId);
10702
10853
  deps.delete(spec.moduleId);
10703
10854
  return deps;
10704
10855
  }
@@ -10754,24 +10905,23 @@ class Vitest {
10754
10905
  const specs = [];
10755
10906
  for (const project of this.projects) {
10756
10907
  if (project.isTestFile(file)) {
10757
- const pool = getFilePoolName(project, file);
10758
- specs.push(project.createSpec(file, pool));
10908
+ specs.push(project.createSpecification(file));
10759
10909
  }
10760
10910
  if (project.isTypecheckFile(file)) {
10761
- specs.push(project.createSpec(file, "typescript"));
10911
+ specs.push(project.createSpecification(file, "typescript"));
10762
10912
  }
10763
10913
  }
10764
10914
  specs.forEach((spec) => this.ensureSpecCached(spec));
10765
10915
  return specs;
10766
10916
  }
10767
10917
  async initializeGlobalSetup(paths) {
10768
- const projects = new Set(paths.map((spec) => spec.project.workspaceProject));
10769
- const coreProject = this.getCoreWorkspaceProject();
10918
+ const projects = new Set(paths.map((spec) => spec.project));
10919
+ const coreProject = this.getRootTestProject();
10770
10920
  if (!projects.has(coreProject)) {
10771
10921
  projects.add(coreProject);
10772
10922
  }
10773
10923
  for (const project of projects) {
10774
- await project.initializeGlobalSetup();
10924
+ await project._initializeGlobalSetup();
10775
10925
  }
10776
10926
  }
10777
10927
  async runFiles(specs, allTestsRun) {
@@ -10855,17 +11005,37 @@ class Vitest {
10855
11005
  await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason)));
10856
11006
  }
10857
11007
  async initBrowserServers() {
10858
- await Promise.all(this.projects.map((p) => p.initBrowserServer()));
11008
+ await Promise.all(this.projects.map((p) => p._initBrowserServer()));
10859
11009
  }
10860
- async rerunFiles(files = this.state.getFilepaths(), trigger, allTestsRun = true) {
11010
+ async rerunFiles(files = this.state.getFilepaths(), trigger, allTestsRun = true, resetTestNamePattern = false) {
11011
+ if (resetTestNamePattern) {
11012
+ this.configOverride.testNamePattern = void 0;
11013
+ }
10861
11014
  if (this.filenamePattern) {
10862
11015
  const filteredFiles = await this.globTestFiles([this.filenamePattern]);
10863
11016
  files = files.filter((file) => filteredFiles.some((f) => f[1] === file));
10864
11017
  }
10865
- await this.report("onWatcherRerun", files, trigger);
11018
+ await Promise.all([
11019
+ this.report("onWatcherRerun", files, trigger),
11020
+ ...this._onUserTestsRerun.map((fn) => fn(files))
11021
+ ]);
10866
11022
  await this.runFiles(files.flatMap((file) => this.getProjectsByTestFile(file)), allTestsRun);
10867
11023
  await this.report("onWatcherStart", this.state.getFiles(files));
10868
11024
  }
11025
+ isSuite(task) {
11026
+ return Object.hasOwnProperty.call(task, "tasks");
11027
+ }
11028
+ async rerunTask(id) {
11029
+ const task = this.state.idMap.get(id);
11030
+ if (!task) {
11031
+ throw new Error(`Task ${id} was not found`);
11032
+ }
11033
+ await this.changeNamePattern(
11034
+ task.name,
11035
+ [task.file.filepath],
11036
+ this.isSuite(task) ? "rerun suite" : "rerun test"
11037
+ );
11038
+ }
10869
11039
  async changeProjectName(pattern) {
10870
11040
  if (pattern === "") {
10871
11041
  delete this.configOverride.project;
@@ -10954,7 +11124,10 @@ class Vitest {
10954
11124
  this.changedTests.clear();
10955
11125
  const triggerIds = new Set(triggerId.map((id) => relative(this.config.root, id)));
10956
11126
  const triggerLabel = Array.from(triggerIds).join(", ");
10957
- await this.report("onWatcherRerun", files, triggerLabel);
11127
+ await Promise.all([
11128
+ this.report("onWatcherRerun", files, triggerLabel),
11129
+ ...this._onUserTestsRerun.map((fn) => fn(files))
11130
+ ]);
10958
11131
  await this.runFiles(files.flatMap((file) => this.getProjectsByTestFile(file)), false);
10959
11132
  await this.report("onWatcherStart", this.state.getFiles(files));
10960
11133
  }, WATCHER_DEBOUNCE);
@@ -11007,13 +11180,14 @@ class Vitest {
11007
11180
  onAdd = async (id) => {
11008
11181
  id = slash(id);
11009
11182
  this.updateLastChanged(id);
11183
+ const fileContent = readFileSync(id, "utf-8");
11010
11184
  const matchingProjects = [];
11011
- await Promise.all(this.projects.map(async (project) => {
11012
- if (await project.isTargetFile(id)) {
11185
+ this.projects.forEach((project) => {
11186
+ if (project.matchesTestGlob(id, fileContent)) {
11013
11187
  matchingProjects.push(project);
11014
- project.testFilesList?.push(id);
11188
+ project._markTestFile(id);
11015
11189
  }
11016
- }));
11190
+ });
11017
11191
  if (matchingProjects.length > 0) {
11018
11192
  this.changedTests.add(id);
11019
11193
  this.scheduleRerun([id]);
@@ -11117,10 +11291,10 @@ class Vitest {
11117
11291
  if (!teardownProjects.includes(this.coreWorkspaceProject)) {
11118
11292
  teardownProjects.push(this.coreWorkspaceProject);
11119
11293
  }
11120
- for await (const project of teardownProjects.reverse()) {
11121
- await project.teardownGlobalSetup();
11294
+ for (const project of teardownProjects.reverse()) {
11295
+ await project._teardownGlobalSetup();
11122
11296
  }
11123
- const closePromises = this.resolvedProjects.map((w) => w.close().then(() => w.server = void 0));
11297
+ const closePromises = this.resolvedProjects.map((w) => w.close());
11124
11298
  if (!this.resolvedProjects.includes(this.coreWorkspaceProject)) {
11125
11299
  closePromises.push(this.coreWorkspaceProject.close().then(() => this.server = void 0));
11126
11300
  }
@@ -11183,13 +11357,12 @@ class Vitest {
11183
11357
  await Promise.all(this.projects.map(async (project) => {
11184
11358
  const { testFiles, typecheckTestFiles } = await project.globTestFiles(filters);
11185
11359
  testFiles.forEach((file) => {
11186
- const pool = getFilePoolName(project, file);
11187
- const spec = project.createSpec(file, pool);
11360
+ const spec = project.createSpecification(file);
11188
11361
  this.ensureSpecCached(spec);
11189
11362
  files.push(spec);
11190
11363
  });
11191
11364
  typecheckTestFiles.forEach((file) => {
11192
- const spec = project.createSpec(file, "typescript");
11365
+ const spec = project.createSpecification(file, "typescript");
11193
11366
  this.ensureSpecCached(spec);
11194
11367
  files.push(spec);
11195
11368
  });
@@ -11197,7 +11370,7 @@ class Vitest {
11197
11370
  return files;
11198
11371
  }
11199
11372
  /**
11200
- * @deprecated use globTestSpecs instead
11373
+ * @deprecated use `globTestSpecs` instead
11201
11374
  */
11202
11375
  async globTestFiles(filters = []) {
11203
11376
  return this.globTestSpecs(filters);
@@ -11227,6 +11400,9 @@ class Vitest {
11227
11400
  onClose(fn) {
11228
11401
  this._onClose.push(fn);
11229
11402
  }
11403
+ onTestsRerun(fn) {
11404
+ this._onUserTestsRerun.push(fn);
11405
+ }
11230
11406
  }
11231
11407
 
11232
11408
  async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
@@ -11315,7 +11491,9 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
11315
11491
  forks: {
11316
11492
  isolate: options.poolOptions?.forks?.isolate ?? options.isolate ?? testConfig.poolOptions?.forks?.isolate ?? viteConfig.test?.isolate
11317
11493
  }
11318
- }
11494
+ },
11495
+ root: testConfig.root ?? viteConfig.test?.root,
11496
+ deps: testConfig.deps ?? viteConfig.test?.deps
11319
11497
  }
11320
11498
  };
11321
11499
  config.customLogger = createViteLogger(