vitest 2.1.0-beta.6 → 2.1.0-beta.7

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 (56) hide show
  1. package/LICENSE.md +52 -342
  2. package/dist/browser.d.ts +4 -2
  3. package/dist/browser.js +1 -1
  4. package/dist/chunks/{RandomSequencer.CjkAy_bL.js → RandomSequencer.Bh5-tlNJ.js} +10 -37
  5. package/dist/chunks/{base.BH-FAiX7.js → base.BlXpj3e_.js} +1 -29
  6. package/dist/chunks/{base.B-9RAXb6.js → base.CchlWrnV.js} +2 -4
  7. package/dist/chunks/{cac.BZlOqtiQ.js → cac.B5XYKv2_.js} +25 -16
  8. package/dist/chunks/{cli-api.B-2f6g4d.js → cli-api.ByZPnilx.js} +2778 -3488
  9. package/dist/chunks/{creator.D0TxjnLa.js → creator.zfBZSJzo.js} +8 -11
  10. package/dist/chunks/{execute.DT9BA6zp.js → execute._eQQfgI8.js} +322 -232
  11. package/dist/chunks/{git.ZtkbKc8u.js → git.B5SDxu-n.js} +5 -5
  12. package/dist/chunks/{globals.Br36EZIp.js → globals.jM7MxN2t.js} +3 -3
  13. package/dist/chunks/{index.CM5UI-4O.js → index.Bn75ITYg.js} +3 -3
  14. package/dist/chunks/index.CPD77dLA.js +133 -0
  15. package/dist/chunks/{index.dWDhoZDV.js → index.CSjyR2-v.js} +1 -1
  16. package/dist/chunks/{index.C4LZENmc.js → index.DpJO1tkB.js} +40 -44
  17. package/dist/chunks/{index.m3Xip5Zz.js → index.xm8OIiKD.js} +1 -1
  18. package/dist/chunks/mocker.cRtM890J.d.ts +17 -0
  19. package/dist/chunks/{reporters.B0Ao6Zu1.d.ts → reporters.WnPwkmgA.d.ts} +30 -22
  20. package/dist/chunks/{resolveConfig.C0vpvVRF.js → resolveConfig.-K5hHm0S.js} +19 -6
  21. package/dist/chunks/{runBaseTests.Cf8lGnUq.js → runBaseTests.Cztfoflv.js} +6 -6
  22. package/dist/chunks/{setup-common.B7uEQsGB.js → setup-common.fGBFoQKJ.js} +1 -1
  23. package/dist/chunks/{utils.C3_cBsyn.js → utils.Cn0zI1t3.js} +16 -3
  24. package/dist/chunks/{utils.DO38lwfj.js → utils.Dbnmsfq1.js} +1 -1
  25. package/dist/chunks/{vi.DBepMgvg.js → vi.DGgiNzJE.js} +37 -37
  26. package/dist/chunks/{vite.Bvz2vSw0.d.ts → vite.D2yAwzwa.d.ts} +1 -1
  27. package/dist/chunks/{vm.kl9T_5ai.js → vm.CPXwWp4C.js} +1 -2
  28. package/dist/chunks/{worker.DTM-0OlZ.d.ts → worker.Bws9Zuxu.d.ts} +1 -1
  29. package/dist/chunks/{worker.CTdJUeeB.d.ts → worker.CmPmTxgH.d.ts} +1 -14
  30. package/dist/cli.js +2 -2
  31. package/dist/config.d.ts +2 -2
  32. package/dist/coverage.d.ts +1 -1
  33. package/dist/coverage.js +4 -4
  34. package/dist/execute.d.ts +12 -13
  35. package/dist/execute.js +3 -2
  36. package/dist/index.d.ts +17 -15
  37. package/dist/index.js +4 -4
  38. package/dist/mocker.d.ts +1 -0
  39. package/dist/mocker.js +1 -0
  40. package/dist/node.d.ts +15 -7
  41. package/dist/node.js +18 -16
  42. package/dist/reporters.d.ts +1 -1
  43. package/dist/reporters.js +5 -5
  44. package/dist/runners.js +2 -2
  45. package/dist/utils.d.ts +1 -0
  46. package/dist/worker.js +3 -2
  47. package/dist/workers/forks.js +5 -4
  48. package/dist/workers/runVmTests.js +5 -5
  49. package/dist/workers/threads.js +5 -4
  50. package/dist/workers/vmForks.js +4 -4
  51. package/dist/workers/vmThreads.js +4 -4
  52. package/dist/workers.d.ts +2 -2
  53. package/dist/workers.js +6 -5
  54. package/mocker.d.ts +1 -0
  55. package/package.json +22 -17
  56. package/dist/chunks/index.CWhwfxXK.js +0 -835
@@ -2,34 +2,239 @@ import vm from 'node:vm';
2
2
  import { pathToFileURL } from 'node:url';
3
3
  import fs from 'node:fs';
4
4
  import { ViteNodeRunner, DEFAULT_REQUEST_STUBS } from 'vite-node/client';
5
- import { isNodeBuiltin, isInternalRequest, toFilePath, isPrimitive } from 'vite-node/utils';
6
- import { resolve, isAbsolute, dirname, join, basename, extname, normalize, relative } from 'pathe';
5
+ import { isInternalRequest, isNodeBuiltin as isNodeBuiltin$1, toFilePath, isPrimitive } from 'vite-node/utils';
6
+ import { resolve as resolve$1, isAbsolute as isAbsolute$1, normalize as normalize$1, relative } from 'pathe';
7
7
  import { processError } from '@vitest/utils/error';
8
8
  import { distDir } from '../path.js';
9
- import { highlight, getType } from '@vitest/utils';
10
- import { g as getAllMockableProperties } from './base.BH-FAiX7.js';
9
+ import { highlight } from '@vitest/utils';
10
+ import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker';
11
+ import { builtinModules } from 'node:module';
11
12
 
12
- const { existsSync, readdirSync } = fs;
13
- const spyModulePath = resolve(distDir, "spy.js");
14
- class RefTracker {
15
- idMap = /* @__PURE__ */ new Map();
16
- mockedValueMap = /* @__PURE__ */ new Map();
17
- getId(value) {
18
- return this.idMap.get(value);
19
- }
20
- getMockedValue(id) {
21
- return this.mockedValueMap.get(id);
22
- }
23
- track(originalValue, mockedValue) {
24
- const newId = this.idMap.size;
25
- this.idMap.set(originalValue, newId);
26
- this.mockedValueMap.set(newId, mockedValue);
27
- return newId;
13
+ const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
14
+ function normalizeWindowsPath(input = "") {
15
+ if (!input) {
16
+ return input;
28
17
  }
18
+ return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
29
19
  }
30
- function isSpecialProp(prop, parentType) {
31
- return parentType.includes("Function") && typeof prop === "string" && ["arguments", "callee", "caller", "length", "name"].includes(prop);
20
+ const _UNC_REGEX = /^[/\\]{2}/;
21
+ const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
22
+ const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
23
+ const normalize = function(path) {
24
+ if (path.length === 0) {
25
+ return ".";
26
+ }
27
+ path = normalizeWindowsPath(path);
28
+ const isUNCPath = path.match(_UNC_REGEX);
29
+ const isPathAbsolute = isAbsolute(path);
30
+ const trailingSeparator = path[path.length - 1] === "/";
31
+ path = normalizeString(path, !isPathAbsolute);
32
+ if (path.length === 0) {
33
+ if (isPathAbsolute) {
34
+ return "/";
35
+ }
36
+ return trailingSeparator ? "./" : ".";
37
+ }
38
+ if (trailingSeparator) {
39
+ path += "/";
40
+ }
41
+ if (_DRIVE_LETTER_RE.test(path)) {
42
+ path += "/";
43
+ }
44
+ if (isUNCPath) {
45
+ if (!isPathAbsolute) {
46
+ return `//./${path}`;
47
+ }
48
+ return `//${path}`;
49
+ }
50
+ return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
51
+ };
52
+ const join = function(...arguments_) {
53
+ if (arguments_.length === 0) {
54
+ return ".";
55
+ }
56
+ let joined;
57
+ for (const argument of arguments_) {
58
+ if (argument && argument.length > 0) {
59
+ if (joined === void 0) {
60
+ joined = argument;
61
+ } else {
62
+ joined += `/${argument}`;
63
+ }
64
+ }
65
+ }
66
+ if (joined === void 0) {
67
+ return ".";
68
+ }
69
+ return normalize(joined.replace(/\/\/+/g, "/"));
70
+ };
71
+ function cwd() {
72
+ if (typeof process !== "undefined" && typeof process.cwd === "function") {
73
+ return process.cwd().replace(/\\/g, "/");
74
+ }
75
+ return "/";
32
76
  }
77
+ const resolve = function(...arguments_) {
78
+ arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
79
+ let resolvedPath = "";
80
+ let resolvedAbsolute = false;
81
+ for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
82
+ const path = index >= 0 ? arguments_[index] : cwd();
83
+ if (!path || path.length === 0) {
84
+ continue;
85
+ }
86
+ resolvedPath = `${path}/${resolvedPath}`;
87
+ resolvedAbsolute = isAbsolute(path);
88
+ }
89
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
90
+ if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
91
+ return `/${resolvedPath}`;
92
+ }
93
+ return resolvedPath.length > 0 ? resolvedPath : ".";
94
+ };
95
+ function normalizeString(path, allowAboveRoot) {
96
+ let res = "";
97
+ let lastSegmentLength = 0;
98
+ let lastSlash = -1;
99
+ let dots = 0;
100
+ let char = null;
101
+ for (let index = 0; index <= path.length; ++index) {
102
+ if (index < path.length) {
103
+ char = path[index];
104
+ } else if (char === "/") {
105
+ break;
106
+ } else {
107
+ char = "/";
108
+ }
109
+ if (char === "/") {
110
+ if (lastSlash === index - 1 || dots === 1) ;
111
+ else if (dots === 2) {
112
+ if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
113
+ if (res.length > 2) {
114
+ const lastSlashIndex = res.lastIndexOf("/");
115
+ if (lastSlashIndex === -1) {
116
+ res = "";
117
+ lastSegmentLength = 0;
118
+ } else {
119
+ res = res.slice(0, lastSlashIndex);
120
+ lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
121
+ }
122
+ lastSlash = index;
123
+ dots = 0;
124
+ continue;
125
+ } else if (res.length > 0) {
126
+ res = "";
127
+ lastSegmentLength = 0;
128
+ lastSlash = index;
129
+ dots = 0;
130
+ continue;
131
+ }
132
+ }
133
+ if (allowAboveRoot) {
134
+ res += res.length > 0 ? "/.." : "..";
135
+ lastSegmentLength = 2;
136
+ }
137
+ } else {
138
+ if (res.length > 0) {
139
+ res += `/${path.slice(lastSlash + 1, index)}`;
140
+ } else {
141
+ res = path.slice(lastSlash + 1, index);
142
+ }
143
+ lastSegmentLength = index - lastSlash - 1;
144
+ }
145
+ lastSlash = index;
146
+ dots = 0;
147
+ } else if (char === "." && dots !== -1) {
148
+ ++dots;
149
+ } else {
150
+ dots = -1;
151
+ }
152
+ }
153
+ return res;
154
+ }
155
+ const isAbsolute = function(p) {
156
+ return _IS_ABSOLUTE_RE.test(p);
157
+ };
158
+ const _EXTNAME_RE = /.(\.[^./]+)$/;
159
+ const extname = function(p) {
160
+ const match = _EXTNAME_RE.exec(normalizeWindowsPath(p));
161
+ return match && match[1] || "";
162
+ };
163
+ const dirname = function(p) {
164
+ const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
165
+ if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) {
166
+ segments[0] += "/";
167
+ }
168
+ return segments.join("/") || (isAbsolute(p) ? "/" : ".");
169
+ };
170
+ const basename = function(p, extension) {
171
+ const lastSegment = normalizeWindowsPath(p).split("/").pop();
172
+ return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
173
+ };
174
+
175
+ const { existsSync, readdirSync, statSync } = fs;
176
+ function findMockRedirect(root, mockPath, external) {
177
+ const path = external || mockPath;
178
+ if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
179
+ let findFile2 = function(mockFolder2, baseOriginal2) {
180
+ const files = readdirSync(mockFolder2);
181
+ for (const file of files) {
182
+ const baseFile = basename(file, extname(file));
183
+ if (baseFile === baseOriginal2) {
184
+ const path2 = resolve(mockFolder2, file);
185
+ if (statSync(path2).isFile()) {
186
+ return path2;
187
+ } else {
188
+ const indexFile = findFile2(path2, "index");
189
+ if (indexFile) {
190
+ return indexFile;
191
+ }
192
+ }
193
+ }
194
+ }
195
+ return null;
196
+ };
197
+ const mockDirname = dirname(path);
198
+ const mockFolder = join(root, "__mocks__", mockDirname);
199
+ if (!existsSync(mockFolder)) {
200
+ return null;
201
+ }
202
+ const baseOriginal = basename(path);
203
+ return findFile2(mockFolder, baseOriginal);
204
+ }
205
+ const dir = dirname(path);
206
+ const baseId = basename(path);
207
+ const fullPath = resolve(dir, "__mocks__", baseId);
208
+ return existsSync(fullPath) ? fullPath : null;
209
+ }
210
+ const builtins = /* @__PURE__ */ new Set([
211
+ ...builtinModules,
212
+ "assert/strict",
213
+ "diagnostics_channel",
214
+ "dns/promises",
215
+ "fs/promises",
216
+ "path/posix",
217
+ "path/win32",
218
+ "readline/promises",
219
+ "stream/consumers",
220
+ "stream/promises",
221
+ "stream/web",
222
+ "timers/promises",
223
+ "util/types",
224
+ "wasi"
225
+ ]);
226
+ const prefixedBuiltins = /* @__PURE__ */ new Set(["node:test", "node:sqlite"]);
227
+ const NODE_BUILTIN_NAMESPACE = "node:";
228
+ function isNodeBuiltin(id) {
229
+ if (prefixedBuiltins.has(id)) {
230
+ return true;
231
+ }
232
+ return builtins.has(
233
+ id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(NODE_BUILTIN_NAMESPACE.length) : id
234
+ );
235
+ }
236
+
237
+ const spyModulePath = resolve$1(distDir, "spy.js");
33
238
  class VitestMocker {
34
239
  constructor(executor) {
35
240
  this.executor = executor;
@@ -70,18 +275,15 @@ class VitestMocker {
70
275
  }
71
276
  static pendingIds = [];
72
277
  spyModule;
73
- resolveCache = /* @__PURE__ */ new Map();
74
278
  primitives;
75
279
  filterPublicKeys;
280
+ registries = /* @__PURE__ */ new Map();
76
281
  mockContext = {
77
282
  callstack: null
78
283
  };
79
284
  get root() {
80
285
  return this.executor.options.root;
81
286
  }
82
- get mockMap() {
83
- return this.executor.options.mockMap;
84
- }
85
287
  get moduleCache() {
86
288
  return this.executor.moduleCache;
87
289
  }
@@ -91,6 +293,16 @@ class VitestMocker {
91
293
  async initializeSpyModule() {
92
294
  this.spyModule = await this.executor.executeId(spyModulePath);
93
295
  }
296
+ getMockerRegistry() {
297
+ const suite = this.getSuiteFilepath();
298
+ if (!this.registries.has(suite)) {
299
+ this.registries.set(suite, new MockerRegistry());
300
+ }
301
+ return this.registries.get(suite);
302
+ }
303
+ reset() {
304
+ this.registries.clear();
305
+ }
94
306
  deleteCachedItem(id) {
95
307
  const mockId = this.getMockPath(id);
96
308
  if (this.moduleCache.has(mockId)) {
@@ -109,15 +321,6 @@ class VitestMocker {
109
321
  Object.assign(error, { codeFrame });
110
322
  return error;
111
323
  }
112
- getMocks() {
113
- const suite = this.getSuiteFilepath();
114
- const suiteMocks = this.mockMap.get(suite);
115
- const globalMocks = this.mockMap.get("global");
116
- return {
117
- ...globalMocks,
118
- ...suiteMocks
119
- };
120
- }
121
324
  async resolvePath(rawId, importer) {
122
325
  let id;
123
326
  let fsPath;
@@ -132,7 +335,7 @@ class VitestMocker {
132
335
  throw error;
133
336
  }
134
337
  }
135
- const external = !isAbsolute(fsPath) || this.isModuleDirectory(fsPath) ? rawId : null;
338
+ const external = !isAbsolute$1(fsPath) || this.isModuleDirectory(fsPath) ? rawId : null;
136
339
  return {
137
340
  id,
138
341
  fsPath,
@@ -149,11 +352,17 @@ class VitestMocker {
149
352
  mock.id,
150
353
  mock.importer
151
354
  );
152
- if (mock.type === "unmock") {
355
+ if (mock.action === "unmock") {
153
356
  this.unmockPath(fsPath);
154
357
  }
155
- if (mock.type === "mock") {
156
- this.mockPath(mock.id, fsPath, external, mock.factory);
358
+ if (mock.action === "mock") {
359
+ this.mockPath(
360
+ mock.id,
361
+ fsPath,
362
+ external,
363
+ mock.type,
364
+ mock.factory
365
+ );
157
366
  }
158
367
  })
159
368
  );
@@ -164,23 +373,7 @@ class VitestMocker {
164
373
  if (cached) {
165
374
  return cached;
166
375
  }
167
- let exports;
168
- try {
169
- exports = await mock();
170
- } catch (err) {
171
- const vitestError = this.createError(
172
- '[vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock'
173
- );
174
- vitestError.cause = err;
175
- throw vitestError;
176
- }
177
- const filepath = dep.slice(5);
178
- const mockpath = this.resolveCache.get(this.getSuiteFilepath())?.[filepath] || filepath;
179
- if (exports === null || typeof exports !== "object") {
180
- throw this.createError(
181
- `[vitest] vi.mock("${mockpath}", factory?: () => unknown) is not returning an object. Did you mean to return an object with a "default" key?`
182
- );
183
- }
376
+ const exports = await mock.resolve();
184
377
  const moduleExports = new Proxy(exports, {
185
378
  get: (target, prop) => {
186
379
  const val = target[prop];
@@ -193,12 +386,10 @@ class VitestMocker {
193
386
  return void 0;
194
387
  }
195
388
  throw this.createError(
196
- `[vitest] No "${String(
197
- prop
198
- )}" export is defined on the "${mockpath}" mock. Did you forget to return it from "vi.mock"?
389
+ `[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"?
199
390
  If you need to partially mock a module, you can use "importOriginal" helper inside:
200
391
  `,
201
- highlight(`vi.mock("${mockpath}", async (importOriginal) => {
392
+ highlight(`vi.mock(import("${mock.raw}"), async (importOriginal) => {
202
393
  const actual = await importOriginal()
203
394
  return {
204
395
  ...actual,
@@ -213,172 +404,58 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
213
404
  this.moduleCache.set(dep, { exports: moduleExports });
214
405
  return moduleExports;
215
406
  }
407
+ // public method to avoid circular dependency
216
408
  getMockContext() {
217
409
  return this.mockContext;
218
410
  }
411
+ // path used to store mocked dependencies
219
412
  getMockPath(dep) {
220
413
  return `mock:${dep}`;
221
414
  }
222
415
  getDependencyMock(id) {
223
- return this.getMocks()[id];
416
+ const registry = this.getMockerRegistry();
417
+ return registry.get(id);
224
418
  }
225
419
  normalizePath(path) {
226
420
  return this.moduleCache.normalizePath(path);
227
421
  }
228
422
  resolveMockPath(mockPath, external) {
229
- const path = external || mockPath;
230
- if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
231
- let findFile2 = function(mockFolder2, baseOriginal2) {
232
- const files = readdirSync(mockFolder2);
233
- for (const file of files) {
234
- const baseFile = basename(file, extname(file));
235
- if (baseFile === baseOriginal2) {
236
- const path2 = resolve(mockFolder2, file);
237
- if (fs.statSync(path2).isFile()) {
238
- return path2;
239
- } else {
240
- const indexFile = findFile2(path2, "index");
241
- if (indexFile) {
242
- return indexFile;
243
- }
244
- }
245
- }
246
- }
247
- return null;
248
- };
249
- const mockDirname = dirname(path);
250
- const mockFolder = join(this.root, "__mocks__", mockDirname);
251
- if (!existsSync(mockFolder)) {
252
- return null;
253
- }
254
- const baseOriginal = basename(path);
255
- return findFile2(mockFolder, baseOriginal);
256
- }
257
- const dir = dirname(path);
258
- const baseId = basename(path);
259
- const fullPath = resolve(dir, "__mocks__", baseId);
260
- return existsSync(fullPath) ? fullPath : null;
261
- }
262
- mockObject(object, mockExports = {}) {
263
- const finalizers = new Array();
264
- const refs = new RefTracker();
265
- const define = (container, key, value) => {
266
- try {
267
- container[key] = value;
268
- return true;
269
- } catch {
270
- return false;
271
- }
272
- };
273
- const mockPropertiesOf = (container, newContainer) => {
274
- const containerType = getType(container);
275
- const isModule = containerType === "Module" || !!container.__esModule;
276
- for (const { key: property, descriptor } of getAllMockableProperties(
277
- container,
278
- isModule,
279
- this.primitives
280
- )) {
281
- if (!isModule && descriptor.get) {
282
- try {
283
- Object.defineProperty(newContainer, property, descriptor);
284
- } catch {
285
- }
286
- continue;
287
- }
288
- if (isSpecialProp(property, containerType)) {
289
- continue;
290
- }
291
- const value = container[property];
292
- const refId = refs.getId(value);
293
- if (refId !== void 0) {
294
- finalizers.push(
295
- () => define(newContainer, property, refs.getMockedValue(refId))
296
- );
297
- continue;
298
- }
299
- const type = getType(value);
300
- if (Array.isArray(value)) {
301
- define(newContainer, property, []);
302
- continue;
303
- }
304
- const isFunction = type.includes("Function") && typeof value === "function";
305
- if ((!isFunction || value.__isMockFunction) && type !== "Object" && type !== "Module") {
306
- define(newContainer, property, value);
307
- continue;
308
- }
309
- if (!define(newContainer, property, isFunction ? value : {})) {
310
- continue;
311
- }
312
- if (isFunction) {
313
- let mockFunction2 = function() {
314
- if (this instanceof newContainer[property]) {
315
- for (const { key, descriptor: descriptor2 } of getAllMockableProperties(
316
- this,
317
- false,
318
- primitives
319
- )) {
320
- if (descriptor2.get) {
321
- continue;
322
- }
323
- const value2 = this[key];
324
- const type2 = getType(value2);
325
- const isFunction2 = type2.includes("Function") && typeof value2 === "function";
326
- if (isFunction2) {
327
- const original = this[key];
328
- const mock2 = spyModule.spyOn(this, key).mockImplementation(original);
329
- mock2.mockRestore = () => {
330
- mock2.mockReset();
331
- mock2.mockImplementation(original);
332
- return mock2;
333
- };
334
- }
335
- }
336
- }
337
- };
338
- if (!this.spyModule) {
339
- throw this.createError(
340
- "[vitest] `spyModule` is not defined. This is Vitest error. Please open a new issue with reproduction."
341
- );
342
- }
343
- const spyModule = this.spyModule;
344
- const primitives = this.primitives;
345
- const mock = spyModule.spyOn(newContainer, property).mockImplementation(mockFunction2);
346
- mock.mockRestore = () => {
347
- mock.mockReset();
348
- mock.mockImplementation(mockFunction2);
349
- return mock;
350
- };
351
- Object.defineProperty(newContainer[property], "length", { value: 0 });
352
- }
353
- refs.track(value, newContainer[property]);
354
- mockPropertiesOf(value, newContainer[property]);
355
- }
356
- };
357
- const mockedObject = mockExports;
358
- mockPropertiesOf(object, mockedObject);
359
- for (const finalizer of finalizers) {
360
- finalizer();
423
+ return findMockRedirect(this.root, mockPath, external);
424
+ }
425
+ mockObject(object, mockExports = {}, behavior = "automock") {
426
+ const spyOn = this.spyModule?.spyOn;
427
+ if (!spyOn) {
428
+ throw this.createError(
429
+ "[vitest] `spyModule` is not defined. This is a Vitest error. Please open a new issue with reproduction."
430
+ );
361
431
  }
362
- return mockedObject;
432
+ return mockObject({
433
+ globalConstructors: this.primitives,
434
+ spyOn,
435
+ type: behavior
436
+ }, object, mockExports);
363
437
  }
364
438
  unmockPath(path) {
365
- const suitefile = this.getSuiteFilepath();
439
+ const registry = this.getMockerRegistry();
366
440
  const id = this.normalizePath(path);
367
- const mock = this.mockMap.get(suitefile);
368
- if (mock && id in mock) {
369
- delete mock[id];
370
- }
441
+ registry.delete(id);
371
442
  this.deleteCachedItem(id);
372
443
  }
373
- mockPath(originalId, path, external, factory) {
444
+ mockPath(originalId, path, external, mockType, factory) {
445
+ const registry = this.getMockerRegistry();
374
446
  const id = this.normalizePath(path);
375
- const suitefile = this.getSuiteFilepath();
376
- const mocks = this.mockMap.get(suitefile) || {};
377
- const resolves = this.resolveCache.get(suitefile) || {};
378
- mocks[id] = factory || this.resolveMockPath(id, external);
379
- resolves[id] = originalId;
380
- this.mockMap.set(suitefile, mocks);
381
- this.resolveCache.set(suitefile, resolves);
447
+ if (mockType === "manual") {
448
+ registry.register("manual", originalId, id, factory);
449
+ } else if (mockType === "autospy") {
450
+ registry.register("autospy", originalId, id);
451
+ } else {
452
+ const redirect = this.resolveMockPath(id, external);
453
+ if (redirect) {
454
+ registry.register("redirect", originalId, id, redirect);
455
+ } else {
456
+ registry.register("automock", originalId, id);
457
+ }
458
+ }
382
459
  this.deleteCachedItem(id);
383
460
  }
384
461
  async importActual(rawId, importer, callstack) {
@@ -394,23 +471,31 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
394
471
  const { id, fsPath, external } = await this.resolvePath(rawId, importee);
395
472
  const normalizedId = this.normalizePath(fsPath);
396
473
  let mock = this.getDependencyMock(normalizedId);
397
- if (mock === void 0) {
398
- mock = this.resolveMockPath(normalizedId, external);
474
+ if (!mock) {
475
+ const redirect = this.resolveMockPath(normalizedId, external);
476
+ if (redirect) {
477
+ mock = new RedirectedModule(rawId, normalizedId, redirect);
478
+ } else {
479
+ mock = new AutomockedModule(rawId, normalizedId);
480
+ }
399
481
  }
400
- if (mock === null) {
482
+ if (mock.type === "automock" || mock.type === "autospy") {
401
483
  const mod = await this.executor.cachedRequest(id, fsPath, [importee]);
402
- return this.mockObject(mod);
484
+ return this.mockObject(mod, {}, mock.type);
403
485
  }
404
- if (typeof mock === "function") {
486
+ if (mock.type === "manual") {
405
487
  return this.callFunctionMock(fsPath, mock);
406
488
  }
407
- return this.executor.dependencyRequest(mock, mock, [importee]);
489
+ return this.executor.dependencyRequest(mock.redirect, mock.redirect, [importee]);
408
490
  }
409
491
  async requestWithMock(url, callstack) {
410
492
  const id = this.normalizePath(url);
411
493
  const mock = this.getDependencyMock(id);
494
+ if (!mock) {
495
+ return;
496
+ }
412
497
  const mockPath = this.getMockPath(id);
413
- if (mock === null) {
498
+ if (mock.type === "automock" || mock.type === "autospy") {
414
499
  const cache = this.moduleCache.get(mockPath);
415
500
  if (cache.exports) {
416
501
  return cache.exports;
@@ -418,10 +503,10 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
418
503
  const exports = {};
419
504
  this.moduleCache.set(mockPath, { exports });
420
505
  const mod = await this.executor.directRequest(url, url, callstack);
421
- this.mockObject(mod, exports);
506
+ this.mockObject(mod, exports, mock.type);
422
507
  return exports;
423
508
  }
424
- if (typeof mock === "function" && !callstack.includes(mockPath) && !callstack.includes(url)) {
509
+ if (mock.type === "manual" && !callstack.includes(mockPath) && !callstack.includes(url)) {
425
510
  try {
426
511
  callstack.push(mockPath);
427
512
  this.mockContext.callstack = callstack;
@@ -431,29 +516,37 @@ If you need to partially mock a module, you can use "importOriginal" helper insi
431
516
  const indexMock = callstack.indexOf(mockPath);
432
517
  callstack.splice(indexMock, 1);
433
518
  }
434
- }
435
- if (typeof mock === "string" && !callstack.includes(mock)) {
436
- return mock;
519
+ } else if (mock.type === "redirect" && !callstack.includes(mock.redirect)) {
520
+ return mock.redirect;
437
521
  }
438
522
  }
439
- queueMock(id, importer, factory, throwIfCached = false) {
523
+ queueMock(id, importer, factoryOrOptions) {
524
+ const mockType = getMockType(factoryOrOptions);
440
525
  VitestMocker.pendingIds.push({
441
- type: "mock",
526
+ action: "mock",
442
527
  id,
443
528
  importer,
444
- factory,
445
- throwIfCached
529
+ factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0,
530
+ type: mockType
446
531
  });
447
532
  }
448
- queueUnmock(id, importer, throwIfCached = false) {
533
+ queueUnmock(id, importer) {
449
534
  VitestMocker.pendingIds.push({
450
- type: "unmock",
535
+ action: "unmock",
451
536
  id,
452
- importer,
453
- throwIfCached
537
+ importer
454
538
  });
455
539
  }
456
540
  }
541
+ function getMockType(factoryOrOptions) {
542
+ if (!factoryOrOptions) {
543
+ return "automock";
544
+ }
545
+ if (typeof factoryOrOptions === "function") {
546
+ return "manual";
547
+ }
548
+ return factoryOrOptions.spy ? "autospy" : "automock";
549
+ }
457
550
 
458
551
  const { readFileSync } = fs;
459
552
  async function createVitestExecutor(options) {
@@ -536,9 +629,6 @@ async function startVitestExecutor(options) {
536
629
  get moduleCache() {
537
630
  return state().moduleCache;
538
631
  },
539
- get mockMap() {
540
- return state().mockMap;
541
- },
542
632
  get interopDefault() {
543
633
  return state().config.deps.interopDefault;
544
634
  },
@@ -642,7 +732,7 @@ class VitestExecutor extends ViteNodeRunner {
642
732
  return false;
643
733
  }
644
734
  const transformMode = this.state.environment?.transformMode ?? "ssr";
645
- return transformMode === "ssr" ? !isNodeBuiltin(id) : !id.startsWith("node:");
735
+ return transformMode === "ssr" ? !isNodeBuiltin$1(id) : !id.startsWith("node:");
646
736
  }
647
737
  async originalResolveUrl(id, importer) {
648
738
  return super.resolveUrl(id, importer);
@@ -707,7 +797,7 @@ class VitestExecutor extends ViteNodeRunner {
707
797
  return super.dependencyRequest(id, fsPath, callstack);
708
798
  }
709
799
  prepareContext(context) {
710
- if (this.state.filepath && normalize(this.state.filepath) === normalize(context.__filename)) {
800
+ if (this.state.filepath && normalize$1(this.state.filepath) === normalize$1(context.__filename)) {
711
801
  const globalNamespace = this.options.context || globalThis;
712
802
  Object.defineProperty(context.__vite_ssr_import_meta__, "vitest", {
713
803
  // @ts-expect-error injected untyped global