@vitest/browser 0.29.7 → 0.30.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.
@@ -17,8 +17,8 @@
17
17
  })()
18
18
  </script>
19
19
  <!-- !LOAD_METADATA! -->
20
- <script type="module" crossorigin src="./assets/index-d8f092a0.js"></script>
21
- <link rel="stylesheet" href="./assets/index-57d38fc4.css">
20
+ <script type="module" crossorigin src="./assets/index-d949d382.js"></script>
21
+ <link rel="stylesheet" href="./assets/index-561b5dad.css">
22
22
  </head>
23
23
  <body>
24
24
  <div id="app"></div>
@@ -23,15 +23,15 @@ var __publicField = (obj, key, value) => {
23
23
  }
24
24
  }
25
25
  }).observe(document, { childList: true, subtree: true });
26
- function getFetchOpts(script) {
26
+ function getFetchOpts(link) {
27
27
  const fetchOpts = {};
28
- if (script.integrity)
29
- fetchOpts.integrity = script.integrity;
30
- if (script.referrerpolicy)
31
- fetchOpts.referrerPolicy = script.referrerpolicy;
32
- if (script.crossorigin === "use-credentials")
28
+ if (link.integrity)
29
+ fetchOpts.integrity = link.integrity;
30
+ if (link.referrerPolicy)
31
+ fetchOpts.referrerPolicy = link.referrerPolicy;
32
+ if (link.crossOrigin === "use-credentials")
33
33
  fetchOpts.credentials = "include";
34
- else if (script.crossorigin === "anonymous")
34
+ else if (link.crossOrigin === "anonymous")
35
35
  fetchOpts.credentials = "omit";
36
36
  else
37
37
  fetchOpts.credentials = "same-origin";
@@ -100,7 +100,7 @@ function createBirpc(functions, options) {
100
100
  timeout = DEFAULT_TIMEOUT
101
101
  } = options;
102
102
  const rpcPromiseMap = /* @__PURE__ */ new Map();
103
- const rpc = new Proxy({}, {
103
+ const rpc2 = new Proxy({}, {
104
104
  get(_, method) {
105
105
  const sendEvent = (...args) => {
106
106
  post(serialize({ m: method, a: args, t: "q" }));
@@ -132,7 +132,7 @@ function createBirpc(functions, options) {
132
132
  const { m: method, a: args } = msg;
133
133
  let result, error;
134
134
  try {
135
- result = await functions[method].apply(rpc, args);
135
+ result = await functions[method].apply(rpc2, args);
136
136
  } catch (e) {
137
137
  error = e;
138
138
  }
@@ -148,7 +148,7 @@ function createBirpc(functions, options) {
148
148
  rpcPromiseMap.delete(ack);
149
149
  }
150
150
  });
151
- return rpc;
151
+ return rpc2;
152
152
  }
153
153
  const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
154
154
  function nanoid(size = 21) {
@@ -158,6 +158,7 @@ function nanoid(size = 21) {
158
158
  id += urlAlphabet[Math.random() * 64 | 0];
159
159
  return id;
160
160
  }
161
+ /*! (c) 2020 Andrea Giammarchi */
161
162
  const { parse: $parse, stringify: $stringify } = JSON;
162
163
  const { keys } = Object;
163
164
  const Primitive = String;
@@ -229,16 +230,17 @@ const stringify = (value, replacer, space) => {
229
230
  return after;
230
231
  }
231
232
  };
232
- const isAggregateError = (err) => {
233
+ function isAggregateError(err) {
233
234
  if (typeof AggregateError !== "undefined" && err instanceof AggregateError)
234
235
  return true;
235
236
  return err instanceof Error && "errors" in err;
236
- };
237
+ }
237
238
  class StateManager {
238
239
  constructor() {
239
240
  this.filesMap = /* @__PURE__ */ new Map();
240
241
  this.pathsSet = /* @__PURE__ */ new Set();
241
242
  this.collectingPromise = void 0;
243
+ this.browserTestPromises = /* @__PURE__ */ new Map();
242
244
  this.idMap = /* @__PURE__ */ new Map();
243
245
  this.taskFileMap = /* @__PURE__ */ new WeakMap();
244
246
  this.errorsSet = /* @__PURE__ */ new Set();
@@ -267,8 +269,8 @@ class StateManager {
267
269
  }
268
270
  getFiles(keys2) {
269
271
  if (keys2)
270
- return keys2.map((key) => this.filesMap.get(key)).filter(Boolean);
271
- return Array.from(this.filesMap.values());
272
+ return keys2.map((key) => this.filesMap.get(key)).filter(Boolean).flat();
273
+ return Array.from(this.filesMap.values()).flat();
272
274
  }
273
275
  getFilepaths() {
274
276
  return Array.from(this.filesMap.keys());
@@ -286,13 +288,23 @@ class StateManager {
286
288
  }
287
289
  collectFiles(files = []) {
288
290
  files.forEach((file) => {
289
- this.filesMap.set(file.filepath, file);
291
+ const existing = this.filesMap.get(file.filepath) || [];
292
+ const otherProject = existing.filter((i) => i.projectName !== file.projectName);
293
+ otherProject.push(file);
294
+ this.filesMap.set(file.filepath, otherProject);
290
295
  this.updateId(file);
291
296
  });
292
297
  }
293
- clearFiles(paths = []) {
298
+ clearFiles(project, paths = []) {
294
299
  paths.forEach((path) => {
295
- this.filesMap.delete(path);
300
+ const files = this.filesMap.get(path);
301
+ if (!files)
302
+ return;
303
+ const filtered = files.filter((file) => file.projectName !== project.config.name);
304
+ if (!filtered.length)
305
+ this.filesMap.delete(path);
306
+ else
307
+ this.filesMap.set(path, filtered);
296
308
  });
297
309
  }
298
310
  updateId(task) {
@@ -402,16 +414,72 @@ function createClient(url2, options = {}) {
402
414
  }
403
415
  return ctx;
404
416
  }
405
- function createBrowserRunner(original) {
417
+ const { get } = Reflect;
418
+ const safeRandom = Math.random;
419
+ function withSafeTimers(getTimers, fn) {
420
+ const { setTimeout: setTimeout2, clearTimeout, nextTick, setImmediate, clearImmediate } = getTimers();
421
+ const currentSetTimeout = globalThis.setTimeout;
422
+ const currentClearTimeout = globalThis.clearTimeout;
423
+ const currentRandom = globalThis.Math.random;
424
+ const currentNextTick = globalThis.process.nextTick;
425
+ const currentSetImmediate = globalThis.setImmediate;
426
+ const currentClearImmediate = globalThis.clearImmediate;
427
+ try {
428
+ globalThis.setTimeout = setTimeout2;
429
+ globalThis.clearTimeout = clearTimeout;
430
+ globalThis.Math.random = safeRandom;
431
+ globalThis.process.nextTick = nextTick;
432
+ globalThis.setImmediate = setImmediate;
433
+ globalThis.clearImmediate = clearImmediate;
434
+ const result = fn();
435
+ return result;
436
+ } finally {
437
+ globalThis.setTimeout = currentSetTimeout;
438
+ globalThis.clearTimeout = currentClearTimeout;
439
+ globalThis.Math.random = currentRandom;
440
+ globalThis.setImmediate = currentSetImmediate;
441
+ globalThis.clearImmediate = currentClearImmediate;
442
+ nextTick(() => {
443
+ globalThis.process.nextTick = currentNextTick;
444
+ });
445
+ }
446
+ }
447
+ const promises = /* @__PURE__ */ new Set();
448
+ async function rpcDone() {
449
+ if (!promises.size)
450
+ return;
451
+ const awaitable = Array.from(promises);
452
+ return Promise.all(awaitable);
453
+ }
454
+ function createSafeRpc(client2, getTimers) {
455
+ return new Proxy(client2.rpc, {
456
+ get(target, p, handler) {
457
+ const sendCall = get(target, p, handler);
458
+ const safeSendCall = (...args) => withSafeTimers(getTimers, async () => {
459
+ const result = sendCall(...args);
460
+ promises.add(result);
461
+ try {
462
+ return await result;
463
+ } finally {
464
+ promises.delete(result);
465
+ }
466
+ });
467
+ safeSendCall.asEvent = sendCall.asEvent;
468
+ return safeSendCall;
469
+ }
470
+ });
471
+ }
472
+ function rpc() {
473
+ return globalThis.__vitest_worker__.safeRpc;
474
+ }
475
+ function createBrowserRunner(original, coverageModule) {
406
476
  return class BrowserTestRunner extends original {
407
477
  constructor(options) {
408
478
  super(options.config);
409
479
  __publicField(this, "config");
410
480
  __publicField(this, "hashMap", /* @__PURE__ */ new Map());
411
- __publicField(this, "client");
412
481
  this.config = options.config;
413
482
  this.hashMap = options.browserHashMap;
414
- this.client = options.client;
415
483
  }
416
484
  async onAfterRunTest(task) {
417
485
  var _a, _b, _c;
@@ -420,11 +488,17 @@ function createBrowserRunner(original) {
420
488
  console.error(error.message);
421
489
  });
422
490
  }
491
+ async onAfterRunSuite() {
492
+ var _a, _b;
493
+ await ((_a = super.onAfterRunSuite) == null ? void 0 : _a.call(this));
494
+ const coverage = await ((_b = coverageModule == null ? void 0 : coverageModule.takeCoverage) == null ? void 0 : _b.call(coverageModule));
495
+ await rpc().onAfterSuiteRun({ coverage });
496
+ }
423
497
  onCollected(files) {
424
- return this.client.rpc.onCollected(files);
498
+ return rpc().onCollected(files);
425
499
  }
426
500
  onTaskUpdate(task) {
427
- return this.client.rpc.onTaskUpdate(task);
501
+ return rpc().onTaskUpdate(task);
428
502
  }
429
503
  async importFile(filepath) {
430
504
  const match = filepath.match(/^(\w:\/)/);
@@ -438,24 +512,144 @@ function createBrowserRunner(original) {
438
512
  }
439
513
  };
440
514
  }
515
+ function importId(id) {
516
+ const name = `/@id/${id}`;
517
+ return __vitePreload(() => import(name), true ? [] : void 0);
518
+ }
519
+ const { Date: Date$1, console: console$1 } = globalThis;
520
+ async function setupConsoleLogSpy() {
521
+ const { stringify: stringify2, format, utilInspect } = await importId("vitest/utils");
522
+ const { log, info, error, dir, dirxml, trace, time, timeEnd, timeLog, warn, debug, count, countReset } = console$1;
523
+ const formatInput = (input) => {
524
+ if (input instanceof Node)
525
+ return stringify2(input);
526
+ return format(input);
527
+ };
528
+ const processLog = (args) => args.map(formatInput).join(" ");
529
+ const sendLog = (type, content) => {
530
+ var _a, _b;
531
+ if (content.startsWith("[vite]"))
532
+ return;
533
+ const unknownTestId = "__vitest__unknown_test__";
534
+ const taskId = ((_b = (_a = globalThis.__vitest_worker__) == null ? void 0 : _a.current) == null ? void 0 : _b.id) ?? unknownTestId;
535
+ rpc().sendLog({
536
+ content,
537
+ time: Date$1.now(),
538
+ taskId,
539
+ type,
540
+ size: content.length
541
+ });
542
+ };
543
+ const stdout = (base) => (...args) => {
544
+ sendLog("stdout", processLog(args));
545
+ return base(...args);
546
+ };
547
+ const stderr = (base) => (...args) => {
548
+ sendLog("stderr", processLog(args));
549
+ return base(...args);
550
+ };
551
+ console$1.log = stdout(log);
552
+ console$1.debug = stdout(debug);
553
+ console$1.info = stdout(info);
554
+ console$1.error = stderr(error);
555
+ console$1.warn = stderr(warn);
556
+ console$1.dir = (item, options) => {
557
+ sendLog("stdout", utilInspect(item, options));
558
+ return dir(item, options);
559
+ };
560
+ console$1.dirxml = (...args) => {
561
+ sendLog("stdout", processLog(args));
562
+ return dirxml(...args);
563
+ };
564
+ console$1.trace = (...args) => {
565
+ const content = processLog(args);
566
+ const error2 = new Error("Trace");
567
+ const stack = (error2.stack || "").split("\n").slice(2).join("\n");
568
+ sendLog("stdout", `${content}
569
+ ${stack}`);
570
+ return trace(...args);
571
+ };
572
+ const timeLabels = {};
573
+ console$1.time = (label = "default") => {
574
+ const now = performance.now();
575
+ time(label);
576
+ timeLabels[label] = now;
577
+ };
578
+ console$1.timeLog = (label = "default") => {
579
+ timeLog(label);
580
+ if (!(label in timeLabels))
581
+ sendLog("stderr", `Timer "${label}" does not exist`);
582
+ else
583
+ sendLog("stdout", `${label}: ${timeLabels[label]} ms`);
584
+ };
585
+ console$1.timeEnd = (label = "default") => {
586
+ const end = performance.now();
587
+ timeEnd(label);
588
+ const start = timeLabels[label];
589
+ if (!(label in timeLabels)) {
590
+ sendLog("stderr", `Timer "${label}" does not exist`);
591
+ } else if (start) {
592
+ const duration = end - start;
593
+ sendLog("stdout", `${label}: ${duration} ms`);
594
+ }
595
+ };
596
+ const countLabels = {};
597
+ console$1.count = (label = "default") => {
598
+ const counter = (countLabels[label] ?? 0) + 1;
599
+ countLabels[label] = counter;
600
+ sendLog("stdout", `${label}: ${counter}`);
601
+ return count(label);
602
+ };
603
+ console$1.countReset = (label = "default") => {
604
+ countLabels[label] = 0;
605
+ return countReset(label);
606
+ };
607
+ }
608
+ function showPopupWarning(name, value, defaultValue) {
609
+ return (...params) => {
610
+ const formatedParams = params.map((p) => JSON.stringify(p)).join(", ");
611
+ console.warn(`Vitest encountered a \`${name}(${formatedParams})\` call that it cannot handle by default, so it returned \`${value}\`. Read more in https://vitest.dev/guide/browser#thread-blocking-dialogs.
612
+ If needed, mock the \`${name}\` call manually like:
613
+
614
+ \`\`\`
615
+ import { expect, vi } from "vitest"
616
+
617
+ vi.spyOn(window, "${name}")${defaultValue ? `.mockReturnValue(${JSON.stringify(defaultValue)})` : ""}
618
+ ${name}(${formatedParams})
619
+ expect(${name}).toHaveBeenCalledWith(${formatedParams})
620
+ \`\`\``);
621
+ return value;
622
+ };
623
+ }
624
+ function setupDialogsSpy() {
625
+ globalThis.alert = showPopupWarning("alert", void 0);
626
+ globalThis.confirm = showPopupWarning("confirm", false, true);
627
+ globalThis.prompt = showPopupWarning("prompt", null, "your value");
628
+ }
441
629
  class BrowserSnapshotEnvironment {
442
- constructor(client2) {
443
- this.client = client2;
630
+ getVersion() {
631
+ return "1";
632
+ }
633
+ getHeader() {
634
+ return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html`;
444
635
  }
445
636
  readSnapshotFile(filepath) {
446
- return this.client.rpc.readFile(filepath);
637
+ return rpc().readFile(filepath);
447
638
  }
448
639
  saveSnapshotFile(filepath, snapshot) {
449
- return this.client.rpc.writeFile(filepath, snapshot);
640
+ return rpc().writeFile(filepath, snapshot);
450
641
  }
451
642
  resolvePath(filepath) {
452
- return this.client.rpc.resolveSnapshotPath(filepath);
643
+ return rpc().resolveSnapshotPath(filepath);
644
+ }
645
+ resolveRawPath(testPath, rawPath) {
646
+ return rpc().resolveSnapshotRawPath(testPath, rawPath);
453
647
  }
454
648
  removeSnapshotFile(filepath) {
455
- return this.client.rpc.removeFile(filepath);
649
+ return rpc().removeFile(filepath);
456
650
  }
457
651
  async prepareDirectory(filepath) {
458
- await this.client.rpc.createDirectory(filepath);
652
+ await rpc().createDirectory(filepath);
459
653
  }
460
654
  }
461
655
  globalThis.process = { env: {}, argv: [], cwd: () => "/", stdout: { write: () => {
@@ -469,9 +663,9 @@ let runner;
469
663
  const browserHashMap = /* @__PURE__ */ new Map();
470
664
  const url = new URL(location.href);
471
665
  const testId = url.searchParams.get("id") || "unknown";
472
- const getQueryPaths = () => {
666
+ function getQueryPaths() {
473
667
  return url.searchParams.getAll("path");
474
- };
668
+ }
475
669
  const client = createClient(ENTRY_URL);
476
670
  const ws = client.ws;
477
671
  async function loadConfig() {
@@ -488,43 +682,56 @@ async function loadConfig() {
488
682
  }
489
683
  ws.addEventListener("open", async () => {
490
684
  await loadConfig();
685
+ const { getSafeTimers } = await importId("vitest/utils");
686
+ const safeRpc = createSafeRpc(client, getSafeTimers);
687
+ globalThis.__vitest_browser__ = true;
491
688
  globalThis.__vitest_worker__ = {
492
689
  config,
493
690
  browserHashMap,
494
691
  moduleCache: /* @__PURE__ */ new Map(),
495
- rpc: client.rpc
692
+ rpc: client.rpc,
693
+ safeRpc,
694
+ durations: {
695
+ environment: 0,
696
+ prepare: 0
697
+ }
496
698
  };
497
- globalThis.__vitest_mocker__ = {};
498
699
  const paths = getQueryPaths();
499
700
  const iFrame = document.getElementById("vitest-ui");
500
701
  iFrame.setAttribute("src", "/__vitest__/");
501
- await runTests(paths, config, client);
702
+ await setupConsoleLogSpy();
703
+ setupDialogsSpy();
704
+ await runTests(paths, config);
502
705
  });
503
- let hasSnapshot = false;
504
- async function runTests(paths, config2, client2) {
706
+ async function runTests(paths, config2) {
505
707
  const viteClientPath = "/@vite/client";
506
708
  await __vitePreload(() => import(viteClientPath), true ? [] : void 0);
507
- const path = "/__vitest_index__";
508
- const { startTests, setupCommonEnv, setupSnapshotEnvironment } = await __vitePreload(() => import(path), true ? [] : void 0);
709
+ const {
710
+ startTests,
711
+ setupCommonEnv,
712
+ takeCoverageInsideWorker
713
+ } = await importId("vitest/browser");
714
+ const executor = {
715
+ executeId: (id) => importId(id)
716
+ };
509
717
  if (!runner) {
510
- const runnerPath = "/__vitest_runners__";
511
- const { VitestTestRunner } = await __vitePreload(() => import(runnerPath), true ? [] : void 0);
512
- const BrowserRunner = createBrowserRunner(VitestTestRunner);
513
- runner = new BrowserRunner({ config: config2, client: client2, browserHashMap });
514
- }
515
- if (!hasSnapshot) {
516
- setupSnapshotEnvironment(new BrowserSnapshotEnvironment(client2));
517
- hasSnapshot = true;
718
+ const { VitestTestRunner } = await importId("vitest/runners");
719
+ const BrowserRunner = createBrowserRunner(VitestTestRunner, { takeCoverage: () => takeCoverageInsideWorker(config2.coverage, executor) });
720
+ runner = new BrowserRunner({ config: config2, browserHashMap });
518
721
  }
722
+ if (!config2.snapshotOptions.snapshotEnvironment)
723
+ config2.snapshotOptions.snapshotEnvironment = new BrowserSnapshotEnvironment();
519
724
  try {
520
725
  await setupCommonEnv(config2);
521
- const files = paths.map((path2) => {
522
- return `${config2.root}/${path2}`.replace(/\/+/g, "/");
726
+ const files = paths.map((path) => {
727
+ return `${config2.root}/${path}`.replace(/\/+/g, "/");
523
728
  });
524
- const now = `${new Date().getTime()}`;
729
+ const now = `${(/* @__PURE__ */ new Date()).getTime()}`;
525
730
  files.forEach((i) => browserHashMap.set(i, now));
526
- await startTests(files, runner);
731
+ for (const file of files)
732
+ await startTests([file], runner);
527
733
  } finally {
528
- await client2.rpc.onDone(testId);
734
+ await rpcDone();
735
+ await rpc().onDone(testId);
529
736
  }
530
737
  }
@@ -21,7 +21,7 @@
21
21
  border: none;
22
22
  }
23
23
  </style>
24
- <script type="module" crossorigin src="/assets/index-ca7a263d.js"></script>
24
+ <script type="module" crossorigin src="/assets/index-b8629a79.js"></script>
25
25
  </head>
26
26
  <body>
27
27
  <iframe id="vitest-ui" src=""></iframe>
package/dist/index.js CHANGED
@@ -14,16 +14,10 @@ var index = (base = "/") => {
14
14
  {
15
15
  enforce: "pre",
16
16
  name: "vitest:browser",
17
- async resolveId(id) {
18
- if (id === "/__vitest_index__")
19
- return this.resolve("vitest/browser");
20
- if (id === "/__vitest_runners__")
21
- return this.resolve("vitest/runners");
22
- if (id.startsWith("node:"))
23
- id = id.slice(5);
24
- if (polyfills.includes(id))
25
- return polyfillPath(normalizeId(id));
26
- return null;
17
+ async config(viteConfig) {
18
+ // Enables using ignore hint for coverage providers with @preserve keyword
19
+ viteConfig.esbuild || (viteConfig.esbuild = {});
20
+ viteConfig.esbuild.legalComments = "inline";
27
21
  },
28
22
  async configureServer(server) {
29
23
  server.middlewares.use(
@@ -37,8 +31,16 @@ var index = (base = "/") => {
37
31
  },
38
32
  {
39
33
  name: "modern-node-polyfills",
34
+ enforce: "pre",
35
+ config() {
36
+ return {
37
+ optimizeDeps: {
38
+ exclude: [...polyfills, ...builtinModules]
39
+ }
40
+ };
41
+ },
40
42
  async resolveId(id) {
41
- if (!builtinModules.includes(id))
43
+ if (!builtinModules.includes(id) && !polyfills.includes(id) && !id.startsWith("node:"))
42
44
  return;
43
45
  id = normalizeId(id);
44
46
  return { id: await polyfillPath(id), moduleSideEffects: false };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/browser",
3
3
  "type": "module",
4
- "version": "0.29.7",
4
+ "version": "0.30.0",
5
5
  "description": "Browser running for Vitest",
6
6
  "repository": {
7
7
  "type": "git",
@@ -27,27 +27,22 @@
27
27
  "vitest": ">=0.29.4"
28
28
  },
29
29
  "dependencies": {
30
- "local-pkg": "^0.4.2",
31
- "mlly": "^1.1.0",
32
30
  "modern-node-polyfills": "0.1.0",
33
- "rollup-plugin-node-polyfills": "^0.2.1",
34
- "sirv": "^2.0.2",
35
- "@vitest/runner": "0.29.7"
31
+ "sirv": "^2.0.2"
36
32
  },
37
33
  "devDependencies": {
38
34
  "@types/ws": "^8.5.4",
39
- "rollup": "^2.79.1",
40
- "@vitest/ws-client": "0.29.7",
41
- "@vitest/ui": "0.29.7",
42
- "vitest": "0.29.7"
35
+ "@vitest/ws-client": "0.30.0",
36
+ "@vitest/ui": "0.30.0",
37
+ "@vitest/runner": "0.30.0",
38
+ "vitest": "0.30.0"
43
39
  },
44
40
  "scripts": {
45
- "build": "rimraf dist && pnpm build:node && pnpm build:client && pnpm copy",
41
+ "build": "rimraf dist && pnpm build:node && pnpm build:client",
46
42
  "build:client": "vite build src/client",
47
43
  "build:node": "rollup -c",
48
44
  "dev:client": "vite build src/client --watch",
49
45
  "dev:node": "rollup -c --watch --watch.include src/node/index.ts",
50
- "dev": "rimraf dist && run-p dev:node dev:client",
51
- "copy": "esno scripts/copy-ui-to-browser.ts"
46
+ "dev": "rimraf dist && run-p dev:node dev:client"
52
47
  }
53
48
  }