@vitest/browser 0.30.1 → 0.31.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-d949d382.js"></script>
21
- <link rel="stylesheet" href="./assets/index-561b5dad.css">
20
+ <script type="module" crossorigin src="./assets/index-ee62cb59.js"></script>
21
+ <link rel="stylesheet" href="./assets/index-412667a2.css">
22
22
  </head>
23
23
  <body>
24
24
  <div id="app"></div>
@@ -110,9 +110,9 @@ function createBirpc(functions, options) {
110
110
  return sendEvent;
111
111
  }
112
112
  const sendCall = (...args) => {
113
- return new Promise((resolve, reject) => {
113
+ return new Promise((resolve2, reject) => {
114
114
  const id = nanoid();
115
- rpcPromiseMap.set(id, { resolve, reject });
115
+ rpcPromiseMap.set(id, { resolve: resolve2, reject });
116
116
  post(serialize({ m: method, a: args, i: id, t: "q" }));
117
117
  if (timeout >= 0) {
118
118
  setTimeout(() => {
@@ -230,6 +230,114 @@ const stringify = (value, replacer, space) => {
230
230
  return after;
231
231
  }
232
232
  };
233
+ function normalizeWindowsPath(input = "") {
234
+ if (!input || !input.includes("\\")) {
235
+ return input;
236
+ }
237
+ return input.replace(/\\/g, "/");
238
+ }
239
+ const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
240
+ function cwd() {
241
+ if (typeof process !== "undefined") {
242
+ return process.cwd().replace(/\\/g, "/");
243
+ }
244
+ return "/";
245
+ }
246
+ const resolve = function(...arguments_) {
247
+ arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
248
+ let resolvedPath = "";
249
+ let resolvedAbsolute = false;
250
+ for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
251
+ const path = index >= 0 ? arguments_[index] : cwd();
252
+ if (!path || path.length === 0) {
253
+ continue;
254
+ }
255
+ resolvedPath = `${path}/${resolvedPath}`;
256
+ resolvedAbsolute = isAbsolute(path);
257
+ }
258
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
259
+ if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
260
+ return `/${resolvedPath}`;
261
+ }
262
+ return resolvedPath.length > 0 ? resolvedPath : ".";
263
+ };
264
+ function normalizeString(path, allowAboveRoot) {
265
+ let res = "";
266
+ let lastSegmentLength = 0;
267
+ let lastSlash = -1;
268
+ let dots = 0;
269
+ let char = null;
270
+ for (let index = 0; index <= path.length; ++index) {
271
+ if (index < path.length) {
272
+ char = path[index];
273
+ } else if (char === "/") {
274
+ break;
275
+ } else {
276
+ char = "/";
277
+ }
278
+ if (char === "/") {
279
+ if (lastSlash === index - 1 || dots === 1)
280
+ ;
281
+ else if (dots === 2) {
282
+ if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
283
+ if (res.length > 2) {
284
+ const lastSlashIndex = res.lastIndexOf("/");
285
+ if (lastSlashIndex === -1) {
286
+ res = "";
287
+ lastSegmentLength = 0;
288
+ } else {
289
+ res = res.slice(0, lastSlashIndex);
290
+ lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
291
+ }
292
+ lastSlash = index;
293
+ dots = 0;
294
+ continue;
295
+ } else if (res.length > 0) {
296
+ res = "";
297
+ lastSegmentLength = 0;
298
+ lastSlash = index;
299
+ dots = 0;
300
+ continue;
301
+ }
302
+ }
303
+ if (allowAboveRoot) {
304
+ res += res.length > 0 ? "/.." : "..";
305
+ lastSegmentLength = 2;
306
+ }
307
+ } else {
308
+ if (res.length > 0) {
309
+ res += `/${path.slice(lastSlash + 1, index)}`;
310
+ } else {
311
+ res = path.slice(lastSlash + 1, index);
312
+ }
313
+ lastSegmentLength = index - lastSlash - 1;
314
+ }
315
+ lastSlash = index;
316
+ dots = 0;
317
+ } else if (char === "." && dots !== -1) {
318
+ ++dots;
319
+ } else {
320
+ dots = -1;
321
+ }
322
+ }
323
+ return res;
324
+ }
325
+ const isAbsolute = function(p) {
326
+ return _IS_ABSOLUTE_RE.test(p);
327
+ };
328
+ const relative = function(from, to) {
329
+ const _from = resolve(from).split("/");
330
+ const _to = resolve(to).split("/");
331
+ const _fromCopy = [..._from];
332
+ for (const segment of _fromCopy) {
333
+ if (_to[0] !== segment) {
334
+ break;
335
+ }
336
+ _from.shift();
337
+ _to.shift();
338
+ }
339
+ return [..._from.map(() => ".."), ..._to].join("/");
340
+ };
233
341
  function isAggregateError(err) {
234
342
  if (typeof AggregateError !== "undefined" && err instanceof AggregateError)
235
343
  return true;
@@ -331,6 +439,26 @@ class StateManager {
331
439
  task.logs.push(log);
332
440
  }
333
441
  }
442
+ getCountOfFailedTests() {
443
+ return Array.from(this.idMap.values()).filter((t) => {
444
+ var _a;
445
+ return ((_a = t.result) == null ? void 0 : _a.state) === "fail";
446
+ }).length;
447
+ }
448
+ cancelFiles(files, root) {
449
+ this.collectFiles(files.map((filepath) => ({
450
+ filepath,
451
+ name: relative(root, filepath),
452
+ id: filepath,
453
+ mode: "skip",
454
+ type: "suite",
455
+ result: {
456
+ state: "skip"
457
+ },
458
+ // Cancelled files have not yet collected tests
459
+ tasks: []
460
+ })));
461
+ }
334
462
  }
335
463
  function createClient(url2, options = {}) {
336
464
  const {
@@ -373,6 +501,10 @@ function createClient(url2, options = {}) {
373
501
  onFinished(files) {
374
502
  var _a;
375
503
  (_a = handlers.onFinished) == null ? void 0 : _a.call(handlers, files);
504
+ },
505
+ onCancel(reason) {
506
+ var _a;
507
+ (_a = handlers.onCancel) == null ? void 0 : _a.call(handlers, reason);
376
508
  }
377
509
  };
378
510
  const birpcHandlers = {
@@ -393,10 +525,10 @@ function createClient(url2, options = {}) {
393
525
  registerWS();
394
526
  }
395
527
  function registerWS() {
396
- openPromise = new Promise((resolve) => {
528
+ openPromise = new Promise((resolve2) => {
397
529
  ctx.ws.addEventListener("open", () => {
398
530
  tries = reconnectTries;
399
- resolve();
531
+ resolve2();
400
532
  });
401
533
  });
402
534
  ctx.ws.addEventListener("message", (v) => {
@@ -482,11 +614,19 @@ function createBrowserRunner(original, coverageModule) {
482
614
  this.hashMap = options.browserHashMap;
483
615
  }
484
616
  async onAfterRunTest(task) {
485
- var _a, _b, _c;
486
- await ((_a = super.onAfterRunTest) == null ? void 0 : _a.call(this));
617
+ var _a, _b, _c, _d, _e;
618
+ await ((_a = super.onAfterRunTest) == null ? void 0 : _a.call(this, task));
487
619
  (_c = (_b = task.result) == null ? void 0 : _b.errors) == null ? void 0 : _c.forEach((error) => {
488
620
  console.error(error.message);
489
621
  });
622
+ if (this.config.bail && ((_d = task.result) == null ? void 0 : _d.state) === "fail") {
623
+ const previousFailures = await rpc().getCountOfFailedTests();
624
+ const currentFailures = 1 + previousFailures;
625
+ if (currentFailures >= this.config.bail) {
626
+ rpc().onCancel("test-failure");
627
+ (_e = this.onCancel) == null ? void 0 : _e.call(this, "test-failure");
628
+ }
629
+ }
490
630
  }
491
631
  async onAfterRunSuite() {
492
632
  var _a, _b;
@@ -501,20 +641,19 @@ function createBrowserRunner(original, coverageModule) {
501
641
  return rpc().onTaskUpdate(task);
502
642
  }
503
643
  async importFile(filepath) {
504
- const match = filepath.match(/^(\w:\/)/);
505
- let hash = this.hashMap.get(filepath);
506
- if (!hash) {
644
+ let [test, hash] = this.hashMap.get(filepath) ?? [false, ""];
645
+ if (hash === "") {
507
646
  hash = Date.now().toString();
508
- this.hashMap.set(filepath, hash);
647
+ this.hashMap.set(filepath, [false, hash]);
509
648
  }
510
- const importpath = match ? `/@fs/${filepath.slice(match[1].length)}?v=${hash}` : `${filepath}?v=${hash}`;
649
+ const importpath = /^\w:/.test(filepath) ? `/@fs/${filepath}?${test ? "browserv" : "v"}=${hash}` : `${filepath}?${test ? "browserv" : "v"}=${hash}`;
511
650
  await __vitePreload(() => import(importpath), true ? [] : void 0);
512
651
  }
513
652
  };
514
653
  }
515
654
  function importId(id) {
516
655
  const name = `/@id/${id}`;
517
- return __vitePreload(() => import(name), true ? [] : void 0);
656
+ return __vi_wrap_module__(__vitePreload(() => import(name), true ? [] : void 0));
518
657
  }
519
658
  const { Date: Date$1, console: console$1 } = globalThis;
520
659
  async function setupConsoleLogSpy() {
@@ -652,6 +791,25 @@ class BrowserSnapshotEnvironment {
652
791
  await rpc().createDirectory(dirPath);
653
792
  }
654
793
  }
794
+ function throwNotImplemented(name) {
795
+ throw new Error(`[vitest] ${name} is not implemented in browser environment yet.`);
796
+ }
797
+ class VitestBrowserClientMocker {
798
+ importActual() {
799
+ throwNotImplemented("importActual");
800
+ }
801
+ importMock() {
802
+ throwNotImplemented("importMock");
803
+ }
804
+ queueMock() {
805
+ throwNotImplemented("queueMock");
806
+ }
807
+ queueUnmock() {
808
+ throwNotImplemented("queueUnmock");
809
+ }
810
+ prepare() {
811
+ }
812
+ }
655
813
  globalThis.process = { env: {}, argv: [], cwd: () => "/", stdout: { write: () => {
656
814
  } }, nextTick: (cb) => cb() };
657
815
  globalThis.global = globalThis;
@@ -666,13 +824,22 @@ const testId = url.searchParams.get("id") || "unknown";
666
824
  function getQueryPaths() {
667
825
  return url.searchParams.getAll("path");
668
826
  }
669
- const client = createClient(ENTRY_URL);
827
+ let setCancel = (_) => {
828
+ };
829
+ const onCancel = new Promise((resolve2) => {
830
+ setCancel = resolve2;
831
+ });
832
+ const client = createClient(ENTRY_URL, {
833
+ handlers: {
834
+ onCancel: setCancel
835
+ }
836
+ });
670
837
  const ws = client.ws;
671
838
  async function loadConfig() {
672
839
  let retries = 5;
673
840
  do {
674
841
  try {
675
- await new Promise((resolve) => setTimeout(resolve, 150));
842
+ await new Promise((resolve2) => setTimeout(resolve2, 150));
676
843
  config = await client.rpc.getConfig();
677
844
  return;
678
845
  } catch (_) {
@@ -688,7 +855,8 @@ ws.addEventListener("open", async () => {
688
855
  globalThis.__vitest_worker__ = {
689
856
  config,
690
857
  browserHashMap,
691
- moduleCache: /* @__PURE__ */ new Map(),
858
+ // @ts-expect-error untyped global for internal use
859
+ moduleCache: globalThis.__vi_module_cache__,
692
860
  rpc: client.rpc,
693
861
  safeRpc,
694
862
  durations: {
@@ -696,6 +864,7 @@ ws.addEventListener("open", async () => {
696
864
  prepare: 0
697
865
  }
698
866
  };
867
+ globalThis.__vitest_mocker__ = new VitestBrowserClientMocker();
699
868
  const paths = getQueryPaths();
700
869
  const iFrame = document.getElementById("vitest-ui");
701
870
  iFrame.setAttribute("src", "/__vitest__/");
@@ -719,6 +888,10 @@ async function runTests(paths, config2) {
719
888
  const BrowserRunner = createBrowserRunner(VitestTestRunner, { takeCoverage: () => takeCoverageInsideWorker(config2.coverage, executor) });
720
889
  runner = new BrowserRunner({ config: config2, browserHashMap });
721
890
  }
891
+ onCancel.then((reason) => {
892
+ var _a;
893
+ (_a = runner == null ? void 0 : runner.onCancel) == null ? void 0 : _a.call(runner, reason);
894
+ });
722
895
  if (!config2.snapshotOptions.snapshotEnvironment)
723
896
  config2.snapshotOptions.snapshotEnvironment = new BrowserSnapshotEnvironment();
724
897
  try {
@@ -727,7 +900,7 @@ async function runTests(paths, config2) {
727
900
  return `${config2.root}/${path}`.replace(/\/+/g, "/");
728
901
  });
729
902
  const now = `${(/* @__PURE__ */ new Date()).getTime()}`;
730
- files.forEach((i) => browserHashMap.set(i, now));
903
+ files.forEach((i) => browserHashMap.set(i, [true, now]));
731
904
  for (const file of files)
732
905
  await startTests([file], runner);
733
906
  } finally {
@@ -21,10 +21,59 @@
21
21
  border: none;
22
22
  }
23
23
  </style>
24
- <script type="module" crossorigin src="/assets/index-8a9c2d7a.js"></script>
24
+ <script type="module" crossorigin src="/assets/index-5fc20d62.js"></script>
25
25
  </head>
26
26
  <body>
27
27
  <iframe id="vitest-ui" src=""></iframe>
28
+ <script>
29
+ const moduleCache = new Map()
30
+
31
+ // this method receives a module object or "import" promise that it resolves and keeps track of
32
+ // and returns a hijacked module object that can be used to mock module exports
33
+ function wrapModule(module) {
34
+ if (module instanceof Promise) {
35
+ moduleCache.set(module, { promise: module, evaluated: false })
36
+ return module
37
+ .then(m => m.__vi_inject__)
38
+ .finally(() => moduleCache.delete(module))
39
+ }
40
+ return module.__vi_inject__
41
+ }
42
+
43
+ function exportAll(exports, sourceModule) {
44
+ // #1120 when a module exports itself it causes
45
+ // call stack error
46
+ if (exports === sourceModule)
47
+ return
48
+
49
+ if (Object(sourceModule) !== sourceModule || Array.isArray(sourceModule))
50
+ return
51
+
52
+ for (const key in sourceModule) {
53
+ if (key !== 'default') {
54
+ try {
55
+ Object.defineProperty(exports, key, {
56
+ enumerable: true,
57
+ configurable: true,
58
+ get: () => sourceModule[key],
59
+ })
60
+ }
61
+ catch (_err) { }
62
+ }
63
+ }
64
+ }
65
+
66
+ window.__vi_export_all__ = exportAll
67
+
68
+ // TODO: allow easier rewriting of import.meta.env
69
+ window.__vi_import_meta__ = {
70
+ env: {},
71
+ url: location.href,
72
+ }
73
+
74
+ window.__vi_module_cache__ = moduleCache
75
+ window.__vi_wrap_module__ = wrapModule
76
+ </script>
28
77
 
29
78
  </body>
30
79
  </html>
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- declare const _default: (base?: string) => Plugin[];
3
+ declare const _default: (project: any, base?: string) => Plugin[];
4
4
 
5
5
  export { _default as default };