@vitest/browser 5.0.0-beta.7 → 5.0.0-rc.2

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/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { distClientRoot } from '@vitest/ui';
6
6
  import { slash as slash$1, deepMerge, cleanUrl as cleanUrl$1, toArray } from '@vitest/utils/helpers';
7
7
  import sirv from 'sirv';
8
8
  import c from 'tinyrainbow';
9
- import { isFileLoadingAllowed, createDebugger, isValidApiRequest, isCSSRequest, distDir, rolldownVersion, isFileServingAllowed } from 'vitest/node';
9
+ import { isFileLoadingAllowed, createDebugger, isValidApiRequest, BrowserConnectionError, isCSSRequest, distDir, rolldownVersion, isFileServingAllowed } from 'vitest/node';
10
10
  import { fileURLToPath } from 'node:url';
11
11
  import crypto from 'node:crypto';
12
12
  import MagicString from 'magic-string';
@@ -209,7 +209,7 @@ const basename = function(p, extension) {
209
209
  return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
210
210
  };
211
211
 
212
- var version = "5.0.0-beta.7";
212
+ var version = "5.0.0-rc.2";
213
213
 
214
214
  const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
215
215
  const distRoot = resolve(pkgRoot, "dist");
@@ -509,11 +509,10 @@ var DOM_KEY_LOCATION = /*#__PURE__*/ function(DOM_KEY_LOCATION) {
509
509
  }
510
510
  ];
511
511
 
512
- var bracketDict = /*#__PURE__*/ function(bracketDict) {
513
- bracketDict["{"] = "}";
514
- bracketDict["["] = "]";
515
- return bracketDict;
516
- }(bracketDict || {});
512
+ const bracketDict = {
513
+ '{': '}',
514
+ '[': ']'
515
+ };
517
516
  /**
518
517
  * Read the next key definition from user input
519
518
  *
@@ -548,16 +547,16 @@ function readPrintableChar(text, pos, context) {
548
547
  };
549
548
  }
550
549
  function readTag(text, pos, startBracket, context) {
550
+ var _ref;
551
551
  var _text_slice_match, _text_slice_match1;
552
552
  const releasePreviousModifier = text[pos] === '/' ? '/' : '';
553
553
  pos += releasePreviousModifier.length;
554
554
  const escapedDescriptor = startBracket === '{' && text[pos] === '\\';
555
555
  pos += Number(escapedDescriptor);
556
- const descriptor = escapedDescriptor ? text[pos] : (_text_slice_match = text.slice(pos).match(startBracket === '{' ? /^\w+|^[^}>/]/ : /^\w+/)) === null || _text_slice_match === undefined ? undefined : _text_slice_match[0];
556
+ const descriptor = escapedDescriptor ? text[pos] : (_text_slice_match = text.slice(pos).match(startBracket === '{' ? /^\w+|^[^}>/]/ : /^\w+/)) === null || _text_slice_match === void 0 ? void 0 : _text_slice_match[0];
557
557
  assertDescriptor(descriptor, text, pos);
558
558
  pos += descriptor.length;
559
- var _text_slice_match_;
560
- const repeatModifier = (_text_slice_match_ = (_text_slice_match1 = text.slice(pos).match(/^>\d+/)) === null || _text_slice_match1 === undefined ? undefined : _text_slice_match1[0]) !== null && _text_slice_match_ !== undefined ? _text_slice_match_ : '';
559
+ const repeatModifier = (_ref = (_text_slice_match1 = text.slice(pos).match(/^>\d+/)) === null || _text_slice_match1 === void 0 ? void 0 : _text_slice_match1[0]) !== null && _ref !== void 0 ? _ref : '';
561
560
  pos += repeatModifier.length;
562
561
  const releaseSelfModifier = text[pos] === '/' || !repeatModifier && text[pos] === '>' ? text[pos] : '';
563
562
  pos += releaseSelfModifier.length;
@@ -593,7 +592,7 @@ function hasReleaseSelf(releaseSelfModifier, repeatModifier) {
593
592
  }
594
593
  }
595
594
  function getErrorMessage(expected, found, text, context) {
596
- return `Expected ${expected} but found "${found !== null && found !== undefined ? found : ''}" in "${text}"
595
+ return `Expected ${expected} but found "${found !== null && found !== void 0 ? found : ''}" in "${text}"
597
596
  See ${`https://testing-library.com/docs/user-event/keyboard`}
598
597
  for more information about how userEvent parses your input.`;
599
598
  }
@@ -610,18 +609,18 @@ function getErrorMessage(expected, found, text, context) {
610
609
  */ function parseKeyDef$1(keyboardMap, text) {
611
610
  const defs = [];
612
611
  do {
613
- const { type, descriptor, consumedLength, releasePrevious, releaseSelf = true, repeat } = readNextDescriptor(text);
614
612
  var _keyboardMap_find;
613
+ const { type, descriptor, consumedLength, releasePrevious, releaseSelf = true, repeat } = readNextDescriptor(text);
615
614
  const keyDef = (_keyboardMap_find = keyboardMap.find((def)=>{
616
615
  if (type === '[') {
617
616
  var _def_code;
618
- return ((_def_code = def.code) === null || _def_code === undefined ? undefined : _def_code.toLowerCase()) === descriptor.toLowerCase();
617
+ return ((_def_code = def.code) === null || _def_code === void 0 ? void 0 : _def_code.toLowerCase()) === descriptor.toLowerCase();
619
618
  } else if (type === '{') {
620
619
  var _def_key;
621
- return ((_def_key = def.key) === null || _def_key === undefined ? undefined : _def_key.toLowerCase()) === descriptor.toLowerCase();
620
+ return ((_def_key = def.key) === null || _def_key === void 0 ? void 0 : _def_key.toLowerCase()) === descriptor.toLowerCase();
622
621
  }
623
622
  return def.key === descriptor;
624
- })) !== null && _keyboardMap_find !== undefined ? _keyboardMap_find : {
623
+ })) !== null && _keyboardMap_find !== void 0 ? _keyboardMap_find : {
625
624
  key: 'Unknown',
626
625
  code: 'Unknown',
627
626
  [type === '[' ? 'code' : 'key']: descriptor
@@ -968,6 +967,7 @@ var BrowserPlugin = (contribution) => {
968
967
  BrowserContext(contribution),
969
968
  dynamicImportPlugin({
970
969
  globalThisAccessor: "\"__vitest_browser_runner__\"",
970
+ // injected only into the `client` environment via the browser contribution
971
971
  filter(id) {
972
972
  if (id.includes(distRoot)) {
973
973
  return false;
@@ -1025,6 +1025,8 @@ function cleanUrl(url) {
1025
1025
  }
1026
1026
 
1027
1027
  class BrowserServerCDPHandler {
1028
+ session;
1029
+ tester;
1028
1030
  listenerIds = {};
1029
1031
  listeners = {};
1030
1032
  constructor(session, tester) {
@@ -1668,6 +1670,7 @@ function getComparator(comparator, context) {
1668
1670
 
1669
1671
  const defaultOptions = {
1670
1672
  comparatorName: "pixelmatch",
1673
+ // these are handled by each comparator on its own
1671
1674
  comparatorOptions: {},
1672
1675
  screenshotOptions: {
1673
1676
  animations: "disabled",
@@ -1722,6 +1725,7 @@ function resolveOptions({ context, name, options, testName }) {
1722
1725
  resolvedOptions,
1723
1726
  paths: {
1724
1727
  reference: resolvedOptions.resolveScreenshotPath(resolvePathData),
1728
+ // lazily initialize this, as it might not be needed at all
1725
1729
  get diffs() {
1726
1730
  const diffs = {
1727
1731
  reference: resolvedOptions.resolveDiffPath({
@@ -1967,6 +1971,7 @@ async function determineOutcome({ comparator, comparatorOptions, paths, referenc
1967
1971
  diff: comparisonResult.diff && {
1968
1972
  image: {
1969
1973
  data: comparisonResult.diff,
1974
+ // `comparator` only returns pixel data; diff dimensions always match reference
1970
1975
  metadata: reference.metadata
1971
1976
  },
1972
1977
  path: paths.diffs.diff
@@ -2202,6 +2207,7 @@ var builtinCommands = {
2202
2207
  readFile,
2203
2208
  removeFile,
2204
2209
  writeFile,
2210
+ // private commands
2205
2211
  __vitest_markTrace: _markTrace,
2206
2212
  __vitest_groupTraceStart: _groupTraceStart,
2207
2213
  __vitest_groupTraceEnd: _groupTraceEnd,
@@ -2217,6 +2223,9 @@ class BrowserServerState {
2217
2223
  }
2218
2224
 
2219
2225
  class ProjectBrowser {
2226
+ parent;
2227
+ project;
2228
+ base;
2220
2229
  testerHtml;
2221
2230
  testerFilepath;
2222
2231
  // the tester template is read once per server, so the transformed HTML
@@ -2304,6 +2313,7 @@ function wrapConfig(config) {
2304
2313
  }
2305
2314
 
2306
2315
  class ParentBrowserProject {
2316
+ base;
2307
2317
  orchestratorScripts;
2308
2318
  faviconUrl;
2309
2319
  prefixOrchestratorUrl;
@@ -2486,11 +2496,348 @@ class ParentBrowserProject {
2486
2496
  }
2487
2497
  }
2488
2498
 
2489
- //#region src/messages.ts
2490
- const TYPE_REQUEST = "q";
2491
- const TYPE_RESPONSE = "s";
2499
+ function _mergeNamespaces$1(n, m) {
2500
+ m.forEach(function(e) {
2501
+ e && typeof e !== "string" && !Array.isArray(e) && Object.keys(e).forEach(function(k) {
2502
+ if (k !== "default" && !(k in n)) {
2503
+ var d = Object.getOwnPropertyDescriptor(e, k);
2504
+ Object.defineProperty(n, k, d.get ? d : {
2505
+ enumerable: true,
2506
+ get: function() {
2507
+ return e[k];
2508
+ }
2509
+ });
2510
+ }
2511
+ });
2512
+ });
2513
+ return Object.freeze(n);
2514
+ }
2515
+ function getDefaultExportFromCjs(x) {
2516
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
2517
+ }
2518
+ var reactIs$1 = { exports: {} };
2519
+ var reactIs_production = {};
2520
+ /**
2521
+ * @license React
2522
+ * react-is.production.js
2523
+ *
2524
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
2525
+ *
2526
+ * This source code is licensed under the MIT license found in the
2527
+ * LICENSE file in the root directory of this source tree.
2528
+ */
2529
+ var hasRequiredReactIs_production;
2530
+ function requireReactIs_production() {
2531
+ if (hasRequiredReactIs_production) return reactIs_production;
2532
+ hasRequiredReactIs_production = 1;
2533
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_VIEW_TRANSITION_TYPE = Symbol.for("react.view_transition"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference");
2534
+ function typeOf(object) {
2535
+ if ("object" === typeof object && null !== object) {
2536
+ var $$typeof = object.$$typeof;
2537
+ switch ($$typeof) {
2538
+ case REACT_ELEMENT_TYPE: switch (object = object.type, object) {
2539
+ case REACT_FRAGMENT_TYPE:
2540
+ case REACT_PROFILER_TYPE:
2541
+ case REACT_STRICT_MODE_TYPE:
2542
+ case REACT_SUSPENSE_TYPE:
2543
+ case REACT_SUSPENSE_LIST_TYPE:
2544
+ case REACT_VIEW_TRANSITION_TYPE: return object;
2545
+ default: switch (object = object && object.$$typeof, object) {
2546
+ case REACT_CONTEXT_TYPE:
2547
+ case REACT_FORWARD_REF_TYPE:
2548
+ case REACT_LAZY_TYPE:
2549
+ case REACT_MEMO_TYPE: return object;
2550
+ case REACT_CONSUMER_TYPE: return object;
2551
+ default: return $$typeof;
2552
+ }
2553
+ }
2554
+ case REACT_PORTAL_TYPE: return $$typeof;
2555
+ }
2556
+ }
2557
+ }
2558
+ reactIs_production.ContextConsumer = REACT_CONSUMER_TYPE;
2559
+ reactIs_production.ContextProvider = REACT_CONTEXT_TYPE;
2560
+ reactIs_production.Element = REACT_ELEMENT_TYPE;
2561
+ reactIs_production.ForwardRef = REACT_FORWARD_REF_TYPE;
2562
+ reactIs_production.Fragment = REACT_FRAGMENT_TYPE;
2563
+ reactIs_production.Lazy = REACT_LAZY_TYPE;
2564
+ reactIs_production.Memo = REACT_MEMO_TYPE;
2565
+ reactIs_production.Portal = REACT_PORTAL_TYPE;
2566
+ reactIs_production.Profiler = REACT_PROFILER_TYPE;
2567
+ reactIs_production.StrictMode = REACT_STRICT_MODE_TYPE;
2568
+ reactIs_production.Suspense = REACT_SUSPENSE_TYPE;
2569
+ reactIs_production.SuspenseList = REACT_SUSPENSE_LIST_TYPE;
2570
+ reactIs_production.isContextConsumer = function(object) {
2571
+ return typeOf(object) === REACT_CONSUMER_TYPE;
2572
+ };
2573
+ reactIs_production.isContextProvider = function(object) {
2574
+ return typeOf(object) === REACT_CONTEXT_TYPE;
2575
+ };
2576
+ reactIs_production.isElement = function(object) {
2577
+ return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
2578
+ };
2579
+ reactIs_production.isForwardRef = function(object) {
2580
+ return typeOf(object) === REACT_FORWARD_REF_TYPE;
2581
+ };
2582
+ reactIs_production.isFragment = function(object) {
2583
+ return typeOf(object) === REACT_FRAGMENT_TYPE;
2584
+ };
2585
+ reactIs_production.isLazy = function(object) {
2586
+ return typeOf(object) === REACT_LAZY_TYPE;
2587
+ };
2588
+ reactIs_production.isMemo = function(object) {
2589
+ return typeOf(object) === REACT_MEMO_TYPE;
2590
+ };
2591
+ reactIs_production.isPortal = function(object) {
2592
+ return typeOf(object) === REACT_PORTAL_TYPE;
2593
+ };
2594
+ reactIs_production.isProfiler = function(object) {
2595
+ return typeOf(object) === REACT_PROFILER_TYPE;
2596
+ };
2597
+ reactIs_production.isStrictMode = function(object) {
2598
+ return typeOf(object) === REACT_STRICT_MODE_TYPE;
2599
+ };
2600
+ reactIs_production.isSuspense = function(object) {
2601
+ return typeOf(object) === REACT_SUSPENSE_TYPE;
2602
+ };
2603
+ reactIs_production.isSuspenseList = function(object) {
2604
+ return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;
2605
+ };
2606
+ reactIs_production.isValidElementType = function(type) {
2607
+ return "string" === typeof type || "function" === typeof type || type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || "object" === typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_CLIENT_REFERENCE || void 0 !== type.getModuleId) ? true : false;
2608
+ };
2609
+ reactIs_production.typeOf = typeOf;
2610
+ return reactIs_production;
2611
+ }
2612
+ var hasRequiredReactIs$1;
2613
+ function requireReactIs$1() {
2614
+ if (hasRequiredReactIs$1) return reactIs$1.exports;
2615
+ hasRequiredReactIs$1 = 1;
2616
+ {
2617
+ reactIs$1.exports = requireReactIs_production();
2618
+ }
2619
+ return reactIs$1.exports;
2620
+ }
2621
+ var reactIsExports$1 = requireReactIs$1();
2622
+ var index$1 = /*@__PURE__*/ getDefaultExportFromCjs(reactIsExports$1);
2623
+ var ReactIs19 = /*#__PURE__*/ _mergeNamespaces$1({
2624
+ __proto__: null,
2625
+ default: index$1
2626
+ }, [reactIsExports$1]);
2627
+ var reactIs = { exports: {} };
2628
+ var reactIs_production_min = {};
2629
+ /**
2630
+ * @license React
2631
+ * react-is.production.min.js
2632
+ *
2633
+ * Copyright (c) Facebook, Inc. and its affiliates.
2634
+ *
2635
+ * This source code is licensed under the MIT license found in the
2636
+ * LICENSE file in the root directory of this source tree.
2637
+ */
2638
+ var hasRequiredReactIs_production_min;
2639
+ function requireReactIs_production_min() {
2640
+ if (hasRequiredReactIs_production_min) return reactIs_production_min;
2641
+ hasRequiredReactIs_production_min = 1;
2642
+ var b = Symbol.for("react.element"), c = Symbol.for("react.portal"), d = Symbol.for("react.fragment"), e = Symbol.for("react.strict_mode"), f = Symbol.for("react.profiler"), g = Symbol.for("react.provider"), h = Symbol.for("react.context"), k = Symbol.for("react.server_context"), l = Symbol.for("react.forward_ref"), m = Symbol.for("react.suspense"), n = Symbol.for("react.suspense_list"), p = Symbol.for("react.memo"), q = Symbol.for("react.lazy"), t = Symbol.for("react.offscreen"), u;
2643
+ u = Symbol.for("react.module.reference");
2644
+ function v(a) {
2645
+ if ("object" === typeof a && null !== a) {
2646
+ var r = a.$$typeof;
2647
+ switch (r) {
2648
+ case b: switch (a = a.type, a) {
2649
+ case d:
2650
+ case f:
2651
+ case e:
2652
+ case m:
2653
+ case n: return a;
2654
+ default: switch (a = a && a.$$typeof, a) {
2655
+ case k:
2656
+ case h:
2657
+ case l:
2658
+ case q:
2659
+ case p:
2660
+ case g: return a;
2661
+ default: return r;
2662
+ }
2663
+ }
2664
+ case c: return r;
2665
+ }
2666
+ }
2667
+ }
2668
+ reactIs_production_min.ContextConsumer = h;
2669
+ reactIs_production_min.ContextProvider = g;
2670
+ reactIs_production_min.Element = b;
2671
+ reactIs_production_min.ForwardRef = l;
2672
+ reactIs_production_min.Fragment = d;
2673
+ reactIs_production_min.Lazy = q;
2674
+ reactIs_production_min.Memo = p;
2675
+ reactIs_production_min.Portal = c;
2676
+ reactIs_production_min.Profiler = f;
2677
+ reactIs_production_min.StrictMode = e;
2678
+ reactIs_production_min.Suspense = m;
2679
+ reactIs_production_min.SuspenseList = n;
2680
+ reactIs_production_min.isAsyncMode = function() {
2681
+ return false;
2682
+ };
2683
+ reactIs_production_min.isConcurrentMode = function() {
2684
+ return false;
2685
+ };
2686
+ reactIs_production_min.isContextConsumer = function(a) {
2687
+ return v(a) === h;
2688
+ };
2689
+ reactIs_production_min.isContextProvider = function(a) {
2690
+ return v(a) === g;
2691
+ };
2692
+ reactIs_production_min.isElement = function(a) {
2693
+ return "object" === typeof a && null !== a && a.$$typeof === b;
2694
+ };
2695
+ reactIs_production_min.isForwardRef = function(a) {
2696
+ return v(a) === l;
2697
+ };
2698
+ reactIs_production_min.isFragment = function(a) {
2699
+ return v(a) === d;
2700
+ };
2701
+ reactIs_production_min.isLazy = function(a) {
2702
+ return v(a) === q;
2703
+ };
2704
+ reactIs_production_min.isMemo = function(a) {
2705
+ return v(a) === p;
2706
+ };
2707
+ reactIs_production_min.isPortal = function(a) {
2708
+ return v(a) === c;
2709
+ };
2710
+ reactIs_production_min.isProfiler = function(a) {
2711
+ return v(a) === f;
2712
+ };
2713
+ reactIs_production_min.isStrictMode = function(a) {
2714
+ return v(a) === e;
2715
+ };
2716
+ reactIs_production_min.isSuspense = function(a) {
2717
+ return v(a) === m;
2718
+ };
2719
+ reactIs_production_min.isSuspenseList = function(a) {
2720
+ return v(a) === n;
2721
+ };
2722
+ reactIs_production_min.isValidElementType = function(a) {
2723
+ return "string" === typeof a || "function" === typeof a || a === d || a === f || a === e || a === m || a === n || a === t || "object" === typeof a && null !== a && (a.$$typeof === q || a.$$typeof === p || a.$$typeof === g || a.$$typeof === h || a.$$typeof === l || a.$$typeof === u || void 0 !== a.getModuleId) ? true : false;
2724
+ };
2725
+ reactIs_production_min.typeOf = v;
2726
+ return reactIs_production_min;
2727
+ }
2728
+ var hasRequiredReactIs;
2729
+ function requireReactIs() {
2730
+ if (hasRequiredReactIs) return reactIs.exports;
2731
+ hasRequiredReactIs = 1;
2732
+ {
2733
+ reactIs.exports = requireReactIs_production_min();
2734
+ }
2735
+ return reactIs.exports;
2736
+ }
2737
+ var reactIsExports = requireReactIs();
2738
+ var index = /*@__PURE__*/ getDefaultExportFromCjs(reactIsExports);
2739
+ var ReactIs18 = /*#__PURE__*/ _mergeNamespaces$1({
2740
+ __proto__: null,
2741
+ default: index
2742
+ }, [reactIsExports]);
2743
+ const reactIsMethods = [
2744
+ "isAsyncMode",
2745
+ "isConcurrentMode",
2746
+ "isContextConsumer",
2747
+ "isContextProvider",
2748
+ "isElement",
2749
+ "isForwardRef",
2750
+ "isFragment",
2751
+ "isLazy",
2752
+ "isMemo",
2753
+ "isPortal",
2754
+ "isProfiler",
2755
+ "isStrictMode",
2756
+ "isSuspense",
2757
+ "isSuspenseList",
2758
+ "isValidElementType"
2759
+ ];
2760
+ Object.fromEntries(reactIsMethods.map((m) => [m, (v) => ReactIs18[m](v) || ReactIs19[m](v)]));
2761
+
2762
+ var naturalCompare = {exports: {}};
2763
+
2764
+ var hasRequiredNaturalCompare;
2765
+
2766
+ function requireNaturalCompare () {
2767
+ if (hasRequiredNaturalCompare) return naturalCompare.exports;
2768
+ hasRequiredNaturalCompare = 1;
2769
+ /*
2770
+ * @version 1.4.0
2771
+ * @date 2015-10-26
2772
+ * @stability 3 - Stable
2773
+ * @author Lauri Rooden (https://github.com/litejs/natural-compare-lite)
2774
+ * @license MIT License
2775
+ */
2776
+
2777
+
2778
+ var naturalCompare$1 = function(a, b) {
2779
+ var i, codeA
2780
+ , codeB = 1
2781
+ , posA = 0
2782
+ , posB = 0
2783
+ , alphabet = String.alphabet;
2784
+
2785
+ function getCode(str, pos, code) {
2786
+ if (code) {
2787
+ for (i = pos; code = getCode(str, i), code < 76 && code > 65;) ++i;
2788
+ return +str.slice(pos - 1, i)
2789
+ }
2790
+ code = alphabet && alphabet.indexOf(str.charAt(pos));
2791
+ return code > -1 ? code + 76 : ((code = str.charCodeAt(pos) || 0), code < 45 || code > 127) ? code
2792
+ : code < 46 ? 65 // -
2793
+ : code < 48 ? code - 1
2794
+ : code < 58 ? code + 18 // 0-9
2795
+ : code < 65 ? code - 11
2796
+ : code < 91 ? code + 11 // A-Z
2797
+ : code < 97 ? code - 37
2798
+ : code < 123 ? code + 5 // a-z
2799
+ : code - 63
2800
+ }
2801
+
2802
+
2803
+ if ((a+="") != (b+="")) for (;codeB;) {
2804
+ codeA = getCode(a, posA++);
2805
+ codeB = getCode(b, posB++);
2806
+
2807
+ if (codeA < 76 && codeB < 76 && codeA > 66 && codeB > 66) {
2808
+ codeA = getCode(a, posA, posA);
2809
+ codeB = getCode(b, posB, posA = i);
2810
+ posB = i;
2811
+ }
2812
+
2813
+ if (codeA != codeB) return (codeA < codeB) ? -1 : 1
2814
+ }
2815
+ return 0
2816
+ };
2817
+
2818
+ try {
2819
+ naturalCompare.exports = naturalCompare$1;
2820
+ } catch (e) {
2821
+ String.naturalCompare = naturalCompare$1;
2822
+ }
2823
+ return naturalCompare.exports;
2824
+ }
2825
+
2826
+ requireNaturalCompare();
2827
+
2828
+ // Evaluate a snapshot file's content into its snapshot key/value pairs.
2829
+ function evaluateSnapshotFile(filepath, content) {
2830
+ const data = Object.create(null);
2831
+ try {
2832
+ // eslint-disable-next-line no-new-func
2833
+ const populate = new Function("exports", content);
2834
+ populate(data);
2835
+ } catch (cause) {
2836
+ throw new Error(`Invalid snapshot file, please manually fix or delete it: ${filepath}`, { cause });
2837
+ }
2838
+ return data;
2839
+ }
2492
2840
 
2493
- //#endregion
2494
2841
  //#region src/utils.ts
2495
2842
  function createPromiseWithResolvers() {
2496
2843
  let resolve;
@@ -2513,7 +2860,6 @@ function nanoid(size = 21) {
2513
2860
  return id;
2514
2861
  }
2515
2862
 
2516
- //#endregion
2517
2863
  //#region src/main.ts
2518
2864
  const DEFAULT_TIMEOUT = 6e4;
2519
2865
  const defaultSerialize = (i) => i;
@@ -2530,7 +2876,7 @@ function createBirpc($functions, options) {
2530
2876
  const req = {
2531
2877
  m: method,
2532
2878
  a: args,
2533
- t: TYPE_REQUEST
2879
+ t: "q"
2534
2880
  };
2535
2881
  if (optional) req.o = true;
2536
2882
  const send = async (_req) => post(serialize(_req));
@@ -2584,7 +2930,7 @@ function createBirpc($functions, options) {
2584
2930
  $call: (method, ...args) => _call(method, args, false),
2585
2931
  $callOptional: (method, ...args) => _call(method, args, false, true),
2586
2932
  $callEvent: (method, ...args) => _call(method, args, true),
2587
- $callRaw: (options$1) => _call(options$1.method, options$1.args, options$1.event, options$1.optional),
2933
+ $callRaw: (options) => _call(options.method, options.args, options.event, options.optional),
2588
2934
  $rejectPendingCalls,
2589
2935
  get $closed() {
2590
2936
  return $closed;
@@ -2596,7 +2942,7 @@ function createBirpc($functions, options) {
2596
2942
  $functions
2597
2943
  };
2598
2944
  if (proxify) rpc = new Proxy({}, { get(_, method) {
2599
- if (Object.prototype.hasOwnProperty.call(builtinMethods, method)) return builtinMethods[method];
2945
+ if (Object.hasOwn(builtinMethods, method)) return builtinMethods[method];
2600
2946
  if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) return void 0;
2601
2947
  const sendEvent = (...args) => _call(method, args, true);
2602
2948
  if (eventNames.includes(method)) {
@@ -2640,7 +2986,7 @@ function createBirpc($functions, options) {
2640
2986
  if (options.onGeneralError?.call(rpc, e) !== true) throw e;
2641
2987
  return;
2642
2988
  }
2643
- if (msg.t === TYPE_REQUEST) {
2989
+ if (msg.t === "q") {
2644
2990
  const { m: method, a: args, o: optional } = msg;
2645
2991
  let result, error;
2646
2992
  let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]);
@@ -2657,7 +3003,7 @@ function createBirpc($functions, options) {
2657
3003
  }
2658
3004
  if (!error) try {
2659
3005
  await post(serialize({
2660
- t: TYPE_RESPONSE,
3006
+ t: "s",
2661
3007
  i: msg.i,
2662
3008
  r: result
2663
3009
  }), ...extra);
@@ -2668,7 +3014,7 @@ function createBirpc($functions, options) {
2668
3014
  }
2669
3015
  try {
2670
3016
  await post(serialize({
2671
- t: TYPE_RESPONSE,
3017
+ t: "s",
2672
3018
  i: msg.i,
2673
3019
  e: error
2674
3020
  }), ...extra);
@@ -2693,6 +3039,24 @@ function createBirpc($functions, options) {
2693
3039
 
2694
3040
  const debug = createDebugger("vitest:browser:api");
2695
3041
  const BROWSER_API_PATH = "/__vitest_browser_api__";
3042
+ const DEFAULT_HEARTBEAT_INTERVAL = 15e3;
3043
+ const HEARTBEAT_MAX_MISSED = 2;
3044
+ let warnedInvalidHeartbeatInterval = false;
3045
+ function resolveHeartbeatInterval(vitest) {
3046
+ const rawInterval = process.env.VITEST_BROWSER_HEARTBEAT_INTERVAL;
3047
+ if (!rawInterval) {
3048
+ return DEFAULT_HEARTBEAT_INTERVAL;
3049
+ }
3050
+ const interval = Number(rawInterval);
3051
+ if (Number.isNaN(interval)) {
3052
+ if (!warnedInvalidHeartbeatInterval) {
3053
+ warnedInvalidHeartbeatInterval = true;
3054
+ vitest.logger.warn(`VITEST_BROWSER_HEARTBEAT_INTERVAL is expected to be a number, received "${rawInterval}". Using the default interval of ${DEFAULT_HEARTBEAT_INTERVAL}ms instead.`);
3055
+ }
3056
+ return DEFAULT_HEARTBEAT_INTERVAL;
3057
+ }
3058
+ return interval;
3059
+ }
2696
3060
  function setupBrowserRpc(globalServer, defaultMockerRegistry) {
2697
3061
  const vite = globalServer.vite;
2698
3062
  const vitest = globalServer.vitest;
@@ -2741,8 +3105,31 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
2741
3105
  const clients = type === "tester" ? state.testers : state.orchestrators;
2742
3106
  clients.set(rpcId, rpc);
2743
3107
  debug?.("[%s] Browser API connected to %s", rpcId, type);
3108
+ // if the browser stops answering pings, terminate the socket so the
3109
+ // "close" handler below rejects pending calls (like `createTesters`)
3110
+ // instead of the run hanging forever; timeouts that live in the browser
3111
+ // (`testTimeout`, iframe ack) cannot fire once its process is frozen
3112
+ const heartbeatInterval = resolveHeartbeatInterval(vitest);
3113
+ let missedPongs = 0;
3114
+ ws.on("pong", () => {
3115
+ missedPongs = 0;
3116
+ });
3117
+ const heartbeat = heartbeatInterval > 0 ? setInterval(() => {
3118
+ if (ws.readyState !== ws.OPEN) {
3119
+ return;
3120
+ }
3121
+ if (missedPongs >= HEARTBEAT_MAX_MISSED) {
3122
+ debug?.("[%s] %s did not respond to %s heartbeat pings, terminating the connection", rpcId, type, missedPongs);
3123
+ rpc.$close(new Error(`[vitest] The browser ${type} did not respond to a heartbeat ping for ${missedPongs * heartbeatInterval}ms. The browser process might be frozen or killed. Closing the connection.`));
3124
+ ws.terminate();
3125
+ return;
3126
+ }
3127
+ missedPongs++;
3128
+ ws.ping();
3129
+ }, heartbeatInterval).unref() : undefined;
2744
3130
  ws.on("close", () => {
2745
3131
  debug?.("[%s] Browser API disconnected from %s", rpcId, type);
3132
+ clearInterval(heartbeat);
2746
3133
  offCancel();
2747
3134
  clients.delete(rpcId);
2748
3135
  globalServer.removeCDPHandler(rpcId);
@@ -2750,7 +3137,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
2750
3137
  sessions.destroySession(sessionId);
2751
3138
  }
2752
3139
  // this will reject any hanging methods if there are any
2753
- rpc.$close(new Error(`[vitest] Browser connection was closed while running tests. Was the page closed unexpectedly?`));
3140
+ rpc.$close(new BrowserConnectionError(`[vitest] Browser connection was closed while running tests. Was the page closed unexpectedly?`));
2754
3141
  });
2755
3142
  });
2756
3143
  });
@@ -2767,8 +3154,11 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
2767
3154
  function canWrite(project) {
2768
3155
  return project.config.api.allowWrite && project.vitest.config.api.allowWrite;
2769
3156
  }
3157
+ function canExec(project) {
3158
+ return project.config.api.allowExec && project.vitest.config.api.allowExec;
3159
+ }
2770
3160
  function isCdpAllowed(project) {
2771
- return project.config.api.allowExec && project.vitest.config.api.allowExec && project.config.api.allowWrite && project.vitest.config.api.allowWrite;
3161
+ return canExec(project) && canWrite(project);
2772
3162
  }
2773
3163
  function assertCdpAllowed(project) {
2774
3164
  if (!isCdpAllowed(project)) {
@@ -2877,6 +3267,17 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
2877
3267
  }
2878
3268
  return promises.readFile(snapshotPath, "utf-8");
2879
3269
  },
3270
+ async readSnapshotFileData(snapshotPath) {
3271
+ checkFileAccess(snapshotPath);
3272
+ if (!existsSync(snapshotPath)) {
3273
+ return null;
3274
+ }
3275
+ if (!canExec(project)) {
3276
+ throw new Error(`Cannot read snapshot file because browser API exec operations are disabled. See https://vitest.dev/config/api.`);
3277
+ }
3278
+ const content = await promises.readFile(snapshotPath, "utf-8");
3279
+ return evaluateSnapshotFile(snapshotPath, content);
3280
+ },
2880
3281
  async saveSnapshotFile(id, content) {
2881
3282
  checkFileAccess(id);
2882
3283
  if (!canWrite(project)) {
@@ -2983,6 +3384,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
2983
3384
  if (module.type === "redirect") {
2984
3385
  const redirectUrl = new URL(module.redirect);
2985
3386
  module.redirect = join(vite.config.root, redirectUrl.pathname);
3387
+ checkFileAccess(module.redirect);
2986
3388
  }
2987
3389
  defaultMockerRegistry.register(module);
2988
3390
  }
@@ -3014,6 +3416,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3014
3416
  }
3015
3417
  return mocker.delete(sessionId, id);
3016
3418
  },
3419
+ // CDP
3017
3420
  async sendCdpEvent(sessionId, event, payload) {
3018
3421
  assertCdpAllowed(project);
3019
3422
  const cdp = await globalServer.ensureCDPHandler(sessionId, rpcId);
@@ -3071,6 +3474,17 @@ function defineBrowserCommand(fn) {
3071
3474
  return fn;
3072
3475
  }
3073
3476
  const versionRegexp = /(?:\?|&)v=\w{8}/;
3477
+ // pin a Cache-Control value and stop Vite's later middleware from overriding it
3478
+ function pinCacheControl(res, value) {
3479
+ res.setHeader("Cache-Control", value);
3480
+ const setHeader = res.setHeader.bind(res);
3481
+ res.setHeader = function(name, ...args) {
3482
+ if (name === "Cache-Control") {
3483
+ return res;
3484
+ }
3485
+ return setHeader(name, ...args);
3486
+ };
3487
+ }
3074
3488
  /**
3075
3489
  * The browser provider's `serverFactory`. Returns a `BrowserServerContribution`
3076
3490
  * that Vitest core uses to build the SINGLE Vite server shared by `project.vite`
@@ -3218,21 +3632,24 @@ body {
3218
3632
  }
3219
3633
  }));
3220
3634
  }
3635
+ // vitest's own dist files only change with the vitest version and
3636
+ // browser contexts don't outlive the process, so there is no reason
3637
+ // to revalidate them in every tester iframe. Skipped for persistent
3638
+ // contexts and preview providers — their disk cache would survive a vitest upgrade
3639
+ const persistentContext = (parentServer.config.browser.provider?.options)?.persistentContext;
3640
+ const immutablePrefixes = persistentContext || parentServer.config.browser.provider?.name === "preview" ? [] : [
3641
+ "/__vitest_browser__/",
3642
+ `/@fs${distDir}`,
3643
+ `/@fs${distRoot}`
3644
+ ];
3221
3645
  server.middlewares.use((req, res, next) => {
3222
- // 9000 mega head move
3223
- // Vite always caches optimized dependencies, but users might mock
3224
- // them in _some_ tests, while keeping original modules in others
3225
- // there is no way to configure that in Vite, so we patch it here
3226
- // to always ignore the cache-control set by Vite in the next middleware
3227
- if (req.url && versionRegexp.test(req.url) && !req.url.includes("chunk-")) {
3228
- res.setHeader("Cache-Control", "no-cache");
3229
- const setHeader = res.setHeader.bind(res);
3230
- res.setHeader = function(name, value) {
3231
- if (name === "Cache-Control") {
3232
- return res;
3233
- }
3234
- return setHeader(name, value);
3235
- };
3646
+ const url = req.url;
3647
+ if (url) {
3648
+ if (immutablePrefixes.some((prefix) => url.startsWith(prefix))) {
3649
+ pinCacheControl(res, "public,max-age=31536000,immutable");
3650
+ } else if (versionRegexp.test(url) && !url.includes("chunk-")) {
3651
+ pinCacheControl(res, "no-cache");
3652
+ }
3236
3653
  }
3237
3654
  next();
3238
3655
  });
@@ -3268,6 +3685,9 @@ body {
3268
3685
  server.middlewares.use("/__vitest__", sirv(distClientRoot));
3269
3686
  }
3270
3687
  },
3688
+ // Resolution-time config: only what is derivable from the (partial) user
3689
+ // config. The mocks / coverage / meta-env plugins come from the shared
3690
+ // workspace plugin set, not from here.
3271
3691
  async config(viteConfig) {
3272
3692
  const testConfig = viteConfig.test || {};
3273
3693
  const config = {
@@ -3279,6 +3699,9 @@ body {
3279
3699
  fs: { allow: [distRoot] },
3280
3700
  middlewareMode: false,
3281
3701
  watch: null,
3702
+ // Vitest forwards browser console logs and unhandled errors through its
3703
+ // own RPC, so Vite's client forwarding (defaults on under agents) would
3704
+ // double-report them and leak into stderr.
3282
3705
  forwardConsole: false
3283
3706
  }
3284
3707
  };
@@ -3314,7 +3737,10 @@ body {
3314
3737
  };
3315
3738
  contribution.plugins = [
3316
3739
  ...BrowserPlugin(contribution),
3317
- interceptorPlugin({ registry: mockerRegistry }),
3740
+ interceptorPlugin({
3741
+ registry: mockerRegistry,
3742
+ registerWebSocketEvents: false
3743
+ }),
3318
3744
  {
3319
3745
  name: "vitest:browser:framework-sourcemaps",
3320
3746
  enforce: "post",
@@ -3389,13 +3815,13 @@ function resolveBrowserOptimizeDeps(projectConfigs, testFiles, harness) {
3389
3815
  // - vitest/browser, @vitest/browser/context, @vitest/browser/utils are
3390
3816
  // VIRTUAL modules generated per-server (see pluginContext.ts) — optimizer
3391
3817
  // cannot resolve/run their `load`, it would freeze stale/empty content.
3392
- // - vite/module-runner is small enough to not need pre-bundling.
3393
3818
  // - msw is a large, side-effectful service-worker library.
3394
3819
  const exclude = [
3395
3820
  "vitest/browser",
3396
- "vite/module-runner",
3397
3821
  "@vitest/browser/utils",
3398
3822
  "@vitest/browser/context",
3823
+ "@vitest/browser/locators",
3824
+ "@vitest/browser/client",
3399
3825
  "msw",
3400
3826
  "msw/browser"
3401
3827
  ];
@@ -3422,19 +3848,20 @@ function resolveBrowserOptimizeDeps(projectConfigs, testFiles, harness) {
3422
3848
  }
3423
3849
  // Pre-bundle the vitest runtime so the browser fetches a few optimized
3424
3850
  // chunks instead of ~20 separately-served dist chunks (faster startup).
3425
- // `vitest`, `vitest/internal/browser` and `@vitest/browser/client` are
3426
- // optimized together in a single pass, so esbuild dedupes their shared
3427
- // stateful chunks (the test collector, the runner, the RPC client) to a
3428
- // single instance — preserving module identity between the test files'
3429
- // `import 'vitest'` and the tester. Their transitive deps (@vitest/utils,
3430
- // @vitest/spy, pathe, tinyrainbow, …) are inlined into these bundles.
3851
+ // `vitest` and `vitest/internal/browser` are optimized together in a single
3852
+ // pass, so esbuild dedupes their shared stateful chunks (the test collector,
3853
+ // the runner) to a single instance, preserving module identity between the
3854
+ // test files' `import 'vitest'` and the tester. Their transitive deps
3855
+ // (@vitest/utils, @vitest/spy, pathe, tinyrainbow, …) are inlined into
3856
+ // these bundles.
3431
3857
  const include = [
3432
3858
  "vitest > expect-type",
3433
3859
  "vitest > magic-string",
3434
3860
  "vitest > chai",
3861
+ "vitest > vite/module-runner",
3435
3862
  "vitest",
3436
3863
  "vitest/internal/browser",
3437
- "@vitest/browser/client"
3864
+ "vitest/internal/traces"
3438
3865
  ];
3439
3866
  const provider = testConfig.browser?.provider;
3440
3867
  if (provider?.name === "preview") {