@vitest/browser 5.0.2 → 5.0.4

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
@@ -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.2";
212
+ var version = "5.0.4";
213
213
 
214
214
  const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
215
215
  const distRoot = resolve(pkgRoot, "dist");
@@ -728,6 +728,7 @@ async function resolveOrchestrator(globalServer, url, res) {
728
728
  const jsEntry = manifestContent["orchestrator.html"].file;
729
729
  const base = browserProject.parent.vite.config.base || "/";
730
730
  baseHtml = baseHtml.replace("href=\"./favicon.ico\"", `href="${base}__vitest__/favicon.ico"`).replace("href=\"./favicon.svg\"", `href="${base}__vitest__/favicon.svg"`).replaceAll("./assets/", `${base}__vitest__/assets/`).replace("<!-- !LOAD_METADATA! -->", [
731
+ `<script>window.VITEST_UI_THEME = ${JSON.stringify(globalServer.vitest.config.uiOptions.theme)}<\/script>`,
731
732
  "{__VITEST_INJECTOR__}",
732
733
  "{__VITEST_ERROR_CATCHER__}",
733
734
  "{__VITEST_SCRIPTS__}",
@@ -801,7 +802,7 @@ async function resolveTester(globalServer, url, res, next) {
801
802
  }
802
803
  const injectorJs = typeof globalServer.injectorJs === "string" ? globalServer.injectorJs : await globalServer.injectorJs;
803
804
  const injector = replacer(injectorJs, {
804
- __VITEST_PROVIDER__: JSON.stringify(project.browser.provider.name),
805
+ __VITEST_PROVIDER__: JSON.stringify(browserProject.config.browser.provider?.name || "preview"),
805
806
  __VITEST_CONFIG__: JSON.stringify(browserProject.wrapSerializedConfig()),
806
807
  __VITEST_VITE_CONFIG__: JSON.stringify({ root: browserProject.vite.config.root }),
807
808
  __VITEST_TYPE__: "\"tester\"",
@@ -838,7 +839,7 @@ function createTesterMiddleware(browserServer) {
838
839
  return next();
839
840
  }
840
841
  const url = new URL(req.url, "http://localhost");
841
- if (url.pathname !== browserServer.prefixTesterUrl || !url.searchParams.has("sessionId")) {
842
+ if (url.pathname !== browserServer.prefixTesterUrl) {
842
843
  return next();
843
844
  }
844
845
  const html = await resolveTester(browserServer, url, res, next);
@@ -977,6 +978,8 @@ var BrowserPlugin = (contribution) => {
977
978
  }),
978
979
  {
979
980
  name: "vitest:browser:in-source-tests",
981
+ // runs after `vitest:mocks`, so hoisted mocks can read `import.meta.vitest`
982
+ enforce: "post",
980
983
  transform: {
981
984
  filter: { code: /import\.meta\.vitest/ },
982
985
  handler(code, id) {
@@ -1652,7 +1655,10 @@ const pixelmatch = (reference, actual, { createDiff, ...options }) => {
1652
1655
  return {
1653
1656
  pass,
1654
1657
  diff: diffBuffer ?? null,
1655
- message: pass ? null : `${mismatchedPixels} pixels (ratio ${(Math.ceil(mismatchedPixels / imageArea * 100) / 100).toFixed(2)}) differ.`
1658
+ message: pass ? null : `${mismatchedPixels} pixels (ratio ${
1659
+ // as we compare using `<=`, use `Math.ceil` to ensure the reported ratio
1660
+ // doesn't appear equal to the allowed limit when it's a bit over
1661
+ (Math.ceil(mismatchedPixels / imageArea * 100) / 100).toFixed(2)}) differ.`
1656
1662
  };
1657
1663
  };
1658
1664
 
@@ -2267,7 +2273,7 @@ class ProjectBrowser {
2267
2273
  if (name in this.parent.commands) {
2268
2274
  return this.parent.commands[name](context, ...args);
2269
2275
  }
2270
- throw new Error(`Provider ${this.provider.name} does not support command "${name}".`);
2276
+ throw new Error(`Provider ${this.config.browser.provider?.name} does not support command "${name}".`);
2271
2277
  });
2272
2278
  wrapSerializedConfig() {
2273
2279
  const config = wrapConfig(this.project.serializedConfig);
@@ -2291,6 +2297,15 @@ class ProjectBrowser {
2291
2297
  });
2292
2298
  }
2293
2299
  }
2300
+ async closeBrowserProvider(options) {
2301
+ const provider = this.provider;
2302
+ if (!provider) {
2303
+ return;
2304
+ }
2305
+ // detach first so the next run can create a new provider while this one closes
2306
+ this.provider = undefined;
2307
+ await provider.close(options);
2308
+ }
2294
2309
  parseErrorStacktrace(e, options = {}) {
2295
2310
  return this.parent.parseErrorStacktrace(e, options);
2296
2311
  }
@@ -2426,13 +2441,21 @@ class ParentBrowserProject {
2426
2441
  ...options
2427
2442
  });
2428
2443
  }
2429
- cdps = new Map();
2430
- cdpSessionsPromises = new Map();
2431
- async ensureCDPHandler(sessionId, rpcId) {
2432
- const cachedHandler = this.cdps.get(rpcId);
2433
- if (cachedHandler) {
2434
- return cachedHandler;
2444
+ cdpHandlers = new Map();
2445
+ ensureCDPHandler(sessionId, rpcId) {
2446
+ let handler = this.cdpHandlers.get(rpcId);
2447
+ if (!handler) {
2448
+ handler = this.createCDPHandler(sessionId, rpcId);
2449
+ this.cdpHandlers.set(rpcId, handler);
2450
+ handler.catch(() => {
2451
+ if (this.cdpHandlers.get(rpcId) === handler) {
2452
+ this.cdpHandlers.delete(rpcId);
2453
+ }
2454
+ });
2435
2455
  }
2456
+ return handler;
2457
+ }
2458
+ async createCDPHandler(sessionId, rpcId) {
2436
2459
  const browserSession = this.vitest._browserSessions.getSession(sessionId);
2437
2460
  if (!browserSession) {
2438
2461
  throw new Error(`Session "${sessionId}" not found.`);
@@ -2445,23 +2468,15 @@ class ParentBrowserProject {
2445
2468
  if (!provider.getCDPSession) {
2446
2469
  throw new Error(`CDP is not supported by the provider "${provider.name}".`);
2447
2470
  }
2448
- const session = await this.cdpSessionsPromises.get(rpcId) ?? await (async () => {
2449
- const promise = provider.getCDPSession(sessionId).finally(() => {
2450
- this.cdpSessionsPromises.delete(rpcId);
2451
- });
2452
- this.cdpSessionsPromises.set(rpcId, promise);
2453
- return promise;
2454
- })();
2471
+ const session = await provider.getCDPSession(sessionId);
2455
2472
  const rpc = browser.state.testers.get(rpcId);
2456
2473
  if (!rpc) {
2457
2474
  throw new Error(`Tester RPC "${rpcId}" was not established.`);
2458
2475
  }
2459
- const handler = new BrowserServerCDPHandler(session, rpc);
2460
- this.cdps.set(rpcId, handler);
2461
- return handler;
2476
+ return new BrowserServerCDPHandler(session, rpc);
2462
2477
  }
2463
- removeCDPHandler(sessionId) {
2464
- this.cdps.delete(sessionId);
2478
+ removeCDPHandler(rpcId) {
2479
+ this.cdpHandlers.delete(rpcId);
2465
2480
  }
2466
2481
  async formatScripts(scripts) {
2467
2482
  if (!scripts?.length) {
@@ -2496,269 +2511,6 @@ class ParentBrowserProject {
2496
2511
  }
2497
2512
  }
2498
2513
 
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
2514
  var naturalCompare = {exports: {}};
2763
2515
 
2764
2516
  var hasRequiredNaturalCompare;
@@ -2829,7 +2581,7 @@ requireNaturalCompare();
2829
2581
  function evaluateSnapshotFile(filepath, content) {
2830
2582
  const data = Object.create(null);
2831
2583
  try {
2832
- // eslint-disable-next-line no-new-func
2584
+ // oxlint-disable-next-line no-new-func
2833
2585
  const populate = new Function("exports", content);
2834
2586
  populate(data);
2835
2587
  } catch (cause) {
@@ -3037,6 +2789,15 @@ function createBirpc($functions, options) {
3037
2789
  return rpc;
3038
2790
  }
3039
2791
 
2792
+ // JSON drops `undefined` in objects and turns it into `null` in arrays
2793
+ const UNDEFINED_VALUE = "__vitest_undefined__";
2794
+ function replaceUndefined(value) {
2795
+ return value === undefined ? UNDEFINED_VALUE : value;
2796
+ }
2797
+ function reviveUndefined(_key, value) {
2798
+ return value === UNDEFINED_VALUE ? undefined : value;
2799
+ }
2800
+
3040
2801
  const debug = createDebugger("vitest:browser:api");
3041
2802
  const BROWSER_API_PATH = "/__vitest_browser_api__";
3042
2803
  const DEFAULT_HEARTBEAT_INTERVAL = 15e3;
@@ -3099,6 +2860,11 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3099
2860
  return error(new Error(`[vitest] Project "${projectName}" not found.`));
3100
2861
  }
3101
2862
  wss.handleUpgrade(request, socket, head, (ws) => {
2863
+ // the pool closed this instance, its pages can still reconnect while they close
2864
+ if (!project.browser?.provider) {
2865
+ ws.terminate();
2866
+ return;
2867
+ }
3102
2868
  wss.emit("connection", ws, request);
3103
2869
  const { rpc, offCancel } = setupClient(project, rpcId, ws, { sessionId });
3104
2870
  const state = project.browser.state;
@@ -3167,7 +2933,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3167
2933
  }
3168
2934
  function setupClient(project, rpcId, ws, options) {
3169
2935
  const mockResolver = new ServerMockResolver(globalServer.vite, { moduleDirectories: project.config?.deps?.moduleDirectories });
3170
- const mocker = project.browser?.provider.mocker;
2936
+ const mocker = project.browser?.provider?.mocker;
3171
2937
  const rpc = createBirpc({
3172
2938
  onOrchestratorReady() {
3173
2939
  const sessions = vitest._browserSessions;
@@ -3213,7 +2979,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3213
2979
  for (const attachment of attachments) {
3214
2980
  const path = attachment.path;
3215
2981
  if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
3216
- checkFileAccess(resolve(project.config.root, path));
2982
+ checkFileAccess(resolve(project.config.root, slash(path)));
3217
2983
  }
3218
2984
  }
3219
2985
  }
@@ -3223,7 +2989,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3223
2989
  return vitest._testRun.recordBenchmark(testId, benchmark);
3224
2990
  },
3225
2991
  async readBenchmarkResult(relativePath) {
3226
- checkFileAccess(project.benchmark.resolve(relativePath));
2992
+ checkFileAccess(project.benchmark.resolve(slash(relativePath)));
3227
2993
  return project.benchmark.readResult(relativePath);
3228
2994
  },
3229
2995
  async writeBenchmarkResult(relativePath, data) {
@@ -3231,7 +2997,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3231
2997
  vitest.logger.error(`[vitest] Cannot write benchmark artifact "${relativePath}" because file writing is disabled. See https://vitest.dev/config/api.`);
3232
2998
  return;
3233
2999
  }
3234
- checkFileAccess(project.benchmark.resolve(relativePath));
3000
+ checkFileAccess(project.benchmark.resolve(slash(relativePath)));
3235
3001
  return project.benchmark.writeResult(relativePath, data);
3236
3002
  },
3237
3003
  async onTaskUpdate(method, packs, events) {
@@ -3322,9 +3088,9 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3322
3088
  return vitest.state.getCountOfFailedTests();
3323
3089
  },
3324
3090
  async wdioSwitchContext(direction) {
3325
- const provider = project.browser.provider;
3091
+ const provider = project.browser?.provider;
3326
3092
  if (!provider) {
3327
- throw new Error("Commands are only available for browser tests.");
3093
+ throw new Error(`The browser of the "${project.name}" project is closed.`);
3328
3094
  }
3329
3095
  if (provider.name !== "webdriverio") {
3330
3096
  throw new Error("Switch context is only available for WebDriverIO provider.");
@@ -3337,9 +3103,9 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3337
3103
  },
3338
3104
  async triggerCommand(sessionId, command, testPath, payload) {
3339
3105
  debug?.("[%s] Triggering command \"%s\"", sessionId, command);
3340
- const provider = project.browser.provider;
3106
+ const provider = project.browser?.provider;
3341
3107
  if (!provider) {
3342
- throw new Error("Commands are only available for browser tests.");
3108
+ throw new Error(`Cannot run the "${command}" command because the browser of the "${project.name}" project is closed.`);
3343
3109
  }
3344
3110
  const context = Object.assign({
3345
3111
  testPath,
@@ -3383,8 +3149,9 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3383
3149
  } else {
3384
3150
  if (module.type === "redirect") {
3385
3151
  const redirectUrl = new URL(module.redirect);
3386
- module.redirect = join(vite.config.root, redirectUrl.pathname);
3387
- checkFileAccess(module.redirect);
3152
+ const redirect = join(vite.config.root, slash(decodeURI(redirectUrl.pathname)));
3153
+ checkFileAccess(redirect);
3154
+ module.redirect = redirect;
3388
3155
  }
3389
3156
  defaultMockerRegistry.register(module);
3390
3157
  }
@@ -3432,7 +3199,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3432
3199
  on: (fn) => ws.on("message", fn),
3433
3200
  eventNames: ["onCancel", "cdpEvent"],
3434
3201
  serialize: (data) => stringify(data, stringifyReplace),
3435
- deserialize: parse,
3202
+ deserialize: (data) => parse(data, reviveUndefined),
3436
3203
  timeout: -1
3437
3204
  });
3438
3205
  const offCancel = vitest.onCancel((reason) => rpc.onCancel(reason));
@@ -3466,7 +3233,7 @@ function stringifyReplace(key, value) {
3466
3233
  ...cloned
3467
3234
  };
3468
3235
  } else {
3469
- return value;
3236
+ return replaceUndefined(value);
3470
3237
  }
3471
3238
  }
3472
3239
 
@@ -3590,7 +3357,7 @@ body {
3590
3357
  configureServer(server) {
3591
3358
  const parentServer = contribution.parent;
3592
3359
  parentServer.setServer(server);
3593
- // eslint-disable-next-line prefer-arrow-callback
3360
+ // oxlint-disable-next-line prefer-arrow-callback
3594
3361
  server.middlewares.use(function vitestHeaders(_req, res, next) {
3595
3362
  const headers = server.config.server.headers;
3596
3363
  if (headers) {