vitest 4.0.0-beta.2 → 4.0.0-beta.4

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 (60) hide show
  1. package/dist/browser.d.ts +6 -6
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{base.Bj3pWTr1.js → base.BaCDDRPG.js} +2 -2
  4. package/dist/chunks/{benchmark.d.BwvBVTda.d.ts → benchmark.d.DAaHLpsq.d.ts} +4 -4
  5. package/dist/chunks/{browser.d.DP0ACFkh.d.ts → browser.d.BRP8scJf.d.ts} +5 -5
  6. package/dist/chunks/{cac.CVVvMokL.js → cac.CY0IAxC4.js} +19 -18
  7. package/dist/chunks/{cli-api.BUkNuHvl.js → cli-api.B8xRY9Zt.js} +45 -71
  8. package/dist/chunks/{config.d.HJdfX-8k.d.ts → config.d.DZo8c7fw.d.ts} +58 -58
  9. package/dist/chunks/{console.CtFJOzRO.js → console.DoJHFxmj.js} +3 -3
  10. package/dist/chunks/{constants.DnKduX2e.js → constants.CXzqaLmq.js} +1 -4
  11. package/dist/chunks/{coverage.BjMqihzx.js → coverage.C84l9G-M.js} +92 -64
  12. package/dist/chunks/{coverage.d.S9RMNXIe.d.ts → coverage.d.CNYjU4GF.d.ts} +4 -4
  13. package/dist/chunks/{creator.GK6I-cL4.js → creator.yfA2ExGt.js} +68 -7
  14. package/dist/chunks/{environment.d.CUq4cUgQ.d.ts → environment.d.Bhm9oc0v.d.ts} +1 -1
  15. package/dist/chunks/{execute.B7h3T_Hc.js → execute.Dt-pCVcL.js} +1 -1
  16. package/dist/chunks/{global.d.CVbXEflG.d.ts → global.d.DAhT2emn.d.ts} +2 -2
  17. package/dist/chunks/{globals.Cxal6MLI.js → globals.Dgo-vS5G.js} +3 -3
  18. package/dist/chunks/{index.B521nVV-.js → index.Bgo3tNWt.js} +23 -4
  19. package/dist/chunks/{index.a-yuRg2G.js → index.Bz6b0Ib7.js} +5 -4
  20. package/dist/chunks/{index.D-VkfKhf.js → index.CtUvr1c8.js} +2 -2
  21. package/dist/chunks/{index.BWf_gE5n.js → index.D1_MsKEt.js} +1 -1
  22. package/dist/chunks/{index.CJvUWPky.js → index.D3SKT3tv.js} +1 -1
  23. package/dist/chunks/{plugin.d.NmsBIHuT.d.ts → plugin.d.CLhMcYdD.d.ts} +1 -1
  24. package/dist/chunks/{reporters.d.BbsDWlO9.d.ts → reporters.d.DWg40D2B.d.ts} +200 -110
  25. package/dist/chunks/{rpc.CsFtxqeq.js → rpc.jnQO9F8a.js} +4 -8
  26. package/dist/chunks/{runBaseTests.BC7ZIH5L.js → runBaseTests.DBVVLMSb.js} +7 -7
  27. package/dist/chunks/{setup-common.D7ZqXFx-.js → setup-common.Ebx5x0eP.js} +1 -1
  28. package/dist/chunks/{suite.d.FvehnV49.d.ts → suite.d.BJWk38HB.d.ts} +1 -1
  29. package/dist/chunks/{typechecker.CVytUJuF.js → typechecker.CMNPqJOo.js} +3 -3
  30. package/dist/chunks/{utils.CAioKnHs.js → utils.CcGm2cd1.js} +1 -1
  31. package/dist/chunks/{vi.bdSIJ99Y.js → vi.CA0EPI9Y.js} +11 -11
  32. package/dist/chunks/{vm.BThCzidc.js → vm.BUnLJt_P.js} +11 -3
  33. package/dist/chunks/{worker.d.CVn8WGlF.d.ts → worker.d.C-1AbnVe.d.ts} +1 -1
  34. package/dist/chunks/{worker.d.COAQvn4k.d.ts → worker.d.zjyR34Pb.d.ts} +18 -9
  35. package/dist/cli.js +4 -4
  36. package/dist/config.d.ts +44 -44
  37. package/dist/config.js +1 -1
  38. package/dist/coverage.d.ts +20 -18
  39. package/dist/coverage.js +4 -4
  40. package/dist/environments.d.ts +9 -9
  41. package/dist/execute.d.ts +7 -7
  42. package/dist/execute.js +1 -1
  43. package/dist/index.d.ts +28 -23
  44. package/dist/index.js +2 -2
  45. package/dist/node.d.ts +23 -21
  46. package/dist/node.js +10 -10
  47. package/dist/reporters.d.ts +7 -7
  48. package/dist/reporters.js +3 -3
  49. package/dist/runners.d.ts +1 -1
  50. package/dist/runners.js +4 -4
  51. package/dist/suite.d.ts +2 -2
  52. package/dist/worker.js +11 -5
  53. package/dist/workers/forks.js +3 -3
  54. package/dist/workers/runVmTests.js +6 -6
  55. package/dist/workers/threads.js +3 -3
  56. package/dist/workers/vmForks.js +4 -4
  57. package/dist/workers/vmThreads.js +4 -4
  58. package/dist/workers.d.ts +4 -4
  59. package/dist/workers.js +7 -7
  60. package/package.json +19 -19
@@ -98,68 +98,68 @@ interface SerializedConfig {
98
98
  maxConcurrency: number;
99
99
  defines: Record<string, any>;
100
100
  expect: {
101
- requireAssertions?: boolean
101
+ requireAssertions?: boolean;
102
102
  poll?: {
103
- timeout?: number
104
- interval?: number
105
- }
103
+ timeout?: number;
104
+ interval?: number;
105
+ };
106
106
  };
107
107
  printConsoleTrace: boolean | undefined;
108
108
  sequence: {
109
- shuffle?: boolean
110
- concurrent?: boolean
111
- seed: number
112
- hooks: SequenceHooks
113
- setupFiles: SequenceSetupFiles
109
+ shuffle?: boolean;
110
+ concurrent?: boolean;
111
+ seed: number;
112
+ hooks: SequenceHooks;
113
+ setupFiles: SequenceSetupFiles;
114
114
  };
115
115
  poolOptions: {
116
116
  forks: {
117
- singleFork: boolean
118
- isolate: boolean
119
- }
117
+ singleFork: boolean;
118
+ isolate: boolean;
119
+ };
120
120
  threads: {
121
- singleThread: boolean
122
- isolate: boolean
123
- }
121
+ singleThread: boolean;
122
+ isolate: boolean;
123
+ };
124
124
  vmThreads: {
125
- singleThread: boolean
126
- }
125
+ singleThread: boolean;
126
+ };
127
127
  vmForks: {
128
- singleFork: boolean
129
- }
128
+ singleFork: boolean;
129
+ };
130
130
  };
131
131
  deps: {
132
132
  web: {
133
- transformAssets?: boolean
134
- transformCss?: boolean
135
- transformGlobPattern?: RegExp | RegExp[]
136
- }
133
+ transformAssets?: boolean;
134
+ transformCss?: boolean;
135
+ transformGlobPattern?: RegExp | RegExp[];
136
+ };
137
137
  optimizer: {
138
138
  web: {
139
- enabled: boolean
140
- }
139
+ enabled: boolean;
140
+ };
141
141
  ssr: {
142
- enabled: boolean
143
- }
144
- }
145
- interopDefault: boolean | undefined
146
- moduleDirectories: string[] | undefined
142
+ enabled: boolean;
143
+ };
144
+ };
145
+ interopDefault: boolean | undefined;
146
+ moduleDirectories: string[] | undefined;
147
147
  };
148
148
  snapshotOptions: {
149
- updateSnapshot: SnapshotUpdateState
150
- expand: boolean | undefined
151
- snapshotFormat: PrettyFormatOptions | undefined
149
+ updateSnapshot: SnapshotUpdateState;
150
+ expand: boolean | undefined;
151
+ snapshotFormat: PrettyFormatOptions | undefined;
152
152
  /**
153
153
  * only exists for tests, not available in the main process
154
154
  */
155
- snapshotEnvironment: SnapshotEnvironment
155
+ snapshotEnvironment: SnapshotEnvironment;
156
156
  };
157
157
  pool: string;
158
158
  snapshotSerializers: string[];
159
159
  chaiConfig: {
160
- includeStack?: boolean
161
- showDiff?: boolean
162
- truncateThreshold?: number
160
+ includeStack?: boolean;
161
+ showDiff?: boolean;
162
+ truncateThreshold?: number;
163
163
  } | undefined;
164
164
  diff: string | SerializedDiffOptions | undefined;
165
165
  retry: number;
@@ -167,52 +167,52 @@ interface SerializedConfig {
167
167
  inspect: boolean | string | undefined;
168
168
  inspectBrk: boolean | string | undefined;
169
169
  inspector: {
170
- enabled?: boolean
171
- port?: number
172
- host?: string
173
- waitForDebugger?: boolean
170
+ enabled?: boolean;
171
+ port?: number;
172
+ host?: string;
173
+ waitForDebugger?: boolean;
174
174
  };
175
175
  watch: boolean;
176
176
  env: Record<string, any>;
177
177
  browser: {
178
- name: string
179
- headless: boolean
180
- isolate: boolean
181
- fileParallelism: boolean
182
- ui: boolean
178
+ name: string;
179
+ headless: boolean;
180
+ isolate: boolean;
181
+ fileParallelism: boolean;
182
+ ui: boolean;
183
183
  viewport: {
184
- width: number
185
- height: number
186
- }
184
+ width: number;
185
+ height: number;
186
+ };
187
187
  locators: {
188
- testIdAttribute: string
189
- }
190
- screenshotFailures: boolean
188
+ testIdAttribute: string;
189
+ };
190
+ screenshotFailures: boolean;
191
191
  providerOptions: {
192
192
  // for playwright
193
- actionTimeout?: number
194
- }
193
+ actionTimeout?: number;
194
+ };
195
195
  };
196
196
  standalone: boolean;
197
197
  logHeapUsage: boolean | undefined;
198
198
  coverage: SerializedCoverageConfig;
199
199
  benchmark: {
200
- includeSamples: boolean
200
+ includeSamples: boolean;
201
201
  } | undefined;
202
202
  }
203
203
  interface SerializedCoverageConfig {
204
204
  provider: "istanbul" | "v8" | "custom" | undefined;
205
205
  reportsDirectory: string;
206
206
  htmlReporter: {
207
- subdir: string | undefined
207
+ subdir: string | undefined;
208
208
  } | undefined;
209
209
  enabled: boolean;
210
210
  customProviderModule: string | undefined;
211
211
  }
212
212
  type RuntimeConfig = Pick<SerializedConfig, "allowOnly" | "testTimeout" | "hookTimeout" | "clearMocks" | "mockReset" | "restoreMocks" | "fakeTimers" | "maxConcurrency" | "expect" | "printConsoleTrace"> & {
213
213
  sequence?: {
214
- hooks?: SequenceHooks
215
- }
214
+ hooks?: SequenceHooks;
215
+ };
216
216
  };
217
217
  type RuntimeOptions = Partial<RuntimeConfig>;
218
218
 
@@ -8,7 +8,7 @@ import { g as getWorkerState } from './utils.XdZDrNZV.js';
8
8
 
9
9
  const UNKNOWN_TEST_ID = "__vitest__unknown_test__";
10
10
  function getTaskIdByStack(root) {
11
- const stack = new Error("STACK_TRACE_ERROR").stack?.split("\n");
11
+ const stack = (/* @__PURE__ */ new Error("STACK_TRACE_ERROR")).stack?.split("\n");
12
12
  if (!stack) return UNKNOWN_TEST_ID;
13
13
  const index = stack.findIndex((line) => line.includes("at Console.value"));
14
14
  const line = index === -1 ? null : stack[index + 2];
@@ -101,7 +101,7 @@ function createCustomConsole(defaultState) {
101
101
  if (state().config.printConsoleTrace) {
102
102
  const limit = Error.stackTraceLimit;
103
103
  Error.stackTraceLimit = limit + 6;
104
- const stack = new Error("STACK_TRACE").stack;
104
+ const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack;
105
105
  const trace = stack?.split("\n").slice(7).join("\n");
106
106
  Error.stackTraceLimit = limit;
107
107
  buffer.push([data, trace]);
@@ -129,7 +129,7 @@ function createCustomConsole(defaultState) {
129
129
  if (state().config.printConsoleTrace) {
130
130
  const limit = Error.stackTraceLimit;
131
131
  Error.stackTraceLimit = limit + 6;
132
- const stack = new Error("STACK_TRACE").stack?.split("\n");
132
+ const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n");
133
133
  Error.stackTraceLimit = limit;
134
134
  const isTrace = stack?.some((line) => line.includes("at Console.trace"));
135
135
  if (isTrace) buffer.push([data, void 0]);
@@ -9,7 +9,6 @@ const extraInlineDeps = [
9
9
  /vite\w*\/dist\/client\/env.mjs/
10
10
  ];
11
11
  const CONFIG_NAMES = ["vitest.config", "vite.config"];
12
- const WORKSPACES_NAMES = ["vitest.workspace", "vitest.projects"];
13
12
  const CONFIG_EXTENSIONS = [
14
13
  ".ts",
15
14
  ".mts",
@@ -19,8 +18,6 @@ const CONFIG_EXTENSIONS = [
19
18
  ".cjs"
20
19
  ];
21
20
  const configFiles = CONFIG_NAMES.flatMap((name) => CONFIG_EXTENSIONS.map((ext) => name + ext));
22
- const WORKSPACES_EXTENSIONS = [...CONFIG_EXTENSIONS, ".json"];
23
- const workspacesFiles = WORKSPACES_NAMES.flatMap((name) => WORKSPACES_EXTENSIONS.map((ext) => name + ext));
24
21
  const globalApis = [
25
22
  "suite",
26
23
  "test",
@@ -41,4 +38,4 @@ const globalApis = [
41
38
  "onTestFailed"
42
39
  ];
43
40
 
44
- export { API_PATH as A, defaultPort as a, defaultInspectPort as b, configFiles as c, defaultBrowserPort as d, extraInlineDeps as e, globalApis as g, workspacesFiles as w };
41
+ export { API_PATH as A, defaultPort as a, defaultInspectPort as b, configFiles as c, defaultBrowserPort as d, extraInlineDeps as e, globalApis as g };
@@ -16,15 +16,15 @@ import assert from 'node:assert';
16
16
  import v8 from 'node:v8';
17
17
  import { format, inspect } from 'node:util';
18
18
  import { version, mergeConfig } from 'vite';
19
- import { c as configFiles, w as workspacesFiles, e as extraInlineDeps, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort } from './constants.DnKduX2e.js';
19
+ import { c as configFiles, e as extraInlineDeps, d as defaultBrowserPort, b as defaultInspectPort, a as defaultPort } from './constants.CXzqaLmq.js';
20
20
  import { a as isWindows } from './env.D4Lgay0q.js';
21
21
  import * as nodeos from 'node:os';
22
22
  import nodeos__default from 'node:os';
23
23
  import { isatty } from 'node:tty';
24
24
  import EventEmitter from 'node:events';
25
- import { c as createBirpc } from './index.B521nVV-.js';
25
+ import { c as createBirpc } from './index.Bgo3tNWt.js';
26
26
  import Tinypool$1, { Tinypool } from 'tinypool';
27
- import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.CVytUJuF.js';
27
+ import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.CMNPqJOo.js';
28
28
  import { MessageChannel } from 'node:worker_threads';
29
29
  import { hasFailed } from '@vitest/runner/utils';
30
30
  import { rootDir } from '../path.js';
@@ -2556,11 +2556,6 @@ function createChildProcessChannel$1(project, collect = false) {
2556
2556
  message: "message",
2557
2557
  response: "response"
2558
2558
  };
2559
- const channel = {
2560
- onMessage: (callback) => emitter.on(events.message, callback),
2561
- postMessage: (message) => emitter.emit(events.response, message),
2562
- onClose: () => emitter.removeAllListeners()
2563
- };
2564
2559
  const rpc = createBirpc(createMethodsRPC(project, {
2565
2560
  cacheFs: true,
2566
2561
  collect
@@ -2584,11 +2579,17 @@ function createChildProcessChannel$1(project, collect = false) {
2584
2579
  on(fn) {
2585
2580
  emitter.on(events.response, fn);
2586
2581
  },
2587
- onTimeoutError(functionName) {
2588
- throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
2589
- }
2582
+ timeout: -1
2590
2583
  });
2591
2584
  project.vitest.onCancel((reason) => rpc.onCancel(reason));
2585
+ const channel = {
2586
+ onMessage: (callback) => emitter.on(events.message, callback),
2587
+ postMessage: (message) => emitter.emit(events.response, message),
2588
+ onClose: () => {
2589
+ emitter.removeAllListeners();
2590
+ rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2591
+ }
2592
+ };
2592
2593
  return channel;
2593
2594
  }
2594
2595
  function createForksPool(vitest, { execArgv, env }) {
@@ -2717,14 +2718,18 @@ function createWorkerChannel$1(project, collect) {
2717
2718
  on(fn) {
2718
2719
  port.on("message", fn);
2719
2720
  },
2720
- onTimeoutError(functionName) {
2721
- throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
2722
- }
2721
+ timeout: -1
2723
2722
  });
2724
2723
  project.vitest.onCancel((reason) => rpc.onCancel(reason));
2724
+ const onClose = () => {
2725
+ port.close();
2726
+ workerPort.close();
2727
+ rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2728
+ };
2725
2729
  return {
2726
2730
  workerPort,
2727
- port
2731
+ port,
2732
+ onClose
2728
2733
  };
2729
2734
  }
2730
2735
  function createThreadsPool(vitest, { execArgv, env }) {
@@ -2757,11 +2762,7 @@ function createThreadsPool(vitest, { execArgv, env }) {
2757
2762
  async function runFiles(project, config, files, environment, invalidates = []) {
2758
2763
  const paths = files.map((f) => f.filepath);
2759
2764
  vitest.state.clearFiles(project, paths);
2760
- const { workerPort, port } = createWorkerChannel$1(project, name === "collect");
2761
- const onClose = () => {
2762
- port.close();
2763
- workerPort.close();
2764
- };
2765
+ const { workerPort, onClose } = createWorkerChannel$1(project, name === "collect");
2765
2766
  const workerId = ++id;
2766
2767
  const data = {
2767
2768
  pool: "threads",
@@ -3013,15 +3014,10 @@ function stringToBytes(input, percentageReference) {
3013
3014
  const suppressWarningsPath$1 = resolve(rootDir, "./suppress-warnings.cjs");
3014
3015
  function createChildProcessChannel(project, collect) {
3015
3016
  const emitter = new EventEmitter();
3016
- const cleanup = () => emitter.removeAllListeners();
3017
3017
  const events = {
3018
3018
  message: "message",
3019
3019
  response: "response"
3020
3020
  };
3021
- const channel = {
3022
- onMessage: (callback) => emitter.on(events.message, callback),
3023
- postMessage: (message) => emitter.emit(events.response, message)
3024
- };
3025
3021
  const rpc = createBirpc(createMethodsRPC(project, {
3026
3022
  cacheFs: true,
3027
3023
  collect
@@ -3045,15 +3041,18 @@ function createChildProcessChannel(project, collect) {
3045
3041
  on(fn) {
3046
3042
  emitter.on(events.response, fn);
3047
3043
  },
3048
- onTimeoutError(functionName) {
3049
- throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
3050
- }
3044
+ timeout: -1
3051
3045
  });
3052
3046
  project.vitest.onCancel((reason) => rpc.onCancel(reason));
3053
- return {
3054
- channel,
3055
- cleanup
3047
+ const channel = {
3048
+ onMessage: (callback) => emitter.on(events.message, callback),
3049
+ postMessage: (message) => emitter.emit(events.response, message),
3050
+ onClose: () => {
3051
+ emitter.removeAllListeners();
3052
+ rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
3053
+ }
3056
3054
  };
3055
+ return { channel };
3057
3056
  }
3058
3057
  function createVmForksPool(vitest, { execArgv, env }) {
3059
3058
  const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length;
@@ -3090,7 +3089,7 @@ function createVmForksPool(vitest, { execArgv, env }) {
3090
3089
  async function runFiles(project, config, files, environment, invalidates = []) {
3091
3090
  const paths = files.map((f) => f.filepath);
3092
3091
  vitest.state.clearFiles(project, paths);
3093
- const { channel, cleanup } = createChildProcessChannel(project, name === "collect");
3092
+ const { channel } = createChildProcessChannel(project, name === "collect");
3094
3093
  const workerId = ++id;
3095
3094
  const data = {
3096
3095
  pool: "forks",
@@ -3114,7 +3113,7 @@ function createVmForksPool(vitest, { execArgv, env }) {
3114
3113
  else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
3115
3114
  else throw error;
3116
3115
  } finally {
3117
- cleanup();
3116
+ channel.onClose();
3118
3117
  }
3119
3118
  }
3120
3119
  return async (specs, invalidates) => {
@@ -3165,14 +3164,17 @@ function createWorkerChannel(project, collect) {
3165
3164
  on(fn) {
3166
3165
  port.on("message", fn);
3167
3166
  },
3168
- onTimeoutError(functionName) {
3169
- throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`);
3170
- }
3167
+ timeout: -1
3171
3168
  });
3172
3169
  project.vitest.onCancel((reason) => rpc.onCancel(reason));
3170
+ function onClose() {
3171
+ workerPort.close();
3172
+ port.close();
3173
+ rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
3174
+ }
3173
3175
  return {
3174
3176
  workerPort,
3175
- port
3177
+ onClose
3176
3178
  };
3177
3179
  }
3178
3180
  function createVmThreadsPool(vitest, { execArgv, env }) {
@@ -3210,7 +3212,7 @@ function createVmThreadsPool(vitest, { execArgv, env }) {
3210
3212
  async function runFiles(project, config, files, environment, invalidates = []) {
3211
3213
  const paths = files.map((f) => f.filepath);
3212
3214
  vitest.state.clearFiles(project, paths);
3213
- const { workerPort, port } = createWorkerChannel(project, name === "collect");
3215
+ const { workerPort, onClose } = createWorkerChannel(project, name === "collect");
3214
3216
  const workerId = ++id;
3215
3217
  const data = {
3216
3218
  pool: "vmThreads",
@@ -3235,8 +3237,7 @@ function createVmThreadsPool(vitest, { execArgv, env }) {
3235
3237
  else if (vitest.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) vitest.state.cancelFiles(paths, project);
3236
3238
  else throw error;
3237
3239
  } finally {
3238
- port.close();
3239
- workerPort.close();
3240
+ onClose();
3240
3241
  }
3241
3242
  }
3242
3243
  return async (specs, invalidates) => {
@@ -3438,9 +3439,7 @@ class BaseSequencer {
3438
3439
  async shard(files) {
3439
3440
  const { config } = this.ctx;
3440
3441
  const { index, count } = config.shard;
3441
- const shardSize = Math.ceil(files.length / count);
3442
- const shardStart = shardSize * (index - 1);
3443
- const shardEnd = shardSize * index;
3442
+ const [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
3444
3443
  return [...files].map((spec) => {
3445
3444
  const fullPath = resolve$1(slash(config.root), slash(spec.moduleId));
3446
3445
  const specPath = fullPath?.slice(config.root.length);
@@ -3473,6 +3472,20 @@ class BaseSequencer {
3473
3472
  return bState.duration - aState.duration;
3474
3473
  });
3475
3474
  }
3475
+ // Calculate distributed shard range [start, end] distributed equally
3476
+ calculateShardRange(filesCount, index, count) {
3477
+ const baseShardSize = Math.floor(filesCount / count);
3478
+ const remainderTestFilesCount = filesCount % count;
3479
+ if (remainderTestFilesCount >= index) {
3480
+ const shardSize = baseShardSize + 1;
3481
+ const shardStart = shardSize * (index - 1);
3482
+ const shardEnd = shardSize * index;
3483
+ return [shardStart, shardEnd];
3484
+ }
3485
+ const shardStart = remainderTestFilesCount * (baseShardSize + 1) + (index - remainderTestFilesCount - 1) * baseShardSize;
3486
+ const shardEnd = shardStart + baseShardSize;
3487
+ return [shardStart, shardEnd];
3488
+ }
3476
3489
  }
3477
3490
 
3478
3491
  class RandomSequencer extends BaseSequencer {
@@ -3532,6 +3545,7 @@ function resolveConfig$1(vitest, options, viteConfig) {
3532
3545
  resolved.provide ??= {};
3533
3546
  resolved.name = typeof options.name === "string" ? options.name : options.name?.label || "";
3534
3547
  resolved.color = typeof options.name !== "string" ? options.name?.color : void 0;
3548
+ if (resolved.environment === "browser") throw new Error(`Looks like you set "test.environment" to "browser". To enabled Browser Mode, use "test.browser.enabled" instead.`);
3535
3549
  const inspector = resolved.inspect || resolved.inspectBrk;
3536
3550
  resolved.inspector = {
3537
3551
  ...resolved.inspector,
@@ -3642,7 +3656,6 @@ function resolveConfig$1(vitest, options, viteConfig) {
3642
3656
  ...resolved.include,
3643
3657
  resolved.config && slash$1(resolved.config),
3644
3658
  ...configFiles,
3645
- ...workspacesFiles,
3646
3659
  "**/virtual:*",
3647
3660
  "**/__x00__*",
3648
3661
  "**/node_modules/**"
@@ -3683,7 +3696,11 @@ function resolveConfig$1(vitest, options, viteConfig) {
3683
3696
  resolved.attachmentsDir = resolve$1(resolved.root, resolved.attachmentsDir ?? ".vitest-attachments");
3684
3697
  if (resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root);
3685
3698
  resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0;
3686
- if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) resolved.snapshotFormat.plugins = [];
3699
+ if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) {
3700
+ resolved.snapshotFormat.plugins = [];
3701
+ // TODO: support it via separate config (like DiffOptions) or via `Function.toString()`
3702
+ if (typeof resolved.snapshotFormat.compareKeys === "function") throw new TypeError(`"snapshotFormat.compareKeys" function is not supported.`);
3703
+ }
3687
3704
  const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT;
3688
3705
  resolved.snapshotOptions = {
3689
3706
  expand: resolved.expandSnapshotDiff ?? false,
@@ -3755,9 +3772,6 @@ function resolveConfig$1(vitest, options, viteConfig) {
3755
3772
  ["vmForks", "maxForks"]
3756
3773
  ];
3757
3774
  for (const [poolOptionKey, workerOptionKey] of poolForksOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3758
- if (typeof resolved.workspace === "string")
3759
- // if passed down from the CLI and it's relative, resolve relative to CWD
3760
- resolved.workspace = typeof options.workspace === "string" && options.workspace[0] === "." ? resolve$1(process.cwd(), options.workspace) : resolvePath(resolved.workspace, resolved.root);
3761
3775
  if (!builtinPools.includes(resolved.pool)) resolved.pool = resolvePath(resolved.pool, resolved.root);
3762
3776
  if (mode === "benchmark") {
3763
3777
  resolved.benchmark = {
@@ -3948,6 +3962,7 @@ class BaseCoverageProvider {
3948
3962
  coverageFiles = /* @__PURE__ */ new Map();
3949
3963
  pendingPromises = [];
3950
3964
  coverageFilesDirectory;
3965
+ roots = [];
3951
3966
  _initialize(ctx) {
3952
3967
  this.ctx = ctx;
3953
3968
  if (ctx.version !== this.version) ctx.logger.warn(c.yellow(`Loaded ${c.inverse(c.yellow(` vitest@${ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/coverage-${this.name}@${this.version} `))}.
@@ -3971,44 +3986,55 @@ Update your dependencies and make sure the versions match.`));
3971
3986
  const shard = this.ctx.config.shard;
3972
3987
  const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
3973
3988
  this.coverageFilesDirectory = resolve$1(this.options.reportsDirectory, tempDirectory);
3989
+ // If --project filter is set pick only roots of resolved projects
3990
+ this.roots = ctx.config.project?.length ? [...new Set(ctx.projects.map((project) => project.config.root))] : [ctx.config.root];
3974
3991
  }
3975
3992
  /**
3976
3993
  * Check if file matches `coverage.include` but not `coverage.exclude`
3977
3994
  */
3978
- isIncluded(_filename) {
3995
+ isIncluded(_filename, root) {
3996
+ const roots = root ? [root] : this.roots;
3979
3997
  const filename = slash(_filename);
3980
3998
  const cacheHit = this.globCache.get(filename);
3981
3999
  if (cacheHit !== void 0) return cacheHit;
3982
4000
  // File outside project root with default allowExternal
3983
- if (this.options.allowExternal === false && !filename.startsWith(this.ctx.config.root)) {
4001
+ if (this.options.allowExternal === false && roots.every((root) => !filename.startsWith(root))) {
3984
4002
  this.globCache.set(filename, false);
3985
4003
  return false;
3986
4004
  }
3987
- const options = {
3988
- contains: true,
3989
- dot: true,
3990
- cwd: this.ctx.config.root,
3991
- ignore: this.options.exclude
3992
- };
3993
4005
  // By default `coverage.include` matches all files, except "coverage.exclude"
3994
4006
  const glob = this.options.include || "**";
3995
- const included = pm.isMatch(filename, glob, options) && existsSync(cleanUrl(filename));
4007
+ let included = roots.some((root) => {
4008
+ const options = {
4009
+ contains: true,
4010
+ dot: true,
4011
+ cwd: root,
4012
+ ignore: this.options.exclude
4013
+ };
4014
+ return pm.isMatch(filename, glob, options);
4015
+ });
4016
+ included &&= existsSync(cleanUrl(filename));
3996
4017
  this.globCache.set(filename, included);
3997
4018
  return included;
3998
4019
  }
3999
- async getUntestedFiles(testedFiles) {
4000
- if (this.options.include == null) return [];
4001
- let includedFiles = await glob(this.options.include, {
4002
- cwd: this.ctx.config.root,
4020
+ async getUntestedFilesByRoot(testedFiles, include, root) {
4021
+ let includedFiles = await glob(include, {
4022
+ cwd: root,
4003
4023
  ignore: [...this.options.exclude, ...testedFiles.map((file) => slash(file))],
4004
4024
  absolute: true,
4005
4025
  dot: true,
4006
4026
  onlyFiles: true
4007
4027
  });
4008
4028
  // Run again through picomatch as tinyglobby's exclude pattern is different ({ "exclude": ["math"] } should ignore "src/math.ts")
4009
- includedFiles = includedFiles.filter((file) => this.isIncluded(file));
4029
+ includedFiles = includedFiles.filter((file) => this.isIncluded(file, root));
4010
4030
  if (this.ctx.config.changed) includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
4011
- return includedFiles.map((file) => slash(path.resolve(this.ctx.config.root, file)));
4031
+ return includedFiles.map((file) => slash(path.resolve(root, file)));
4032
+ }
4033
+ async getUntestedFiles(testedFiles) {
4034
+ if (this.options.include == null) return [];
4035
+ const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
4036
+ const matrix = await Promise.all(this.roots.map(rootMapper));
4037
+ return matrix.flatMap((files) => files);
4012
4038
  }
4013
4039
  createCoverageMap() {
4014
4040
  throw new Error("BaseReporter's createCoverageMap was not overwritten");
@@ -4268,7 +4294,9 @@ Update your dependencies and make sure the versions match.`));
4268
4294
  root: project.config.root,
4269
4295
  isBrowserEnabled: project.isBrowserEnabled(),
4270
4296
  vitenode: project.vitenode
4271
- })), {
4297
+ })),
4298
+ // Check core last as it will match all files anyway
4299
+ {
4272
4300
  root: ctx.config.root,
4273
4301
  vitenode: ctx.vitenode,
4274
4302
  isBrowserEnabled: ctx.getRootProject().isBrowserEnabled()
@@ -2,7 +2,7 @@ import { ModuleExecutionInfo } from 'vite-node/client';
2
2
 
3
3
  interface RuntimeCoverageModuleLoader {
4
4
  executeId: (id: string) => Promise<{
5
- default: RuntimeCoverageProviderModule
5
+ default: RuntimeCoverageProviderModule;
6
6
  }>;
7
7
  isBrowser?: boolean;
8
8
  moduleExecutionInfo?: ModuleExecutionInfo;
@@ -16,19 +16,19 @@ interface RuntimeCoverageProviderModule {
16
16
  * Executed before tests are run in the worker thread.
17
17
  */
18
18
  startCoverage?: (runtimeOptions: {
19
- isolate: boolean
19
+ isolate: boolean;
20
20
  }) => unknown | Promise<unknown>;
21
21
  /**
22
22
  * Executed on after each run in the worker thread. Possible to return a payload passed to the provider
23
23
  */
24
24
  takeCoverage?: (runtimeOptions?: {
25
- moduleExecutionInfo?: ModuleExecutionInfo
25
+ moduleExecutionInfo?: ModuleExecutionInfo;
26
26
  }) => unknown | Promise<unknown>;
27
27
  /**
28
28
  * Executed after all tests have been run in the worker thread.
29
29
  */
30
30
  stopCoverage?: (runtimeOptions: {
31
- isolate: boolean
31
+ isolate: boolean;
32
32
  }) => unknown | Promise<unknown>;
33
33
  }
34
34