@depup/vitest__mocker 4.1.0-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +25 -0
- package/changes.json +5 -0
- package/dist/auto-register.d.ts +2 -0
- package/dist/auto-register.js +10 -0
- package/dist/automock.d.ts +13 -0
- package/dist/automock.js +8 -0
- package/dist/browser.d.ts +53 -0
- package/dist/browser.js +92 -0
- package/dist/chunk-automock.js +522 -0
- package/dist/chunk-helpers.js +44 -0
- package/dist/chunk-hoistMocks.js +659 -0
- package/dist/chunk-interceptor-native.js +15 -0
- package/dist/chunk-mocker.js +532 -0
- package/dist/chunk-pathe.M-eThtNZ.js +174 -0
- package/dist/chunk-registry.js +199 -0
- package/dist/chunk-utils.js +27 -0
- package/dist/hoistMocks.d-w2ILr1dG.d.ts +739 -0
- package/dist/index.d-B41z0AuW.d.ts +25 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +200 -0
- package/dist/mocker.d-QEntlm6J.d.ts +86 -0
- package/dist/node.d.ts +71 -0
- package/dist/node.js +409 -0
- package/dist/redirect.d.ts +3 -0
- package/dist/redirect.js +79 -0
- package/dist/register.d.ts +9 -0
- package/dist/register.js +42 -0
- package/dist/transforms.d.ts +8 -0
- package/dist/transforms.js +10 -0
- package/dist/types.d-BjI5eAwu.d.ts +123 -0
- package/package.json +111 -0
package/dist/node.js
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { a as cleanUrl, c as createManualModuleSource } from './chunk-utils.js';
|
|
2
|
+
import { a as automockModule, e as esmWalker } from './chunk-automock.js';
|
|
3
|
+
import MagicString from 'magic-string';
|
|
4
|
+
import { createFilter } from 'vite';
|
|
5
|
+
import { h as hoistMocks } from './chunk-hoistMocks.js';
|
|
6
|
+
import { readFile } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path/posix';
|
|
8
|
+
import { M as MockerRegistry, a as ManualMockedModule } from './chunk-registry.js';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { findMockRedirect } from './redirect.js';
|
|
12
|
+
import { i as isAbsolute, j as join$1, r as resolve } from './chunk-pathe.M-eThtNZ.js';
|
|
13
|
+
import 'estree-walker';
|
|
14
|
+
import 'node:module';
|
|
15
|
+
import 'node:path';
|
|
16
|
+
import './chunk-helpers.js';
|
|
17
|
+
|
|
18
|
+
function automockPlugin(options = {}) {
|
|
19
|
+
return {
|
|
20
|
+
name: "vitest:automock",
|
|
21
|
+
enforce: "post",
|
|
22
|
+
transform(code, id) {
|
|
23
|
+
if (id.includes("mock=automock") || id.includes("mock=autospy")) {
|
|
24
|
+
const mockType = id.includes("mock=automock") ? "automock" : "autospy";
|
|
25
|
+
const ms = automockModule(code, mockType, this.parse, options);
|
|
26
|
+
return {
|
|
27
|
+
code: ms.toString(),
|
|
28
|
+
map: ms.generateMap({
|
|
29
|
+
hires: "boundary",
|
|
30
|
+
source: cleanUrl(id)
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const regexDynamicImport = /import\s*\(/;
|
|
39
|
+
function dynamicImportPlugin(options = {}) {
|
|
40
|
+
return {
|
|
41
|
+
name: "vitest:browser:esm-injector",
|
|
42
|
+
enforce: "post",
|
|
43
|
+
transform(source, id) {
|
|
44
|
+
// TODO: test is not called for static imports
|
|
45
|
+
if (!regexDynamicImport.test(source)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (options.filter && !options.filter(id)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
return injectDynamicImport(source, id, this.parse, options);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function injectDynamicImport(code, id, parse, options = {}) {
|
|
56
|
+
if (code.includes("wrapDynamicImport")) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const s = new MagicString(code);
|
|
60
|
+
let ast;
|
|
61
|
+
try {
|
|
62
|
+
ast = parse(code);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(`Cannot parse ${id}:\n${err.message}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// 3. convert references to import bindings & import.meta references
|
|
68
|
+
esmWalker(ast, {
|
|
69
|
+
onImportMeta() {
|
|
70
|
+
// s.update(node.start, node.end, viImportMetaKey)
|
|
71
|
+
},
|
|
72
|
+
onDynamicImport(node) {
|
|
73
|
+
const globalThisAccessor = options.globalThisAccessor || "\"__vitest_mocker__\"";
|
|
74
|
+
const replaceString = `globalThis[${globalThisAccessor}].wrapDynamicImport(() => import(`;
|
|
75
|
+
const importSubstring = code.substring(node.start, node.end);
|
|
76
|
+
const hasIgnore = importSubstring.includes("/* @vite-ignore */");
|
|
77
|
+
s.overwrite(node.start, node.source.start, replaceString + (hasIgnore ? "/* @vite-ignore */ " : ""));
|
|
78
|
+
s.overwrite(node.end - 1, node.end, "))");
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
code: s.toString(),
|
|
83
|
+
map: s.generateMap({
|
|
84
|
+
hires: "boundary",
|
|
85
|
+
source: id
|
|
86
|
+
})
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function hoistMocksPlugin(options = {}) {
|
|
91
|
+
const filter = options.filter || createFilter(options.include, options.exclude);
|
|
92
|
+
const { hoistableMockMethodNames = ["mock", "unmock"], dynamicImportMockMethodNames = [
|
|
93
|
+
"mock",
|
|
94
|
+
"unmock",
|
|
95
|
+
"doMock",
|
|
96
|
+
"doUnmock"
|
|
97
|
+
], hoistedMethodNames = ["hoisted"], utilsObjectNames = ["vi", "vitest"] } = options;
|
|
98
|
+
const methods = new Set([
|
|
99
|
+
...hoistableMockMethodNames,
|
|
100
|
+
...hoistedMethodNames,
|
|
101
|
+
...dynamicImportMockMethodNames
|
|
102
|
+
]);
|
|
103
|
+
const regexpHoistable = new RegExp(`\\b(?:${utilsObjectNames.join("|")})\\s*\.\\s*(?:${Array.from(methods).join("|")})\\s*\\(`);
|
|
104
|
+
return {
|
|
105
|
+
name: "vitest:mocks",
|
|
106
|
+
enforce: "post",
|
|
107
|
+
transform(code, id) {
|
|
108
|
+
if (!filter(id)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const s = hoistMocks(code, id, this.parse, {
|
|
112
|
+
regexpHoistable,
|
|
113
|
+
hoistableMockMethodNames,
|
|
114
|
+
hoistedMethodNames,
|
|
115
|
+
utilsObjectNames,
|
|
116
|
+
dynamicImportMockMethodNames,
|
|
117
|
+
...options
|
|
118
|
+
});
|
|
119
|
+
if (s) {
|
|
120
|
+
return {
|
|
121
|
+
code: s.toString(),
|
|
122
|
+
map: s.generateMap({
|
|
123
|
+
hires: "boundary",
|
|
124
|
+
source: cleanUrl(id)
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// to keeb backwards compat
|
|
132
|
+
function hoistMockAndResolve(code, id, parse, options = {}) {
|
|
133
|
+
const s = hoistMocks(code, id, parse, options);
|
|
134
|
+
if (s) {
|
|
135
|
+
return {
|
|
136
|
+
code: s.toString(),
|
|
137
|
+
map: s.generateMap({
|
|
138
|
+
hires: "boundary",
|
|
139
|
+
source: cleanUrl(id)
|
|
140
|
+
})
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function interceptorPlugin(options = {}) {
|
|
146
|
+
const registry = options.registry || new MockerRegistry();
|
|
147
|
+
return {
|
|
148
|
+
name: "vitest:mocks:interceptor",
|
|
149
|
+
enforce: "pre",
|
|
150
|
+
load: {
|
|
151
|
+
order: "pre",
|
|
152
|
+
async handler(id) {
|
|
153
|
+
const mock = registry.getById(id);
|
|
154
|
+
if (!mock) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (mock.type === "manual") {
|
|
158
|
+
const exports$1 = Object.keys(await mock.resolve());
|
|
159
|
+
const accessor = options.globalThisAccessor || "\"__vitest_mocker__\"";
|
|
160
|
+
return createManualModuleSource(mock.url, exports$1, accessor);
|
|
161
|
+
}
|
|
162
|
+
if (mock.type === "redirect") {
|
|
163
|
+
return readFile(mock.redirect, "utf-8");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
transform: {
|
|
168
|
+
order: "post",
|
|
169
|
+
handler(code, id) {
|
|
170
|
+
const mock = registry.getById(id);
|
|
171
|
+
if (!mock) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (mock.type === "automock" || mock.type === "autospy") {
|
|
175
|
+
const m = automockModule(code, mock.type, this.parse, { globalThisAccessor: options.globalThisAccessor });
|
|
176
|
+
return {
|
|
177
|
+
code: m.toString(),
|
|
178
|
+
map: m.generateMap({
|
|
179
|
+
hires: "boundary",
|
|
180
|
+
source: cleanUrl(id)
|
|
181
|
+
})
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
configureServer(server) {
|
|
187
|
+
server.ws.on("vitest:interceptor:register", (event) => {
|
|
188
|
+
if (event.type === "manual") {
|
|
189
|
+
const module = ManualMockedModule.fromJSON(event, async () => {
|
|
190
|
+
const keys = await getFactoryExports(event.url);
|
|
191
|
+
return Object.fromEntries(keys.map((key) => [key, null]));
|
|
192
|
+
});
|
|
193
|
+
registry.add(module);
|
|
194
|
+
} else {
|
|
195
|
+
if (event.type === "redirect") {
|
|
196
|
+
const redirectUrl = new URL(event.redirect);
|
|
197
|
+
event.redirect = join(server.config.root, redirectUrl.pathname);
|
|
198
|
+
}
|
|
199
|
+
registry.register(event);
|
|
200
|
+
}
|
|
201
|
+
server.ws.send("vitest:interceptor:register:result");
|
|
202
|
+
});
|
|
203
|
+
server.ws.on("vitest:interceptor:delete", (id) => {
|
|
204
|
+
registry.delete(id);
|
|
205
|
+
server.ws.send("vitest:interceptor:delete:result");
|
|
206
|
+
});
|
|
207
|
+
server.ws.on("vitest:interceptor:invalidate", () => {
|
|
208
|
+
registry.clear();
|
|
209
|
+
server.ws.send("vitest:interceptor:invalidate:result");
|
|
210
|
+
});
|
|
211
|
+
function getFactoryExports(url) {
|
|
212
|
+
server.ws.send("vitest:interceptor:resolve", url);
|
|
213
|
+
let timeout;
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
timeout = setTimeout(() => {
|
|
216
|
+
reject(new Error(`Timeout while waiting for factory exports of ${url}`));
|
|
217
|
+
}, 1e4);
|
|
218
|
+
server.ws.on("vitest:interceptor:resolved", ({ url: resolvedUrl, keys }) => {
|
|
219
|
+
if (resolvedUrl === url) {
|
|
220
|
+
clearTimeout(timeout);
|
|
221
|
+
resolve(keys);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const VALID_ID_PREFIX = "/@id/";
|
|
231
|
+
class ServerMockResolver {
|
|
232
|
+
constructor(server, options = {}) {
|
|
233
|
+
this.server = server;
|
|
234
|
+
this.options = options;
|
|
235
|
+
}
|
|
236
|
+
async resolveMock(rawId, importer, options) {
|
|
237
|
+
const { id, fsPath, external } = await this.resolveMockId(rawId, importer);
|
|
238
|
+
const resolvedUrl = this.normalizeResolveIdToUrl({ id }).url;
|
|
239
|
+
if (options.mock === "factory") {
|
|
240
|
+
const manifest = getViteDepsManifest(this.server.config);
|
|
241
|
+
const needsInterop = manifest?.[fsPath]?.needsInterop ?? false;
|
|
242
|
+
return {
|
|
243
|
+
mockType: "manual",
|
|
244
|
+
resolvedId: id,
|
|
245
|
+
resolvedUrl,
|
|
246
|
+
needsInterop
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
if (options.mock === "spy") {
|
|
250
|
+
return {
|
|
251
|
+
mockType: "autospy",
|
|
252
|
+
resolvedId: id,
|
|
253
|
+
resolvedUrl
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
const redirectUrl = findMockRedirect(this.server.config.root, fsPath, external);
|
|
257
|
+
return {
|
|
258
|
+
mockType: redirectUrl === null ? "automock" : "redirect",
|
|
259
|
+
redirectUrl,
|
|
260
|
+
resolvedId: id,
|
|
261
|
+
resolvedUrl
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
invalidate(ids) {
|
|
265
|
+
ids.forEach((id) => {
|
|
266
|
+
const moduleGraph = this.server.moduleGraph;
|
|
267
|
+
const module = moduleGraph.getModuleById(id);
|
|
268
|
+
if (module) {
|
|
269
|
+
module.transformResult = null;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
async resolveId(id, importer) {
|
|
274
|
+
const resolved = await this.server.pluginContainer.resolveId(id, importer, { ssr: false });
|
|
275
|
+
if (!resolved) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return this.normalizeResolveIdToUrl(resolved);
|
|
279
|
+
}
|
|
280
|
+
normalizeResolveIdToUrl(resolved) {
|
|
281
|
+
const isOptimized = resolved.id.startsWith(withTrailingSlash(this.server.config.cacheDir));
|
|
282
|
+
let url;
|
|
283
|
+
// normalise the URL to be acceptable by the browser
|
|
284
|
+
// https://github.com/vitejs/vite/blob/14027b0f2a9b01c14815c38aab22baf5b29594bb/packages/vite/src/node/plugins/importAnalysis.ts#L103
|
|
285
|
+
const root = this.server.config.root;
|
|
286
|
+
if (resolved.id.startsWith(withTrailingSlash(root))) {
|
|
287
|
+
url = resolved.id.slice(root.length);
|
|
288
|
+
} else if (resolved.id !== "/@react-refresh" && isAbsolute(resolved.id) && existsSync(cleanUrl(resolved.id))) {
|
|
289
|
+
url = join$1("/@fs/", resolved.id);
|
|
290
|
+
} else {
|
|
291
|
+
url = resolved.id;
|
|
292
|
+
}
|
|
293
|
+
if (url[0] !== "." && url[0] !== "/") {
|
|
294
|
+
url = resolved.id.startsWith(VALID_ID_PREFIX) ? resolved.id : VALID_ID_PREFIX + resolved.id.replace("\0", "__x00__");
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
id: resolved.id,
|
|
298
|
+
url,
|
|
299
|
+
optimized: isOptimized
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
async resolveMockId(rawId, importer) {
|
|
303
|
+
if (!this.server.moduleGraph.getModuleById(importer) && !importer.startsWith(this.server.config.root)) {
|
|
304
|
+
importer = join$1(this.server.config.root, importer);
|
|
305
|
+
}
|
|
306
|
+
const resolved = await this.server.pluginContainer.resolveId(rawId, importer, { ssr: false });
|
|
307
|
+
return this.resolveModule(rawId, resolved);
|
|
308
|
+
}
|
|
309
|
+
resolveModule(rawId, resolved) {
|
|
310
|
+
const id = resolved?.id || rawId;
|
|
311
|
+
const external = !isAbsolute(id) || isModuleDirectory(this.options, id) ? rawId : null;
|
|
312
|
+
return {
|
|
313
|
+
id,
|
|
314
|
+
fsPath: cleanUrl(id),
|
|
315
|
+
external
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function isModuleDirectory(config, path) {
|
|
320
|
+
const moduleDirectories = config.moduleDirectories || ["/node_modules/"];
|
|
321
|
+
return moduleDirectories.some((dir) => path.includes(dir));
|
|
322
|
+
}
|
|
323
|
+
const metadata = new WeakMap();
|
|
324
|
+
function getViteDepsManifest(config) {
|
|
325
|
+
if (metadata.has(config)) {
|
|
326
|
+
return metadata.get(config);
|
|
327
|
+
}
|
|
328
|
+
const cacheDirPath = getDepsCacheDir(config);
|
|
329
|
+
const metadataPath = resolve(cacheDirPath, "_metadata.json");
|
|
330
|
+
if (!existsSync(metadataPath)) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
const { optimized } = JSON.parse(readFileSync(metadataPath, "utf-8"));
|
|
334
|
+
const newManifest = {};
|
|
335
|
+
for (const name in optimized) {
|
|
336
|
+
const dep = optimized[name];
|
|
337
|
+
const file = resolve(cacheDirPath, dep.file);
|
|
338
|
+
newManifest[file] = {
|
|
339
|
+
hash: dep.fileHash,
|
|
340
|
+
needsInterop: dep.needsInterop
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
metadata.set(config, newManifest);
|
|
344
|
+
return newManifest;
|
|
345
|
+
}
|
|
346
|
+
function getDepsCacheDir(config) {
|
|
347
|
+
return resolve(config.cacheDir, "deps");
|
|
348
|
+
}
|
|
349
|
+
function withTrailingSlash(path) {
|
|
350
|
+
if (path.at(-1) !== "/") {
|
|
351
|
+
return `${path}/`;
|
|
352
|
+
}
|
|
353
|
+
return path;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// this is an implementation for public usage
|
|
357
|
+
// vitest doesn't use this plugin directly
|
|
358
|
+
function mockerPlugin(options = {}) {
|
|
359
|
+
let server;
|
|
360
|
+
const registerPath = resolve(fileURLToPath(new URL("./register.js", import.meta.url)));
|
|
361
|
+
return [
|
|
362
|
+
{
|
|
363
|
+
name: "vitest:mocker:ws-rpc",
|
|
364
|
+
config(_, { command }) {
|
|
365
|
+
if (command !== "serve") {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
server: { preTransformRequests: false },
|
|
370
|
+
optimizeDeps: { exclude: ["@vitest/mocker/register", "@vitest/mocker/browser"] }
|
|
371
|
+
};
|
|
372
|
+
},
|
|
373
|
+
configureServer(server_) {
|
|
374
|
+
server = server_;
|
|
375
|
+
const mockResolver = new ServerMockResolver(server);
|
|
376
|
+
server.ws.on("vitest:mocks:resolveId", async ({ id, importer }) => {
|
|
377
|
+
const resolved = await mockResolver.resolveId(id, importer);
|
|
378
|
+
server.ws.send("vitest:mocks:resolvedId:result", resolved);
|
|
379
|
+
});
|
|
380
|
+
server.ws.on("vitest:mocks:resolveMock", async ({ id, importer, options }) => {
|
|
381
|
+
const resolved = await mockResolver.resolveMock(id, importer, options);
|
|
382
|
+
server.ws.send("vitest:mocks:resolveMock:result", resolved);
|
|
383
|
+
});
|
|
384
|
+
server.ws.on("vitest:mocks:invalidate", async ({ ids }) => {
|
|
385
|
+
mockResolver.invalidate(ids);
|
|
386
|
+
server.ws.send("vitest:mocks:invalidate:result");
|
|
387
|
+
});
|
|
388
|
+
},
|
|
389
|
+
async load(id) {
|
|
390
|
+
if (id !== registerPath) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (!server) {
|
|
394
|
+
// mocker doesn't work during build
|
|
395
|
+
return "export {}";
|
|
396
|
+
}
|
|
397
|
+
const content = await readFile(registerPath, "utf-8");
|
|
398
|
+
const result = content.replace(/__VITEST_GLOBAL_THIS_ACCESSOR__/g, options.globalThisAccessor ?? "\"__vitest_mocker__\"").replace("__VITEST_MOCKER_ROOT__", JSON.stringify(server.config.root));
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
hoistMocksPlugin(options.hoistMocks),
|
|
403
|
+
interceptorPlugin(options),
|
|
404
|
+
automockPlugin(options),
|
|
405
|
+
dynamicImportPlugin(options)
|
|
406
|
+
];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export { ServerMockResolver, automockModule, automockPlugin, createManualModuleSource, dynamicImportPlugin, findMockRedirect, hoistMockAndResolve as hoistMocks, hoistMocksPlugin, interceptorPlugin, mockerPlugin };
|
package/dist/redirect.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import module$1 from 'node:module';
|
|
3
|
+
import { d as dirname, j as join, b as basename, r as resolve, e as extname } from './chunk-pathe.M-eThtNZ.js';
|
|
4
|
+
|
|
5
|
+
const { existsSync, readdirSync, statSync } = fs;
|
|
6
|
+
function findMockRedirect(root, mockPath, external) {
|
|
7
|
+
const path = external || mockPath;
|
|
8
|
+
// it's a node_module alias
|
|
9
|
+
// all mocks should be inside <root>/__mocks__
|
|
10
|
+
if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
|
|
11
|
+
const mockDirname = dirname(path);
|
|
12
|
+
const mockFolder = join(root, "__mocks__", mockDirname);
|
|
13
|
+
if (!existsSync(mockFolder)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const baseOriginal = basename(path);
|
|
17
|
+
function findFile(mockFolder, baseOriginal) {
|
|
18
|
+
const files = readdirSync(mockFolder);
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
const baseFile = basename(file, extname(file));
|
|
21
|
+
if (baseFile === baseOriginal) {
|
|
22
|
+
const path = resolve(mockFolder, file);
|
|
23
|
+
// if the same name, return the file
|
|
24
|
+
if (statSync(path).isFile()) {
|
|
25
|
+
return path;
|
|
26
|
+
} else {
|
|
27
|
+
// find folder/index.{js,ts}
|
|
28
|
+
const indexFile = findFile(path, "index");
|
|
29
|
+
if (indexFile) {
|
|
30
|
+
return indexFile;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return findFile(mockFolder, baseOriginal);
|
|
38
|
+
}
|
|
39
|
+
const dir = dirname(path);
|
|
40
|
+
const baseId = basename(path);
|
|
41
|
+
const fullPath = resolve(dir, "__mocks__", baseId);
|
|
42
|
+
return existsSync(fullPath) ? fullPath : null;
|
|
43
|
+
}
|
|
44
|
+
const builtins = new Set([
|
|
45
|
+
...module$1.builtinModules,
|
|
46
|
+
"assert/strict",
|
|
47
|
+
"diagnostics_channel",
|
|
48
|
+
"dns/promises",
|
|
49
|
+
"fs/promises",
|
|
50
|
+
"path/posix",
|
|
51
|
+
"path/win32",
|
|
52
|
+
"readline/promises",
|
|
53
|
+
"stream/consumers",
|
|
54
|
+
"stream/promises",
|
|
55
|
+
"stream/web",
|
|
56
|
+
"timers/promises",
|
|
57
|
+
"util/types",
|
|
58
|
+
"wasi"
|
|
59
|
+
]);
|
|
60
|
+
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
|
|
61
|
+
const prefixedBuiltins = new Set([
|
|
62
|
+
"node:sea",
|
|
63
|
+
"node:sqlite",
|
|
64
|
+
"node:test",
|
|
65
|
+
"node:test/reporters"
|
|
66
|
+
]);
|
|
67
|
+
const NODE_BUILTIN_NAMESPACE = "node:";
|
|
68
|
+
function isNodeBuiltin(id) {
|
|
69
|
+
// Added in v18.6.0
|
|
70
|
+
if (module$1.isBuiltin) {
|
|
71
|
+
return module$1.isBuiltin(id);
|
|
72
|
+
}
|
|
73
|
+
if (prefixedBuiltins.has(id)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return builtins.has(id.startsWith(NODE_BUILTIN_NAMESPACE) ? id.slice(NODE_BUILTIN_NAMESPACE.length) : id);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { findMockRedirect };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { M as ModuleMockerInterceptor, a as ModuleMockerCompilerHints, b as ModuleMocker } from './mocker.d-QEntlm6J.js';
|
|
2
|
+
import '@vitest/spy';
|
|
3
|
+
import './types.d-BjI5eAwu.js';
|
|
4
|
+
import './index.d-B41z0AuW.js';
|
|
5
|
+
|
|
6
|
+
declare function registerModuleMocker(interceptor: (accessor: string) => ModuleMockerInterceptor): ModuleMockerCompilerHints;
|
|
7
|
+
declare function registerNativeFactoryResolver(mocker: ModuleMocker): void;
|
|
8
|
+
|
|
9
|
+
export { registerModuleMocker, registerNativeFactoryResolver };
|
package/dist/register.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createMockInstance } from '@vitest/spy';
|
|
2
|
+
import { M as ModuleMocker, r as rpc, c as createCompilerHints, h as hot } from './chunk-mocker.js';
|
|
3
|
+
import './chunk-helpers.js';
|
|
4
|
+
import './index.js';
|
|
5
|
+
import './chunk-registry.js';
|
|
6
|
+
import './chunk-pathe.M-eThtNZ.js';
|
|
7
|
+
|
|
8
|
+
function registerModuleMocker(interceptor) {
|
|
9
|
+
const mocker = new ModuleMocker(interceptor(__VITEST_GLOBAL_THIS_ACCESSOR__), {
|
|
10
|
+
resolveId(id, importer) {
|
|
11
|
+
return rpc("vitest:mocks:resolveId", {
|
|
12
|
+
id,
|
|
13
|
+
importer
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
resolveMock(id, importer, options) {
|
|
17
|
+
return rpc("vitest:mocks:resolveMock", {
|
|
18
|
+
id,
|
|
19
|
+
importer,
|
|
20
|
+
options
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
async invalidate(ids) {
|
|
24
|
+
return rpc("vitest:mocks:invalidate", { ids });
|
|
25
|
+
}
|
|
26
|
+
}, createMockInstance, { root: __VITEST_MOCKER_ROOT__ });
|
|
27
|
+
globalThis[__VITEST_GLOBAL_THIS_ACCESSOR__] = mocker;
|
|
28
|
+
registerNativeFactoryResolver(mocker);
|
|
29
|
+
return createCompilerHints({ globalThisKey: __VITEST_GLOBAL_THIS_ACCESSOR__ });
|
|
30
|
+
}
|
|
31
|
+
function registerNativeFactoryResolver(mocker) {
|
|
32
|
+
hot.on("vitest:interceptor:resolve", async (url) => {
|
|
33
|
+
const exports$1 = await mocker.resolveFactoryModule(url);
|
|
34
|
+
const keys = Object.keys(exports$1);
|
|
35
|
+
hot.send("vitest:interceptor:resolved", {
|
|
36
|
+
url,
|
|
37
|
+
keys
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { registerModuleMocker, registerNativeFactoryResolver };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { c as createManualModuleSource, h as hoistMocks } from './hoistMocks.d-w2ILr1dG.js';
|
|
2
|
+
export { automockModule } from './automock.js';
|
|
3
|
+
import 'magic-string';
|
|
4
|
+
|
|
5
|
+
declare function initSyntaxLexers(): Promise<void>;
|
|
6
|
+
declare function collectModuleExports(filename: string, code: string, format: "module" | "commonjs", exports?: string[]): string[];
|
|
7
|
+
|
|
8
|
+
export { collectModuleExports, initSyntaxLexers };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { c as createManualModuleSource } from './chunk-utils.js';
|
|
2
|
+
export { a as automockModule, c as collectModuleExports, i as initSyntaxLexers } from './chunk-automock.js';
|
|
3
|
+
export { h as hoistMocks } from './chunk-hoistMocks.js';
|
|
4
|
+
import 'node:fs';
|
|
5
|
+
import 'node:url';
|
|
6
|
+
import 'magic-string';
|
|
7
|
+
import 'estree-walker';
|
|
8
|
+
import 'node:module';
|
|
9
|
+
import 'node:path';
|
|
10
|
+
import './chunk-helpers.js';
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
declare class MockerRegistry {
|
|
2
|
+
private readonly registryByUrl;
|
|
3
|
+
private readonly registryById;
|
|
4
|
+
clear(): void;
|
|
5
|
+
keys(): IterableIterator<string>;
|
|
6
|
+
add(mock: MockedModule): void;
|
|
7
|
+
register(json: MockedModuleSerialized): MockedModule;
|
|
8
|
+
register(type: "redirect", raw: string, id: string, url: string, redirect: string): RedirectedModule;
|
|
9
|
+
register(type: "manual", raw: string, id: string, url: string, factory: () => any): ManualMockedModule;
|
|
10
|
+
register(type: "automock", raw: string, id: string, url: string): AutomockedModule;
|
|
11
|
+
register(type: "autospy", id: string, raw: string, url: string): AutospiedModule;
|
|
12
|
+
delete(id: string): void;
|
|
13
|
+
deleteById(id: string): void;
|
|
14
|
+
get(id: string): MockedModule | undefined;
|
|
15
|
+
getById(id: string): MockedModule | undefined;
|
|
16
|
+
has(id: string): boolean;
|
|
17
|
+
}
|
|
18
|
+
type MockedModule = AutomockedModule | AutospiedModule | ManualMockedModule | RedirectedModule;
|
|
19
|
+
type MockedModuleType = "automock" | "autospy" | "manual" | "redirect";
|
|
20
|
+
type MockedModuleSerialized = AutomockedModuleSerialized | AutospiedModuleSerialized | ManualMockedModuleSerialized | RedirectedModuleSerialized;
|
|
21
|
+
declare class AutomockedModule {
|
|
22
|
+
raw: string;
|
|
23
|
+
id: string;
|
|
24
|
+
url: string;
|
|
25
|
+
readonly type = "automock";
|
|
26
|
+
constructor(raw: string, id: string, url: string);
|
|
27
|
+
static fromJSON(data: AutomockedModuleSerialized): AutospiedModule;
|
|
28
|
+
toJSON(): AutomockedModuleSerialized;
|
|
29
|
+
}
|
|
30
|
+
interface AutomockedModuleSerialized {
|
|
31
|
+
type: "automock";
|
|
32
|
+
url: string;
|
|
33
|
+
raw: string;
|
|
34
|
+
id: string;
|
|
35
|
+
}
|
|
36
|
+
declare class AutospiedModule {
|
|
37
|
+
raw: string;
|
|
38
|
+
id: string;
|
|
39
|
+
url: string;
|
|
40
|
+
readonly type = "autospy";
|
|
41
|
+
constructor(raw: string, id: string, url: string);
|
|
42
|
+
static fromJSON(data: AutospiedModuleSerialized): AutospiedModule;
|
|
43
|
+
toJSON(): AutospiedModuleSerialized;
|
|
44
|
+
}
|
|
45
|
+
interface AutospiedModuleSerialized {
|
|
46
|
+
type: "autospy";
|
|
47
|
+
url: string;
|
|
48
|
+
raw: string;
|
|
49
|
+
id: string;
|
|
50
|
+
}
|
|
51
|
+
declare class RedirectedModule {
|
|
52
|
+
raw: string;
|
|
53
|
+
id: string;
|
|
54
|
+
url: string;
|
|
55
|
+
redirect: string;
|
|
56
|
+
readonly type = "redirect";
|
|
57
|
+
constructor(raw: string, id: string, url: string, redirect: string);
|
|
58
|
+
static fromJSON(data: RedirectedModuleSerialized): RedirectedModule;
|
|
59
|
+
toJSON(): RedirectedModuleSerialized;
|
|
60
|
+
}
|
|
61
|
+
interface RedirectedModuleSerialized {
|
|
62
|
+
type: "redirect";
|
|
63
|
+
url: string;
|
|
64
|
+
id: string;
|
|
65
|
+
raw: string;
|
|
66
|
+
redirect: string;
|
|
67
|
+
}
|
|
68
|
+
declare class ManualMockedModule<T = any> {
|
|
69
|
+
raw: string;
|
|
70
|
+
id: string;
|
|
71
|
+
url: string;
|
|
72
|
+
factory: () => T;
|
|
73
|
+
cache: T | undefined;
|
|
74
|
+
readonly type = "manual";
|
|
75
|
+
constructor(raw: string, id: string, url: string, factory: () => T);
|
|
76
|
+
resolve(): T;
|
|
77
|
+
static fromJSON(data: ManualMockedModuleSerialized, factory: () => any): ManualMockedModule;
|
|
78
|
+
toJSON(): ManualMockedModuleSerialized;
|
|
79
|
+
}
|
|
80
|
+
interface ManualMockedModuleSerialized {
|
|
81
|
+
type: "manual";
|
|
82
|
+
url: string;
|
|
83
|
+
id: string;
|
|
84
|
+
raw: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type Awaitable<T> = T | PromiseLike<T>;
|
|
88
|
+
type ModuleMockFactoryWithHelper<M = unknown> = (importOriginal: <T extends M = M>() => Promise<T>) => Awaitable<Partial<M>>;
|
|
89
|
+
type ModuleMockFactory = () => any;
|
|
90
|
+
interface ModuleMockOptions {
|
|
91
|
+
spy?: boolean;
|
|
92
|
+
}
|
|
93
|
+
interface ServerMockResolution {
|
|
94
|
+
mockType: "manual" | "redirect" | "automock" | "autospy";
|
|
95
|
+
resolvedId: string;
|
|
96
|
+
resolvedUrl: string;
|
|
97
|
+
needsInterop?: boolean;
|
|
98
|
+
redirectUrl?: string | null;
|
|
99
|
+
}
|
|
100
|
+
interface ServerIdResolution {
|
|
101
|
+
id: string;
|
|
102
|
+
url: string;
|
|
103
|
+
optimized: boolean;
|
|
104
|
+
}
|
|
105
|
+
interface ModuleMockContext {
|
|
106
|
+
/**
|
|
107
|
+
* When mocking with a factory, this refers to the module that imported the mock.
|
|
108
|
+
*/
|
|
109
|
+
callstack: null | string[];
|
|
110
|
+
}
|
|
111
|
+
interface TestModuleMocker {
|
|
112
|
+
queueMock(id: string, importer: string, factoryOrOptions?: ModuleMockFactory | ModuleMockOptions): void;
|
|
113
|
+
queueUnmock(id: string, importer: string): void;
|
|
114
|
+
importActual<T>(rawId: string, importer: string, callstack?: string[] | null): Promise<T>;
|
|
115
|
+
importMock(rawId: string, importer: string): Promise<any>;
|
|
116
|
+
mockObject(object: Record<string | symbol, any>, moduleType?: "automock" | "autospy"): Record<string | symbol, any>;
|
|
117
|
+
mockObject(object: Record<string | symbol, any>, mockExports: Record<string | symbol, any> | undefined, moduleType?: "automock" | "autospy"): Record<string | symbol, any>;
|
|
118
|
+
getMockContext(): ModuleMockContext;
|
|
119
|
+
reset(): void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { AutomockedModule as A, MockerRegistry as M, RedirectedModule as R, AutospiedModule as h, ManualMockedModule as j };
|
|
123
|
+
export type { ServerMockResolution as S, TestModuleMocker as T, MockedModule as a, ModuleMockOptions as b, ModuleMockFactoryWithHelper as c, MockedModuleType as d, ModuleMockContext as e, ServerIdResolution as f, AutomockedModuleSerialized as g, AutospiedModuleSerialized as i, ManualMockedModuleSerialized as k, MockedModuleSerialized as l, ModuleMockFactory as m, RedirectedModuleSerialized as n };
|