chunk-runtime-mocker.4bbb070f.mjs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. import { V as ViteNodeRunner } from './chunk-vite-node-client.da0a17ff.mjs';
  2. import { normalizePath } from 'vite';
  3. import { g as getWorkerState, G as mergeSlashes, s as slash, l as getType, H as getAllMockableProperties } from './chunk-mock-date.2917be60.mjs';
  4. import { existsSync, readdirSync } from 'fs';
  5. import { n as normalizeRequestId, p as pathFromRoot, i as isNodeBuiltin, b as toFilePath } from './chunk-vite-node-utils.473cd0b2.mjs';
  6. import { d as dirname, j as join, b as basename, h as extname, a as resolve, c as distDir } from './chunk-constants.71e8a211.mjs';
  7. class RefTracker {
  8. constructor() {
  9. this.idMap = /* @__PURE__ */ new Map();
  10. this.mockedValueMap = /* @__PURE__ */ new Map();
  11. }
  12. getId(value) {
  13. return this.idMap.get(value);
  14. }
  15. getMockedValue(id) {
  16. return this.mockedValueMap.get(id);
  17. }
  18. track(originalValue, mockedValue) {
  19. const newId = this.idMap.size;
  20. this.idMap.set(originalValue, newId);
  21. this.mockedValueMap.set(newId, mockedValue);
  22. return newId;
  23. }
  24. }
  25. function isSpecialProp(prop, parentType) {
  26. return parentType.includes("Function") && typeof prop === "string" && ["arguments", "callee", "caller", "length", "name"].includes(prop);
  27. }
  28. const _VitestMocker = class {
  29. constructor(options, moduleCache, request) {
  30. this.options = options;
  31. this.moduleCache = moduleCache;
  32. this.request = request;
  33. }
  34. get root() {
  35. return this.options.root;
  36. }
  37. get base() {
  38. return this.options.base;
  39. }
  40. get mockMap() {
  41. return this.options.mockMap;
  42. }
  43. getSuiteFilepath() {
  44. return getWorkerState().filepath || "global";
  45. }
  46. getMocks() {
  47. const suite = this.getSuiteFilepath();
  48. const suiteMocks = this.mockMap.get(suite);
  49. const globalMocks = this.mockMap.get("global");
  50. return {
  51. ...globalMocks,
  52. ...suiteMocks
  53. };
  54. }
  55. async resolvePath(id, importer) {
  56. const path = await this.options.resolveId(id, importer);
  57. const external = path == null || path.id.includes("/node_modules/") ? id : null;
  58. return {
  59. path: normalizeRequestId((path == null ? void 0 : path.id) || id),
  60. external
  61. };
  62. }
  63. async resolveMocks() {
  64. await Promise.all(_VitestMocker.pendingIds.map(async (mock) => {
  65. const { path, external } = await this.resolvePath(mock.id, mock.importer);
  66. if (mock.type === "unmock")
  67. this.unmockPath(path);
  68. if (mock.type === "mock")
  69. this.mockPath(path, external, mock.factory);
  70. }));
  71. _VitestMocker.pendingIds = [];
  72. }
  73. async callFunctionMock(dep, mock) {
  74. var _a;
  75. const cached = (_a = this.moduleCache.get(dep)) == null ? void 0 : _a.exports;
  76. if (cached)
  77. return cached;
  78. let exports;
  79. try {
  80. exports = await mock();
  81. } catch (err) {
  82. const vitestError = new Error(
  83. "[vitest] There was an error, when mocking a module. If you are using vi.mock, make sure you are not using top level variables inside, since this call is hoisted. Read more: https://vitest.dev/api/#vi-mock"
  84. );
  85. vitestError.cause = err;
  86. throw vitestError;
  87. }
  88. if (exports === null || typeof exports !== "object")
  89. throw new Error('[vitest] vi.mock(path: string, factory?: () => unknown) is not returning an object. Did you mean to return an object with a "default" key?');
  90. this.moduleCache.set(dep, { exports });
  91. const filepath = dep.slice("mock:".length);
  92. const exportHandler = {
  93. get(target, prop) {
  94. const val = target[prop];
  95. if (prop === "then") {
  96. if (target instanceof Promise)
  97. return target.then.bind(target);
  98. } else if (!(prop in target)) {
  99. throw new Error(`[vitest] No "${prop}" export is defined on the "${filepath}"`);
  100. }
  101. return val;
  102. }
  103. };
  104. return new Proxy(exports, exportHandler);
  105. }
  106. getMockPath(dep) {
  107. return `mock:${dep}`;
  108. }
  109. getDependencyMock(id) {
  110. return this.getMocks()[id];
  111. }
  112. normalizePath(path) {
  113. return pathFromRoot(this.root, normalizeRequestId(path, this.base));
  114. }
  115. getFsPath(path, external) {
  116. if (external)
  117. return mergeSlashes(`/@fs/${path}`);
  118. return normalizeRequestId(path, this.base);
  119. }
  120. resolveMockPath(mockPath, external) {
  121. const path = normalizeRequestId(external || mockPath);
  122. if (external || isNodeBuiltin(mockPath) || !existsSync(mockPath)) {
  123. const mockDirname = dirname(path);
  124. const mockFolder = join(this.root, "__mocks__", mockDirname);
  125. if (!existsSync(mockFolder))
  126. return null;
  127. const files = readdirSync(mockFolder);
  128. const baseOriginal = basename(path);
  129. for (const file of files) {
  130. const baseFile = basename(file, extname(file));
  131. if (baseFile === baseOriginal)
  132. return resolve(mockFolder, file);
  133. }
  134. return null;
  135. }
  136. const dir = dirname(path);
  137. const baseId = basename(path);
  138. const fullPath = resolve(dir, "__mocks__", baseId);
  139. return existsSync(fullPath) ? fullPath : null;
  140. }
  141. mockObject(object) {
  142. if (!_VitestMocker.spyModule) {
  143. throw new Error(
  144. "Error: Spy module is not defined. This is likely an internal bug in Vitest. Please report it to https://github.com/vitest-dev/vitest/issues"
  145. );
  146. }
  147. const spyModule = _VitestMocker.spyModule;
  148. const finalizers = new Array();
  149. const refs = new RefTracker();
  150. const define = (container, key, value) => {
  151. try {
  152. container[key] = value;
  153. return true;
  154. } catch {
  155. return false;
  156. }
  157. };
  158. const mockPropertiesOf = (container, newContainer) => {
  159. const containerType = getType(container);
  160. const isModule = containerType === "Module" || !!container.__esModule;
  161. for (const { key: property, descriptor } of getAllMockableProperties(container)) {
  162. if (!isModule && descriptor.get) {
  163. try {
  164. Object.defineProperty(newContainer, property, descriptor);
  165. } catch (error) {
  166. }
  167. continue;
  168. }
  169. if (isSpecialProp(property, containerType))
  170. continue;
  171. const value = container[property];
  172. const refId = refs.getId(value);
  173. if (refId !== void 0) {
  174. finalizers.push(() => define(newContainer, property, refs.getMockedValue(refId)));
  175. continue;
  176. }
  177. const type = getType(value);
  178. if (Array.isArray(value)) {
  179. define(newContainer, property, []);
  180. continue;
  181. }
  182. const isFunction = type.includes("Function") && typeof value === "function";
  183. if ((!isFunction || value.__isMockFunction) && type !== "Object" && type !== "Module") {
  184. define(newContainer, property, value);
  185. continue;
  186. }
  187. if (!define(newContainer, property, isFunction ? value : {}))
  188. continue;
  189. if (isFunction) {
  190. spyModule.spyOn(newContainer, property).mockImplementation(() => void 0);
  191. Object.defineProperty(newContainer[property], "length", { value: 0 });
  192. }
  193. refs.track(value, newContainer[property]);
  194. mockPropertiesOf(value, newContainer[property]);
  195. }
  196. };
  197. const mockedObject = {};
  198. mockPropertiesOf(object, mockedObject);
  199. for (const finalizer of finalizers)
  200. finalizer();
  201. return mockedObject;
  202. }
  203. unmockPath(path) {
  204. const suitefile = this.getSuiteFilepath();
  205. const id = this.normalizePath(path);
  206. const mock = this.mockMap.get(suitefile);
  207. if (mock == null ? void 0 : mock[id])
  208. delete mock[id];
  209. const mockId = this.getMockPath(id);
  210. if (this.moduleCache.get(mockId))
  211. this.moduleCache.delete(mockId);
  212. }
  213. mockPath(path, external, factory) {
  214. const suitefile = this.getSuiteFilepath();
  215. const id = this.normalizePath(path);
  216. const mocks = this.mockMap.get(suitefile) || {};
  217. mocks[id] = factory || this.resolveMockPath(path, external);
  218. this.mockMap.set(suitefile, mocks);
  219. }
  220. async importActual(id, importer) {
  221. const { path, external } = await this.resolvePath(id, importer);
  222. const fsPath = this.getFsPath(path, external);
  223. const result = await this.request(fsPath);
  224. return result;
  225. }
  226. async importMock(id, importer) {
  227. const { path, external } = await this.resolvePath(id, importer);
  228. const fsPath = this.getFsPath(path, external);
  229. const normalizedId = this.normalizePath(fsPath);
  230. let mock = this.getDependencyMock(normalizedId);
  231. if (mock === void 0)
  232. mock = this.resolveMockPath(fsPath, external);
  233. if (mock === null) {
  234. await this.ensureSpy();
  235. const mod = await this.request(fsPath);
  236. return this.mockObject(mod);
  237. }
  238. if (typeof mock === "function")
  239. return this.callFunctionMock(fsPath, mock);
  240. return this.requestWithMock(mock);
  241. }
  242. async ensureSpy() {
  243. if (_VitestMocker.spyModule)
  244. return;
  245. _VitestMocker.spyModule = await this.request(`/@fs/${slash(resolve(distDir, "spy.mjs"))}`);
  246. }
  247. async requestWithMock(dep) {
  248. var _a;
  249. await Promise.all([
  250. this.ensureSpy(),
  251. this.resolveMocks()
  252. ]);
  253. const id = this.normalizePath(dep);
  254. const mock = this.getDependencyMock(id);
  255. const callstack = this.request.callstack;
  256. const mockPath = this.getMockPath(id);
  257. if (mock === null) {
  258. const cache = this.moduleCache.get(mockPath);
  259. if (cache == null ? void 0 : cache.exports)
  260. return cache.exports;
  261. const cacheKey = toFilePath(dep, this.root);
  262. const mod = ((_a = this.moduleCache.get(cacheKey)) == null ? void 0 : _a.exports) || await this.request(dep);
  263. const exports = this.mockObject(mod);
  264. this.moduleCache.set(mockPath, { exports });
  265. return exports;
  266. }
  267. if (typeof mock === "function" && !callstack.includes(mockPath)) {
  268. callstack.push(mockPath);
  269. const result = await this.callFunctionMock(mockPath, mock);
  270. const indexMock = callstack.indexOf(mockPath);
  271. callstack.splice(indexMock, 1);
  272. return result;
  273. }
  274. if (typeof mock === "string" && !callstack.includes(mock))
  275. dep = mock;
  276. return this.request(dep);
  277. }
  278. queueMock(id, importer, factory) {
  279. _VitestMocker.pendingIds.push({ type: "mock", id, importer, factory });
  280. }
  281. queueUnmock(id, importer) {
  282. _VitestMocker.pendingIds.push({ type: "unmock", id, importer });
  283. }
  284. };
  285. let VitestMocker = _VitestMocker;
  286. VitestMocker.pendingIds = [];
  287. async function executeInViteNode(options) {
  288. const runner = new VitestRunner(options);
  289. await runner.executeId("/@vite/env");
  290. const result = [];
  291. for (const file of options.files)
  292. result.push(await runner.executeFile(file));
  293. return result;
  294. }
  295. class VitestRunner extends ViteNodeRunner {
  296. constructor(options) {
  297. super(options);
  298. this.options = options;
  299. }
  300. prepareContext(context) {
  301. const request = context.__vite_ssr_import__;
  302. const resolveId = context.__vitest_resolve_id__;
  303. const mocker = new VitestMocker(this.options, this.moduleCache, request);
  304. const workerState = getWorkerState();
  305. if (workerState.filepath && normalizePath(workerState.filepath) === normalizePath(context.__filename)) {
  306. Object.defineProperty(context.__vite_ssr_import_meta__, "vitest", { get: () => globalThis.__vitest_index__ });
  307. }
  308. return Object.assign(context, {
  309. __vite_ssr_import__: async (dep) => mocker.requestWithMock(await resolveId(dep)),
  310. __vite_ssr_dynamic_import__: async (dep) => mocker.requestWithMock(await resolveId(dep)),
  311. __vitest_mocker__: mocker
  312. });
  313. }
  314. }
  315. export { VitestRunner as V, executeInViteNode as e };