@vitest/browser 2.0.0-beta.2 → 2.0.0-beta.5

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.
@@ -10,7 +10,10 @@ var __publicField = (obj, key, value) => {
10
10
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
11
11
  return value;
12
12
  };
13
- import { i as importId, d as rpc$1, g as getConfig, _ as __vitePreload, b as channel, a as getBrowserState, c as client, l as loadSafeRpc, o as onCancel } from "./rpc-By4jD8av.js";
13
+ import { i as importId, b as getConfig, e as rpc$1, _ as __vitePreload, f as extname, g as getBrowserState, a as channel, c as client, l as loadSafeRpc, o as onCancel } from "./rpc-DBukiZYG.js";
14
+ function getType(value) {
15
+ return Object.prototype.toString.apply(value).slice(8, -1);
16
+ }
14
17
  function showPopupWarning(name, value, defaultValue) {
15
18
  return (...params) => {
16
19
  const formatedParams = params.map((p) => JSON.stringify(p)).join(", ");
@@ -42,14 +45,17 @@ async function setupConsoleLogSpy() {
42
45
  return format(input);
43
46
  };
44
47
  const processLog = (args) => args.map(formatInput).join(" ");
45
- const sendLog = (type, content) => {
46
- var _a, _b;
48
+ const sendLog = (type, content, disableStack) => {
49
+ var _a, _b, _c;
47
50
  if (content.startsWith("[vite]"))
48
51
  return;
49
52
  const unknownTestId = "__vitest__unknown_test__";
50
53
  const taskId = ((_b = (_a = globalThis.__vitest_worker__) == null ? void 0 : _a.current) == null ? void 0 : _b.id) ?? unknownTestId;
54
+ const origin = getConfig().printConsoleTrace && !disableStack ? (_c = new Error("STACK_TRACE").stack) == null ? void 0 : _c.split("\n").slice(1).join("\n") : void 0;
51
55
  rpc$1().sendLog({
56
+ origin,
52
57
  content,
58
+ browser: true,
53
59
  time: Date$1.now(),
54
60
  taskId,
55
61
  type,
@@ -78,18 +84,19 @@ async function setupConsoleLogSpy() {
78
84
  return dirxml(...args);
79
85
  };
80
86
  console$1.trace = (...args) => {
87
+ var _a;
81
88
  const content = processLog(args);
82
- const error2 = new Error("Trace");
83
- const stack = (error2.stack || "").split("\n").slice(2).join("\n");
84
- sendLog("stdout", `${content}
85
- ${stack}`);
89
+ const error2 = new Error("$$Trace");
90
+ const stack = (error2.stack || "").split("\n").slice(((_a = error2.stack) == null ? void 0 : _a.includes("$$Trace")) ? 2 : 1).join("\n");
91
+ sendLog("stderr", `${content}
92
+ ${stack}`, true);
86
93
  return trace(...args);
87
94
  };
88
95
  const timeLabels = {};
89
96
  console$1.time = (label = "default") => {
90
- const now = performance.now();
97
+ const now2 = performance.now();
91
98
  time(label);
92
- timeLabels[label] = now;
99
+ timeLabels[label] = now2;
93
100
  };
94
101
  console$1.timeLog = (label = "default") => {
95
102
  timeLog(label);
@@ -168,6 +175,7 @@ function createBrowserRunner(runnerClass, coverageModule) {
168
175
  });
169
176
  __publicField(this, "onAfterRunFiles", async (files) => {
170
177
  var _a, _b;
178
+ await rpc$1().invalidateMocks();
171
179
  await ((_a = super.onAfterRunFiles) == null ? void 0 : _a.call(this, files));
172
180
  const coverage = await ((_b = coverageModule == null ? void 0 : coverageModule.takeCoverage) == null ? void 0 : _b.call(coverageModule));
173
181
  if (coverage) {
@@ -207,10 +215,9 @@ function createBrowserRunner(runnerClass, coverageModule) {
207
215
  };
208
216
  }
209
217
  let cachedRunner = null;
210
- async function initiateRunner() {
218
+ async function initiateRunner(config) {
211
219
  if (cachedRunner)
212
220
  return cachedRunner;
213
- const config = getConfig();
214
221
  const [
215
222
  { VitestTestRunner, NodeBenchmarkRunner },
216
223
  { takeCoverageInsideWorker, loadDiffConfig, loadSnapshotSerializers }
@@ -258,25 +265,219 @@ async function updateFilesLocations(files) {
258
265
  });
259
266
  await Promise.all(promises);
260
267
  }
261
- function throwNotImplemented(name) {
262
- throw new Error(`[vitest] ${name} is not implemented in browser environment yet.`);
263
- }
268
+ const now = Date.now;
264
269
  class VitestBrowserClientMocker {
265
- importActual() {
266
- throwNotImplemented("importActual");
270
+ constructor() {
271
+ __publicField(this, "queue", /* @__PURE__ */ new Set());
272
+ __publicField(this, "mocks", {});
273
+ __publicField(this, "factories", {});
274
+ __publicField(this, "spyModule");
275
+ }
276
+ setSpyModule(mod) {
277
+ this.spyModule = mod;
278
+ }
279
+ async importActual(id, importer) {
280
+ const resolved = await rpc$1().resolveId(id, importer);
281
+ if (resolved == null)
282
+ throw new Error(`[vitest] Cannot resolve ${id} imported from ${importer}`);
283
+ const ext = extname(resolved.id);
284
+ const base = getBrowserState().config.base || "/";
285
+ const url2 = new URL(`/@id${base}${resolved.id}`, location.href);
286
+ const query = `_vitest_original&ext.${ext}`;
287
+ const actualUrl = `${url2.pathname}${url2.search ? `${url2.search}&${query}` : `?${query}`}${url2.hash}`;
288
+ return getBrowserState().wrapModule(() => __vitePreload(() => import(actualUrl), true ? __vite__mapDeps([]) : void 0));
289
+ }
290
+ async importMock(rawId, importer) {
291
+ await this.prepare();
292
+ const { resolvedId, type, mockPath } = await rpc$1().resolveMock(rawId, importer);
293
+ const factoryReturn = this.get(resolvedId);
294
+ if (factoryReturn)
295
+ return factoryReturn;
296
+ if (this.factories[resolvedId])
297
+ return await this.resolve(resolvedId);
298
+ const base = getBrowserState().config.base || "/";
299
+ if (type === "redirect") {
300
+ const url22 = new URL(`/@id${base}${mockPath}`, location.href);
301
+ return __vitePreload(() => import(url22.toString()), true ? __vite__mapDeps([]) : void 0);
302
+ }
303
+ const url2 = new URL(`/@id${base}${resolvedId}`, location.href);
304
+ const query = url2.search ? `${url2.search}&t=${now()}` : `?t=${now()}`;
305
+ const moduleObject = await __vitePreload(() => import(`${url2.pathname}${query}${url2.hash}`), true ? __vite__mapDeps([]) : void 0);
306
+ return this.mockObject(moduleObject);
307
+ }
308
+ getMockContext() {
309
+ return { callstack: null };
310
+ }
311
+ get(id) {
312
+ return this.mocks[id];
313
+ }
314
+ async resolve(id) {
315
+ const factory = this.factories[id];
316
+ if (!factory)
317
+ throw new Error(`Cannot resolve ${id} mock: no factory provided`);
318
+ try {
319
+ this.mocks[id] = await factory();
320
+ return this.mocks[id];
321
+ } catch (err) {
322
+ const vitestError = new Error(
323
+ '[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'
324
+ );
325
+ vitestError.cause = err;
326
+ throw vitestError;
327
+ }
328
+ }
329
+ queueMock(id, importer, factory) {
330
+ const promise = rpc$1().queueMock(id, importer, !!factory).then((id2) => {
331
+ this.factories[id2] = factory;
332
+ }).finally(() => {
333
+ this.queue.delete(promise);
334
+ });
335
+ this.queue.add(promise);
336
+ }
337
+ queueUnmock(id, importer) {
338
+ const promise = rpc$1().queueUnmock(id, importer).then((id2) => {
339
+ delete this.factories[id2];
340
+ }).finally(() => {
341
+ this.queue.delete(promise);
342
+ });
343
+ this.queue.add(promise);
344
+ }
345
+ async prepare() {
346
+ if (!this.queue.size)
347
+ return;
348
+ await Promise.all([...this.queue.values()]);
267
349
  }
268
- importMock() {
269
- throwNotImplemented("importMock");
350
+ // TODO: move this logic into a util(?)
351
+ mockObject(object, mockExports = {}) {
352
+ const finalizers = new Array();
353
+ const refs = new RefTracker();
354
+ const define = (container, key, value) => {
355
+ try {
356
+ container[key] = value;
357
+ return true;
358
+ } catch {
359
+ return false;
360
+ }
361
+ };
362
+ const mockPropertiesOf = (container, newContainer) => {
363
+ const containerType = /* @__PURE__ */ getType(container);
364
+ const isModule = containerType === "Module" || !!container.__esModule;
365
+ for (const { key: property, descriptor } of getAllMockableProperties(container, isModule)) {
366
+ if (!isModule && descriptor.get) {
367
+ try {
368
+ Object.defineProperty(newContainer, property, descriptor);
369
+ } catch (error) {
370
+ }
371
+ continue;
372
+ }
373
+ if (isSpecialProp(property, containerType))
374
+ continue;
375
+ const value = container[property];
376
+ const refId = refs.getId(value);
377
+ if (refId !== void 0) {
378
+ finalizers.push(() => define(newContainer, property, refs.getMockedValue(refId)));
379
+ continue;
380
+ }
381
+ const type = /* @__PURE__ */ getType(value);
382
+ if (Array.isArray(value)) {
383
+ define(newContainer, property, []);
384
+ continue;
385
+ }
386
+ const isFunction = type.includes("Function") && typeof value === "function";
387
+ if ((!isFunction || value.__isMockFunction) && type !== "Object" && type !== "Module") {
388
+ define(newContainer, property, value);
389
+ continue;
390
+ }
391
+ if (!define(newContainer, property, isFunction ? value : {}))
392
+ continue;
393
+ if (isFunction) {
394
+ let mockFunction = function() {
395
+ if (this instanceof newContainer[property]) {
396
+ for (const { key, descriptor: descriptor2 } of getAllMockableProperties(this, false)) {
397
+ if (descriptor2.get)
398
+ continue;
399
+ const value2 = this[key];
400
+ const type2 = /* @__PURE__ */ getType(value2);
401
+ const isFunction2 = type2.includes("Function") && typeof value2 === "function";
402
+ if (isFunction2) {
403
+ const original = this[key];
404
+ const mock2 = spyModule.vi.spyOn(this, key).mockImplementation(original);
405
+ mock2.mockRestore = () => {
406
+ mock2.mockReset();
407
+ mock2.mockImplementation(original);
408
+ return mock2;
409
+ };
410
+ }
411
+ }
412
+ }
413
+ };
414
+ const spyModule = this.spyModule;
415
+ if (!spyModule)
416
+ throw new Error("[vitest] `spyModule` is not defined. This is Vitest error. Please open a new issue with reproduction.");
417
+ const mock = spyModule.vi.spyOn(newContainer, property).mockImplementation(mockFunction);
418
+ mock.mockRestore = () => {
419
+ mock.mockReset();
420
+ mock.mockImplementation(mockFunction);
421
+ return mock;
422
+ };
423
+ Object.defineProperty(newContainer[property], "length", { value: 0 });
424
+ }
425
+ refs.track(value, newContainer[property]);
426
+ mockPropertiesOf(value, newContainer[property]);
427
+ }
428
+ };
429
+ const mockedObject = mockExports;
430
+ mockPropertiesOf(object, mockedObject);
431
+ for (const finalizer of finalizers)
432
+ finalizer();
433
+ return mockedObject;
270
434
  }
271
- queueMock() {
272
- throwNotImplemented("queueMock");
435
+ }
436
+ function isSpecialProp(prop, parentType) {
437
+ return parentType.includes("Function") && typeof prop === "string" && ["arguments", "callee", "caller", "length", "name"].includes(prop);
438
+ }
439
+ class RefTracker {
440
+ constructor() {
441
+ __publicField(this, "idMap", /* @__PURE__ */ new Map());
442
+ __publicField(this, "mockedValueMap", /* @__PURE__ */ new Map());
443
+ }
444
+ getId(value) {
445
+ return this.idMap.get(value);
273
446
  }
274
- queueUnmock() {
275
- throwNotImplemented("queueUnmock");
447
+ getMockedValue(id) {
448
+ return this.mockedValueMap.get(id);
276
449
  }
277
- prepare() {
450
+ track(originalValue, mockedValue) {
451
+ const newId = this.idMap.size;
452
+ this.idMap.set(originalValue, newId);
453
+ this.mockedValueMap.set(newId, mockedValue);
454
+ return newId;
278
455
  }
279
456
  }
457
+ function getAllMockableProperties(obj, isModule) {
458
+ const allProps = /* @__PURE__ */ new Map();
459
+ let curr = obj;
460
+ do {
461
+ if (curr === Object.prototype || curr === Function.prototype || curr === RegExp.prototype)
462
+ break;
463
+ collectOwnProperties(curr, (key) => {
464
+ const descriptor = Object.getOwnPropertyDescriptor(curr, key);
465
+ if (descriptor)
466
+ allProps.set(key, { key, descriptor });
467
+ });
468
+ } while (curr = Object.getPrototypeOf(curr));
469
+ if (isModule && !allProps.has("default") && "default" in obj) {
470
+ const descriptor = Object.getOwnPropertyDescriptor(obj, "default");
471
+ if (descriptor)
472
+ allProps.set("default", { key: "default", descriptor });
473
+ }
474
+ return Array.from(allProps.values());
475
+ }
476
+ function collectOwnProperties(obj, collector) {
477
+ const collect = typeof collector === "function" ? collector : (key) => collector.add(key);
478
+ Object.getOwnPropertyNames(obj).forEach(collect);
479
+ Object.getOwnPropertySymbols(obj).forEach(collect);
480
+ }
280
481
  function on(event, listener) {
281
482
  window.addEventListener(event, listener);
282
483
  return () => window.removeEventListener(event, listener);
@@ -347,9 +548,16 @@ async function tryCall(fn) {
347
548
  try {
348
549
  return await fn();
349
550
  } catch (err) {
350
- const now = Date.now();
351
- const canTry = !reloadStart || now - Number(reloadStart) < 3e4;
352
- debug("failed to resolve runner", err == null ? void 0 : err.message, "trying again:", canTry, "time is", now, "reloadStart is", reloadStart);
551
+ const now2 = Date.now();
552
+ const canTry = !reloadStart || now2 - Number(reloadStart) < 3e4;
553
+ const errorStack = (() => {
554
+ var _a;
555
+ if (!err)
556
+ return null;
557
+ return ((_a = err.stack) == null ? void 0 : _a.includes(err.message)) ? err.stack : `${err.message}
558
+ ${err.stack}`;
559
+ })();
560
+ debug("failed to resolve runner", "trying again:", canTry, "time is", now2, "reloadStart is", reloadStart, ":\n", errorStack);
353
561
  if (!canTry) {
354
562
  const error = serializeError(new Error("Vitest failed to load its runner after 30 seconds."));
355
563
  error.cause = serializeError(err);
@@ -358,7 +566,7 @@ async function tryCall(fn) {
358
566
  }
359
567
  if (!reloadStart) {
360
568
  const newUrl = new URL(location.href);
361
- newUrl.searchParams.set("__reloadStart", now.toString());
569
+ newUrl.searchParams.set("__reloadStart", now2.toString());
362
570
  debug("set the new url because reload start is not set to", newUrl);
363
571
  location.href = newUrl.toString();
364
572
  } else {
@@ -382,7 +590,7 @@ async function prepareTestEnvironment(files) {
382
590
  worker: "./browser.js",
383
591
  workerId: 1,
384
592
  config,
385
- projectName: config.name,
593
+ projectName: config.name || "",
386
594
  files,
387
595
  environment: {
388
596
  name: "browser",
@@ -405,23 +613,27 @@ async function prepareTestEnvironment(files) {
405
613
  rpc: rpc2,
406
614
  durations: {
407
615
  environment: 0,
408
- prepare: 0
616
+ prepare: performance.now()
409
617
  },
410
618
  providedContext
411
619
  };
412
620
  globalThis.__vitest_browser__ = true;
413
621
  globalThis.__vitest_worker__ = state;
414
- globalThis.__vitest_mocker__ = new VitestBrowserClientMocker();
622
+ const mocker = new VitestBrowserClientMocker();
623
+ globalThis.__vitest_mocker__ = mocker;
415
624
  await setupConsoleLogSpy();
416
625
  setupDialogsSpy();
417
- const { startTests, setupCommonEnv } = await importId("vitest/browser");
418
- const version = url.searchParams.get("browserv") || "0";
626
+ const version = url.searchParams.get("browserv") || "";
419
627
  files.forEach((filename) => {
420
628
  const currentVersion = browserHashMap.get(filename);
421
629
  if (!currentVersion || currentVersion[1] !== version)
422
630
  browserHashMap.set(filename, [true, version]);
423
631
  });
424
- const runner = await initiateRunner();
632
+ const [runner, { startTests, setupCommonEnv, Vitest }] = await Promise.all([
633
+ initiateRunner(config),
634
+ importId("vitest/browser")
635
+ ]);
636
+ mocker.setSpyModule(Vitest);
425
637
  onCancel.then((reason) => {
426
638
  var _a;
427
639
  (_a = runner.onCancel) == null ? void 0 : _a.call(runner, reason);
@@ -460,6 +672,7 @@ async function runTests(files) {
460
672
  }
461
673
  debug("runner resolved successfully");
462
674
  const { config, runner, state, setupCommonEnv, startTests } = preparedData;
675
+ state.durations.prepare = performance.now() - state.durations.prepare;
463
676
  try {
464
677
  await setupCommonEnv(config);
465
678
  for (const file of files)
@@ -1,42 +1,26 @@
1
1
  const moduleCache = new Map()
2
2
 
3
3
  function wrapModule(module) {
4
- if (module instanceof Promise) {
5
- moduleCache.set(module, { promise: module, evaluated: false })
6
- return module
7
- .then(m => '__vi_inject__' in m ? m.__vi_inject__ : m)
8
- .finally(() => moduleCache.delete(module))
9
- }
10
- return '__vi_inject__' in module ? module.__vi_inject__ : module
11
- }
12
-
13
- function exportAll(exports, sourceModule) {
14
- if (exports === sourceModule)
15
- return
16
-
17
- if (Object(sourceModule) !== sourceModule || Array.isArray(sourceModule))
18
- return
19
-
20
- for (const key in sourceModule) {
21
- if (key !== 'default') {
22
- try {
23
- Object.defineProperty(exports, key, {
24
- enumerable: true,
25
- configurable: true,
26
- get: () => sourceModule[key],
27
- })
28
- }
29
- catch (_err) { }
30
- }
4
+ if (typeof module === 'function') {
5
+ const promise = new Promise((resolve, reject) => {
6
+ if (typeof __vitest_mocker__ === 'undefined')
7
+ return module().then(resolve, reject)
8
+ __vitest_mocker__.prepare().finally(() => {
9
+ module().then(resolve, reject)
10
+ })
11
+ })
12
+ moduleCache.set(promise, { promise, evaluated: false })
13
+ return promise.finally(() => moduleCache.delete(promise))
31
14
  }
15
+ return module
32
16
  }
33
17
 
34
18
  window.__vitest_browser_runner__ = {
35
- exportAll,
36
19
  wrapModule,
37
20
  moduleCache,
38
21
  config: { __VITEST_CONFIG__ },
39
22
  files: { __VITEST_FILES__ },
23
+ type: { __VITEST_TYPE__ },
40
24
  }
41
25
 
42
26
  const config = __vitest_browser_runner__.config
@@ -15,19 +15,20 @@
15
15
  padding: 0;
16
16
  margin: 0;
17
17
  }
18
- #vitest-ui {
19
- width: 100vw;
20
- height: 100vh;
21
- border: none;
18
+ html,
19
+ body,
20
+ iframe[data-vitest],
21
+ #vitest-tester {
22
+ width: 100%;
23
+ height: 100%;
22
24
  }
23
25
  </style>
24
26
  <script>{__VITEST_INJECTOR__}</script>
25
27
  {__VITEST_SCRIPTS__}
26
- <script type="module" crossorigin src="/__vitest_browser__/main-DmAU-Uff.js"></script>
27
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/rpc-By4jD8av.js">
28
+ <script type="module" crossorigin src="/__vitest_browser__/orchestrator-CEB54dI4.js"></script>
29
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/rpc-DBukiZYG.js">
28
30
  </head>
29
31
  <body>
30
- <iframe id="vitest-ui" src=""></iframe>
31
32
  <div id="vitest-tester"></div>
32
33
  </body>
33
34
  </html>
@@ -13,14 +13,15 @@
13
13
  body {
14
14
  padding: 0;
15
15
  margin: 0;
16
+ min-height: 100vh;
16
17
  }
17
18
  </style>
18
19
  <script>{__VITEST_INJECTOR__}</script>
19
20
  {__VITEST_SCRIPTS__}
20
- <script type="module" crossorigin src="/__vitest_browser__/tester-CrKhlp5g.js"></script>
21
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/rpc-By4jD8av.js">
21
+ <script type="module" crossorigin src="/__vitest_browser__/tester-C3Mchfpf.js"></script>
22
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/rpc-DBukiZYG.js">
22
23
  </head>
23
- <body>
24
+ <body style="width: 100%; height: 100%; transform: scale(1); transform-origin: left top;">
24
25
  {__VITEST_APPEND__}
25
26
  </body>
26
27
  </html>
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { Plugin } from 'vite';
2
1
  import { WorkspaceProject } from 'vitest/node';
2
+ export { BrowserCommand } from 'vitest/node';
3
+ import { Plugin } from 'vitest/config';
3
4
 
4
5
  declare const _default: (project: WorkspaceProject, base?: string) => Plugin[];
5
6