@vitest/browser 3.0.0-beta.2 → 3.0.0-beta.3

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
@@ -1,22 +1,22 @@
1
1
  import c from 'tinyrainbow';
2
- import { isFileServingAllowed, getFilePoolName, distDir, resolveApiServerConfig, resolveFsAllow, createDebugger, createViteLogger, createViteServer } from 'vitest/node';
3
- import fs, { promises, readFileSync, lstatSync, existsSync } from 'node:fs';
2
+ import { getFilePoolName, distDir, resolveApiServerConfig, resolveFsAllow, isFileServingAllowed, createDebugger, createViteLogger, createViteServer } from 'vitest/node';
3
+ import fs, { readFileSync, lstatSync, promises, existsSync } from 'node:fs';
4
4
  import { createRequire } from 'node:module';
5
5
  import { dynamicImportPlugin, ServerMockResolver } from '@vitest/mocker/node';
6
- import { slash, toArray, createDefer } from '@vitest/utils';
6
+ import { slash as slash$1, toArray } from '@vitest/utils';
7
7
  import MagicString from 'magic-string';
8
8
  import sirv from 'sirv';
9
9
  import { coverageConfigDefaults } from 'vitest/config';
10
10
  import { fileURLToPath } from 'node:url';
11
- import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-JzwxG3Ek.js';
12
- import { resolve as resolve$1, dirname as dirname$1, basename as basename$1, normalize as normalize$1 } from 'node:path';
13
- import { mkdir, readFile as readFile$1 } from 'node:fs/promises';
14
11
  import crypto from 'node:crypto';
15
- import { WebSocketServer } from 'ws';
12
+ import { mkdir, readFile as readFile$1 } from 'node:fs/promises';
16
13
  import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
14
+ import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-dkCg9pjp.js';
15
+ import { resolve as resolve$1, dirname as dirname$1, basename as basename$1, normalize as normalize$1 } from 'node:path';
16
+ import { WebSocketServer } from 'ws';
17
17
  import * as nodeos from 'node:os';
18
18
 
19
- var version = "3.0.0-beta.2";
19
+ var version = "3.0.0-beta.3";
20
20
 
21
21
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
22
22
  function normalizeWindowsPath(input = "") {
@@ -200,1763 +200,2453 @@ const basename = function(p, extension) {
200
200
  const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
201
201
  const distRoot = resolve(pkgRoot, "dist");
202
202
 
203
- const clear = async (context, selector) => {
204
- if (context.provider instanceof PlaywrightBrowserProvider) {
205
- const { iframe } = context;
206
- const element = iframe.locator(selector);
207
- await element.clear();
208
- } else if (context.provider instanceof WebdriverBrowserProvider) {
209
- const browser = context.browser;
210
- const element = await browser.$(selector);
211
- await element.clearValue();
212
- } else {
213
- throw new TypeError(`Provider "${context.provider.name}" does not support clearing elements`);
214
- }
215
- };
216
-
217
- const click = async (context, selector, options = {}) => {
218
- const provider = context.provider;
219
- if (provider instanceof PlaywrightBrowserProvider) {
220
- const tester = context.iframe;
221
- await tester.locator(selector).click(options);
222
- } else if (provider instanceof WebdriverBrowserProvider) {
223
- const browser = context.browser;
224
- await browser.$(selector).click(options);
225
- } else {
226
- throw new TypeError(`Provider "${provider.name}" doesn't support click command`);
203
+ function replacer(code, values) {
204
+ return code.replace(/\{\s*(\w+)\s*\}/g, (_, key) => values[key] ?? _);
205
+ }
206
+ const builtinProviders = ["webdriverio", "playwright", "preview"];
207
+ async function getBrowserProvider(options, project) {
208
+ if (options.provider == null || builtinProviders.includes(options.provider)) {
209
+ const providers = await import('./providers.js');
210
+ const provider = options.provider || "preview";
211
+ return providers[provider];
227
212
  }
228
- };
229
- const dblClick = async (context, selector, options = {}) => {
230
- const provider = context.provider;
231
- if (provider instanceof PlaywrightBrowserProvider) {
232
- const tester = context.iframe;
233
- await tester.locator(selector).dblclick(options);
234
- } else if (provider instanceof WebdriverBrowserProvider) {
235
- const browser = context.browser;
236
- await browser.$(selector).doubleClick();
237
- } else {
238
- throw new TypeError(`Provider "${provider.name}" doesn't support dblClick command`);
213
+ let customProviderModule;
214
+ try {
215
+ customProviderModule = await project.import(
216
+ options.provider
217
+ );
218
+ } catch (error) {
219
+ throw new Error(
220
+ `Failed to load custom BrowserProvider from ${options.provider}`,
221
+ { cause: error }
222
+ );
239
223
  }
240
- };
241
- const tripleClick = async (context, selector, options = {}) => {
242
- const provider = context.provider;
243
- if (provider instanceof PlaywrightBrowserProvider) {
244
- const tester = context.iframe;
245
- await tester.locator(selector).click({
246
- ...options,
247
- clickCount: 3
248
- });
249
- } else if (provider instanceof WebdriverBrowserProvider) {
250
- const browser = context.browser;
251
- await browser.action("pointer", { parameters: { pointerType: "mouse" } }).move({ origin: await browser.$(selector) }).down().up().pause(50).down().up().pause(50).down().up().pause(50).perform();
252
- } else {
253
- throw new TypeError(`Provider "${provider.name}" doesn't support tripleClick command`);
224
+ if (customProviderModule.default == null) {
225
+ throw new Error(
226
+ `Custom BrowserProvider loaded from ${options.provider} was not the default export`
227
+ );
254
228
  }
255
- };
229
+ return customProviderModule.default;
230
+ }
231
+ function slash(path) {
232
+ return path.replace(/\\/g, "/").replace(/\/+/g, "/");
233
+ }
256
234
 
257
- const dragAndDrop = async (context, source, target, options_) => {
258
- if (context.provider instanceof PlaywrightBrowserProvider) {
259
- const frame = await context.frame();
260
- await frame.dragAndDrop(
261
- source,
262
- target,
263
- options_
235
+ async function resolveOrchestrator(globalServer, url, res) {
236
+ let sessionId = url.searchParams.get("sessionId");
237
+ if (!sessionId) {
238
+ const contexts = [...globalServer.children].flatMap((p) => [...p.state.orchestrators.keys()]);
239
+ sessionId = contexts[contexts.length - 1] ?? "none";
240
+ }
241
+ const session = globalServer.vitest._browserSessions.getSession(sessionId);
242
+ const files = session?.files ?? [];
243
+ const browserProject = session?.project.browser || [...globalServer.children][0];
244
+ if (!browserProject) {
245
+ return;
246
+ }
247
+ const injectorJs = typeof globalServer.injectorJs === "string" ? globalServer.injectorJs : await globalServer.injectorJs;
248
+ const injector = replacer(injectorJs, {
249
+ __VITEST_PROVIDER__: JSON.stringify(browserProject.config.browser.provider || "preview"),
250
+ __VITEST_CONFIG__: JSON.stringify(browserProject.wrapSerializedConfig()),
251
+ __VITEST_VITE_CONFIG__: JSON.stringify({
252
+ root: browserProject.vite.config.root
253
+ }),
254
+ __VITEST_FILES__: JSON.stringify(files),
255
+ __VITEST_TYPE__: '"orchestrator"',
256
+ __VITEST_SESSION_ID__: JSON.stringify(sessionId),
257
+ __VITEST_TESTER_ID__: '"none"',
258
+ __VITEST_PROVIDED_CONTEXT__: "{}"
259
+ });
260
+ res.removeHeader("Content-Security-Policy");
261
+ if (!globalServer.orchestratorScripts) {
262
+ globalServer.orchestratorScripts = (await globalServer.formatScripts(
263
+ globalServer.config.browser.orchestratorScripts
264
+ )).map((script) => {
265
+ let html = "<script ";
266
+ for (const attr in script.attrs || {}) {
267
+ html += `${attr}="${script.attrs[attr]}" `;
268
+ }
269
+ html += `>${script.children}<\/script>`;
270
+ return html;
271
+ }).join("\n");
272
+ }
273
+ let baseHtml = typeof globalServer.orchestratorHtml === "string" ? globalServer.orchestratorHtml : await globalServer.orchestratorHtml;
274
+ if (globalServer.config.browser.ui) {
275
+ const manifestContent = globalServer.manifest instanceof Promise ? await globalServer.manifest : globalServer.manifest;
276
+ const jsEntry = manifestContent["orchestrator.html"].file;
277
+ const base = browserProject.parent.vite.config.base || "/";
278
+ baseHtml = baseHtml.replaceAll("./assets/", `${base}__vitest__/assets/`).replace(
279
+ "<!-- !LOAD_METADATA! -->",
280
+ [
281
+ "{__VITEST_INJECTOR__}",
282
+ "{__VITEST_ERROR_CATCHER__}",
283
+ "{__VITEST_SCRIPTS__}",
284
+ `<script type="module" crossorigin src="${base}${jsEntry}"><\/script>`
285
+ ].join("\n")
264
286
  );
265
- } else if (context.provider instanceof WebdriverBrowserProvider) {
266
- const $source = context.browser.$(source);
267
- const $target = context.browser.$(target);
268
- const options = options_ || {};
269
- const duration = options.duration ?? 10;
270
- await context.browser.action("pointer").move({ duration: 0, origin: $source, x: options.sourceX ?? 0, y: options.sourceY ?? 0 }).down({ button: 0 }).move({ duration: 0, origin: "pointer", x: 0, y: 0 }).pause(duration).move({ duration: 0, origin: $target, x: options.targetX ?? 0, y: options.targetY ?? 0 }).move({ duration: 0, origin: "pointer", x: 1, y: 0 }).move({ duration: 0, origin: "pointer", x: -1, y: 0 }).up({ button: 0 }).perform();
271
- } else {
272
- throw new TypeError(`Provider "${context.provider.name}" does not support dragging elements`);
273
287
  }
274
- };
288
+ return replacer(baseHtml, {
289
+ __VITEST_FAVICON__: globalServer.faviconUrl,
290
+ __VITEST_TITLE__: "Vitest Browser Runner",
291
+ __VITEST_SCRIPTS__: globalServer.orchestratorScripts,
292
+ __VITEST_INJECTOR__: `<script type="module">${injector}<\/script>`,
293
+ __VITEST_ERROR_CATCHER__: `<script type="module" src="${globalServer.errorCatcherUrl}"><\/script>`,
294
+ __VITEST_SESSION_ID__: JSON.stringify(sessionId)
295
+ });
296
+ }
275
297
 
276
- const fill = async (context, selector, text, options = {}) => {
277
- if (context.provider instanceof PlaywrightBrowserProvider) {
278
- const { iframe } = context;
279
- const element = iframe.locator(selector);
280
- await element.fill(text, options);
281
- } else if (context.provider instanceof WebdriverBrowserProvider) {
282
- const browser = context.browser;
283
- await browser.$(selector).setValue(text);
284
- } else {
285
- throw new TypeError(`Provider "${context.provider.name}" does not support clearing elements`);
298
+ function disableCache(res) {
299
+ res.setHeader(
300
+ "Cache-Control",
301
+ "no-cache, max-age=0, must-revalidate"
302
+ );
303
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
304
+ }
305
+ function allowIframes(res) {
306
+ res.removeHeader("X-Frame-Options");
307
+ }
308
+
309
+ function createOrchestratorMiddleware(parentServer) {
310
+ return async function vitestOrchestratorMiddleware(req, res, next) {
311
+ if (!req.url) {
312
+ return next();
313
+ }
314
+ const url = new URL(req.url, "http://localhost");
315
+ if (url.pathname !== parentServer.base) {
316
+ return next();
317
+ }
318
+ const html = await resolveOrchestrator(parentServer, url, res);
319
+ if (html) {
320
+ disableCache(res);
321
+ allowIframes(res);
322
+ res.write(html, "utf-8");
323
+ res.end();
324
+ }
325
+ };
326
+ }
327
+
328
+ /// <reference types="../types/index.d.ts" />
329
+
330
+ // (c) 2020-present Andrea Giammarchi
331
+
332
+ const {parse: $parse, stringify: $stringify} = JSON;
333
+ const {keys} = Object;
334
+
335
+ const Primitive = String; // it could be Number
336
+ const primitive = 'string'; // it could be 'number'
337
+
338
+ const ignore = {};
339
+ const object = 'object';
340
+
341
+ const noop = (_, value) => value;
342
+
343
+ const primitives = value => (
344
+ value instanceof Primitive ? Primitive(value) : value
345
+ );
346
+
347
+ const Primitives = (_, value) => (
348
+ typeof value === primitive ? new Primitive(value) : value
349
+ );
350
+
351
+ const revive = (input, parsed, output, $) => {
352
+ const lazy = [];
353
+ for (let ke = keys(output), {length} = ke, y = 0; y < length; y++) {
354
+ const k = ke[y];
355
+ const value = output[k];
356
+ if (value instanceof Primitive) {
357
+ const tmp = input[value];
358
+ if (typeof tmp === object && !parsed.has(tmp)) {
359
+ parsed.add(tmp);
360
+ output[k] = ignore;
361
+ lazy.push({k, a: [input, parsed, tmp, $]});
362
+ }
363
+ else
364
+ output[k] = $.call(output, k, tmp);
365
+ }
366
+ else if (output[k] !== ignore)
367
+ output[k] = $.call(output, k, value);
368
+ }
369
+ for (let {length} = lazy, i = 0; i < length; i++) {
370
+ const {k, a} = lazy[i];
371
+ output[k] = $.call(output, k, revive.apply(null, a));
286
372
  }
373
+ return output;
287
374
  };
288
375
 
289
- const types = { "application/andrew-inset": ["ez"], "application/appinstaller": ["appinstaller"], "application/applixware": ["aw"], "application/appx": ["appx"], "application/appxbundle": ["appxbundle"], "application/atom+xml": ["atom"], "application/atomcat+xml": ["atomcat"], "application/atomdeleted+xml": ["atomdeleted"], "application/atomsvc+xml": ["atomsvc"], "application/atsc-dwd+xml": ["dwd"], "application/atsc-held+xml": ["held"], "application/atsc-rsat+xml": ["rsat"], "application/automationml-aml+xml": ["aml"], "application/automationml-amlx+zip": ["amlx"], "application/bdoc": ["bdoc"], "application/calendar+xml": ["xcs"], "application/ccxml+xml": ["ccxml"], "application/cdfx+xml": ["cdfx"], "application/cdmi-capability": ["cdmia"], "application/cdmi-container": ["cdmic"], "application/cdmi-domain": ["cdmid"], "application/cdmi-object": ["cdmio"], "application/cdmi-queue": ["cdmiq"], "application/cpl+xml": ["cpl"], "application/cu-seeme": ["cu"], "application/cwl": ["cwl"], "application/dash+xml": ["mpd"], "application/dash-patch+xml": ["mpp"], "application/davmount+xml": ["davmount"], "application/docbook+xml": ["dbk"], "application/dssc+der": ["dssc"], "application/dssc+xml": ["xdssc"], "application/ecmascript": ["ecma"], "application/emma+xml": ["emma"], "application/emotionml+xml": ["emotionml"], "application/epub+zip": ["epub"], "application/exi": ["exi"], "application/express": ["exp"], "application/fdf": ["fdf"], "application/fdt+xml": ["fdt"], "application/font-tdpfr": ["pfr"], "application/geo+json": ["geojson"], "application/gml+xml": ["gml"], "application/gpx+xml": ["gpx"], "application/gxf": ["gxf"], "application/gzip": ["gz"], "application/hjson": ["hjson"], "application/hyperstudio": ["stk"], "application/inkml+xml": ["ink", "inkml"], "application/ipfix": ["ipfix"], "application/its+xml": ["its"], "application/java-archive": ["jar", "war", "ear"], "application/java-serialized-object": ["ser"], "application/java-vm": ["class"], "application/javascript": ["*js"], "application/json": ["json", "map"], "application/json5": ["json5"], "application/jsonml+json": ["jsonml"], "application/ld+json": ["jsonld"], "application/lgr+xml": ["lgr"], "application/lost+xml": ["lostxml"], "application/mac-binhex40": ["hqx"], "application/mac-compactpro": ["cpt"], "application/mads+xml": ["mads"], "application/manifest+json": ["webmanifest"], "application/marc": ["mrc"], "application/marcxml+xml": ["mrcx"], "application/mathematica": ["ma", "nb", "mb"], "application/mathml+xml": ["mathml"], "application/mbox": ["mbox"], "application/media-policy-dataset+xml": ["mpf"], "application/mediaservercontrol+xml": ["mscml"], "application/metalink+xml": ["metalink"], "application/metalink4+xml": ["meta4"], "application/mets+xml": ["mets"], "application/mmt-aei+xml": ["maei"], "application/mmt-usd+xml": ["musd"], "application/mods+xml": ["mods"], "application/mp21": ["m21", "mp21"], "application/mp4": ["*mp4", "*mpg4", "mp4s", "m4p"], "application/msix": ["msix"], "application/msixbundle": ["msixbundle"], "application/msword": ["doc", "dot"], "application/mxf": ["mxf"], "application/n-quads": ["nq"], "application/n-triples": ["nt"], "application/node": ["cjs"], "application/octet-stream": ["bin", "dms", "lrf", "mar", "so", "dist", "distz", "pkg", "bpk", "dump", "elc", "deploy", "exe", "dll", "deb", "dmg", "iso", "img", "msi", "msp", "msm", "buffer"], "application/oda": ["oda"], "application/oebps-package+xml": ["opf"], "application/ogg": ["ogx"], "application/omdoc+xml": ["omdoc"], "application/onenote": ["onetoc", "onetoc2", "onetmp", "onepkg"], "application/oxps": ["oxps"], "application/p2p-overlay+xml": ["relo"], "application/patch-ops-error+xml": ["xer"], "application/pdf": ["pdf"], "application/pgp-encrypted": ["pgp"], "application/pgp-keys": ["asc"], "application/pgp-signature": ["sig", "*asc"], "application/pics-rules": ["prf"], "application/pkcs10": ["p10"], "application/pkcs7-mime": ["p7m", "p7c"], "application/pkcs7-signature": ["p7s"], "application/pkcs8": ["p8"], "application/pkix-attr-cert": ["ac"], "application/pkix-cert": ["cer"], "application/pkix-crl": ["crl"], "application/pkix-pkipath": ["pkipath"], "application/pkixcmp": ["pki"], "application/pls+xml": ["pls"], "application/postscript": ["ai", "eps", "ps"], "application/provenance+xml": ["provx"], "application/pskc+xml": ["pskcxml"], "application/raml+yaml": ["raml"], "application/rdf+xml": ["rdf", "owl"], "application/reginfo+xml": ["rif"], "application/relax-ng-compact-syntax": ["rnc"], "application/resource-lists+xml": ["rl"], "application/resource-lists-diff+xml": ["rld"], "application/rls-services+xml": ["rs"], "application/route-apd+xml": ["rapd"], "application/route-s-tsid+xml": ["sls"], "application/route-usd+xml": ["rusd"], "application/rpki-ghostbusters": ["gbr"], "application/rpki-manifest": ["mft"], "application/rpki-roa": ["roa"], "application/rsd+xml": ["rsd"], "application/rss+xml": ["rss"], "application/rtf": ["rtf"], "application/sbml+xml": ["sbml"], "application/scvp-cv-request": ["scq"], "application/scvp-cv-response": ["scs"], "application/scvp-vp-request": ["spq"], "application/scvp-vp-response": ["spp"], "application/sdp": ["sdp"], "application/senml+xml": ["senmlx"], "application/sensml+xml": ["sensmlx"], "application/set-payment-initiation": ["setpay"], "application/set-registration-initiation": ["setreg"], "application/shf+xml": ["shf"], "application/sieve": ["siv", "sieve"], "application/smil+xml": ["smi", "smil"], "application/sparql-query": ["rq"], "application/sparql-results+xml": ["srx"], "application/sql": ["sql"], "application/srgs": ["gram"], "application/srgs+xml": ["grxml"], "application/sru+xml": ["sru"], "application/ssdl+xml": ["ssdl"], "application/ssml+xml": ["ssml"], "application/swid+xml": ["swidtag"], "application/tei+xml": ["tei", "teicorpus"], "application/thraud+xml": ["tfi"], "application/timestamped-data": ["tsd"], "application/toml": ["toml"], "application/trig": ["trig"], "application/ttml+xml": ["ttml"], "application/ubjson": ["ubj"], "application/urc-ressheet+xml": ["rsheet"], "application/urc-targetdesc+xml": ["td"], "application/voicexml+xml": ["vxml"], "application/wasm": ["wasm"], "application/watcherinfo+xml": ["wif"], "application/widget": ["wgt"], "application/winhlp": ["hlp"], "application/wsdl+xml": ["wsdl"], "application/wspolicy+xml": ["wspolicy"], "application/xaml+xml": ["xaml"], "application/xcap-att+xml": ["xav"], "application/xcap-caps+xml": ["xca"], "application/xcap-diff+xml": ["xdf"], "application/xcap-el+xml": ["xel"], "application/xcap-ns+xml": ["xns"], "application/xenc+xml": ["xenc"], "application/xfdf": ["xfdf"], "application/xhtml+xml": ["xhtml", "xht"], "application/xliff+xml": ["xlf"], "application/xml": ["xml", "xsl", "xsd", "rng"], "application/xml-dtd": ["dtd"], "application/xop+xml": ["xop"], "application/xproc+xml": ["xpl"], "application/xslt+xml": ["*xsl", "xslt"], "application/xspf+xml": ["xspf"], "application/xv+xml": ["mxml", "xhvml", "xvml", "xvm"], "application/yang": ["yang"], "application/yin+xml": ["yin"], "application/zip": ["zip"], "audio/3gpp": ["*3gpp"], "audio/aac": ["adts", "aac"], "audio/adpcm": ["adp"], "audio/amr": ["amr"], "audio/basic": ["au", "snd"], "audio/midi": ["mid", "midi", "kar", "rmi"], "audio/mobile-xmf": ["mxmf"], "audio/mp3": ["*mp3"], "audio/mp4": ["m4a", "mp4a"], "audio/mpeg": ["mpga", "mp2", "mp2a", "mp3", "m2a", "m3a"], "audio/ogg": ["oga", "ogg", "spx", "opus"], "audio/s3m": ["s3m"], "audio/silk": ["sil"], "audio/wav": ["wav"], "audio/wave": ["*wav"], "audio/webm": ["weba"], "audio/xm": ["xm"], "font/collection": ["ttc"], "font/otf": ["otf"], "font/ttf": ["ttf"], "font/woff": ["woff"], "font/woff2": ["woff2"], "image/aces": ["exr"], "image/apng": ["apng"], "image/avci": ["avci"], "image/avcs": ["avcs"], "image/avif": ["avif"], "image/bmp": ["bmp", "dib"], "image/cgm": ["cgm"], "image/dicom-rle": ["drle"], "image/dpx": ["dpx"], "image/emf": ["emf"], "image/fits": ["fits"], "image/g3fax": ["g3"], "image/gif": ["gif"], "image/heic": ["heic"], "image/heic-sequence": ["heics"], "image/heif": ["heif"], "image/heif-sequence": ["heifs"], "image/hej2k": ["hej2"], "image/hsj2": ["hsj2"], "image/ief": ["ief"], "image/jls": ["jls"], "image/jp2": ["jp2", "jpg2"], "image/jpeg": ["jpeg", "jpg", "jpe"], "image/jph": ["jph"], "image/jphc": ["jhc"], "image/jpm": ["jpm", "jpgm"], "image/jpx": ["jpx", "jpf"], "image/jxr": ["jxr"], "image/jxra": ["jxra"], "image/jxrs": ["jxrs"], "image/jxs": ["jxs"], "image/jxsc": ["jxsc"], "image/jxsi": ["jxsi"], "image/jxss": ["jxss"], "image/ktx": ["ktx"], "image/ktx2": ["ktx2"], "image/png": ["png"], "image/sgi": ["sgi"], "image/svg+xml": ["svg", "svgz"], "image/t38": ["t38"], "image/tiff": ["tif", "tiff"], "image/tiff-fx": ["tfx"], "image/webp": ["webp"], "image/wmf": ["wmf"], "message/disposition-notification": ["disposition-notification"], "message/global": ["u8msg"], "message/global-delivery-status": ["u8dsn"], "message/global-disposition-notification": ["u8mdn"], "message/global-headers": ["u8hdr"], "message/rfc822": ["eml", "mime"], "model/3mf": ["3mf"], "model/gltf+json": ["gltf"], "model/gltf-binary": ["glb"], "model/iges": ["igs", "iges"], "model/jt": ["jt"], "model/mesh": ["msh", "mesh", "silo"], "model/mtl": ["mtl"], "model/obj": ["obj"], "model/prc": ["prc"], "model/step+xml": ["stpx"], "model/step+zip": ["stpz"], "model/step-xml+zip": ["stpxz"], "model/stl": ["stl"], "model/u3d": ["u3d"], "model/vrml": ["wrl", "vrml"], "model/x3d+binary": ["*x3db", "x3dbz"], "model/x3d+fastinfoset": ["x3db"], "model/x3d+vrml": ["*x3dv", "x3dvz"], "model/x3d+xml": ["x3d", "x3dz"], "model/x3d-vrml": ["x3dv"], "text/cache-manifest": ["appcache", "manifest"], "text/calendar": ["ics", "ifb"], "text/coffeescript": ["coffee", "litcoffee"], "text/css": ["css"], "text/csv": ["csv"], "text/html": ["html", "htm", "shtml"], "text/jade": ["jade"], "text/javascript": ["js", "mjs"], "text/jsx": ["jsx"], "text/less": ["less"], "text/markdown": ["md", "markdown"], "text/mathml": ["mml"], "text/mdx": ["mdx"], "text/n3": ["n3"], "text/plain": ["txt", "text", "conf", "def", "list", "log", "in", "ini"], "text/richtext": ["rtx"], "text/rtf": ["*rtf"], "text/sgml": ["sgml", "sgm"], "text/shex": ["shex"], "text/slim": ["slim", "slm"], "text/spdx": ["spdx"], "text/stylus": ["stylus", "styl"], "text/tab-separated-values": ["tsv"], "text/troff": ["t", "tr", "roff", "man", "me", "ms"], "text/turtle": ["ttl"], "text/uri-list": ["uri", "uris", "urls"], "text/vcard": ["vcard"], "text/vtt": ["vtt"], "text/wgsl": ["wgsl"], "text/xml": ["*xml"], "text/yaml": ["yaml", "yml"], "video/3gpp": ["3gp", "3gpp"], "video/3gpp2": ["3g2"], "video/h261": ["h261"], "video/h263": ["h263"], "video/h264": ["h264"], "video/iso.segment": ["m4s"], "video/jpeg": ["jpgv"], "video/jpm": ["*jpm", "*jpgm"], "video/mj2": ["mj2", "mjp2"], "video/mp2t": ["ts"], "video/mp4": ["mp4", "mp4v", "mpg4"], "video/mpeg": ["mpeg", "mpg", "mpe", "m1v", "m2v"], "video/ogg": ["ogv"], "video/quicktime": ["qt", "mov"], "video/webm": ["webm"] };
290
- Object.freeze(types);
376
+ const set = (known, input, value) => {
377
+ const index = Primitive(input.push(value) - 1);
378
+ known.set(value, index);
379
+ return index;
380
+ };
291
381
 
292
- var __classPrivateFieldGet = (null && null.__classPrivateFieldGet) || function (receiver, state, kind, f) {
293
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
294
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
295
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
382
+ /**
383
+ * Converts a specialized flatted string into a JS value.
384
+ * @param {string} text
385
+ * @param {(this: any, key: string, value: any) => any} [reviver]
386
+ * @returns {any}
387
+ */
388
+ const parse = (text, reviver) => {
389
+ const input = $parse(text, Primitives).map(primitives);
390
+ const value = input[0];
391
+ const $ = reviver || noop;
392
+ const tmp = typeof value === object && value ?
393
+ revive(input, new Set, value, $) :
394
+ value;
395
+ return $.call({'': tmp}, '', tmp);
296
396
  };
297
- var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
298
- class Mime {
299
- constructor(...args) {
300
- _Mime_extensionToType.set(this, new Map());
301
- _Mime_typeToExtension.set(this, new Map());
302
- _Mime_typeToExtensions.set(this, new Map());
303
- for (const arg of args) {
304
- this.define(arg);
305
- }
397
+
398
+ /**
399
+ * Converts a JS value into a specialized flatted string.
400
+ * @param {any} value
401
+ * @param {((this: any, key: string, value: any) => any) | (string | number)[] | null | undefined} [replacer]
402
+ * @param {string | number | undefined} [space]
403
+ * @returns {string}
404
+ */
405
+ const stringify = (value, replacer, space) => {
406
+ const $ = replacer && typeof replacer === object ?
407
+ (k, v) => (k === '' || -1 < replacer.indexOf(k) ? v : void 0) :
408
+ (replacer || noop);
409
+ const known = new Map;
410
+ const input = [];
411
+ const output = [];
412
+ let i = +set(known, input, $.call({'': value}, '', value));
413
+ let firstRun = !i;
414
+ while (i < input.length) {
415
+ firstRun = true;
416
+ output[i] = $stringify(input[i++], replace, space);
417
+ }
418
+ return '[' + output.join(',') + ']';
419
+ function replace(key, value) {
420
+ if (firstRun) {
421
+ firstRun = !firstRun;
422
+ return value;
306
423
  }
307
- define(typeMap, force = false) {
308
- for (let [type, extensions] of Object.entries(typeMap)) {
309
- type = type.toLowerCase();
310
- extensions = extensions.map((ext) => ext.toLowerCase());
311
- if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
312
- __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, new Set());
313
- }
314
- const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
315
- let first = true;
316
- for (let extension of extensions) {
317
- const starred = extension.startsWith('*');
318
- extension = starred ? extension.slice(1) : extension;
319
- allExtensions?.add(extension);
320
- if (first) {
321
- __classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
322
- }
323
- first = false;
324
- if (starred)
325
- continue;
326
- const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
327
- if (currentType && currentType != type && !force) {
328
- throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
329
- }
330
- __classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
331
- }
332
- }
333
- return this;
334
- }
335
- getType(path) {
336
- if (typeof path !== 'string')
337
- return null;
338
- const last = path.replace(/^.*[/\\]/, '').toLowerCase();
339
- const ext = last.replace(/^.*\./, '').toLowerCase();
340
- const hasPath = last.length < path.length;
341
- const hasDot = ext.length < last.length - 1;
342
- if (!hasDot && hasPath)
343
- return null;
344
- return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
345
- }
346
- getExtension(type) {
347
- if (typeof type !== 'string')
348
- return null;
349
- type = type?.split?.(';')[0];
350
- return ((type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null);
351
- }
352
- getAllExtensions(type) {
353
- if (typeof type !== 'string')
354
- return null;
355
- return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
356
- }
357
- _freeze() {
358
- this.define = () => {
359
- throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
360
- };
361
- Object.freeze(this);
362
- for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
363
- Object.freeze(extensions);
364
- }
365
- return this;
366
- }
367
- _getTestState() {
368
- return {
369
- types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
370
- extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
371
- };
424
+ const after = $.call(this, key, value);
425
+ switch (typeof after) {
426
+ case object:
427
+ if (after === null) return after;
428
+ case primitive:
429
+ return known.get(after) || set(known, input, after);
372
430
  }
373
- }
374
- _Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
375
-
376
- var mime = new Mime(types)._freeze();
431
+ return after;
432
+ }
433
+ };
377
434
 
378
- function assertFileAccess(path, project) {
379
- if (!isFileServingAllowed(path, project.vite) && !isFileServingAllowed(path, project.vitest.server)) {
380
- throw new Error(
381
- `Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`
435
+ async function resolveTester(globalServer, url, res, next) {
436
+ const csp = res.getHeader("Content-Security-Policy");
437
+ if (typeof csp === "string") {
438
+ res.setHeader(
439
+ "Content-Security-Policy",
440
+ csp.replace(/frame-ancestors [^;]+/, "frame-ancestors *")
382
441
  );
383
442
  }
384
- }
385
- const readFile = async ({ project, testPath = process.cwd() }, path, options = {}) => {
386
- const filepath = resolve$1(dirname$1(testPath), path);
387
- assertFileAccess(filepath, project);
388
- if (typeof options === "object" && !options.encoding) {
389
- options.encoding = "utf-8";
443
+ const { sessionId, testFile } = globalServer.resolveTesterUrl(url.pathname);
444
+ const session = globalServer.vitest._browserSessions.getSession(sessionId);
445
+ if (!session) {
446
+ res.statusCode = 400;
447
+ res.end("Invalid session ID");
448
+ return;
390
449
  }
391
- return promises.readFile(filepath, options);
392
- };
393
- const writeFile = async ({ project, testPath = process.cwd() }, path, data, options) => {
394
- const filepath = resolve$1(dirname$1(testPath), path);
395
- assertFileAccess(filepath, project);
396
- const dir = dirname$1(filepath);
397
- if (!fs.existsSync(dir)) {
398
- await promises.mkdir(dir, { recursive: true });
450
+ const project = globalServer.vitest.getProjectByName(session.project.name || "");
451
+ const { testFiles } = await project.globTestFiles();
452
+ const tests = testFile === "__vitest_all__" || !testFiles.includes(testFile) ? "__vitest_browser_runner__.files" : JSON.stringify([testFile]);
453
+ const iframeId = JSON.stringify(testFile);
454
+ const files = session.files ?? [];
455
+ const method = session.method ?? "run";
456
+ const browserProject = project.browser || [...globalServer.children][0];
457
+ if (!browserProject) {
458
+ res.statusCode = 400;
459
+ res.end("Invalid session ID");
460
+ return;
399
461
  }
400
- await promises.writeFile(filepath, data, options);
401
- };
402
- const removeFile = async ({ project, testPath = process.cwd() }, path) => {
403
- const filepath = resolve$1(dirname$1(testPath), path);
404
- assertFileAccess(filepath, project);
405
- await promises.rm(filepath);
406
- };
407
- const _fileInfo = async ({ project, testPath = process.cwd() }, path, encoding) => {
408
- const filepath = resolve$1(dirname$1(testPath), path);
409
- assertFileAccess(filepath, project);
410
- const content = await promises.readFile(filepath, encoding || "base64");
411
- return {
412
- content,
413
- basename: basename$1(filepath),
414
- mime: mime.getType(filepath)
415
- };
416
- };
417
-
418
- const hover = async (context, selector, options = {}) => {
419
- if (context.provider instanceof PlaywrightBrowserProvider) {
420
- await context.iframe.locator(selector).hover(options);
421
- } else if (context.provider instanceof WebdriverBrowserProvider) {
422
- const browser = context.browser;
423
- await browser.$(selector).moveTo(options);
424
- } else {
425
- throw new TypeError(`Provider "${context.provider.name}" does not support hover`);
462
+ const injectorJs = typeof globalServer.injectorJs === "string" ? globalServer.injectorJs : await globalServer.injectorJs;
463
+ const injector = replacer(injectorJs, {
464
+ __VITEST_PROVIDER__: JSON.stringify(project.browser.provider.name),
465
+ __VITEST_CONFIG__: JSON.stringify(browserProject.wrapSerializedConfig()),
466
+ __VITEST_FILES__: JSON.stringify(files),
467
+ __VITEST_VITE_CONFIG__: JSON.stringify({
468
+ root: browserProject.vite.config.root
469
+ }),
470
+ __VITEST_TYPE__: '"tester"',
471
+ __VITEST_SESSION_ID__: JSON.stringify(sessionId),
472
+ __VITEST_TESTER_ID__: JSON.stringify(crypto.randomUUID()),
473
+ __VITEST_PROVIDED_CONTEXT__: JSON.stringify(stringify(project.getProvidedContext()))
474
+ });
475
+ const testerHtml = typeof browserProject.testerHtml === "string" ? browserProject.testerHtml : await browserProject.testerHtml;
476
+ try {
477
+ const url2 = join("/@fs/", browserProject.testerFilepath);
478
+ const indexhtml = await browserProject.vite.transformIndexHtml(url2, testerHtml);
479
+ const html = replacer(indexhtml, {
480
+ __VITEST_FAVICON__: globalServer.faviconUrl,
481
+ __VITEST_INJECTOR__: injector,
482
+ __VITEST_APPEND__: `
483
+ __vitest_browser_runner__.runningFiles = ${tests}
484
+ __vitest_browser_runner__.iframeId = ${iframeId}
485
+ __vitest_browser_runner__.${method === "run" ? "runTests" : "collectTests"}(__vitest_browser_runner__.runningFiles)
486
+ document.querySelector('script[data-vitest-append]').remove()
487
+ `
488
+ });
489
+ return html;
490
+ } catch (err) {
491
+ session.reject(err);
492
+ next(err);
426
493
  }
427
- };
428
-
429
- var clickableInputTypes;
430
- (function(clickableInputTypes) {
431
- clickableInputTypes["button"] = "button";
432
- clickableInputTypes["color"] = "color";
433
- clickableInputTypes["file"] = "file";
434
- clickableInputTypes["image"] = "image";
435
- clickableInputTypes["reset"] = "reset";
436
- clickableInputTypes["submit"] = "submit";
437
- clickableInputTypes["checkbox"] = "checkbox";
438
- clickableInputTypes["radio"] = "radio";
439
- })(clickableInputTypes || (clickableInputTypes = {}));
494
+ }
440
495
 
441
- var editableInputTypes;
442
- (function(editableInputTypes) {
443
- editableInputTypes["text"] = "text";
444
- editableInputTypes["date"] = "date";
445
- editableInputTypes["datetime-local"] = "datetime-local";
446
- editableInputTypes["email"] = "email";
447
- editableInputTypes["month"] = "month";
448
- editableInputTypes["number"] = "number";
449
- editableInputTypes["password"] = "password";
450
- editableInputTypes["search"] = "search";
451
- editableInputTypes["tel"] = "tel";
452
- editableInputTypes["time"] = "time";
453
- editableInputTypes["url"] = "url";
454
- editableInputTypes["week"] = "week";
455
- })(editableInputTypes || (editableInputTypes = {}));
496
+ function createTesterMiddleware(browserServer) {
497
+ return async function vitestTesterMiddleware(req, res, next) {
498
+ if (!req.url) {
499
+ return next();
500
+ }
501
+ const url = new URL(req.url, "http://localhost");
502
+ if (!url.pathname.startsWith(browserServer.prefixTesterUrl)) {
503
+ return next();
504
+ }
505
+ const html = await resolveTester(browserServer, url, res, next);
506
+ if (html) {
507
+ disableCache(res);
508
+ allowIframes(res);
509
+ res.write(html, "utf-8");
510
+ res.end();
511
+ }
512
+ };
513
+ }
456
514
 
457
- var maxLengthSupportedTypes;
458
- (function(maxLengthSupportedTypes) {
459
- maxLengthSupportedTypes["email"] = "email";
460
- maxLengthSupportedTypes["password"] = "password";
461
- maxLengthSupportedTypes["search"] = "search";
462
- maxLengthSupportedTypes["telephone"] = "telephone";
463
- maxLengthSupportedTypes["text"] = "text";
464
- maxLengthSupportedTypes["url"] = "url";
465
- })(maxLengthSupportedTypes || (maxLengthSupportedTypes = {}));
515
+ const VIRTUAL_ID_CONTEXT = "\0@vitest/browser/context";
516
+ const ID_CONTEXT = "@vitest/browser/context";
517
+ const __dirname = dirname(fileURLToPath(import.meta.url));
518
+ function BrowserContext(globalServer) {
519
+ return {
520
+ name: "vitest:browser:virtual-module:context",
521
+ enforce: "pre",
522
+ resolveId(id) {
523
+ if (id === ID_CONTEXT) {
524
+ return VIRTUAL_ID_CONTEXT;
525
+ }
526
+ },
527
+ load(id) {
528
+ if (id === VIRTUAL_ID_CONTEXT) {
529
+ return generateContextFile.call(this, globalServer);
530
+ }
531
+ }
532
+ };
533
+ }
534
+ async function generateContextFile(globalServer) {
535
+ const commands = Object.keys(globalServer.commands);
536
+ const filepathCode = "__vitest_worker__.filepath || __vitest_worker__.current?.file?.filepath || undefined";
537
+ const provider = [...globalServer.children][0].provider || { name: "preview" };
538
+ const providerName = provider.name;
539
+ const commandsCode = commands.filter((command) => !command.startsWith("__vitest")).map((command) => {
540
+ return ` ["${command}"]: (...args) => rpc().triggerCommand(sessionId, "${command}", filepath(), args),`;
541
+ }).join("\n");
542
+ const userEventNonProviderImport = await getUserEventImport(
543
+ providerName,
544
+ this.resolve.bind(this)
545
+ );
546
+ const distContextPath = slash$1(`/@fs/${resolve(__dirname, "context.js")}`);
547
+ return `
548
+ import { page, createUserEvent, cdp } from '${distContextPath}'
549
+ ${userEventNonProviderImport}
550
+ const filepath = () => ${filepathCode}
551
+ const rpc = () => __vitest_worker__.rpc
552
+ const sessionId = __vitest_browser_runner__.sessionId
466
553
 
467
- var bracketDict;
468
- (function(bracketDict) {
469
- bracketDict["{"] = "}";
470
- bracketDict["["] = "]";
471
- })(bracketDict || (bracketDict = {}));
472
- /**
473
- * Read the next key definition from user input
474
- *
475
- * Describe key per `{descriptor}` or `[descriptor]`.
476
- * Everything else will be interpreted as a single character as descriptor - e.g. `a`.
477
- * Brackets `{` and `[` can be escaped by doubling - e.g. `foo[[bar` translates to `foo[bar`.
478
- * A previously pressed key can be released per `{/descriptor}`.
479
- * Keeping the key pressed can be written as `{descriptor>}`.
480
- * When keeping the key pressed you can choose how long the key is pressed `{descriptor>3}`.
481
- * You can then release the key per `{descriptor>3/}` or keep it pressed and continue with the next key.
482
- */ function readNextDescriptor(text, context) {
483
- let pos = 0;
484
- const startBracket = text[pos] in bracketDict ? text[pos] : '';
485
- pos += startBracket.length;
486
- const isEscapedChar = new RegExp(`^\\${startBracket}{2}`).test(text);
487
- const type = isEscapedChar ? '' : startBracket;
488
- return {
489
- type,
490
- ...type === '' ? readPrintableChar(text, pos) : readTag(text, pos, type)
491
- };
554
+ export const server = {
555
+ platform: ${JSON.stringify(process.platform)},
556
+ version: ${JSON.stringify(process.version)},
557
+ provider: ${JSON.stringify(providerName)},
558
+ browser: __vitest_browser_runner__.config.browser.name,
559
+ commands: {
560
+ ${commandsCode}
561
+ },
562
+ config: __vitest_browser_runner__.config,
492
563
  }
493
- function readPrintableChar(text, pos, context) {
494
- const descriptor = text[pos];
495
- assertDescriptor(descriptor, text, pos);
496
- pos += descriptor.length;
497
- return {
498
- consumedLength: pos,
499
- descriptor,
500
- releasePrevious: false,
501
- releaseSelf: true,
502
- repeat: 1
503
- };
504
- }
505
- function readTag(text, pos, startBracket, context) {
506
- var _text_slice_match, _text_slice_match1;
507
- const releasePreviousModifier = text[pos] === '/' ? '/' : '';
508
- pos += releasePreviousModifier.length;
509
- const escapedDescriptor = startBracket === '{' && text[pos] === '\\';
510
- pos += Number(escapedDescriptor);
511
- 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];
512
- assertDescriptor(descriptor, text, pos);
513
- pos += descriptor.length;
514
- var _text_slice_match_;
515
- const repeatModifier = (_text_slice_match_ = (_text_slice_match1 = text.slice(pos).match(/^>\d+/)) === null || _text_slice_match1 === void 0 ? void 0 : _text_slice_match1[0]) !== null && _text_slice_match_ !== void 0 ? _text_slice_match_ : '';
516
- pos += repeatModifier.length;
517
- const releaseSelfModifier = text[pos] === '/' || !repeatModifier && text[pos] === '>' ? text[pos] : '';
518
- pos += releaseSelfModifier.length;
519
- const expectedEndBracket = bracketDict[startBracket];
520
- const endBracket = text[pos] === expectedEndBracket ? expectedEndBracket : '';
521
- if (!endBracket) {
522
- throw new Error(getErrorMessage([
523
- !repeatModifier && 'repeat modifier',
524
- !releaseSelfModifier && 'release modifier',
525
- `"${expectedEndBracket}"`
526
- ].filter(Boolean).join(' or '), text[pos], text));
527
- }
528
- pos += endBracket.length;
529
- return {
530
- consumedLength: pos,
531
- descriptor,
532
- releasePrevious: !!releasePreviousModifier,
533
- repeat: repeatModifier ? Math.max(Number(repeatModifier.substr(1)), 1) : 1,
534
- releaseSelf: hasReleaseSelf(releaseSelfModifier, repeatModifier)
535
- };
536
- }
537
- function assertDescriptor(descriptor, text, pos, context) {
538
- if (!descriptor) {
539
- throw new Error(getErrorMessage('key descriptor', text[pos], text));
540
- }
541
- }
542
- function hasReleaseSelf(releaseSelfModifier, repeatModifier) {
543
- if (releaseSelfModifier) {
544
- return releaseSelfModifier === '/';
545
- }
546
- if (repeatModifier) {
547
- return false;
548
- }
564
+ export const commands = server.commands
565
+ export const userEvent = createUserEvent(_userEventSetup)
566
+ export { page, cdp }
567
+ `;
549
568
  }
550
- function getErrorMessage(expected, found, text, context) {
551
- return `Expected ${expected} but found "${found !== null && found !== void 0 ? found : ''}" in "${text}"
552
- See ${`https://testing-library.com/docs/user-event/keyboard`}
553
- for more information about how userEvent parses your input.`;
569
+ async function getUserEventImport(provider, resolve2) {
570
+ if (provider !== "preview") {
571
+ return "const _userEventSetup = undefined";
572
+ }
573
+ const resolved = await resolve2("@testing-library/user-event", __dirname);
574
+ if (!resolved) {
575
+ throw new Error(`Failed to resolve user-event package from ${__dirname}`);
576
+ }
577
+ return `import { userEvent as __vitest_user_event__ } from '${slash$1(`/@fs/${resolved.id}`)}'
578
+ const _userEventSetup = __vitest_user_event__
579
+ `;
554
580
  }
555
581
 
556
- var ApiLevel;
557
- (function(ApiLevel) {
558
- ApiLevel[ApiLevel["Trigger"] = 2] = "Trigger";
559
- ApiLevel[ApiLevel["Call"] = 1] = "Call";
560
- })(ApiLevel || (ApiLevel = {}));
561
-
562
- var PointerEventsCheckLevel;
563
- (function(PointerEventsCheckLevel) {
564
- /**
565
- * Check pointer events on every user interaction that triggers a bunch of events.
566
- * E.g. once for releasing a mouse button even though this triggers `pointerup`, `mouseup`, `click`, etc...
567
- */ PointerEventsCheckLevel[PointerEventsCheckLevel["EachTrigger"] = 4] = "EachTrigger";
568
- /** Check each target once per call to pointer (related) API */ PointerEventsCheckLevel[PointerEventsCheckLevel["EachApiCall"] = 2] = "EachApiCall";
569
- /** Check each event target once */ PointerEventsCheckLevel[PointerEventsCheckLevel["EachTarget"] = 1] = "EachTarget";
570
- /** No pointer events check */ PointerEventsCheckLevel[PointerEventsCheckLevel["Never"] = 0] = "Never";
571
- })(PointerEventsCheckLevel || (PointerEventsCheckLevel = {}));
572
-
573
- var DOM_KEY_LOCATION;
574
- (function(DOM_KEY_LOCATION) {
575
- DOM_KEY_LOCATION[DOM_KEY_LOCATION["STANDARD"] = 0] = "STANDARD";
576
- DOM_KEY_LOCATION[DOM_KEY_LOCATION["LEFT"] = 1] = "LEFT";
577
- DOM_KEY_LOCATION[DOM_KEY_LOCATION["RIGHT"] = 2] = "RIGHT";
578
- DOM_KEY_LOCATION[DOM_KEY_LOCATION["NUMPAD"] = 3] = "NUMPAD";
579
- })(DOM_KEY_LOCATION || (DOM_KEY_LOCATION = {}));
580
-
581
- /**
582
- * Mapping for a default US-104-QWERTY keyboard
583
- */ const defaultKeyMap = [
584
- // alphanumeric keys
585
- ...'0123456789'.split('').map((c)=>({
586
- code: `Digit${c}`,
587
- key: c
588
- })),
589
- ...')!@#$%^&*('.split('').map((c, i)=>({
590
- code: `Digit${i}`,
591
- key: c,
592
- shiftKey: true
593
- })),
594
- ...'abcdefghijklmnopqrstuvwxyz'.split('').map((c)=>({
595
- code: `Key${c.toUpperCase()}`,
596
- key: c
597
- })),
598
- ...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map((c)=>({
599
- code: `Key${c}`,
600
- key: c,
601
- shiftKey: true
602
- })),
603
- // alphanumeric block - functional
604
- {
605
- code: 'Space',
606
- key: ' '
607
- },
608
- {
609
- code: 'AltLeft',
610
- key: 'Alt',
611
- location: DOM_KEY_LOCATION.LEFT
612
- },
613
- {
614
- code: 'AltRight',
615
- key: 'Alt',
616
- location: DOM_KEY_LOCATION.RIGHT
617
- },
618
- {
619
- code: 'ShiftLeft',
620
- key: 'Shift',
621
- location: DOM_KEY_LOCATION.LEFT
622
- },
623
- {
624
- code: 'ShiftRight',
625
- key: 'Shift',
626
- location: DOM_KEY_LOCATION.RIGHT
627
- },
628
- {
629
- code: 'ControlLeft',
630
- key: 'Control',
631
- location: DOM_KEY_LOCATION.LEFT
632
- },
633
- {
634
- code: 'ControlRight',
635
- key: 'Control',
636
- location: DOM_KEY_LOCATION.RIGHT
637
- },
638
- {
639
- code: 'MetaLeft',
640
- key: 'Meta',
641
- location: DOM_KEY_LOCATION.LEFT
642
- },
643
- {
644
- code: 'MetaRight',
645
- key: 'Meta',
646
- location: DOM_KEY_LOCATION.RIGHT
647
- },
582
+ const versionRegexp = /(?:\?|&)v=\w{8}/;
583
+ var BrowserPlugin = (parentServer, base = "/") => {
584
+ function isPackageExists(pkg, root) {
585
+ return parentServer.vitest.packageInstaller.isPackageExists?.(pkg, {
586
+ paths: [root]
587
+ });
588
+ }
589
+ return [
648
590
  {
649
- code: 'OSLeft',
650
- key: 'OS',
651
- location: DOM_KEY_LOCATION.LEFT
591
+ enforce: "pre",
592
+ name: "vitest:browser",
593
+ async configureServer(server) {
594
+ parentServer.setServer(server);
595
+ server.middlewares.use(function vitestHeaders(_req, res, next) {
596
+ const headers = server.config.server.headers;
597
+ if (headers) {
598
+ for (const name in headers) {
599
+ res.setHeader(name, headers[name]);
600
+ }
601
+ }
602
+ next();
603
+ });
604
+ server.middlewares.use(createOrchestratorMiddleware(parentServer));
605
+ server.middlewares.use(createTesterMiddleware(parentServer));
606
+ server.middlewares.use(
607
+ `${base}favicon.svg`,
608
+ (_, res) => {
609
+ const content = readFileSync(resolve(distRoot, "client/favicon.svg"));
610
+ res.write(content, "utf-8");
611
+ res.end();
612
+ }
613
+ );
614
+ const coverageFolder = resolveCoverageFolder(parentServer.vitest);
615
+ const coveragePath = coverageFolder ? coverageFolder[1] : void 0;
616
+ if (coveragePath && base === coveragePath) {
617
+ throw new Error(
618
+ `The ui base path and the coverage path cannot be the same: ${base}, change coverage.reportsDirectory`
619
+ );
620
+ }
621
+ if (coverageFolder) {
622
+ server.middlewares.use(
623
+ coveragePath,
624
+ sirv(coverageFolder[0], {
625
+ single: true,
626
+ dev: true,
627
+ setHeaders: (res) => {
628
+ res.setHeader(
629
+ "Cache-Control",
630
+ "public,max-age=0,must-revalidate"
631
+ );
632
+ }
633
+ })
634
+ );
635
+ }
636
+ const uiEnabled = parentServer.config.browser.ui;
637
+ if (uiEnabled) {
638
+ server.middlewares.use(`${base}__screenshot-error`, function vitestBrowserScreenshotError(req, res) {
639
+ if (!req.url) {
640
+ res.statusCode = 404;
641
+ res.end();
642
+ return;
643
+ }
644
+ const url = new URL(req.url, "http://localhost");
645
+ const file = url.searchParams.get("file");
646
+ if (!file) {
647
+ res.statusCode = 404;
648
+ res.end();
649
+ return;
650
+ }
651
+ let stat;
652
+ try {
653
+ stat = lstatSync(file);
654
+ } catch {
655
+ }
656
+ if (!stat?.isFile()) {
657
+ res.statusCode = 404;
658
+ res.end();
659
+ return;
660
+ }
661
+ const ext = extname(file);
662
+ const buffer = readFileSync(file);
663
+ res.setHeader(
664
+ "Cache-Control",
665
+ "public,max-age=0,must-revalidate"
666
+ );
667
+ res.setHeader("Content-Length", buffer.length);
668
+ res.setHeader("Content-Type", ext === "jpeg" || ext === "jpg" ? "image/jpeg" : ext === "webp" ? "image/webp" : "image/png");
669
+ res.end(buffer);
670
+ });
671
+ }
672
+ server.middlewares.use((req, res, next) => {
673
+ if (req.url && versionRegexp.test(req.url) && !req.url.includes("chunk-")) {
674
+ res.setHeader("Cache-Control", "no-cache");
675
+ const setHeader = res.setHeader.bind(res);
676
+ res.setHeader = function(name, value) {
677
+ if (name === "Cache-Control") {
678
+ return res;
679
+ }
680
+ return setHeader(name, value);
681
+ };
682
+ }
683
+ next();
684
+ });
685
+ }
652
686
  },
653
687
  {
654
- code: 'OSRight',
655
- key: 'OS',
656
- location: DOM_KEY_LOCATION.RIGHT
657
- },
658
- {
659
- code: 'Tab',
660
- key: 'Tab'
661
- },
662
- {
663
- code: 'CapsLock',
664
- key: 'CapsLock'
665
- },
666
- {
667
- code: 'Backspace',
668
- key: 'Backspace'
669
- },
670
- {
671
- code: 'Enter',
672
- key: 'Enter'
673
- },
674
- // function
675
- {
676
- code: 'Escape',
677
- key: 'Escape'
678
- },
679
- // arrows
680
- {
681
- code: 'ArrowUp',
682
- key: 'ArrowUp'
683
- },
684
- {
685
- code: 'ArrowDown',
686
- key: 'ArrowDown'
687
- },
688
- {
689
- code: 'ArrowLeft',
690
- key: 'ArrowLeft'
691
- },
692
- {
693
- code: 'ArrowRight',
694
- key: 'ArrowRight'
695
- },
696
- // control pad
697
- {
698
- code: 'Home',
699
- key: 'Home'
688
+ name: "vitest:browser:tests",
689
+ enforce: "pre",
690
+ async config() {
691
+ const project = parentServer.vitest.getProjectByName(parentServer.config.name);
692
+ const { testFiles: allTestFiles } = await project.globTestFiles();
693
+ const browserTestFiles = allTestFiles.filter(
694
+ (file) => getFilePoolName(project, file) === "browser"
695
+ );
696
+ const setupFiles = toArray(project.config.setupFiles);
697
+ const define = {};
698
+ for (const env in project.config.env || {}) {
699
+ const stringValue = JSON.stringify(project.config.env[env]);
700
+ define[`import.meta.env.${env}`] = stringValue;
701
+ }
702
+ const entries = [
703
+ ...browserTestFiles,
704
+ ...setupFiles,
705
+ resolve(distDir, "index.js"),
706
+ resolve(distDir, "browser.js"),
707
+ resolve(distDir, "runners.js"),
708
+ resolve(distDir, "utils.js"),
709
+ ...project.config.snapshotSerializers || []
710
+ ];
711
+ const exclude = [
712
+ "vitest",
713
+ "vitest/utils",
714
+ "vitest/browser",
715
+ "vitest/runners",
716
+ "@vitest/browser",
717
+ "@vitest/browser/client",
718
+ "@vitest/utils",
719
+ "@vitest/utils/source-map",
720
+ "@vitest/runner",
721
+ "@vitest/spy",
722
+ "@vitest/utils/error",
723
+ "@vitest/snapshot",
724
+ "@vitest/expect",
725
+ "std-env",
726
+ "tinybench",
727
+ "tinyspy",
728
+ "tinyrainbow",
729
+ "pathe",
730
+ "msw",
731
+ "msw/browser"
732
+ ];
733
+ if (typeof project.config.diff === "string") {
734
+ entries.push(project.config.diff);
735
+ }
736
+ if (parentServer.vitest.coverageProvider) {
737
+ const coverage = parentServer.vitest.config.coverage;
738
+ const provider = coverage.provider;
739
+ if (provider === "v8") {
740
+ const path = tryResolve("@vitest/coverage-v8", [parentServer.config.root]);
741
+ if (path) {
742
+ entries.push(path);
743
+ exclude.push("@vitest/coverage-v8/browser");
744
+ }
745
+ } else if (provider === "istanbul") {
746
+ const path = tryResolve("@vitest/coverage-istanbul", [parentServer.config.root]);
747
+ if (path) {
748
+ entries.push(path);
749
+ exclude.push("@vitest/coverage-istanbul");
750
+ }
751
+ } else if (provider === "custom" && coverage.customProviderModule) {
752
+ entries.push(coverage.customProviderModule);
753
+ }
754
+ }
755
+ const include = [
756
+ "vitest > expect-type",
757
+ "vitest > @vitest/snapshot > magic-string",
758
+ "vitest > chai",
759
+ "vitest > chai > loupe",
760
+ "vitest > @vitest/utils > loupe",
761
+ "@vitest/browser > @testing-library/user-event",
762
+ "@vitest/browser > @testing-library/dom"
763
+ ];
764
+ const fileRoot = browserTestFiles[0] ? dirname(browserTestFiles[0]) : project.config.root;
765
+ const svelte = isPackageExists("vitest-browser-svelte", fileRoot);
766
+ if (svelte) {
767
+ exclude.push("vitest-browser-svelte");
768
+ }
769
+ const vueTestUtils = isPackageExists("@vue/test-utils", fileRoot);
770
+ if (vueTestUtils) {
771
+ include.push("@vue/test-utils");
772
+ }
773
+ return {
774
+ define,
775
+ resolve: {
776
+ dedupe: ["vitest"]
777
+ },
778
+ optimizeDeps: {
779
+ entries,
780
+ exclude,
781
+ include
782
+ }
783
+ };
784
+ },
785
+ async resolveId(id) {
786
+ if (!/\?browserv=\w+$/.test(id)) {
787
+ return;
788
+ }
789
+ let useId = id.slice(0, id.lastIndexOf("?"));
790
+ if (useId.startsWith("/@fs/")) {
791
+ useId = useId.slice(5);
792
+ }
793
+ if (/^\w:/.test(useId)) {
794
+ useId = useId.replace(/\\/g, "/");
795
+ }
796
+ return useId;
797
+ }
700
798
  },
701
799
  {
702
- code: 'End',
703
- key: 'End'
800
+ name: "vitest:browser:resolve-virtual",
801
+ async resolveId(rawId) {
802
+ if (rawId === "/mockServiceWorker.js") {
803
+ return this.resolve("msw/mockServiceWorker.js", distRoot, {
804
+ skipSelf: true
805
+ });
806
+ }
807
+ }
704
808
  },
705
809
  {
706
- code: 'Delete',
707
- key: 'Delete'
810
+ name: "vitest:browser:assets",
811
+ configureServer(server) {
812
+ server.middlewares.use(
813
+ "/__vitest__",
814
+ sirv(resolve(distRoot, "client/__vitest__"))
815
+ );
816
+ },
817
+ resolveId(id) {
818
+ if (id.startsWith("/__vitest_browser__/")) {
819
+ return resolve(distRoot, "client", id.slice(1));
820
+ }
821
+ },
822
+ transform(code, id) {
823
+ if (id.includes(parentServer.vite.config.cacheDir) && id.includes("loupe.js")) {
824
+ const utilRequire = "nodeUtil = require_util();";
825
+ return code.replace(utilRequire, " ".repeat(utilRequire.length));
826
+ }
827
+ }
708
828
  },
829
+ BrowserContext(parentServer),
830
+ dynamicImportPlugin({
831
+ globalThisAccessor: '"__vitest_browser_runner__"',
832
+ filter(id) {
833
+ if (id.includes(distRoot)) {
834
+ return false;
835
+ }
836
+ return true;
837
+ }
838
+ }),
709
839
  {
710
- code: 'PageUp',
711
- key: 'PageUp'
840
+ name: "vitest:browser:config",
841
+ enforce: "post",
842
+ async config(viteConfig) {
843
+ // Enables using ignore hint for coverage providers with @preserve keyword
844
+ if (viteConfig.esbuild !== false) {
845
+ viteConfig.esbuild ||= {};
846
+ viteConfig.esbuild.legalComments = "inline";
847
+ }
848
+ const defaultPort = parentServer.vitest._browserLastPort++;
849
+ const api = resolveApiServerConfig(
850
+ viteConfig.test?.browser || {},
851
+ defaultPort
852
+ );
853
+ viteConfig.server = {
854
+ ...viteConfig.server,
855
+ port: defaultPort,
856
+ ...api,
857
+ middlewareMode: false,
858
+ open: false
859
+ };
860
+ viteConfig.server.fs ??= {};
861
+ viteConfig.server.fs.allow = viteConfig.server.fs.allow || [];
862
+ viteConfig.server.fs.allow.push(
863
+ ...resolveFsAllow(
864
+ parentServer.vitest.config.root,
865
+ parentServer.vitest.vite.config.configFile
866
+ ),
867
+ distRoot
868
+ );
869
+ return {
870
+ resolve: {
871
+ alias: viteConfig.test?.alias
872
+ }
873
+ };
874
+ }
712
875
  },
713
876
  {
714
- code: 'PageDown',
715
- key: 'PageDown'
877
+ name: "vitest:browser:in-source-tests",
878
+ transform(code, id) {
879
+ const project = parentServer.vitest.getProjectByName(parentServer.config.name);
880
+ if (!project.isCachedTestFile(id) || !code.includes("import.meta.vitest")) {
881
+ return;
882
+ }
883
+ const s = new MagicString(code, { filename: cleanUrl(id) });
884
+ s.prepend(
885
+ `import.meta.vitest = __vitest_index__;
886
+ `
887
+ );
888
+ return {
889
+ code: s.toString(),
890
+ map: s.generateMap({ hires: true })
891
+ };
892
+ }
716
893
  },
717
- // Special keys that are not part of a default US-layout but included for specific behavior
718
894
  {
719
- code: 'Fn',
720
- key: 'Fn'
895
+ name: "vitest:browser:worker",
896
+ transform(code, id, _options) {
897
+ if (/(?:\?|&)worker_file&type=\w+(?:&|$)/.test(id)) {
898
+ const s = new MagicString(code);
899
+ s.prepend("globalThis.__vitest_browser_runner__ = { wrapDynamicImport: f => f() };\n");
900
+ return {
901
+ code: s.toString(),
902
+ map: s.generateMap({ hires: "boundary" })
903
+ };
904
+ }
905
+ }
721
906
  },
722
907
  {
723
- code: 'Symbol',
724
- key: 'Symbol'
908
+ name: "vitest:browser:transform-tester-html",
909
+ enforce: "pre",
910
+ async transformIndexHtml(html, ctx) {
911
+ const projectBrowser = [...parentServer.children].find((server) => {
912
+ return ctx.filename === server.testerFilepath;
913
+ });
914
+ if (!projectBrowser) {
915
+ return;
916
+ }
917
+ if (!parentServer.testerScripts) {
918
+ const testerScripts = await parentServer.formatScripts(
919
+ parentServer.config.browser.testerScripts
920
+ );
921
+ parentServer.testerScripts = testerScripts;
922
+ }
923
+ const stateJs = typeof parentServer.stateJs === "string" ? parentServer.stateJs : await parentServer.stateJs;
924
+ const testerTags = [];
925
+ const isDefaultTemplate = resolve(distRoot, "client/tester/tester.html") === projectBrowser.testerFilepath;
926
+ if (!isDefaultTemplate) {
927
+ const manifestContent = parentServer.manifest instanceof Promise ? await parentServer.manifest : parentServer.manifest;
928
+ const testerEntry = manifestContent["tester/tester.html"];
929
+ testerTags.push({
930
+ tag: "script",
931
+ attrs: {
932
+ type: "module",
933
+ crossorigin: "",
934
+ src: `${parentServer.base}${testerEntry.file}`
935
+ },
936
+ injectTo: "head"
937
+ });
938
+ for (const importName of testerEntry.imports || []) {
939
+ const entryManifest = manifestContent[importName];
940
+ if (entryManifest) {
941
+ testerTags.push(
942
+ {
943
+ tag: "link",
944
+ attrs: {
945
+ href: `${parentServer.base}${entryManifest.file}`,
946
+ rel: "modulepreload",
947
+ crossorigin: ""
948
+ },
949
+ injectTo: "head"
950
+ }
951
+ );
952
+ }
953
+ }
954
+ } else {
955
+ testerTags.push({
956
+ tag: "style",
957
+ children: `
958
+ html {
959
+ padding: 0;
960
+ margin: 0;
961
+ }
962
+ body {
963
+ padding: 0;
964
+ margin: 0;
965
+ min-height: 100vh;
966
+ }`,
967
+ injectTo: "head"
968
+ });
969
+ }
970
+ return [
971
+ {
972
+ tag: "script",
973
+ children: "{__VITEST_INJECTOR__}",
974
+ injectTo: "head-prepend"
975
+ },
976
+ {
977
+ tag: "script",
978
+ children: stateJs,
979
+ injectTo: "head-prepend"
980
+ },
981
+ {
982
+ tag: "script",
983
+ attrs: {
984
+ type: "module",
985
+ src: parentServer.errorCatcherUrl
986
+ },
987
+ injectTo: "head"
988
+ },
989
+ parentServer.locatorsUrl ? {
990
+ tag: "script",
991
+ attrs: {
992
+ type: "module",
993
+ src: parentServer.locatorsUrl
994
+ },
995
+ injectTo: "head"
996
+ } : null,
997
+ ...parentServer.testerScripts,
998
+ ...testerTags,
999
+ {
1000
+ tag: "script",
1001
+ attrs: {
1002
+ "type": "module",
1003
+ "data-vitest-append": ""
1004
+ },
1005
+ children: "{__VITEST_APPEND__}",
1006
+ injectTo: "body"
1007
+ }
1008
+ ].filter((s) => s != null);
1009
+ }
725
1010
  },
726
1011
  {
727
- code: 'AltRight',
728
- key: 'AltGraph'
729
- }
730
- ];
731
-
732
- /**
733
- * Parse key defintions per `keyboardMap`
734
- *
735
- * Keys can be referenced by `{key}` or `{special}` as well as physical locations per `[code]`.
736
- * Everything else will be interpreted as a typed character - e.g. `a`.
737
- * Brackets `{` and `[` can be escaped by doubling - e.g. `foo[[bar` translates to `foo[bar`.
738
- * Keeping the key pressed can be written as `{key>}`.
739
- * When keeping the key pressed you can choose how long (how many keydown and keypress) the key is pressed `{key>3}`.
740
- * You can then release the key per `{key>3/}` or keep it pressed and continue with the next key.
741
- */ function parseKeyDef(keyboardMap, text) {
742
- const defs = [];
743
- do {
744
- const { type, descriptor, consumedLength, releasePrevious, releaseSelf = true, repeat } = readNextDescriptor(text);
745
- var _keyboardMap_find;
746
- const keyDef = (_keyboardMap_find = keyboardMap.find((def)=>{
747
- if (type === '[') {
748
- var _def_code;
749
- return ((_def_code = def.code) === null || _def_code === void 0 ? void 0 : _def_code.toLowerCase()) === descriptor.toLowerCase();
750
- } else if (type === '{') {
751
- var _def_key;
752
- return ((_def_key = def.key) === null || _def_key === void 0 ? void 0 : _def_key.toLowerCase()) === descriptor.toLowerCase();
1012
+ name: "vitest:browser:support-testing-library",
1013
+ config() {
1014
+ return {
1015
+ optimizeDeps: {
1016
+ esbuildOptions: {
1017
+ plugins: [
1018
+ {
1019
+ name: "test-utils-rewrite",
1020
+ setup(build) {
1021
+ build.onResolve({ filter: /^@vue\/test-utils$/ }, (args) => {
1022
+ const _require2 = getRequire();
1023
+ const resolved = _require2.resolve(args.path, {
1024
+ paths: [args.importer]
1025
+ });
1026
+ return { path: resolved };
1027
+ });
1028
+ }
1029
+ }
1030
+ ]
753
1031
  }
754
- return def.key === descriptor;
755
- })) !== null && _keyboardMap_find !== void 0 ? _keyboardMap_find : {
756
- key: 'Unknown',
757
- code: 'Unknown',
758
- [type === '[' ? 'code' : 'key']: descriptor
1032
+ }
759
1033
  };
760
- defs.push({
761
- keyDef,
762
- releasePrevious,
763
- releaseSelf,
764
- repeat
765
- });
766
- text = text.slice(consumedLength);
767
- }while (text)
768
- return defs;
1034
+ }
1035
+ }
1036
+ ];
1037
+ };
1038
+ function tryResolve(path, paths) {
1039
+ try {
1040
+ const _require2 = getRequire();
1041
+ return _require2.resolve(path, { paths });
1042
+ } catch {
1043
+ return void 0;
1044
+ }
769
1045
  }
770
-
771
- const keyboard = async (context, text, state) => {
772
- if (context.provider instanceof PlaywrightBrowserProvider) {
773
- const frame = await context.frame();
774
- await frame.evaluate(focusIframe);
775
- } else if (context.provider instanceof WebdriverBrowserProvider) {
776
- await context.browser.execute(focusIframe);
1046
+ let _require;
1047
+ function getRequire() {
1048
+ if (!_require) {
1049
+ _require = createRequire(import.meta.url);
777
1050
  }
778
- const pressed = new Set(state.unreleased);
779
- await keyboardImplementation(
780
- pressed,
781
- context.provider,
782
- context.contextId,
783
- text,
784
- async () => {
785
- if (context.provider instanceof PlaywrightBrowserProvider) {
786
- const frame = await context.frame();
787
- await frame.evaluate(selectAll);
788
- } else if (context.provider instanceof WebdriverBrowserProvider) {
789
- await context.browser.execute(selectAll);
790
- } else {
791
- throw new TypeError(`Provider "${context.provider.name}" does not support selecting all text`);
792
- }
793
- },
794
- true
1051
+ return _require;
1052
+ }
1053
+ function resolveCoverageFolder(vitest) {
1054
+ const options = vitest.config;
1055
+ const htmlReporter = options.coverage?.enabled ? toArray(options.coverage.reporter).find((reporter) => {
1056
+ if (typeof reporter === "string") {
1057
+ return reporter === "html";
1058
+ }
1059
+ return reporter[0] === "html";
1060
+ }) : void 0;
1061
+ if (!htmlReporter) {
1062
+ return void 0;
1063
+ }
1064
+ const root = resolve(
1065
+ options.root || process.cwd(),
1066
+ options.coverage.reportsDirectory || coverageConfigDefaults.reportsDirectory
795
1067
  );
796
- return {
797
- unreleased: Array.from(pressed)
798
- };
799
- };
800
- const keyboardCleanup = async (context, state) => {
801
- const { provider, contextId } = context;
802
- if (provider instanceof PlaywrightBrowserProvider) {
803
- const page = provider.getPage(contextId);
804
- for (const key of state.unreleased) {
805
- await page.keyboard.up(key);
1068
+ const subdir = Array.isArray(htmlReporter) && htmlReporter.length > 1 && "subdir" in htmlReporter[1] ? htmlReporter[1].subdir : void 0;
1069
+ if (!subdir || typeof subdir !== "string") {
1070
+ return [root, `/${basename(root)}/`];
1071
+ }
1072
+ return [resolve(root, subdir), `/${basename(root)}/${subdir}/`];
1073
+ }
1074
+ const postfixRE = /[?#].*$/;
1075
+ function cleanUrl(url) {
1076
+ return url.replace(postfixRE, "");
1077
+ }
1078
+
1079
+ class BrowserServerCDPHandler {
1080
+ constructor(session, tester) {
1081
+ this.session = session;
1082
+ this.tester = tester;
1083
+ }
1084
+ listenerIds = {};
1085
+ listeners = {};
1086
+ send(method, params) {
1087
+ return this.session.send(method, params);
1088
+ }
1089
+ on(event, id, once = false) {
1090
+ if (!this.listenerIds[event]) {
1091
+ this.listenerIds[event] = [];
806
1092
  }
807
- } else if (provider instanceof WebdriverBrowserProvider) {
808
- const keyboard2 = provider.browser.action("key");
809
- for (const key of state.unreleased) {
810
- keyboard2.up(key);
1093
+ this.listenerIds[event].push(id);
1094
+ if (!this.listeners[event]) {
1095
+ this.listeners[event] = (payload) => {
1096
+ this.tester.cdpEvent(
1097
+ event,
1098
+ payload
1099
+ );
1100
+ if (once) {
1101
+ this.off(event, id);
1102
+ }
1103
+ };
1104
+ this.session.on(event, this.listeners[event]);
811
1105
  }
812
- await keyboard2.perform();
813
- } else {
814
- throw new TypeError(`Provider "${context.provider.name}" does not support keyboard api`);
815
1106
  }
816
- };
817
- const VALID_KEYS = /* @__PURE__ */ new Set(["Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Backquote", "`", "~", "Digit1", "1", "!", "Digit2", "2", "@", "Digit3", "3", "#", "Digit4", "4", "$", "Digit5", "5", "%", "Digit6", "6", "^", "Digit7", "7", "&", "Digit8", "8", "*", "Digit9", "9", "(", "Digit0", "0", ")", "Minus", "-", "_", "Equal", "=", "+", "Backslash", "\\", "|", "Backspace", "Tab", "KeyQ", "q", "Q", "KeyW", "w", "W", "KeyE", "e", "E", "KeyR", "r", "R", "KeyT", "t", "T", "KeyY", "y", "Y", "KeyU", "u", "U", "KeyI", "i", "I", "KeyO", "o", "O", "KeyP", "p", "P", "BracketLeft", "[", "{", "BracketRight", "]", "}", "CapsLock", "KeyA", "a", "A", "KeyS", "s", "S", "KeyD", "d", "D", "KeyF", "f", "F", "KeyG", "g", "G", "KeyH", "h", "H", "KeyJ", "j", "J", "KeyK", "k", "K", "KeyL", "l", "L", "Semicolon", ";", ":", "Quote", "'", '"', "Enter", "\n", "\r", "ShiftLeft", "Shift", "KeyZ", "z", "Z", "KeyX", "x", "X", "KeyC", "c", "C", "KeyV", "v", "V", "KeyB", "b", "B", "KeyN", "n", "N", "KeyM", "m", "M", "Comma", ",", "<", "Period", ".", ">", "Slash", "/", "?", "ShiftRight", "ControlLeft", "Control", "MetaLeft", "Meta", "AltLeft", "Alt", "Space", " ", "AltRight", "AltGraph", "MetaRight", "ContextMenu", "ControlRight", "PrintScreen", "ScrollLock", "Pause", "PageUp", "PageDown", "Insert", "Delete", "Home", "End", "ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown", "NumLock", "NumpadDivide", "NumpadMultiply", "NumpadSubtract", "Numpad7", "Numpad8", "Numpad9", "Numpad4", "Numpad5", "Numpad6", "NumpadAdd", "Numpad1", "Numpad2", "Numpad3", "Numpad0", "NumpadDecimal", "NumpadEnter"]);
818
- async function keyboardImplementation(pressed, provider, contextId, text, selectAll2, skipRelease) {
819
- if (provider instanceof PlaywrightBrowserProvider) {
820
- const page = provider.getPage(contextId);
821
- const actions = parseKeyDef(defaultKeyMap, text);
822
- for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) {
823
- const key = keyDef.key;
824
- if (pressed.has(key)) {
825
- if (VALID_KEYS.has(key)) {
826
- await page.keyboard.up(key);
827
- }
828
- pressed.delete(key);
829
- }
830
- if (!releasePrevious) {
831
- if (key === "selectall") {
832
- await selectAll2();
833
- continue;
834
- }
835
- for (let i = 1; i <= repeat; i++) {
836
- if (VALID_KEYS.has(key)) {
837
- await page.keyboard.down(key);
838
- } else {
839
- await page.keyboard.insertText(key);
840
- }
841
- }
842
- if (releaseSelf) {
843
- if (VALID_KEYS.has(key)) {
844
- await page.keyboard.up(key);
845
- }
846
- } else {
847
- pressed.add(key);
848
- }
849
- }
850
- }
851
- if (!skipRelease && pressed.size) {
852
- for (const key of pressed) {
853
- if (VALID_KEYS.has(key)) {
854
- await page.keyboard.up(key);
855
- }
856
- }
1107
+ off(event, id) {
1108
+ if (!this.listenerIds[event]) {
1109
+ this.listenerIds[event] = [];
857
1110
  }
858
- } else if (provider instanceof WebdriverBrowserProvider) {
859
- const { Key } = await import('webdriverio');
860
- const browser = provider.browser;
861
- const actions = parseKeyDef(defaultKeyMap, text);
862
- let keyboard2 = browser.action("key");
863
- for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) {
864
- let key = keyDef.key;
865
- const code = "location" in keyDef ? keyDef.key : keyDef.code;
866
- const special = Key[code];
867
- if (special) {
868
- key = special;
869
- }
870
- if (pressed.has(key)) {
871
- keyboard2.up(key);
872
- pressed.delete(key);
873
- }
874
- if (!releasePrevious) {
875
- if (key === "selectall") {
876
- await keyboard2.perform();
877
- keyboard2 = browser.action("key");
878
- await selectAll2();
879
- continue;
880
- }
881
- for (let i = 1; i <= repeat; i++) {
882
- keyboard2.down(key);
883
- }
884
- if (releaseSelf) {
885
- keyboard2.up(key);
886
- } else {
887
- pressed.add(key);
888
- }
889
- }
1111
+ this.listenerIds[event] = this.listenerIds[event].filter((l) => l !== id);
1112
+ if (!this.listenerIds[event].length) {
1113
+ this.session.off(event, this.listeners[event]);
1114
+ delete this.listeners[event];
890
1115
  }
891
- const allRelease = keyboard2.toJSON().actions.every((action) => action.type === "keyUp");
892
- await keyboard2.perform(allRelease ? false : skipRelease);
893
1116
  }
894
- return {
895
- pressed
896
- };
897
- }
898
- function focusIframe() {
899
- if (!document.activeElement || document.activeElement.ownerDocument !== document || document.activeElement === document.body) {
900
- window.focus();
1117
+ once(event, listener) {
1118
+ this.on(event, listener, true);
901
1119
  }
902
1120
  }
903
- function selectAll() {
904
- const element = document.activeElement;
905
- if (element && element.select) {
906
- element.select();
1121
+
1122
+ const clear = async (context, selector) => {
1123
+ if (context.provider instanceof PlaywrightBrowserProvider) {
1124
+ const { iframe } = context;
1125
+ const element = iframe.locator(selector);
1126
+ await element.clear();
1127
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
1128
+ const browser = context.browser;
1129
+ const element = await browser.$(selector);
1130
+ await element.clearValue();
1131
+ } else {
1132
+ throw new TypeError(`Provider "${context.provider.name}" does not support clearing elements`);
907
1133
  }
908
- }
1134
+ };
909
1135
 
910
- const screenshot = async (context, name, options = {}) => {
911
- if (!context.testPath) {
912
- throw new Error(`Cannot take a screenshot without a test path`);
1136
+ const click = async (context, selector, options = {}) => {
1137
+ const provider = context.provider;
1138
+ if (provider instanceof PlaywrightBrowserProvider) {
1139
+ const tester = context.iframe;
1140
+ await tester.locator(selector).click(options);
1141
+ } else if (provider instanceof WebdriverBrowserProvider) {
1142
+ const browser = context.browser;
1143
+ await browser.$(selector).click(options);
1144
+ } else {
1145
+ throw new TypeError(`Provider "${provider.name}" doesn't support click command`);
913
1146
  }
914
- const path = options.path ? resolve(dirname(context.testPath), options.path) : resolveScreenshotPath(
915
- context.testPath,
916
- name,
917
- context.project.config
918
- );
919
- const savePath = normalize$1(path);
920
- await mkdir(dirname(path), { recursive: true });
921
- if (context.provider instanceof PlaywrightBrowserProvider) {
922
- if (options.element) {
923
- const { element: selector, ...config } = options;
924
- const element = context.iframe.locator(`${selector}`);
925
- const buffer2 = await element.screenshot({
926
- ...config,
927
- path: savePath
928
- });
929
- return returnResult(options, path, buffer2);
930
- }
931
- const buffer = await context.iframe.locator("body").screenshot({
1147
+ };
1148
+ const dblClick = async (context, selector, options = {}) => {
1149
+ const provider = context.provider;
1150
+ if (provider instanceof PlaywrightBrowserProvider) {
1151
+ const tester = context.iframe;
1152
+ await tester.locator(selector).dblclick(options);
1153
+ } else if (provider instanceof WebdriverBrowserProvider) {
1154
+ const browser = context.browser;
1155
+ await browser.$(selector).doubleClick();
1156
+ } else {
1157
+ throw new TypeError(`Provider "${provider.name}" doesn't support dblClick command`);
1158
+ }
1159
+ };
1160
+ const tripleClick = async (context, selector, options = {}) => {
1161
+ const provider = context.provider;
1162
+ if (provider instanceof PlaywrightBrowserProvider) {
1163
+ const tester = context.iframe;
1164
+ await tester.locator(selector).click({
932
1165
  ...options,
933
- path: savePath
1166
+ clickCount: 3
934
1167
  });
935
- return returnResult(options, path, buffer);
936
- }
937
- if (context.provider instanceof WebdriverBrowserProvider) {
938
- const page = context.provider.browser;
939
- if (!options.element) {
940
- const body = await page.$("body");
941
- const buffer2 = await body.saveScreenshot(savePath);
942
- return returnResult(options, path, buffer2);
943
- }
944
- const element = await page.$(`${options.element}`);
945
- const buffer = await element.saveScreenshot(savePath);
946
- return returnResult(options, path, buffer);
1168
+ } else if (provider instanceof WebdriverBrowserProvider) {
1169
+ const browser = context.browser;
1170
+ await browser.action("pointer", { parameters: { pointerType: "mouse" } }).move({ origin: await browser.$(selector) }).down().up().pause(50).down().up().pause(50).down().up().pause(50).perform();
1171
+ } else {
1172
+ throw new TypeError(`Provider "${provider.name}" doesn't support tripleClick command`);
947
1173
  }
948
- throw new Error(
949
- `Provider "${context.provider.name}" does not support screenshots`
950
- );
951
1174
  };
952
- function resolveScreenshotPath(testPath, name, config) {
953
- const dir = dirname(testPath);
954
- const base = basename(testPath);
955
- if (config.browser.screenshotDirectory) {
956
- return resolve(
957
- config.browser.screenshotDirectory,
958
- relative(config.root, dir),
959
- base,
960
- name
1175
+
1176
+ const dragAndDrop = async (context, source, target, options_) => {
1177
+ if (context.provider instanceof PlaywrightBrowserProvider) {
1178
+ const frame = await context.frame();
1179
+ await frame.dragAndDrop(
1180
+ source,
1181
+ target,
1182
+ options_
961
1183
  );
1184
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
1185
+ const $source = context.browser.$(source);
1186
+ const $target = context.browser.$(target);
1187
+ const options = options_ || {};
1188
+ const duration = options.duration ?? 10;
1189
+ await context.browser.action("pointer").move({ duration: 0, origin: $source, x: options.sourceX ?? 0, y: options.sourceY ?? 0 }).down({ button: 0 }).move({ duration: 0, origin: "pointer", x: 0, y: 0 }).pause(duration).move({ duration: 0, origin: $target, x: options.targetX ?? 0, y: options.targetY ?? 0 }).move({ duration: 0, origin: "pointer", x: 1, y: 0 }).move({ duration: 0, origin: "pointer", x: -1, y: 0 }).up({ button: 0 }).perform();
1190
+ } else {
1191
+ throw new TypeError(`Provider "${context.provider.name}" does not support dragging elements`);
962
1192
  }
963
- return resolve(dir, "__screenshots__", base, name);
964
- }
965
- function returnResult(options, path, buffer) {
966
- if (options.base64) {
967
- return { path, base64: buffer.toString("base64") };
968
- }
969
- return path;
970
- }
1193
+ };
971
1194
 
972
- const selectOptions = async (context, selector, userValues, options = {}) => {
1195
+ const fill = async (context, selector, text, options = {}) => {
973
1196
  if (context.provider instanceof PlaywrightBrowserProvider) {
974
- const value = userValues;
975
1197
  const { iframe } = context;
976
- const selectElement = iframe.locator(selector);
977
- const values = await Promise.all(value.map(async (v) => {
978
- if (typeof v === "string") {
979
- return v;
980
- }
981
- const elementHandler = await iframe.locator(v.element).elementHandle();
982
- if (!elementHandler) {
983
- throw new Error(`Element not found: ${v.element}`);
984
- }
985
- return elementHandler;
986
- }));
987
- await selectElement.selectOption(values, options);
1198
+ const element = iframe.locator(selector);
1199
+ await element.fill(text, options);
988
1200
  } else if (context.provider instanceof WebdriverBrowserProvider) {
989
- const values = userValues;
990
- if (!values.length) {
991
- return;
992
- }
993
1201
  const browser = context.browser;
994
- if (values.length === 1 && "index" in values[0]) {
995
- const selectElement = browser.$(selector);
996
- await selectElement.selectByIndex(values[0].index);
997
- } else {
998
- throw new Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);
999
- }
1202
+ await browser.$(selector).setValue(text);
1000
1203
  } else {
1001
- throw new TypeError(`Provider "${context.provider.name}" doesn't support selectOptions command`);
1204
+ throw new TypeError(`Provider "${context.provider.name}" does not support clearing elements`);
1002
1205
  }
1003
1206
  };
1004
1207
 
1005
- const tab = async (context, options = {}) => {
1006
- const provider = context.provider;
1007
- if (provider instanceof PlaywrightBrowserProvider) {
1008
- const page = context.page;
1009
- await page.keyboard.press(options.shift === true ? "Shift+Tab" : "Tab");
1010
- return;
1011
- }
1012
- if (provider instanceof WebdriverBrowserProvider) {
1013
- const { Key } = await import('webdriverio');
1014
- const browser = context.browser;
1015
- await browser.keys(options.shift === true ? [Key.Shift, Key.Tab] : [Key.Tab]);
1016
- return;
1017
- }
1018
- throw new Error(`Provider "${provider.name}" doesn't support tab command`);
1208
+ const types = {
1209
+ 'application/andrew-inset': ['ez'],
1210
+ 'application/appinstaller': ['appinstaller'],
1211
+ 'application/applixware': ['aw'],
1212
+ 'application/appx': ['appx'],
1213
+ 'application/appxbundle': ['appxbundle'],
1214
+ 'application/atom+xml': ['atom'],
1215
+ 'application/atomcat+xml': ['atomcat'],
1216
+ 'application/atomdeleted+xml': ['atomdeleted'],
1217
+ 'application/atomsvc+xml': ['atomsvc'],
1218
+ 'application/atsc-dwd+xml': ['dwd'],
1219
+ 'application/atsc-held+xml': ['held'],
1220
+ 'application/atsc-rsat+xml': ['rsat'],
1221
+ 'application/automationml-aml+xml': ['aml'],
1222
+ 'application/automationml-amlx+zip': ['amlx'],
1223
+ 'application/bdoc': ['bdoc'],
1224
+ 'application/calendar+xml': ['xcs'],
1225
+ 'application/ccxml+xml': ['ccxml'],
1226
+ 'application/cdfx+xml': ['cdfx'],
1227
+ 'application/cdmi-capability': ['cdmia'],
1228
+ 'application/cdmi-container': ['cdmic'],
1229
+ 'application/cdmi-domain': ['cdmid'],
1230
+ 'application/cdmi-object': ['cdmio'],
1231
+ 'application/cdmi-queue': ['cdmiq'],
1232
+ 'application/cpl+xml': ['cpl'],
1233
+ 'application/cu-seeme': ['cu'],
1234
+ 'application/cwl': ['cwl'],
1235
+ 'application/dash+xml': ['mpd'],
1236
+ 'application/dash-patch+xml': ['mpp'],
1237
+ 'application/davmount+xml': ['davmount'],
1238
+ 'application/docbook+xml': ['dbk'],
1239
+ 'application/dssc+der': ['dssc'],
1240
+ 'application/dssc+xml': ['xdssc'],
1241
+ 'application/ecmascript': ['ecma'],
1242
+ 'application/emma+xml': ['emma'],
1243
+ 'application/emotionml+xml': ['emotionml'],
1244
+ 'application/epub+zip': ['epub'],
1245
+ 'application/exi': ['exi'],
1246
+ 'application/express': ['exp'],
1247
+ 'application/fdf': ['fdf'],
1248
+ 'application/fdt+xml': ['fdt'],
1249
+ 'application/font-tdpfr': ['pfr'],
1250
+ 'application/geo+json': ['geojson'],
1251
+ 'application/gml+xml': ['gml'],
1252
+ 'application/gpx+xml': ['gpx'],
1253
+ 'application/gxf': ['gxf'],
1254
+ 'application/gzip': ['gz'],
1255
+ 'application/hjson': ['hjson'],
1256
+ 'application/hyperstudio': ['stk'],
1257
+ 'application/inkml+xml': ['ink', 'inkml'],
1258
+ 'application/ipfix': ['ipfix'],
1259
+ 'application/its+xml': ['its'],
1260
+ 'application/java-archive': ['jar', 'war', 'ear'],
1261
+ 'application/java-serialized-object': ['ser'],
1262
+ 'application/java-vm': ['class'],
1263
+ 'application/javascript': ['*js'],
1264
+ 'application/json': ['json', 'map'],
1265
+ 'application/json5': ['json5'],
1266
+ 'application/jsonml+json': ['jsonml'],
1267
+ 'application/ld+json': ['jsonld'],
1268
+ 'application/lgr+xml': ['lgr'],
1269
+ 'application/lost+xml': ['lostxml'],
1270
+ 'application/mac-binhex40': ['hqx'],
1271
+ 'application/mac-compactpro': ['cpt'],
1272
+ 'application/mads+xml': ['mads'],
1273
+ 'application/manifest+json': ['webmanifest'],
1274
+ 'application/marc': ['mrc'],
1275
+ 'application/marcxml+xml': ['mrcx'],
1276
+ 'application/mathematica': ['ma', 'nb', 'mb'],
1277
+ 'application/mathml+xml': ['mathml'],
1278
+ 'application/mbox': ['mbox'],
1279
+ 'application/media-policy-dataset+xml': ['mpf'],
1280
+ 'application/mediaservercontrol+xml': ['mscml'],
1281
+ 'application/metalink+xml': ['metalink'],
1282
+ 'application/metalink4+xml': ['meta4'],
1283
+ 'application/mets+xml': ['mets'],
1284
+ 'application/mmt-aei+xml': ['maei'],
1285
+ 'application/mmt-usd+xml': ['musd'],
1286
+ 'application/mods+xml': ['mods'],
1287
+ 'application/mp21': ['m21', 'mp21'],
1288
+ 'application/mp4': ['*mp4', '*mpg4', 'mp4s', 'm4p'],
1289
+ 'application/msix': ['msix'],
1290
+ 'application/msixbundle': ['msixbundle'],
1291
+ 'application/msword': ['doc', 'dot'],
1292
+ 'application/mxf': ['mxf'],
1293
+ 'application/n-quads': ['nq'],
1294
+ 'application/n-triples': ['nt'],
1295
+ 'application/node': ['cjs'],
1296
+ 'application/octet-stream': [
1297
+ 'bin',
1298
+ 'dms',
1299
+ 'lrf',
1300
+ 'mar',
1301
+ 'so',
1302
+ 'dist',
1303
+ 'distz',
1304
+ 'pkg',
1305
+ 'bpk',
1306
+ 'dump',
1307
+ 'elc',
1308
+ 'deploy',
1309
+ 'exe',
1310
+ 'dll',
1311
+ 'deb',
1312
+ 'dmg',
1313
+ 'iso',
1314
+ 'img',
1315
+ 'msi',
1316
+ 'msp',
1317
+ 'msm',
1318
+ 'buffer',
1319
+ ],
1320
+ 'application/oda': ['oda'],
1321
+ 'application/oebps-package+xml': ['opf'],
1322
+ 'application/ogg': ['ogx'],
1323
+ 'application/omdoc+xml': ['omdoc'],
1324
+ 'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'],
1325
+ 'application/oxps': ['oxps'],
1326
+ 'application/p2p-overlay+xml': ['relo'],
1327
+ 'application/patch-ops-error+xml': ['xer'],
1328
+ 'application/pdf': ['pdf'],
1329
+ 'application/pgp-encrypted': ['pgp'],
1330
+ 'application/pgp-keys': ['asc'],
1331
+ 'application/pgp-signature': ['sig', '*asc'],
1332
+ 'application/pics-rules': ['prf'],
1333
+ 'application/pkcs10': ['p10'],
1334
+ 'application/pkcs7-mime': ['p7m', 'p7c'],
1335
+ 'application/pkcs7-signature': ['p7s'],
1336
+ 'application/pkcs8': ['p8'],
1337
+ 'application/pkix-attr-cert': ['ac'],
1338
+ 'application/pkix-cert': ['cer'],
1339
+ 'application/pkix-crl': ['crl'],
1340
+ 'application/pkix-pkipath': ['pkipath'],
1341
+ 'application/pkixcmp': ['pki'],
1342
+ 'application/pls+xml': ['pls'],
1343
+ 'application/postscript': ['ai', 'eps', 'ps'],
1344
+ 'application/provenance+xml': ['provx'],
1345
+ 'application/pskc+xml': ['pskcxml'],
1346
+ 'application/raml+yaml': ['raml'],
1347
+ 'application/rdf+xml': ['rdf', 'owl'],
1348
+ 'application/reginfo+xml': ['rif'],
1349
+ 'application/relax-ng-compact-syntax': ['rnc'],
1350
+ 'application/resource-lists+xml': ['rl'],
1351
+ 'application/resource-lists-diff+xml': ['rld'],
1352
+ 'application/rls-services+xml': ['rs'],
1353
+ 'application/route-apd+xml': ['rapd'],
1354
+ 'application/route-s-tsid+xml': ['sls'],
1355
+ 'application/route-usd+xml': ['rusd'],
1356
+ 'application/rpki-ghostbusters': ['gbr'],
1357
+ 'application/rpki-manifest': ['mft'],
1358
+ 'application/rpki-roa': ['roa'],
1359
+ 'application/rsd+xml': ['rsd'],
1360
+ 'application/rss+xml': ['rss'],
1361
+ 'application/rtf': ['rtf'],
1362
+ 'application/sbml+xml': ['sbml'],
1363
+ 'application/scvp-cv-request': ['scq'],
1364
+ 'application/scvp-cv-response': ['scs'],
1365
+ 'application/scvp-vp-request': ['spq'],
1366
+ 'application/scvp-vp-response': ['spp'],
1367
+ 'application/sdp': ['sdp'],
1368
+ 'application/senml+xml': ['senmlx'],
1369
+ 'application/sensml+xml': ['sensmlx'],
1370
+ 'application/set-payment-initiation': ['setpay'],
1371
+ 'application/set-registration-initiation': ['setreg'],
1372
+ 'application/shf+xml': ['shf'],
1373
+ 'application/sieve': ['siv', 'sieve'],
1374
+ 'application/smil+xml': ['smi', 'smil'],
1375
+ 'application/sparql-query': ['rq'],
1376
+ 'application/sparql-results+xml': ['srx'],
1377
+ 'application/sql': ['sql'],
1378
+ 'application/srgs': ['gram'],
1379
+ 'application/srgs+xml': ['grxml'],
1380
+ 'application/sru+xml': ['sru'],
1381
+ 'application/ssdl+xml': ['ssdl'],
1382
+ 'application/ssml+xml': ['ssml'],
1383
+ 'application/swid+xml': ['swidtag'],
1384
+ 'application/tei+xml': ['tei', 'teicorpus'],
1385
+ 'application/thraud+xml': ['tfi'],
1386
+ 'application/timestamped-data': ['tsd'],
1387
+ 'application/toml': ['toml'],
1388
+ 'application/trig': ['trig'],
1389
+ 'application/ttml+xml': ['ttml'],
1390
+ 'application/ubjson': ['ubj'],
1391
+ 'application/urc-ressheet+xml': ['rsheet'],
1392
+ 'application/urc-targetdesc+xml': ['td'],
1393
+ 'application/voicexml+xml': ['vxml'],
1394
+ 'application/wasm': ['wasm'],
1395
+ 'application/watcherinfo+xml': ['wif'],
1396
+ 'application/widget': ['wgt'],
1397
+ 'application/winhlp': ['hlp'],
1398
+ 'application/wsdl+xml': ['wsdl'],
1399
+ 'application/wspolicy+xml': ['wspolicy'],
1400
+ 'application/xaml+xml': ['xaml'],
1401
+ 'application/xcap-att+xml': ['xav'],
1402
+ 'application/xcap-caps+xml': ['xca'],
1403
+ 'application/xcap-diff+xml': ['xdf'],
1404
+ 'application/xcap-el+xml': ['xel'],
1405
+ 'application/xcap-ns+xml': ['xns'],
1406
+ 'application/xenc+xml': ['xenc'],
1407
+ 'application/xfdf': ['xfdf'],
1408
+ 'application/xhtml+xml': ['xhtml', 'xht'],
1409
+ 'application/xliff+xml': ['xlf'],
1410
+ 'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
1411
+ 'application/xml-dtd': ['dtd'],
1412
+ 'application/xop+xml': ['xop'],
1413
+ 'application/xproc+xml': ['xpl'],
1414
+ 'application/xslt+xml': ['*xsl', 'xslt'],
1415
+ 'application/xspf+xml': ['xspf'],
1416
+ 'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
1417
+ 'application/yang': ['yang'],
1418
+ 'application/yin+xml': ['yin'],
1419
+ 'application/zip': ['zip'],
1420
+ 'audio/3gpp': ['*3gpp'],
1421
+ 'audio/aac': ['adts', 'aac'],
1422
+ 'audio/adpcm': ['adp'],
1423
+ 'audio/amr': ['amr'],
1424
+ 'audio/basic': ['au', 'snd'],
1425
+ 'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
1426
+ 'audio/mobile-xmf': ['mxmf'],
1427
+ 'audio/mp3': ['*mp3'],
1428
+ 'audio/mp4': ['m4a', 'mp4a'],
1429
+ 'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
1430
+ 'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
1431
+ 'audio/s3m': ['s3m'],
1432
+ 'audio/silk': ['sil'],
1433
+ 'audio/wav': ['wav'],
1434
+ 'audio/wave': ['*wav'],
1435
+ 'audio/webm': ['weba'],
1436
+ 'audio/xm': ['xm'],
1437
+ 'font/collection': ['ttc'],
1438
+ 'font/otf': ['otf'],
1439
+ 'font/ttf': ['ttf'],
1440
+ 'font/woff': ['woff'],
1441
+ 'font/woff2': ['woff2'],
1442
+ 'image/aces': ['exr'],
1443
+ 'image/apng': ['apng'],
1444
+ 'image/avci': ['avci'],
1445
+ 'image/avcs': ['avcs'],
1446
+ 'image/avif': ['avif'],
1447
+ 'image/bmp': ['bmp', 'dib'],
1448
+ 'image/cgm': ['cgm'],
1449
+ 'image/dicom-rle': ['drle'],
1450
+ 'image/dpx': ['dpx'],
1451
+ 'image/emf': ['emf'],
1452
+ 'image/fits': ['fits'],
1453
+ 'image/g3fax': ['g3'],
1454
+ 'image/gif': ['gif'],
1455
+ 'image/heic': ['heic'],
1456
+ 'image/heic-sequence': ['heics'],
1457
+ 'image/heif': ['heif'],
1458
+ 'image/heif-sequence': ['heifs'],
1459
+ 'image/hej2k': ['hej2'],
1460
+ 'image/hsj2': ['hsj2'],
1461
+ 'image/ief': ['ief'],
1462
+ 'image/jls': ['jls'],
1463
+ 'image/jp2': ['jp2', 'jpg2'],
1464
+ 'image/jpeg': ['jpeg', 'jpg', 'jpe'],
1465
+ 'image/jph': ['jph'],
1466
+ 'image/jphc': ['jhc'],
1467
+ 'image/jpm': ['jpm', 'jpgm'],
1468
+ 'image/jpx': ['jpx', 'jpf'],
1469
+ 'image/jxl': ['jxl'],
1470
+ 'image/jxr': ['jxr'],
1471
+ 'image/jxra': ['jxra'],
1472
+ 'image/jxrs': ['jxrs'],
1473
+ 'image/jxs': ['jxs'],
1474
+ 'image/jxsc': ['jxsc'],
1475
+ 'image/jxsi': ['jxsi'],
1476
+ 'image/jxss': ['jxss'],
1477
+ 'image/ktx': ['ktx'],
1478
+ 'image/ktx2': ['ktx2'],
1479
+ 'image/png': ['png'],
1480
+ 'image/sgi': ['sgi'],
1481
+ 'image/svg+xml': ['svg', 'svgz'],
1482
+ 'image/t38': ['t38'],
1483
+ 'image/tiff': ['tif', 'tiff'],
1484
+ 'image/tiff-fx': ['tfx'],
1485
+ 'image/webp': ['webp'],
1486
+ 'image/wmf': ['wmf'],
1487
+ 'message/disposition-notification': ['disposition-notification'],
1488
+ 'message/global': ['u8msg'],
1489
+ 'message/global-delivery-status': ['u8dsn'],
1490
+ 'message/global-disposition-notification': ['u8mdn'],
1491
+ 'message/global-headers': ['u8hdr'],
1492
+ 'message/rfc822': ['eml', 'mime'],
1493
+ 'model/3mf': ['3mf'],
1494
+ 'model/gltf+json': ['gltf'],
1495
+ 'model/gltf-binary': ['glb'],
1496
+ 'model/iges': ['igs', 'iges'],
1497
+ 'model/jt': ['jt'],
1498
+ 'model/mesh': ['msh', 'mesh', 'silo'],
1499
+ 'model/mtl': ['mtl'],
1500
+ 'model/obj': ['obj'],
1501
+ 'model/prc': ['prc'],
1502
+ 'model/step+xml': ['stpx'],
1503
+ 'model/step+zip': ['stpz'],
1504
+ 'model/step-xml+zip': ['stpxz'],
1505
+ 'model/stl': ['stl'],
1506
+ 'model/u3d': ['u3d'],
1507
+ 'model/vrml': ['wrl', 'vrml'],
1508
+ 'model/x3d+binary': ['*x3db', 'x3dbz'],
1509
+ 'model/x3d+fastinfoset': ['x3db'],
1510
+ 'model/x3d+vrml': ['*x3dv', 'x3dvz'],
1511
+ 'model/x3d+xml': ['x3d', 'x3dz'],
1512
+ 'model/x3d-vrml': ['x3dv'],
1513
+ 'text/cache-manifest': ['appcache', 'manifest'],
1514
+ 'text/calendar': ['ics', 'ifb'],
1515
+ 'text/coffeescript': ['coffee', 'litcoffee'],
1516
+ 'text/css': ['css'],
1517
+ 'text/csv': ['csv'],
1518
+ 'text/html': ['html', 'htm', 'shtml'],
1519
+ 'text/jade': ['jade'],
1520
+ 'text/javascript': ['js', 'mjs'],
1521
+ 'text/jsx': ['jsx'],
1522
+ 'text/less': ['less'],
1523
+ 'text/markdown': ['md', 'markdown'],
1524
+ 'text/mathml': ['mml'],
1525
+ 'text/mdx': ['mdx'],
1526
+ 'text/n3': ['n3'],
1527
+ 'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
1528
+ 'text/richtext': ['rtx'],
1529
+ 'text/rtf': ['*rtf'],
1530
+ 'text/sgml': ['sgml', 'sgm'],
1531
+ 'text/shex': ['shex'],
1532
+ 'text/slim': ['slim', 'slm'],
1533
+ 'text/spdx': ['spdx'],
1534
+ 'text/stylus': ['stylus', 'styl'],
1535
+ 'text/tab-separated-values': ['tsv'],
1536
+ 'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
1537
+ 'text/turtle': ['ttl'],
1538
+ 'text/uri-list': ['uri', 'uris', 'urls'],
1539
+ 'text/vcard': ['vcard'],
1540
+ 'text/vtt': ['vtt'],
1541
+ 'text/wgsl': ['wgsl'],
1542
+ 'text/xml': ['*xml'],
1543
+ 'text/yaml': ['yaml', 'yml'],
1544
+ 'video/3gpp': ['3gp', '3gpp'],
1545
+ 'video/3gpp2': ['3g2'],
1546
+ 'video/h261': ['h261'],
1547
+ 'video/h263': ['h263'],
1548
+ 'video/h264': ['h264'],
1549
+ 'video/iso.segment': ['m4s'],
1550
+ 'video/jpeg': ['jpgv'],
1551
+ 'video/jpm': ['*jpm', '*jpgm'],
1552
+ 'video/mj2': ['mj2', 'mjp2'],
1553
+ 'video/mp2t': ['ts', 'm2t', 'm2ts', 'mts'],
1554
+ 'video/mp4': ['mp4', 'mp4v', 'mpg4'],
1555
+ 'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
1556
+ 'video/ogg': ['ogv'],
1557
+ 'video/quicktime': ['qt', 'mov'],
1558
+ 'video/webm': ['webm'],
1019
1559
  };
1560
+ Object.freeze(types);
1020
1561
 
1021
- const type = async (context, selector, text, options = {}) => {
1022
- const { skipClick = false, skipAutoClose = false } = options;
1023
- const unreleased = new Set(Reflect.get(options, "unreleased") ?? []);
1024
- if (context.provider instanceof PlaywrightBrowserProvider) {
1025
- const { iframe } = context;
1026
- const element = iframe.locator(selector);
1027
- if (!skipClick) {
1028
- await element.focus();
1562
+ var __classPrivateFieldGet = (null && null.__classPrivateFieldGet) || function (receiver, state, kind, f) {
1563
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
1564
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
1565
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
1566
+ };
1567
+ var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
1568
+ class Mime {
1569
+ constructor(...args) {
1570
+ _Mime_extensionToType.set(this, new Map());
1571
+ _Mime_typeToExtension.set(this, new Map());
1572
+ _Mime_typeToExtensions.set(this, new Map());
1573
+ for (const arg of args) {
1574
+ this.define(arg);
1575
+ }
1029
1576
  }
1030
- await keyboardImplementation(
1031
- unreleased,
1032
- context.provider,
1033
- context.contextId,
1034
- text,
1035
- () => element.selectText(),
1036
- skipAutoClose
1037
- );
1038
- } else if (context.provider instanceof WebdriverBrowserProvider) {
1039
- const browser = context.browser;
1040
- const element = browser.$(selector);
1041
- if (!skipClick && !await element.isFocused()) {
1042
- await element.click();
1577
+ define(typeMap, force = false) {
1578
+ for (let [type, extensions] of Object.entries(typeMap)) {
1579
+ type = type.toLowerCase();
1580
+ extensions = extensions.map((ext) => ext.toLowerCase());
1581
+ if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
1582
+ __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, new Set());
1583
+ }
1584
+ const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
1585
+ let first = true;
1586
+ for (let extension of extensions) {
1587
+ const starred = extension.startsWith('*');
1588
+ extension = starred ? extension.slice(1) : extension;
1589
+ allExtensions?.add(extension);
1590
+ if (first) {
1591
+ __classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
1592
+ }
1593
+ first = false;
1594
+ if (starred)
1595
+ continue;
1596
+ const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
1597
+ if (currentType && currentType != type && !force) {
1598
+ throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
1599
+ }
1600
+ __classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
1601
+ }
1602
+ }
1603
+ return this;
1043
1604
  }
1044
- await keyboardImplementation(
1045
- unreleased,
1046
- context.provider,
1047
- context.contextId,
1048
- text,
1049
- () => browser.execute(() => {
1050
- const element2 = document.activeElement;
1051
- if (element2) {
1052
- element2.select();
1605
+ getType(path) {
1606
+ if (typeof path !== 'string')
1607
+ return null;
1608
+ const last = path.replace(/^.*[/\\]/, '').toLowerCase();
1609
+ const ext = last.replace(/^.*\./, '').toLowerCase();
1610
+ const hasPath = last.length < path.length;
1611
+ const hasDot = ext.length < last.length - 1;
1612
+ if (!hasDot && hasPath)
1613
+ return null;
1614
+ return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
1615
+ }
1616
+ getExtension(type) {
1617
+ if (typeof type !== 'string')
1618
+ return null;
1619
+ type = type?.split?.(';')[0];
1620
+ return ((type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null);
1621
+ }
1622
+ getAllExtensions(type) {
1623
+ if (typeof type !== 'string')
1624
+ return null;
1625
+ return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
1626
+ }
1627
+ _freeze() {
1628
+ this.define = () => {
1629
+ throw new Error('define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances');
1630
+ };
1631
+ Object.freeze(this);
1632
+ for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
1633
+ Object.freeze(extensions);
1053
1634
  }
1054
- }),
1055
- skipAutoClose
1635
+ return this;
1636
+ }
1637
+ _getTestState() {
1638
+ return {
1639
+ types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
1640
+ extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
1641
+ };
1642
+ }
1643
+ }
1644
+ _Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
1645
+
1646
+ var mime = new Mime(types)._freeze();
1647
+
1648
+ function assertFileAccess(path, project) {
1649
+ if (!isFileServingAllowed(path, project.vite) && !isFileServingAllowed(path, project.vitest.server)) {
1650
+ throw new Error(
1651
+ `Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`
1056
1652
  );
1057
- } else {
1058
- throw new TypeError(`Provider "${context.provider.name}" does not support typing`);
1059
1653
  }
1654
+ }
1655
+ const readFile = async ({ project, testPath = process.cwd() }, path, options = {}) => {
1656
+ const filepath = resolve$1(dirname$1(testPath), path);
1657
+ assertFileAccess(filepath, project);
1658
+ if (typeof options === "object" && !options.encoding) {
1659
+ options.encoding = "utf-8";
1660
+ }
1661
+ return promises.readFile(filepath, options);
1662
+ };
1663
+ const writeFile = async ({ project, testPath = process.cwd() }, path, data, options) => {
1664
+ const filepath = resolve$1(dirname$1(testPath), path);
1665
+ assertFileAccess(filepath, project);
1666
+ const dir = dirname$1(filepath);
1667
+ if (!fs.existsSync(dir)) {
1668
+ await promises.mkdir(dir, { recursive: true });
1669
+ }
1670
+ await promises.writeFile(filepath, data, options);
1671
+ };
1672
+ const removeFile = async ({ project, testPath = process.cwd() }, path) => {
1673
+ const filepath = resolve$1(dirname$1(testPath), path);
1674
+ assertFileAccess(filepath, project);
1675
+ await promises.rm(filepath);
1676
+ };
1677
+ const _fileInfo = async ({ project, testPath = process.cwd() }, path, encoding) => {
1678
+ const filepath = resolve$1(dirname$1(testPath), path);
1679
+ assertFileAccess(filepath, project);
1680
+ const content = await promises.readFile(filepath, encoding || "base64");
1060
1681
  return {
1061
- unreleased: Array.from(unreleased)
1682
+ content,
1683
+ basename: basename$1(filepath),
1684
+ mime: mime.getType(filepath)
1062
1685
  };
1063
1686
  };
1064
1687
 
1065
- const upload = async (context, selector, files) => {
1066
- const testPath = context.testPath;
1067
- if (!testPath) {
1068
- throw new Error(`Cannot upload files outside of a test`);
1069
- }
1070
- const testDir = dirname(testPath);
1688
+ const hover = async (context, selector, options = {}) => {
1071
1689
  if (context.provider instanceof PlaywrightBrowserProvider) {
1072
- const { iframe } = context;
1073
- const playwrightFiles = files.map((file) => {
1074
- if (typeof file === "string") {
1075
- return resolve(testDir, file);
1076
- }
1077
- return {
1078
- name: file.name,
1079
- mimeType: file.mimeType,
1080
- buffer: Buffer.from(file.base64, "base64")
1081
- };
1082
- });
1083
- await iframe.locator(selector).setInputFiles(playwrightFiles);
1690
+ await context.iframe.locator(selector).hover(options);
1084
1691
  } else if (context.provider instanceof WebdriverBrowserProvider) {
1085
- for (const file of files) {
1086
- if (typeof file !== "string") {
1087
- throw new TypeError(`The "${context.provider.name}" provider doesn't support uploading files objects. Provide a file path instead.`);
1088
- }
1089
- }
1090
- const element = context.browser.$(selector);
1091
- for (const file of files) {
1092
- const filepath = resolve(testDir, file);
1093
- const remoteFilePath = await context.browser.uploadFile(filepath);
1094
- await element.addValue(remoteFilePath);
1095
- }
1692
+ const browser = context.browser;
1693
+ await browser.$(selector).moveTo(options);
1096
1694
  } else {
1097
- throw new TypeError(`Provider "${context.provider.name}" does not support uploading files via userEvent.upload`);
1695
+ throw new TypeError(`Provider "${context.provider.name}" does not support hover`);
1098
1696
  }
1099
1697
  };
1100
1698
 
1101
- var builtinCommands = {
1102
- readFile,
1103
- removeFile,
1104
- writeFile,
1105
- __vitest_fileInfo: _fileInfo,
1106
- __vitest_upload: upload,
1107
- __vitest_click: click,
1108
- __vitest_dblClick: dblClick,
1109
- __vitest_tripleClick: tripleClick,
1110
- __vitest_screenshot: screenshot,
1111
- __vitest_type: type,
1112
- __vitest_clear: clear,
1113
- __vitest_fill: fill,
1114
- __vitest_tab: tab,
1115
- __vitest_keyboard: keyboard,
1116
- __vitest_selectOptions: selectOptions,
1117
- __vitest_dragAndDrop: dragAndDrop,
1118
- __vitest_hover: hover,
1119
- __vitest_cleanup: keyboardCleanup
1120
- };
1121
-
1122
- const VIRTUAL_ID_CONTEXT = "\0@vitest/browser/context";
1123
- const ID_CONTEXT = "@vitest/browser/context";
1124
- const __dirname = dirname(fileURLToPath(import.meta.url));
1125
- function BrowserContext(server) {
1126
- const project = server.project;
1127
- project.config.browser.commands ??= {};
1128
- for (const [name, command] of Object.entries(builtinCommands)) {
1129
- project.config.browser.commands[name] ??= command;
1130
- }
1131
- for (const command in project.config.browser.commands) {
1132
- if (!/^[a-z_$][\w$]*$/i.test(command)) {
1133
- throw new Error(
1134
- `Invalid command name "${command}". Only alphanumeric characters, $ and _ are allowed.`
1135
- );
1136
- }
1137
- }
1138
- return {
1139
- name: "vitest:browser:virtual-module:context",
1140
- enforce: "pre",
1141
- resolveId(id) {
1142
- if (id === ID_CONTEXT) {
1143
- return VIRTUAL_ID_CONTEXT;
1144
- }
1145
- },
1146
- load(id) {
1147
- if (id === VIRTUAL_ID_CONTEXT) {
1148
- return generateContextFile.call(this, server);
1149
- }
1150
- }
1151
- };
1152
- }
1153
- async function generateContextFile(server) {
1154
- const commands = Object.keys(server.project.config.browser.commands ?? {});
1155
- const filepathCode = "__vitest_worker__.filepath || __vitest_worker__.current?.file?.filepath || undefined";
1156
- const provider = server.provider;
1157
- const commandsCode = commands.filter((command) => !command.startsWith("__vitest")).map((command) => {
1158
- return ` ["${command}"]: (...args) => rpc().triggerCommand(contextId, "${command}", filepath(), args),`;
1159
- }).join("\n");
1160
- const userEventNonProviderImport = await getUserEventImport(
1161
- provider,
1162
- this.resolve.bind(this)
1163
- );
1164
- const distContextPath = slash(`/@fs/${resolve(__dirname, "context.js")}`);
1165
- return `
1166
- import { page, createUserEvent, cdp } from '${distContextPath}'
1167
- ${userEventNonProviderImport}
1168
- const filepath = () => ${filepathCode}
1169
- const rpc = () => __vitest_worker__.rpc
1170
- const contextId = __vitest_browser_runner__.contextId
1699
+ var clickableInputTypes;
1700
+ (function(clickableInputTypes) {
1701
+ clickableInputTypes["button"] = "button";
1702
+ clickableInputTypes["color"] = "color";
1703
+ clickableInputTypes["file"] = "file";
1704
+ clickableInputTypes["image"] = "image";
1705
+ clickableInputTypes["reset"] = "reset";
1706
+ clickableInputTypes["submit"] = "submit";
1707
+ clickableInputTypes["checkbox"] = "checkbox";
1708
+ clickableInputTypes["radio"] = "radio";
1709
+ })(clickableInputTypes || (clickableInputTypes = {}));
1171
1710
 
1172
- export const server = {
1173
- platform: ${JSON.stringify(process.platform)},
1174
- version: ${JSON.stringify(process.version)},
1175
- provider: ${JSON.stringify(provider.name)},
1176
- browser: ${JSON.stringify(server.project.config.browser.name)},
1177
- commands: {
1178
- ${commandsCode}
1179
- },
1180
- config: __vitest_browser_runner__.config,
1181
- }
1182
- export const commands = server.commands
1183
- export const userEvent = createUserEvent(_userEventSetup)
1184
- export { page, cdp }
1185
- `;
1186
- }
1187
- async function getUserEventImport(provider, resolve2) {
1188
- if (provider.name !== "preview") {
1189
- return "const _userEventSetup = undefined";
1190
- }
1191
- const resolved = await resolve2("@testing-library/user-event", __dirname);
1192
- if (!resolved) {
1193
- throw new Error(`Failed to resolve user-event package from ${__dirname}`);
1194
- }
1195
- return `import { userEvent as __vitest_user_event__ } from '${slash(`/@fs/${resolved.id}`)}'
1196
- const _userEventSetup = __vitest_user_event__
1197
- `;
1198
- }
1711
+ var editableInputTypes;
1712
+ (function(editableInputTypes) {
1713
+ editableInputTypes["text"] = "text";
1714
+ editableInputTypes["date"] = "date";
1715
+ editableInputTypes["datetime-local"] = "datetime-local";
1716
+ editableInputTypes["email"] = "email";
1717
+ editableInputTypes["month"] = "month";
1718
+ editableInputTypes["number"] = "number";
1719
+ editableInputTypes["password"] = "password";
1720
+ editableInputTypes["search"] = "search";
1721
+ editableInputTypes["tel"] = "tel";
1722
+ editableInputTypes["time"] = "time";
1723
+ editableInputTypes["url"] = "url";
1724
+ editableInputTypes["week"] = "week";
1725
+ })(editableInputTypes || (editableInputTypes = {}));
1199
1726
 
1200
- function replacer(code, values) {
1201
- return code.replace(/\{\s*(\w+)\s*\}/g, (_, key) => values[key] ?? _);
1727
+ var maxLengthSupportedTypes;
1728
+ (function(maxLengthSupportedTypes) {
1729
+ maxLengthSupportedTypes["email"] = "email";
1730
+ maxLengthSupportedTypes["password"] = "password";
1731
+ maxLengthSupportedTypes["search"] = "search";
1732
+ maxLengthSupportedTypes["telephone"] = "telephone";
1733
+ maxLengthSupportedTypes["text"] = "text";
1734
+ maxLengthSupportedTypes["url"] = "url";
1735
+ })(maxLengthSupportedTypes || (maxLengthSupportedTypes = {}));
1736
+
1737
+ var bracketDict;
1738
+ (function(bracketDict) {
1739
+ bracketDict["{"] = "}";
1740
+ bracketDict["["] = "]";
1741
+ })(bracketDict || (bracketDict = {}));
1742
+ /**
1743
+ * Read the next key definition from user input
1744
+ *
1745
+ * Describe key per `{descriptor}` or `[descriptor]`.
1746
+ * Everything else will be interpreted as a single character as descriptor - e.g. `a`.
1747
+ * Brackets `{` and `[` can be escaped by doubling - e.g. `foo[[bar` translates to `foo[bar`.
1748
+ * A previously pressed key can be released per `{/descriptor}`.
1749
+ * Keeping the key pressed can be written as `{descriptor>}`.
1750
+ * When keeping the key pressed you can choose how long the key is pressed `{descriptor>3}`.
1751
+ * You can then release the key per `{descriptor>3/}` or keep it pressed and continue with the next key.
1752
+ */ function readNextDescriptor(text, context) {
1753
+ let pos = 0;
1754
+ const startBracket = text[pos] in bracketDict ? text[pos] : '';
1755
+ pos += startBracket.length;
1756
+ const isEscapedChar = new RegExp(`^\\${startBracket}{2}`).test(text);
1757
+ const type = isEscapedChar ? '' : startBracket;
1758
+ return {
1759
+ type,
1760
+ ...type === '' ? readPrintableChar(text, pos) : readTag(text, pos, type)
1761
+ };
1202
1762
  }
1203
- const builtinProviders = ["webdriverio", "playwright", "preview"];
1204
- async function getBrowserProvider(options, project) {
1205
- if (options.provider == null || builtinProviders.includes(options.provider)) {
1206
- const providers = await import('./providers.js');
1207
- const provider = options.provider || "preview";
1208
- return providers[provider];
1209
- }
1210
- let customProviderModule;
1211
- try {
1212
- customProviderModule = await project.import(
1213
- options.provider
1214
- );
1215
- } catch (error) {
1216
- throw new Error(
1217
- `Failed to load custom BrowserProvider from ${options.provider}`,
1218
- { cause: error }
1219
- );
1220
- }
1221
- if (customProviderModule.default == null) {
1222
- throw new Error(
1223
- `Custom BrowserProvider loaded from ${options.provider} was not the default export`
1224
- );
1225
- }
1226
- return customProviderModule.default;
1763
+ function readPrintableChar(text, pos, context) {
1764
+ const descriptor = text[pos];
1765
+ assertDescriptor(descriptor, text, pos);
1766
+ pos += descriptor.length;
1767
+ return {
1768
+ consumedLength: pos,
1769
+ descriptor,
1770
+ releasePrevious: false,
1771
+ releaseSelf: true,
1772
+ repeat: 1
1773
+ };
1227
1774
  }
1228
-
1229
- async function resolveOrchestrator(server, url, res) {
1230
- const project = server.project;
1231
- let contextId = url.searchParams.get("contextId");
1232
- if (!contextId) {
1233
- const contexts = [...server.state.orchestrators.keys()];
1234
- contextId = contexts[contexts.length - 1] ?? "none";
1235
- }
1236
- const files = server.state.getContext(contextId)?.files ?? [];
1237
- const injectorJs = typeof server.injectorJs === "string" ? server.injectorJs : await server.injectorJs;
1238
- const injector = replacer(injectorJs, {
1239
- __VITEST_PROVIDER__: JSON.stringify(server.provider.name),
1240
- __VITEST_CONFIG__: JSON.stringify(server.getSerializableConfig()),
1241
- __VITEST_VITE_CONFIG__: JSON.stringify({
1242
- root: server.vite.config.root
1243
- }),
1244
- __VITEST_FILES__: JSON.stringify(files),
1245
- __VITEST_TYPE__: '"orchestrator"',
1246
- __VITEST_CONTEXT_ID__: JSON.stringify(contextId),
1247
- __VITEST_TESTER_ID__: '"none"',
1248
- __VITEST_PROVIDED_CONTEXT__: "{}"
1249
- });
1250
- res.removeHeader("Content-Security-Policy");
1251
- if (!server.orchestratorScripts) {
1252
- server.orchestratorScripts = (await server.formatScripts(
1253
- project.config.browser.orchestratorScripts
1254
- )).map((script) => {
1255
- let html = "<script ";
1256
- for (const attr in script.attrs || {}) {
1257
- html += `${attr}="${script.attrs[attr]}" `;
1258
- }
1259
- html += `>${script.children}<\/script>`;
1260
- return html;
1261
- }).join("\n");
1262
- }
1263
- let baseHtml = typeof server.orchestratorHtml === "string" ? server.orchestratorHtml : await server.orchestratorHtml;
1264
- if (project.config.browser.ui) {
1265
- const manifestContent = server.manifest instanceof Promise ? await server.manifest : server.manifest;
1266
- const jsEntry = manifestContent["orchestrator.html"].file;
1267
- const base = server.vite.config.base || "/";
1268
- baseHtml = baseHtml.replaceAll("./assets/", `${base}__vitest__/assets/`).replace(
1269
- "<!-- !LOAD_METADATA! -->",
1270
- [
1271
- "{__VITEST_INJECTOR__}",
1272
- "{__VITEST_ERROR_CATCHER__}",
1273
- "{__VITEST_SCRIPTS__}",
1274
- `<script type="module" crossorigin src="${base}${jsEntry}"><\/script>`
1275
- ].join("\n")
1276
- );
1277
- }
1278
- return replacer(baseHtml, {
1279
- __VITEST_FAVICON__: server.faviconUrl,
1280
- __VITEST_TITLE__: "Vitest Browser Runner",
1281
- __VITEST_SCRIPTS__: server.orchestratorScripts,
1282
- __VITEST_INJECTOR__: `<script type="module">${injector}<\/script>`,
1283
- __VITEST_ERROR_CATCHER__: `<script type="module" src="${server.errorCatcherUrl}"><\/script>`,
1284
- __VITEST_CONTEXT_ID__: JSON.stringify(contextId)
1285
- });
1775
+ function readTag(text, pos, startBracket, context) {
1776
+ var _text_slice_match, _text_slice_match1;
1777
+ const releasePreviousModifier = text[pos] === '/' ? '/' : '';
1778
+ pos += releasePreviousModifier.length;
1779
+ const escapedDescriptor = startBracket === '{' && text[pos] === '\\';
1780
+ pos += Number(escapedDescriptor);
1781
+ 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];
1782
+ assertDescriptor(descriptor, text, pos);
1783
+ pos += descriptor.length;
1784
+ var _text_slice_match_;
1785
+ const repeatModifier = (_text_slice_match_ = (_text_slice_match1 = text.slice(pos).match(/^>\d+/)) === null || _text_slice_match1 === void 0 ? void 0 : _text_slice_match1[0]) !== null && _text_slice_match_ !== void 0 ? _text_slice_match_ : '';
1786
+ pos += repeatModifier.length;
1787
+ const releaseSelfModifier = text[pos] === '/' || !repeatModifier && text[pos] === '>' ? text[pos] : '';
1788
+ pos += releaseSelfModifier.length;
1789
+ const expectedEndBracket = bracketDict[startBracket];
1790
+ const endBracket = text[pos] === expectedEndBracket ? expectedEndBracket : '';
1791
+ if (!endBracket) {
1792
+ throw new Error(getErrorMessage([
1793
+ !repeatModifier && 'repeat modifier',
1794
+ !releaseSelfModifier && 'release modifier',
1795
+ `"${expectedEndBracket}"`
1796
+ ].filter(Boolean).join(' or '), text[pos], text));
1797
+ }
1798
+ pos += endBracket.length;
1799
+ return {
1800
+ consumedLength: pos,
1801
+ descriptor,
1802
+ releasePrevious: !!releasePreviousModifier,
1803
+ repeat: repeatModifier ? Math.max(Number(repeatModifier.substr(1)), 1) : 1,
1804
+ releaseSelf: hasReleaseSelf(releaseSelfModifier, repeatModifier)
1805
+ };
1806
+ }
1807
+ function assertDescriptor(descriptor, text, pos, context) {
1808
+ if (!descriptor) {
1809
+ throw new Error(getErrorMessage('key descriptor', text[pos], text));
1810
+ }
1811
+ }
1812
+ function hasReleaseSelf(releaseSelfModifier, repeatModifier) {
1813
+ if (releaseSelfModifier) {
1814
+ return releaseSelfModifier === '/';
1815
+ }
1816
+ if (repeatModifier) {
1817
+ return false;
1818
+ }
1819
+ }
1820
+ function getErrorMessage(expected, found, text, context) {
1821
+ return `Expected ${expected} but found "${found !== null && found !== void 0 ? found : ''}" in "${text}"
1822
+ See ${`https://testing-library.com/docs/user-event/keyboard`}
1823
+ for more information about how userEvent parses your input.`;
1286
1824
  }
1287
1825
 
1288
- /// <reference types="../types/index.d.ts" />
1289
-
1290
- // (c) 2020-present Andrea Giammarchi
1291
-
1292
- const {parse: $parse, stringify: $stringify} = JSON;
1293
- const {keys} = Object;
1294
-
1295
- const Primitive = String; // it could be Number
1296
- const primitive = 'string'; // it could be 'number'
1297
-
1298
- const ignore = {};
1299
- const object = 'object';
1300
-
1301
- const noop = (_, value) => value;
1302
-
1303
- const primitives = value => (
1304
- value instanceof Primitive ? Primitive(value) : value
1305
- );
1306
-
1307
- const Primitives = (_, value) => (
1308
- typeof value === primitive ? new Primitive(value) : value
1309
- );
1826
+ var ApiLevel;
1827
+ (function(ApiLevel) {
1828
+ ApiLevel[ApiLevel["Trigger"] = 2] = "Trigger";
1829
+ ApiLevel[ApiLevel["Call"] = 1] = "Call";
1830
+ })(ApiLevel || (ApiLevel = {}));
1310
1831
 
1311
- const revive = (input, parsed, output, $) => {
1312
- const lazy = [];
1313
- for (let ke = keys(output), {length} = ke, y = 0; y < length; y++) {
1314
- const k = ke[y];
1315
- const value = output[k];
1316
- if (value instanceof Primitive) {
1317
- const tmp = input[value];
1318
- if (typeof tmp === object && !parsed.has(tmp)) {
1319
- parsed.add(tmp);
1320
- output[k] = ignore;
1321
- lazy.push({k, a: [input, parsed, tmp, $]});
1322
- }
1323
- else
1324
- output[k] = $.call(output, k, tmp);
1325
- }
1326
- else if (output[k] !== ignore)
1327
- output[k] = $.call(output, k, value);
1328
- }
1329
- for (let {length} = lazy, i = 0; i < length; i++) {
1330
- const {k, a} = lazy[i];
1331
- output[k] = $.call(output, k, revive.apply(null, a));
1332
- }
1333
- return output;
1334
- };
1832
+ var PointerEventsCheckLevel;
1833
+ (function(PointerEventsCheckLevel) {
1834
+ /**
1835
+ * Check pointer events on every user interaction that triggers a bunch of events.
1836
+ * E.g. once for releasing a mouse button even though this triggers `pointerup`, `mouseup`, `click`, etc...
1837
+ */ PointerEventsCheckLevel[PointerEventsCheckLevel["EachTrigger"] = 4] = "EachTrigger";
1838
+ /** Check each target once per call to pointer (related) API */ PointerEventsCheckLevel[PointerEventsCheckLevel["EachApiCall"] = 2] = "EachApiCall";
1839
+ /** Check each event target once */ PointerEventsCheckLevel[PointerEventsCheckLevel["EachTarget"] = 1] = "EachTarget";
1840
+ /** No pointer events check */ PointerEventsCheckLevel[PointerEventsCheckLevel["Never"] = 0] = "Never";
1841
+ })(PointerEventsCheckLevel || (PointerEventsCheckLevel = {}));
1335
1842
 
1336
- const set = (known, input, value) => {
1337
- const index = Primitive(input.push(value) - 1);
1338
- known.set(value, index);
1339
- return index;
1340
- };
1843
+ var DOM_KEY_LOCATION;
1844
+ (function(DOM_KEY_LOCATION) {
1845
+ DOM_KEY_LOCATION[DOM_KEY_LOCATION["STANDARD"] = 0] = "STANDARD";
1846
+ DOM_KEY_LOCATION[DOM_KEY_LOCATION["LEFT"] = 1] = "LEFT";
1847
+ DOM_KEY_LOCATION[DOM_KEY_LOCATION["RIGHT"] = 2] = "RIGHT";
1848
+ DOM_KEY_LOCATION[DOM_KEY_LOCATION["NUMPAD"] = 3] = "NUMPAD";
1849
+ })(DOM_KEY_LOCATION || (DOM_KEY_LOCATION = {}));
1341
1850
 
1342
1851
  /**
1343
- * Converts a specialized flatted string into a JS value.
1344
- * @param {string} text
1345
- * @param {(this: any, key: string, value: any) => any} [reviver]
1346
- * @returns {any}
1347
- */
1348
- const parse = (text, reviver) => {
1349
- const input = $parse(text, Primitives).map(primitives);
1350
- const value = input[0];
1351
- const $ = reviver || noop;
1352
- const tmp = typeof value === object && value ?
1353
- revive(input, new Set, value, $) :
1354
- value;
1355
- return $.call({'': tmp}, '', tmp);
1356
- };
1852
+ * Mapping for a default US-104-QWERTY keyboard
1853
+ */ const defaultKeyMap = [
1854
+ // alphanumeric keys
1855
+ ...'0123456789'.split('').map((c)=>({
1856
+ code: `Digit${c}`,
1857
+ key: c
1858
+ })),
1859
+ ...')!@#$%^&*('.split('').map((c, i)=>({
1860
+ code: `Digit${i}`,
1861
+ key: c,
1862
+ shiftKey: true
1863
+ })),
1864
+ ...'abcdefghijklmnopqrstuvwxyz'.split('').map((c)=>({
1865
+ code: `Key${c.toUpperCase()}`,
1866
+ key: c
1867
+ })),
1868
+ ...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map((c)=>({
1869
+ code: `Key${c}`,
1870
+ key: c,
1871
+ shiftKey: true
1872
+ })),
1873
+ // alphanumeric block - functional
1874
+ {
1875
+ code: 'Space',
1876
+ key: ' '
1877
+ },
1878
+ {
1879
+ code: 'AltLeft',
1880
+ key: 'Alt',
1881
+ location: DOM_KEY_LOCATION.LEFT
1882
+ },
1883
+ {
1884
+ code: 'AltRight',
1885
+ key: 'Alt',
1886
+ location: DOM_KEY_LOCATION.RIGHT
1887
+ },
1888
+ {
1889
+ code: 'ShiftLeft',
1890
+ key: 'Shift',
1891
+ location: DOM_KEY_LOCATION.LEFT
1892
+ },
1893
+ {
1894
+ code: 'ShiftRight',
1895
+ key: 'Shift',
1896
+ location: DOM_KEY_LOCATION.RIGHT
1897
+ },
1898
+ {
1899
+ code: 'ControlLeft',
1900
+ key: 'Control',
1901
+ location: DOM_KEY_LOCATION.LEFT
1902
+ },
1903
+ {
1904
+ code: 'ControlRight',
1905
+ key: 'Control',
1906
+ location: DOM_KEY_LOCATION.RIGHT
1907
+ },
1908
+ {
1909
+ code: 'MetaLeft',
1910
+ key: 'Meta',
1911
+ location: DOM_KEY_LOCATION.LEFT
1912
+ },
1913
+ {
1914
+ code: 'MetaRight',
1915
+ key: 'Meta',
1916
+ location: DOM_KEY_LOCATION.RIGHT
1917
+ },
1918
+ {
1919
+ code: 'OSLeft',
1920
+ key: 'OS',
1921
+ location: DOM_KEY_LOCATION.LEFT
1922
+ },
1923
+ {
1924
+ code: 'OSRight',
1925
+ key: 'OS',
1926
+ location: DOM_KEY_LOCATION.RIGHT
1927
+ },
1928
+ {
1929
+ code: 'Tab',
1930
+ key: 'Tab'
1931
+ },
1932
+ {
1933
+ code: 'CapsLock',
1934
+ key: 'CapsLock'
1935
+ },
1936
+ {
1937
+ code: 'Backspace',
1938
+ key: 'Backspace'
1939
+ },
1940
+ {
1941
+ code: 'Enter',
1942
+ key: 'Enter'
1943
+ },
1944
+ // function
1945
+ {
1946
+ code: 'Escape',
1947
+ key: 'Escape'
1948
+ },
1949
+ // arrows
1950
+ {
1951
+ code: 'ArrowUp',
1952
+ key: 'ArrowUp'
1953
+ },
1954
+ {
1955
+ code: 'ArrowDown',
1956
+ key: 'ArrowDown'
1957
+ },
1958
+ {
1959
+ code: 'ArrowLeft',
1960
+ key: 'ArrowLeft'
1961
+ },
1962
+ {
1963
+ code: 'ArrowRight',
1964
+ key: 'ArrowRight'
1965
+ },
1966
+ // control pad
1967
+ {
1968
+ code: 'Home',
1969
+ key: 'Home'
1970
+ },
1971
+ {
1972
+ code: 'End',
1973
+ key: 'End'
1974
+ },
1975
+ {
1976
+ code: 'Delete',
1977
+ key: 'Delete'
1978
+ },
1979
+ {
1980
+ code: 'PageUp',
1981
+ key: 'PageUp'
1982
+ },
1983
+ {
1984
+ code: 'PageDown',
1985
+ key: 'PageDown'
1986
+ },
1987
+ // Special keys that are not part of a default US-layout but included for specific behavior
1988
+ {
1989
+ code: 'Fn',
1990
+ key: 'Fn'
1991
+ },
1992
+ {
1993
+ code: 'Symbol',
1994
+ key: 'Symbol'
1995
+ },
1996
+ {
1997
+ code: 'AltRight',
1998
+ key: 'AltGraph'
1999
+ }
2000
+ ];
1357
2001
 
1358
2002
  /**
1359
- * Converts a JS value into a specialized flatted string.
1360
- * @param {any} value
1361
- * @param {((this: any, key: string, value: any) => any) | (string | number)[] | null | undefined} [replacer]
1362
- * @param {string | number | undefined} [space]
1363
- * @returns {string}
1364
- */
1365
- const stringify = (value, replacer, space) => {
1366
- const $ = replacer && typeof replacer === object ?
1367
- (k, v) => (k === '' || -1 < replacer.indexOf(k) ? v : void 0) :
1368
- (replacer || noop);
1369
- const known = new Map;
1370
- const input = [];
1371
- const output = [];
1372
- let i = +set(known, input, $.call({'': value}, '', value));
1373
- let firstRun = !i;
1374
- while (i < input.length) {
1375
- firstRun = true;
1376
- output[i] = $stringify(input[i++], replace, space);
1377
- }
1378
- return '[' + output.join(',') + ']';
1379
- function replace(key, value) {
1380
- if (firstRun) {
1381
- firstRun = !firstRun;
1382
- return value;
1383
- }
1384
- const after = $.call(this, key, value);
1385
- switch (typeof after) {
1386
- case object:
1387
- if (after === null) return after;
1388
- case primitive:
1389
- return known.get(after) || set(known, input, after);
1390
- }
1391
- return after;
1392
- }
1393
- };
2003
+ * Parse key defintions per `keyboardMap`
2004
+ *
2005
+ * Keys can be referenced by `{key}` or `{special}` as well as physical locations per `[code]`.
2006
+ * Everything else will be interpreted as a typed character - e.g. `a`.
2007
+ * Brackets `{` and `[` can be escaped by doubling - e.g. `foo[[bar` translates to `foo[bar`.
2008
+ * Keeping the key pressed can be written as `{key>}`.
2009
+ * When keeping the key pressed you can choose how long (how many keydown and keypress) the key is pressed `{key>3}`.
2010
+ * You can then release the key per `{key>3/}` or keep it pressed and continue with the next key.
2011
+ */ function parseKeyDef(keyboardMap, text) {
2012
+ const defs = [];
2013
+ do {
2014
+ const { type, descriptor, consumedLength, releasePrevious, releaseSelf = true, repeat } = readNextDescriptor(text);
2015
+ var _keyboardMap_find;
2016
+ const keyDef = (_keyboardMap_find = keyboardMap.find((def)=>{
2017
+ if (type === '[') {
2018
+ var _def_code;
2019
+ return ((_def_code = def.code) === null || _def_code === void 0 ? void 0 : _def_code.toLowerCase()) === descriptor.toLowerCase();
2020
+ } else if (type === '{') {
2021
+ var _def_key;
2022
+ return ((_def_key = def.key) === null || _def_key === void 0 ? void 0 : _def_key.toLowerCase()) === descriptor.toLowerCase();
2023
+ }
2024
+ return def.key === descriptor;
2025
+ })) !== null && _keyboardMap_find !== void 0 ? _keyboardMap_find : {
2026
+ key: 'Unknown',
2027
+ code: 'Unknown',
2028
+ [type === '[' ? 'code' : 'key']: descriptor
2029
+ };
2030
+ defs.push({
2031
+ keyDef,
2032
+ releasePrevious,
2033
+ releaseSelf,
2034
+ repeat
2035
+ });
2036
+ text = text.slice(consumedLength);
2037
+ }while (text)
2038
+ return defs;
2039
+ }
1394
2040
 
1395
- async function resolveTester(server, url, res, next) {
1396
- const csp = res.getHeader("Content-Security-Policy");
1397
- if (typeof csp === "string") {
1398
- res.setHeader(
1399
- "Content-Security-Policy",
1400
- csp.replace(/frame-ancestors [^;]+/, "frame-ancestors *")
1401
- );
2041
+ const keyboard = async (context, text, state) => {
2042
+ if (context.provider instanceof PlaywrightBrowserProvider) {
2043
+ const frame = await context.frame();
2044
+ await frame.evaluate(focusIframe);
2045
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
2046
+ await context.browser.execute(focusIframe);
1402
2047
  }
1403
- const { contextId, testFile } = server.resolveTesterUrl(url.pathname);
1404
- const project = server.project;
1405
- const state = server.state;
1406
- const { testFiles } = await project.globTestFiles();
1407
- const tests = testFile === "__vitest_all__" || !testFiles.includes(testFile) ? "__vitest_browser_runner__.files" : JSON.stringify([testFile]);
1408
- const iframeId = JSON.stringify(testFile);
1409
- const context = state.getContext(contextId);
1410
- const files = context?.files ?? [];
1411
- const method = context?.method ?? "run";
1412
- const injectorJs = typeof server.injectorJs === "string" ? server.injectorJs : await server.injectorJs;
1413
- const injector = replacer(injectorJs, {
1414
- __VITEST_PROVIDER__: JSON.stringify(server.provider.name),
1415
- __VITEST_CONFIG__: JSON.stringify(server.getSerializableConfig()),
1416
- __VITEST_FILES__: JSON.stringify(files),
1417
- __VITEST_VITE_CONFIG__: JSON.stringify({
1418
- root: server.vite.config.root
1419
- }),
1420
- __VITEST_TYPE__: '"tester"',
1421
- __VITEST_CONTEXT_ID__: JSON.stringify(contextId),
1422
- __VITEST_TESTER_ID__: JSON.stringify(crypto.randomUUID()),
1423
- __VITEST_PROVIDED_CONTEXT__: JSON.stringify(stringify(project.getProvidedContext()))
1424
- });
1425
- const testerHtml = typeof server.testerHtml === "string" ? server.testerHtml : await server.testerHtml;
1426
- try {
1427
- const url2 = join("/@fs/", server.testerFilepath);
1428
- const indexhtml = await server.vite.transformIndexHtml(url2, testerHtml);
1429
- return replacer(indexhtml, {
1430
- __VITEST_FAVICON__: server.faviconUrl,
1431
- __VITEST_INJECTOR__: injector,
1432
- __VITEST_APPEND__: `
1433
- __vitest_browser_runner__.runningFiles = ${tests}
1434
- __vitest_browser_runner__.iframeId = ${iframeId}
1435
- __vitest_browser_runner__.${method === "run" ? "runTests" : "collectTests"}(__vitest_browser_runner__.runningFiles)
1436
- document.querySelector('script[data-vitest-append]').remove()
1437
- `
1438
- });
1439
- } catch (err) {
1440
- context?.reject(err);
1441
- next(err);
1442
- }
1443
- }
1444
-
1445
- const versionRegexp = /(?:\?|&)v=\w{8}/;
1446
- var BrowserPlugin = (browserServer, base = "/") => {
1447
- const project = browserServer.project;
1448
- function isPackageExists(pkg, root) {
1449
- return browserServer.project.ctx.packageInstaller.isPackageExists?.(pkg, {
1450
- paths: [root]
1451
- });
1452
- }
1453
- return [
1454
- {
1455
- enforce: "pre",
1456
- name: "vitest:browser",
1457
- async configureServer(server) {
1458
- browserServer.setServer(server);
1459
- server.middlewares.use(function vitestHeaders(_req, res, next) {
1460
- const headers = server.config.server.headers;
1461
- if (headers) {
1462
- for (const name in headers) {
1463
- res.setHeader(name, headers[name]);
1464
- }
1465
- }
1466
- next();
1467
- });
1468
- server.middlewares.use(async function vitestBrowserMode(req, res, next) {
1469
- if (!req.url || !browserServer.provider) {
1470
- return next();
1471
- }
1472
- const url = new URL(req.url, "http://localhost");
1473
- if (!url.pathname.startsWith(browserServer.prefixTesterUrl) && url.pathname !== base) {
1474
- return next();
1475
- }
1476
- res.setHeader(
1477
- "Cache-Control",
1478
- "no-cache, max-age=0, must-revalidate"
1479
- );
1480
- res.setHeader("Content-Type", "text/html; charset=utf-8");
1481
- res.removeHeader("X-Frame-Options");
1482
- if (url.pathname === base) {
1483
- const html2 = await resolveOrchestrator(browserServer, url, res);
1484
- res.write(html2, "utf-8");
1485
- res.end();
1486
- return;
1487
- }
1488
- const html = await resolveTester(browserServer, url, res, next);
1489
- if (html) {
1490
- res.write(html, "utf-8");
1491
- res.end();
1492
- }
1493
- });
1494
- server.middlewares.use(
1495
- `${base}favicon.svg`,
1496
- (_, res) => {
1497
- const content = readFileSync(resolve(distRoot, "client/favicon.svg"));
1498
- res.write(content, "utf-8");
1499
- res.end();
1500
- }
1501
- );
1502
- const coverageFolder = resolveCoverageFolder(project);
1503
- const coveragePath = coverageFolder ? coverageFolder[1] : void 0;
1504
- if (coveragePath && base === coveragePath) {
1505
- throw new Error(
1506
- `The ui base path and the coverage path cannot be the same: ${base}, change coverage.reportsDirectory`
1507
- );
1508
- }
1509
- if (coverageFolder) {
1510
- server.middlewares.use(
1511
- coveragePath,
1512
- sirv(coverageFolder[0], {
1513
- single: true,
1514
- dev: true,
1515
- setHeaders: (res) => {
1516
- res.setHeader(
1517
- "Cache-Control",
1518
- "public,max-age=0,must-revalidate"
1519
- );
1520
- }
1521
- })
1522
- );
1523
- }
1524
- const screenshotFailures = project.config.browser.ui && project.config.browser.screenshotFailures;
1525
- if (screenshotFailures) {
1526
- server.middlewares.use(`${base}__screenshot-error`, function vitestBrowserScreenshotError(req, res) {
1527
- if (!req.url || !browserServer.provider) {
1528
- res.statusCode = 404;
1529
- res.end();
1530
- return;
1531
- }
1532
- const url = new URL(req.url, "http://localhost");
1533
- const file = url.searchParams.get("file");
1534
- if (!file) {
1535
- res.statusCode = 404;
1536
- res.end();
1537
- return;
1538
- }
1539
- let stat;
1540
- try {
1541
- stat = lstatSync(file);
1542
- } catch {
1543
- }
1544
- if (!stat?.isFile()) {
1545
- res.statusCode = 404;
1546
- res.end();
1547
- return;
1548
- }
1549
- const ext = extname(file);
1550
- const buffer = readFileSync(file);
1551
- res.setHeader(
1552
- "Cache-Control",
1553
- "public,max-age=0,must-revalidate"
1554
- );
1555
- res.setHeader("Content-Length", buffer.length);
1556
- res.setHeader("Content-Type", ext === "jpeg" || ext === "jpg" ? "image/jpeg" : ext === "webp" ? "image/webp" : "image/png");
1557
- res.end(buffer);
1558
- });
1559
- }
1560
- server.middlewares.use((req, res, next) => {
1561
- if (req.url && versionRegexp.test(req.url) && !req.url.includes("chunk-")) {
1562
- res.setHeader("Cache-Control", "no-cache");
1563
- const setHeader = res.setHeader.bind(res);
1564
- res.setHeader = function(name, value) {
1565
- if (name === "Cache-Control") {
1566
- return res;
1567
- }
1568
- return setHeader(name, value);
1569
- };
1570
- }
1571
- next();
1572
- });
2048
+ const pressed = new Set(state.unreleased);
2049
+ await keyboardImplementation(
2050
+ pressed,
2051
+ context.provider,
2052
+ context.sessionId,
2053
+ text,
2054
+ async () => {
2055
+ if (context.provider instanceof PlaywrightBrowserProvider) {
2056
+ const frame = await context.frame();
2057
+ await frame.evaluate(selectAll);
2058
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
2059
+ await context.browser.execute(selectAll);
2060
+ } else {
2061
+ throw new TypeError(`Provider "${context.provider.name}" does not support selecting all text`);
1573
2062
  }
1574
2063
  },
1575
- {
1576
- name: "vitest:browser:tests",
1577
- enforce: "pre",
1578
- async config() {
1579
- const { testFiles: allTestFiles } = await project.globTestFiles();
1580
- const browserTestFiles = allTestFiles.filter(
1581
- (file) => getFilePoolName(project, file) === "browser"
1582
- );
1583
- const setupFiles = toArray(project.config.setupFiles);
1584
- const define = {};
1585
- for (const env in project.config.env || {}) {
1586
- const stringValue = JSON.stringify(project.config.env[env]);
1587
- define[`import.meta.env.${env}`] = stringValue;
2064
+ true
2065
+ );
2066
+ return {
2067
+ unreleased: Array.from(pressed)
2068
+ };
2069
+ };
2070
+ const keyboardCleanup = async (context, state) => {
2071
+ const { provider, sessionId } = context;
2072
+ if (provider instanceof PlaywrightBrowserProvider) {
2073
+ const page = provider.getPage(sessionId);
2074
+ for (const key of state.unreleased) {
2075
+ await page.keyboard.up(key);
2076
+ }
2077
+ } else if (provider instanceof WebdriverBrowserProvider) {
2078
+ const keyboard2 = provider.browser.action("key");
2079
+ for (const key of state.unreleased) {
2080
+ keyboard2.up(key);
2081
+ }
2082
+ await keyboard2.perform();
2083
+ } else {
2084
+ throw new TypeError(`Provider "${context.provider.name}" does not support keyboard api`);
2085
+ }
2086
+ };
2087
+ const VALID_KEYS = /* @__PURE__ */ new Set(["Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Backquote", "`", "~", "Digit1", "1", "!", "Digit2", "2", "@", "Digit3", "3", "#", "Digit4", "4", "$", "Digit5", "5", "%", "Digit6", "6", "^", "Digit7", "7", "&", "Digit8", "8", "*", "Digit9", "9", "(", "Digit0", "0", ")", "Minus", "-", "_", "Equal", "=", "+", "Backslash", "\\", "|", "Backspace", "Tab", "KeyQ", "q", "Q", "KeyW", "w", "W", "KeyE", "e", "E", "KeyR", "r", "R", "KeyT", "t", "T", "KeyY", "y", "Y", "KeyU", "u", "U", "KeyI", "i", "I", "KeyO", "o", "O", "KeyP", "p", "P", "BracketLeft", "[", "{", "BracketRight", "]", "}", "CapsLock", "KeyA", "a", "A", "KeyS", "s", "S", "KeyD", "d", "D", "KeyF", "f", "F", "KeyG", "g", "G", "KeyH", "h", "H", "KeyJ", "j", "J", "KeyK", "k", "K", "KeyL", "l", "L", "Semicolon", ";", ":", "Quote", "'", '"', "Enter", "\n", "\r", "ShiftLeft", "Shift", "KeyZ", "z", "Z", "KeyX", "x", "X", "KeyC", "c", "C", "KeyV", "v", "V", "KeyB", "b", "B", "KeyN", "n", "N", "KeyM", "m", "M", "Comma", ",", "<", "Period", ".", ">", "Slash", "/", "?", "ShiftRight", "ControlLeft", "Control", "MetaLeft", "Meta", "AltLeft", "Alt", "Space", " ", "AltRight", "AltGraph", "MetaRight", "ContextMenu", "ControlRight", "PrintScreen", "ScrollLock", "Pause", "PageUp", "PageDown", "Insert", "Delete", "Home", "End", "ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown", "NumLock", "NumpadDivide", "NumpadMultiply", "NumpadSubtract", "Numpad7", "Numpad8", "Numpad9", "Numpad4", "Numpad5", "Numpad6", "NumpadAdd", "Numpad1", "Numpad2", "Numpad3", "Numpad0", "NumpadDecimal", "NumpadEnter"]);
2088
+ async function keyboardImplementation(pressed, provider, sessionId, text, selectAll2, skipRelease) {
2089
+ if (provider instanceof PlaywrightBrowserProvider) {
2090
+ const page = provider.getPage(sessionId);
2091
+ const actions = parseKeyDef(defaultKeyMap, text);
2092
+ for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) {
2093
+ const key = keyDef.key;
2094
+ if (pressed.has(key)) {
2095
+ if (VALID_KEYS.has(key)) {
2096
+ await page.keyboard.up(key);
1588
2097
  }
1589
- const entries = [
1590
- ...browserTestFiles,
1591
- ...setupFiles,
1592
- resolve(distDir, "index.js"),
1593
- resolve(distDir, "browser.js"),
1594
- resolve(distDir, "runners.js"),
1595
- resolve(distDir, "utils.js"),
1596
- ...project.config.snapshotSerializers || []
1597
- ];
1598
- const exclude = [
1599
- "vitest",
1600
- "vitest/utils",
1601
- "vitest/browser",
1602
- "vitest/runners",
1603
- "@vitest/browser",
1604
- "@vitest/browser/client",
1605
- "@vitest/utils",
1606
- "@vitest/utils/source-map",
1607
- "@vitest/runner",
1608
- "@vitest/spy",
1609
- "@vitest/utils/error",
1610
- "@vitest/snapshot",
1611
- "@vitest/expect",
1612
- "std-env",
1613
- "tinybench",
1614
- "tinyspy",
1615
- "tinyrainbow",
1616
- "pathe",
1617
- "msw",
1618
- "msw/browser"
1619
- ];
1620
- if (typeof project.config.diff === "string") {
1621
- entries.push(project.config.diff);
2098
+ pressed.delete(key);
2099
+ }
2100
+ if (!releasePrevious) {
2101
+ if (key === "selectall") {
2102
+ await selectAll2();
2103
+ continue;
1622
2104
  }
1623
- if (project.ctx.coverageProvider) {
1624
- const coverage = project.ctx.config.coverage;
1625
- const provider = coverage.provider;
1626
- if (provider === "v8") {
1627
- const path = tryResolve("@vitest/coverage-v8", [project.config.root]);
1628
- if (path) {
1629
- entries.push(path);
1630
- exclude.push("@vitest/coverage-v8/browser");
1631
- }
1632
- } else if (provider === "istanbul") {
1633
- const path = tryResolve("@vitest/coverage-istanbul", [project.config.root]);
1634
- if (path) {
1635
- entries.push(path);
1636
- exclude.push("@vitest/coverage-istanbul");
1637
- }
1638
- } else if (provider === "custom" && coverage.customProviderModule) {
1639
- entries.push(coverage.customProviderModule);
2105
+ for (let i = 1; i <= repeat; i++) {
2106
+ if (VALID_KEYS.has(key)) {
2107
+ await page.keyboard.down(key);
2108
+ } else {
2109
+ await page.keyboard.insertText(key);
1640
2110
  }
1641
2111
  }
1642
- const include = [
1643
- "vitest > expect-type",
1644
- "vitest > @vitest/snapshot > magic-string",
1645
- "vitest > chai",
1646
- "vitest > chai > loupe",
1647
- "vitest > @vitest/utils > loupe",
1648
- "@vitest/browser > @testing-library/user-event",
1649
- "@vitest/browser > @testing-library/dom"
1650
- ];
1651
- const fileRoot = browserTestFiles[0] ? dirname(browserTestFiles[0]) : project.config.root;
1652
- const svelte = isPackageExists("vitest-browser-svelte", fileRoot);
1653
- if (svelte) {
1654
- exclude.push("vitest-browser-svelte");
2112
+ if (releaseSelf) {
2113
+ if (VALID_KEYS.has(key)) {
2114
+ await page.keyboard.up(key);
2115
+ }
2116
+ } else {
2117
+ pressed.add(key);
1655
2118
  }
1656
- const vueTestUtils = isPackageExists("@vue/test-utils", fileRoot);
1657
- if (vueTestUtils) {
1658
- include.push("@vue/test-utils");
1659
- }
1660
- return {
1661
- define,
1662
- resolve: {
1663
- dedupe: ["vitest"]
1664
- },
1665
- optimizeDeps: {
1666
- entries,
1667
- exclude,
1668
- include
1669
- }
1670
- };
1671
- },
1672
- async resolveId(id) {
1673
- if (!/\?browserv=\w+$/.test(id)) {
1674
- return;
1675
- }
1676
- let useId = id.slice(0, id.lastIndexOf("?"));
1677
- if (useId.startsWith("/@fs/")) {
1678
- useId = useId.slice(5);
1679
- }
1680
- if (/^\w:/.test(useId)) {
1681
- useId = useId.replace(/\\/g, "/");
1682
- }
1683
- return useId;
1684
- }
1685
- },
1686
- {
1687
- name: "vitest:browser:resolve-virtual",
1688
- async resolveId(rawId) {
1689
- if (rawId === "/mockServiceWorker.js") {
1690
- return this.resolve("msw/mockServiceWorker.js", distRoot, {
1691
- skipSelf: true
1692
- });
2119
+ }
2120
+ }
2121
+ if (!skipRelease && pressed.size) {
2122
+ for (const key of pressed) {
2123
+ if (VALID_KEYS.has(key)) {
2124
+ await page.keyboard.up(key);
1693
2125
  }
1694
2126
  }
1695
- },
1696
- {
1697
- name: "vitest:browser:assets",
1698
- configureServer(server) {
1699
- server.middlewares.use(
1700
- "/__vitest__",
1701
- sirv(resolve(distRoot, "client/__vitest__"))
1702
- );
1703
- },
1704
- resolveId(id) {
1705
- if (id.startsWith("/__vitest_browser__/")) {
1706
- return resolve(distRoot, "client", id.slice(1));
1707
- }
1708
- },
1709
- transform(code, id) {
1710
- if (id.includes(browserServer.vite.config.cacheDir) && id.includes("loupe.js")) {
1711
- const utilRequire = "nodeUtil = require_util();";
1712
- return code.replace(utilRequire, " ".repeat(utilRequire.length));
1713
- }
2127
+ }
2128
+ } else if (provider instanceof WebdriverBrowserProvider) {
2129
+ const { Key } = await import('webdriverio');
2130
+ const browser = provider.browser;
2131
+ const actions = parseKeyDef(defaultKeyMap, text);
2132
+ let keyboard2 = browser.action("key");
2133
+ for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) {
2134
+ let key = keyDef.key;
2135
+ const code = "location" in keyDef ? keyDef.key : keyDef.code;
2136
+ const special = Key[code];
2137
+ if (special) {
2138
+ key = special;
1714
2139
  }
1715
- },
1716
- BrowserContext(browserServer),
1717
- dynamicImportPlugin({
1718
- globalThisAccessor: '"__vitest_browser_runner__"',
1719
- filter(id) {
1720
- if (id.includes(distRoot)) {
1721
- return false;
1722
- }
1723
- return true;
2140
+ if (pressed.has(key)) {
2141
+ keyboard2.up(key);
2142
+ pressed.delete(key);
1724
2143
  }
1725
- }),
1726
- {
1727
- name: "vitest:browser:config",
1728
- enforce: "post",
1729
- async config(viteConfig) {
1730
- // Enables using ignore hint for coverage providers with @preserve keyword
1731
- if (viteConfig.esbuild !== false) {
1732
- viteConfig.esbuild ||= {};
1733
- viteConfig.esbuild.legalComments = "inline";
2144
+ if (!releasePrevious) {
2145
+ if (key === "selectall") {
2146
+ await keyboard2.perform();
2147
+ keyboard2 = browser.action("key");
2148
+ await selectAll2();
2149
+ continue;
1734
2150
  }
1735
- const defaultPort = project.ctx._browserLastPort++;
1736
- const api = resolveApiServerConfig(
1737
- viteConfig.test?.browser || {},
1738
- defaultPort
1739
- );
1740
- viteConfig.server = {
1741
- ...viteConfig.server,
1742
- port: defaultPort,
1743
- ...api,
1744
- middlewareMode: false,
1745
- open: false
1746
- };
1747
- viteConfig.server.fs ??= {};
1748
- viteConfig.server.fs.allow = viteConfig.server.fs.allow || [];
1749
- viteConfig.server.fs.allow.push(
1750
- ...resolveFsAllow(
1751
- project.ctx.config.root,
1752
- project.ctx.server.config.configFile
1753
- ),
1754
- distRoot
1755
- );
1756
- return {
1757
- resolve: {
1758
- alias: viteConfig.test?.alias
1759
- }
1760
- };
1761
- }
1762
- },
1763
- {
1764
- name: "vitest:browser:in-source-tests",
1765
- transform(code, id) {
1766
- if (!project.isCachedTestFile(id) || !code.includes("import.meta.vitest")) {
1767
- return;
2151
+ for (let i = 1; i <= repeat; i++) {
2152
+ keyboard2.down(key);
1768
2153
  }
1769
- const s = new MagicString(code, { filename: cleanUrl(id) });
1770
- s.prepend(
1771
- `import.meta.vitest = __vitest_index__;
1772
- `
1773
- );
1774
- return {
1775
- code: s.toString(),
1776
- map: s.generateMap({ hires: true })
1777
- };
1778
- }
1779
- },
1780
- {
1781
- name: "vitest:browser:worker",
1782
- transform(code, id, _options) {
1783
- if (/(?:\?|&)worker_file&type=\w+(?:&|$)/.test(id)) {
1784
- const s = new MagicString(code);
1785
- s.prepend("globalThis.__vitest_browser_runner__ = { wrapDynamicImport: f => f() };\n");
1786
- return {
1787
- code: s.toString(),
1788
- map: s.generateMap({ hires: "boundary" })
1789
- };
2154
+ if (releaseSelf) {
2155
+ keyboard2.up(key);
2156
+ } else {
2157
+ pressed.add(key);
1790
2158
  }
1791
2159
  }
1792
- },
1793
- {
1794
- name: "vitest:browser:transform-tester-html",
1795
- enforce: "pre",
1796
- async transformIndexHtml(html, ctx) {
1797
- if (ctx.filename !== browserServer.testerFilepath) {
1798
- return;
1799
- }
1800
- if (!browserServer.testerScripts) {
1801
- const testerScripts = await browserServer.formatScripts(
1802
- project.config.browser.testerScripts
1803
- );
1804
- browserServer.testerScripts = testerScripts;
1805
- }
1806
- const stateJs = typeof browserServer.stateJs === "string" ? browserServer.stateJs : await browserServer.stateJs;
1807
- const testerTags = [];
1808
- const isDefaultTemplate = resolve(distRoot, "client/tester/tester.html") === browserServer.testerFilepath;
1809
- if (!isDefaultTemplate) {
1810
- const manifestContent = browserServer.manifest instanceof Promise ? await browserServer.manifest : browserServer.manifest;
1811
- const testerEntry = manifestContent["tester/tester.html"];
1812
- testerTags.push({
1813
- tag: "script",
1814
- attrs: {
1815
- type: "module",
1816
- crossorigin: "",
1817
- src: `${browserServer.base}${testerEntry.file}`
1818
- },
1819
- injectTo: "head"
1820
- });
1821
- for (const importName of testerEntry.imports || []) {
1822
- const entryManifest = manifestContent[importName];
1823
- if (entryManifest) {
1824
- testerTags.push(
1825
- {
1826
- tag: "link",
1827
- attrs: {
1828
- href: `${browserServer.base}${entryManifest.file}`,
1829
- rel: "modulepreload",
1830
- crossorigin: ""
1831
- },
1832
- injectTo: "head"
1833
- }
1834
- );
1835
- }
1836
- }
1837
- } else {
1838
- testerTags.push({
1839
- tag: "style",
1840
- children: `
1841
- html {
1842
- padding: 0;
1843
- margin: 0;
2160
+ }
2161
+ const allRelease = keyboard2.toJSON().actions.every((action) => action.type === "keyUp");
2162
+ await keyboard2.perform(allRelease ? false : skipRelease);
2163
+ }
2164
+ return {
2165
+ pressed
2166
+ };
1844
2167
  }
1845
- body {
1846
- padding: 0;
1847
- margin: 0;
1848
- min-height: 100vh;
1849
- }`,
1850
- injectTo: "head"
1851
- });
2168
+ function focusIframe() {
2169
+ if (!document.activeElement || document.activeElement.ownerDocument !== document || document.activeElement === document.body) {
2170
+ window.focus();
2171
+ }
2172
+ }
2173
+ function selectAll() {
2174
+ const element = document.activeElement;
2175
+ if (element && element.select) {
2176
+ element.select();
2177
+ }
2178
+ }
2179
+
2180
+ const screenshot = async (context, name, options = {}) => {
2181
+ if (!context.testPath) {
2182
+ throw new Error(`Cannot take a screenshot without a test path`);
2183
+ }
2184
+ const path = options.path ? resolve(dirname(context.testPath), options.path) : resolveScreenshotPath(
2185
+ context.testPath,
2186
+ name,
2187
+ context.project.config
2188
+ );
2189
+ const savePath = normalize$1(path);
2190
+ await mkdir(dirname(path), { recursive: true });
2191
+ if (context.provider instanceof PlaywrightBrowserProvider) {
2192
+ if (options.element) {
2193
+ const { element: selector, ...config } = options;
2194
+ const element = context.iframe.locator(`${selector}`);
2195
+ const buffer2 = await element.screenshot({
2196
+ ...config,
2197
+ path: savePath
2198
+ });
2199
+ return returnResult(options, path, buffer2);
2200
+ }
2201
+ const buffer = await context.iframe.locator("body").screenshot({
2202
+ ...options,
2203
+ path: savePath
2204
+ });
2205
+ return returnResult(options, path, buffer);
2206
+ }
2207
+ if (context.provider instanceof WebdriverBrowserProvider) {
2208
+ const page = context.provider.browser;
2209
+ if (!options.element) {
2210
+ const body = await page.$("body");
2211
+ const buffer2 = await body.saveScreenshot(savePath);
2212
+ return returnResult(options, path, buffer2);
2213
+ }
2214
+ const element = await page.$(`${options.element}`);
2215
+ const buffer = await element.saveScreenshot(savePath);
2216
+ return returnResult(options, path, buffer);
2217
+ }
2218
+ throw new Error(
2219
+ `Provider "${context.provider.name}" does not support screenshots`
2220
+ );
2221
+ };
2222
+ function resolveScreenshotPath(testPath, name, config) {
2223
+ const dir = dirname(testPath);
2224
+ const base = basename(testPath);
2225
+ if (config.browser.screenshotDirectory) {
2226
+ return resolve(
2227
+ config.browser.screenshotDirectory,
2228
+ relative(config.root, dir),
2229
+ base,
2230
+ name
2231
+ );
2232
+ }
2233
+ return resolve(dir, "__screenshots__", base, name);
2234
+ }
2235
+ function returnResult(options, path, buffer) {
2236
+ if (options.base64) {
2237
+ return { path, base64: buffer.toString("base64") };
2238
+ }
2239
+ return path;
2240
+ }
2241
+
2242
+ const selectOptions = async (context, selector, userValues, options = {}) => {
2243
+ if (context.provider instanceof PlaywrightBrowserProvider) {
2244
+ const value = userValues;
2245
+ const { iframe } = context;
2246
+ const selectElement = iframe.locator(selector);
2247
+ const values = await Promise.all(value.map(async (v) => {
2248
+ if (typeof v === "string") {
2249
+ return v;
2250
+ }
2251
+ const elementHandler = await iframe.locator(v.element).elementHandle();
2252
+ if (!elementHandler) {
2253
+ throw new Error(`Element not found: ${v.element}`);
2254
+ }
2255
+ return elementHandler;
2256
+ }));
2257
+ await selectElement.selectOption(values, options);
2258
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
2259
+ const values = userValues;
2260
+ if (!values.length) {
2261
+ return;
2262
+ }
2263
+ const browser = context.browser;
2264
+ if (values.length === 1 && "index" in values[0]) {
2265
+ const selectElement = browser.$(selector);
2266
+ await selectElement.selectByIndex(values[0].index);
2267
+ } else {
2268
+ throw new Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);
2269
+ }
2270
+ } else {
2271
+ throw new TypeError(`Provider "${context.provider.name}" doesn't support selectOptions command`);
2272
+ }
2273
+ };
2274
+
2275
+ const tab = async (context, options = {}) => {
2276
+ const provider = context.provider;
2277
+ if (provider instanceof PlaywrightBrowserProvider) {
2278
+ const page = context.page;
2279
+ await page.keyboard.press(options.shift === true ? "Shift+Tab" : "Tab");
2280
+ return;
2281
+ }
2282
+ if (provider instanceof WebdriverBrowserProvider) {
2283
+ const { Key } = await import('webdriverio');
2284
+ const browser = context.browser;
2285
+ await browser.keys(options.shift === true ? [Key.Shift, Key.Tab] : [Key.Tab]);
2286
+ return;
2287
+ }
2288
+ throw new Error(`Provider "${provider.name}" doesn't support tab command`);
2289
+ };
2290
+
2291
+ const type = async (context, selector, text, options = {}) => {
2292
+ const { skipClick = false, skipAutoClose = false } = options;
2293
+ const unreleased = new Set(Reflect.get(options, "unreleased") ?? []);
2294
+ if (context.provider instanceof PlaywrightBrowserProvider) {
2295
+ const { iframe } = context;
2296
+ const element = iframe.locator(selector);
2297
+ if (!skipClick) {
2298
+ await element.focus();
2299
+ }
2300
+ await keyboardImplementation(
2301
+ unreleased,
2302
+ context.provider,
2303
+ context.sessionId,
2304
+ text,
2305
+ () => element.selectText(),
2306
+ skipAutoClose
2307
+ );
2308
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
2309
+ const browser = context.browser;
2310
+ const element = browser.$(selector);
2311
+ if (!skipClick && !await element.isFocused()) {
2312
+ await element.click();
2313
+ }
2314
+ await keyboardImplementation(
2315
+ unreleased,
2316
+ context.provider,
2317
+ context.sessionId,
2318
+ text,
2319
+ () => browser.execute(() => {
2320
+ const element2 = document.activeElement;
2321
+ if (element2) {
2322
+ element2.select();
1852
2323
  }
1853
- return [
1854
- {
1855
- tag: "script",
1856
- children: "{__VITEST_INJECTOR__}",
1857
- injectTo: "head-prepend"
1858
- },
1859
- {
1860
- tag: "script",
1861
- children: stateJs,
1862
- injectTo: "head-prepend"
1863
- },
1864
- {
1865
- tag: "script",
1866
- attrs: {
1867
- type: "module",
1868
- src: browserServer.errorCatcherUrl
1869
- },
1870
- injectTo: "head"
1871
- },
1872
- browserServer.locatorsUrl ? {
1873
- tag: "script",
1874
- attrs: {
1875
- type: "module",
1876
- src: browserServer.locatorsUrl
1877
- },
1878
- injectTo: "head"
1879
- } : null,
1880
- ...browserServer.testerScripts,
1881
- ...testerTags,
1882
- {
1883
- tag: "script",
1884
- attrs: {
1885
- "type": "module",
1886
- "data-vitest-append": ""
1887
- },
1888
- children: "{__VITEST_APPEND__}",
1889
- injectTo: "body"
1890
- }
1891
- ].filter((s) => s != null);
2324
+ }),
2325
+ skipAutoClose
2326
+ );
2327
+ } else {
2328
+ throw new TypeError(`Provider "${context.provider.name}" does not support typing`);
2329
+ }
2330
+ return {
2331
+ unreleased: Array.from(unreleased)
2332
+ };
2333
+ };
2334
+
2335
+ const upload = async (context, selector, files) => {
2336
+ const testPath = context.testPath;
2337
+ if (!testPath) {
2338
+ throw new Error(`Cannot upload files outside of a test`);
2339
+ }
2340
+ const testDir = dirname(testPath);
2341
+ if (context.provider instanceof PlaywrightBrowserProvider) {
2342
+ const { iframe } = context;
2343
+ const playwrightFiles = files.map((file) => {
2344
+ if (typeof file === "string") {
2345
+ return resolve(testDir, file);
1892
2346
  }
1893
- },
1894
- {
1895
- name: "vitest:browser:support-testing-library",
1896
- config() {
1897
- return {
1898
- optimizeDeps: {
1899
- esbuildOptions: {
1900
- plugins: [
1901
- {
1902
- name: "test-utils-rewrite",
1903
- setup(build) {
1904
- build.onResolve({ filter: /^@vue\/test-utils$/ }, (args) => {
1905
- const _require2 = getRequire();
1906
- const resolved = _require2.resolve(args.path, {
1907
- paths: [args.importer]
1908
- });
1909
- return { path: resolved };
1910
- });
1911
- }
1912
- }
1913
- ]
1914
- }
1915
- }
1916
- };
2347
+ return {
2348
+ name: file.name,
2349
+ mimeType: file.mimeType,
2350
+ buffer: Buffer.from(file.base64, "base64")
2351
+ };
2352
+ });
2353
+ await iframe.locator(selector).setInputFiles(playwrightFiles);
2354
+ } else if (context.provider instanceof WebdriverBrowserProvider) {
2355
+ for (const file of files) {
2356
+ if (typeof file !== "string") {
2357
+ throw new TypeError(`The "${context.provider.name}" provider doesn't support uploading files objects. Provide a file path instead.`);
1917
2358
  }
1918
2359
  }
1919
- ];
1920
- };
1921
- function tryResolve(path, paths) {
1922
- try {
1923
- const _require2 = getRequire();
1924
- return _require2.resolve(path, { paths });
1925
- } catch {
1926
- return void 0;
2360
+ const element = context.browser.$(selector);
2361
+ for (const file of files) {
2362
+ const filepath = resolve(testDir, file);
2363
+ const remoteFilePath = await context.browser.uploadFile(filepath);
2364
+ await element.addValue(remoteFilePath);
2365
+ }
2366
+ } else {
2367
+ throw new TypeError(`Provider "${context.provider.name}" does not support uploading files via userEvent.upload`);
1927
2368
  }
2369
+ };
2370
+
2371
+ var builtinCommands = {
2372
+ readFile,
2373
+ removeFile,
2374
+ writeFile,
2375
+ __vitest_fileInfo: _fileInfo,
2376
+ __vitest_upload: upload,
2377
+ __vitest_click: click,
2378
+ __vitest_dblClick: dblClick,
2379
+ __vitest_tripleClick: tripleClick,
2380
+ __vitest_screenshot: screenshot,
2381
+ __vitest_type: type,
2382
+ __vitest_clear: clear,
2383
+ __vitest_fill: fill,
2384
+ __vitest_tab: tab,
2385
+ __vitest_keyboard: keyboard,
2386
+ __vitest_selectOptions: selectOptions,
2387
+ __vitest_dragAndDrop: dragAndDrop,
2388
+ __vitest_hover: hover,
2389
+ __vitest_cleanup: keyboardCleanup
2390
+ };
2391
+
2392
+ class BrowserServerState {
2393
+ orchestrators = /* @__PURE__ */ new Map();
2394
+ testers = /* @__PURE__ */ new Map();
1928
2395
  }
1929
- let _require;
1930
- function getRequire() {
1931
- if (!_require) {
1932
- _require = createRequire(import.meta.url);
2396
+
2397
+ class ProjectBrowser {
2398
+ constructor(project, base) {
2399
+ this.project = project;
2400
+ this.base = base;
2401
+ this.vitest = project.vitest;
2402
+ this.config = project.config;
2403
+ const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
2404
+ const distRoot = resolve(pkgRoot, "dist");
2405
+ const testerHtmlPath = project.config.browser.testerHtmlPath ? resolve(project.config.root, project.config.browser.testerHtmlPath) : resolve(distRoot, "client/tester/tester.html");
2406
+ if (!existsSync(testerHtmlPath)) {
2407
+ throw new Error(`Tester HTML file "${testerHtmlPath}" doesn't exist.`);
2408
+ }
2409
+ this.testerFilepath = testerHtmlPath;
2410
+ this.testerHtml = readFile$1(
2411
+ testerHtmlPath,
2412
+ "utf8"
2413
+ ).then((html) => this.testerHtml = html);
2414
+ }
2415
+ testerHtml;
2416
+ testerFilepath;
2417
+ locatorsUrl;
2418
+ provider;
2419
+ vitest;
2420
+ config;
2421
+ children = /* @__PURE__ */ new Set();
2422
+ parent;
2423
+ state = new BrowserServerState();
2424
+ get vite() {
2425
+ return this.parent.vite;
2426
+ }
2427
+ wrapSerializedConfig() {
2428
+ const config = wrapConfig(this.project.serializedConfig);
2429
+ config.env ??= {};
2430
+ config.env.VITEST_BROWSER_DEBUG = process.env.VITEST_BROWSER_DEBUG || "";
2431
+ return config;
2432
+ }
2433
+ async initBrowserProvider(project) {
2434
+ if (this.provider) {
2435
+ return;
2436
+ }
2437
+ const Provider = await getBrowserProvider(project.config.browser, project);
2438
+ this.provider = new Provider();
2439
+ const browser = project.config.browser.name;
2440
+ const name = project.name ? `[${project.name}] ` : "";
2441
+ if (!browser) {
2442
+ throw new Error(
2443
+ `${name}Browser name is required. Please, set \`test.browser.instances[].browser\` option manually.`
2444
+ );
2445
+ }
2446
+ const supportedBrowsers = this.provider.getSupportedBrowsers();
2447
+ if (supportedBrowsers.length && !supportedBrowsers.includes(browser)) {
2448
+ throw new Error(
2449
+ `${name}Browser "${browser}" is not supported by the browser provider "${this.provider.name}". Supported browsers: ${supportedBrowsers.join(", ")}.`
2450
+ );
2451
+ }
2452
+ const providerOptions = project.config.browser.providerOptions;
2453
+ await this.provider.initialize(project, {
2454
+ browser,
2455
+ options: providerOptions
2456
+ });
2457
+ }
2458
+ parseErrorStacktrace(e, options = {}) {
2459
+ return this.parent.parseErrorStacktrace(e, options);
2460
+ }
2461
+ parseStacktrace(trace, options = {}) {
2462
+ return this.parent.parseStacktrace(trace, options);
2463
+ }
2464
+ async close() {
2465
+ await this.parent.vite.close();
1933
2466
  }
1934
- return _require;
1935
2467
  }
1936
- function resolveCoverageFolder(project) {
1937
- const options = project.ctx.config;
1938
- const htmlReporter = options.coverage?.enabled ? toArray(options.coverage.reporter).find((reporter) => {
1939
- if (typeof reporter === "string") {
1940
- return reporter === "html";
2468
+ function wrapConfig(config) {
2469
+ return {
2470
+ ...config,
2471
+ // workaround RegExp serialization
2472
+ testNamePattern: config.testNamePattern ? config.testNamePattern.toString() : void 0
2473
+ };
2474
+ }
2475
+
2476
+ class ParentBrowserProject {
2477
+ constructor(project, base) {
2478
+ this.project = project;
2479
+ this.base = base;
2480
+ this.vitest = project.vitest;
2481
+ this.config = project.config;
2482
+ this.stackTraceOptions = {
2483
+ frameFilter: project.config.onStackTrace,
2484
+ getSourceMap: (id) => {
2485
+ const result = this.vite.moduleGraph.getModuleById(id)?.transformResult;
2486
+ return result?.map;
2487
+ },
2488
+ getFileName: (id) => {
2489
+ const mod = this.vite.moduleGraph.getModuleById(id);
2490
+ if (mod?.file) {
2491
+ return mod.file;
2492
+ }
2493
+ const modUrl = this.vite.moduleGraph.urlToModuleMap.get(id);
2494
+ if (modUrl?.file) {
2495
+ return modUrl.file;
2496
+ }
2497
+ return id;
2498
+ }
2499
+ };
2500
+ for (const [name, command] of Object.entries(builtinCommands)) {
2501
+ this.commands[name] ??= command;
1941
2502
  }
1942
- return reporter[0] === "html";
1943
- }) : void 0;
1944
- if (!htmlReporter) {
1945
- return void 0;
2503
+ for (const command in project.config.browser.commands) {
2504
+ if (!/^[a-z_$][\w$]*$/i.test(command)) {
2505
+ throw new Error(
2506
+ `Invalid command name "${command}". Only alphanumeric characters, $ and _ are allowed.`
2507
+ );
2508
+ }
2509
+ this.commands[command] = project.config.browser.commands[command];
2510
+ }
2511
+ this.prefixTesterUrl = `${base}__vitest_test__/__test__/`;
2512
+ this.faviconUrl = `${base}__vitest__/favicon.svg`;
2513
+ this.manifest = (async () => {
2514
+ return JSON.parse(
2515
+ await readFile$1(`${distRoot}/client/.vite/manifest.json`, "utf8")
2516
+ );
2517
+ })().then((manifest) => this.manifest = manifest);
2518
+ this.orchestratorHtml = (project.config.browser.ui ? readFile$1(resolve(distRoot, "client/__vitest__/index.html"), "utf8") : readFile$1(resolve(distRoot, "client/orchestrator.html"), "utf8")).then((html) => this.orchestratorHtml = html);
2519
+ this.injectorJs = readFile$1(
2520
+ resolve(distRoot, "client/esm-client-injector.js"),
2521
+ "utf8"
2522
+ ).then((js) => this.injectorJs = js);
2523
+ this.errorCatcherUrl = join("/@fs/", resolve(distRoot, "client/error-catcher.js"));
2524
+ const builtinProviders = ["playwright", "webdriverio", "preview"];
2525
+ const providerName = project.config.browser.provider || "preview";
2526
+ if (builtinProviders.includes(providerName)) {
2527
+ this.locatorsUrl = join("/@fs/", distRoot, "locators", `${providerName}.js`);
2528
+ }
2529
+ this.stateJs = readFile$1(
2530
+ resolve(distRoot, "state.js"),
2531
+ "utf-8"
2532
+ ).then((js) => this.stateJs = js);
2533
+ }
2534
+ orchestratorScripts;
2535
+ testerScripts;
2536
+ faviconUrl;
2537
+ prefixTesterUrl;
2538
+ manifest;
2539
+ vite;
2540
+ stackTraceOptions;
2541
+ orchestratorHtml;
2542
+ injectorJs;
2543
+ errorCatcherUrl;
2544
+ locatorsUrl;
2545
+ stateJs;
2546
+ commands = {};
2547
+ children = /* @__PURE__ */ new Set();
2548
+ vitest;
2549
+ config;
2550
+ setServer(vite) {
2551
+ this.vite = vite;
2552
+ }
2553
+ spawn(project) {
2554
+ if (!this.vite) {
2555
+ throw new Error(`Cannot spawn child server without a parent dev server.`);
2556
+ }
2557
+ const clone = new ProjectBrowser(
2558
+ project,
2559
+ "/"
2560
+ );
2561
+ clone.parent = this;
2562
+ this.children.add(clone);
2563
+ return clone;
2564
+ }
2565
+ parseErrorStacktrace(e, options = {}) {
2566
+ return parseErrorStacktrace(e, {
2567
+ ...this.stackTraceOptions,
2568
+ ...options
2569
+ });
2570
+ }
2571
+ parseStacktrace(trace, options = {}) {
2572
+ return parseStacktrace(trace, {
2573
+ ...this.stackTraceOptions,
2574
+ ...options
2575
+ });
2576
+ }
2577
+ cdps = /* @__PURE__ */ new Map();
2578
+ cdpSessionsPromises = /* @__PURE__ */ new Map();
2579
+ async ensureCDPHandler(sessionId, rpcId) {
2580
+ const cachedHandler = this.cdps.get(rpcId);
2581
+ if (cachedHandler) {
2582
+ return cachedHandler;
2583
+ }
2584
+ const browserSession = this.vitest._browserSessions.getSession(sessionId);
2585
+ if (!browserSession) {
2586
+ throw new Error(`Session "${sessionId}" not found.`);
2587
+ }
2588
+ const browser = browserSession.project.browser;
2589
+ const provider = browser.provider;
2590
+ if (!provider) {
2591
+ throw new Error(`Browser provider is not defined for the project "${browserSession.project.name}".`);
2592
+ }
2593
+ if (!provider.getCDPSession) {
2594
+ throw new Error(`CDP is not supported by the provider "${provider.name}".`);
2595
+ }
2596
+ const promise = this.cdpSessionsPromises.get(rpcId) ?? await (async () => {
2597
+ const promise2 = provider.getCDPSession(sessionId).finally(() => {
2598
+ this.cdpSessionsPromises.delete(rpcId);
2599
+ });
2600
+ this.cdpSessionsPromises.set(rpcId, promise2);
2601
+ return promise2;
2602
+ })();
2603
+ const session = await promise;
2604
+ const rpc = browser.state.testers.get(rpcId);
2605
+ if (!rpc) {
2606
+ throw new Error(`Tester RPC "${rpcId}" was not established.`);
2607
+ }
2608
+ const handler = new BrowserServerCDPHandler(session, rpc);
2609
+ this.cdps.set(
2610
+ rpcId,
2611
+ handler
2612
+ );
2613
+ return handler;
2614
+ }
2615
+ removeCDPHandler(sessionId) {
2616
+ this.cdps.delete(sessionId);
2617
+ }
2618
+ async formatScripts(scripts) {
2619
+ if (!scripts?.length) {
2620
+ return [];
2621
+ }
2622
+ const server = this.vite;
2623
+ const promises = scripts.map(
2624
+ async ({ content, src, async, id, type = "module" }, index) => {
2625
+ const srcLink = (src ? (await server.pluginContainer.resolveId(src))?.id : void 0) || src;
2626
+ const transformId = srcLink || join(server.config.root, `virtual__${id || `injected-${index}.js`}`);
2627
+ await server.moduleGraph.ensureEntryFromUrl(transformId);
2628
+ const contentProcessed = content && type === "module" ? (await server.pluginContainer.transform(content, transformId)).code : content;
2629
+ return {
2630
+ tag: "script",
2631
+ attrs: {
2632
+ type,
2633
+ ...async ? { async: "" } : {},
2634
+ ...srcLink ? {
2635
+ src: srcLink.startsWith("http") ? srcLink : slash(`/@fs/${srcLink}`)
2636
+ } : {}
2637
+ },
2638
+ injectTo: "head",
2639
+ children: contentProcessed || ""
2640
+ };
2641
+ }
2642
+ );
2643
+ return await Promise.all(promises);
1946
2644
  }
1947
- const root = resolve(
1948
- options.root || process.cwd(),
1949
- options.coverage.reportsDirectory || coverageConfigDefaults.reportsDirectory
1950
- );
1951
- const subdir = Array.isArray(htmlReporter) && htmlReporter.length > 1 && "subdir" in htmlReporter[1] ? htmlReporter[1].subdir : void 0;
1952
- if (!subdir || typeof subdir !== "string") {
1953
- return [root, `/${basename(root)}/`];
2645
+ resolveTesterUrl(pathname) {
2646
+ const [sessionId, testFile] = pathname.slice(this.prefixTesterUrl.length).split("/");
2647
+ const decodedTestFile = decodeURIComponent(testFile);
2648
+ return { sessionId, testFile: decodedTestFile };
1954
2649
  }
1955
- return [resolve(root, subdir), `/${basename(root)}/${subdir}/`];
1956
- }
1957
- const postfixRE = /[?#].*$/;
1958
- function cleanUrl(url) {
1959
- return url.replace(postfixRE, "");
1960
2650
  }
1961
2651
 
1962
2652
  const DEFAULT_TIMEOUT = 6e4;
@@ -2086,10 +2776,9 @@ function nanoid(size = 21) {
2086
2776
 
2087
2777
  const debug$1 = createDebugger("vitest:browser:api");
2088
2778
  const BROWSER_API_PATH = "/__vitest_browser_api__";
2089
- function setupBrowserRpc(server) {
2090
- const project = server.project;
2091
- const vite = server.vite;
2092
- const ctx = project.ctx;
2779
+ function setupBrowserRpc(globalServer) {
2780
+ const vite = globalServer.vite;
2781
+ const vitest = globalServer.vitest;
2093
2782
  const wss = new WebSocketServer({ noServer: true });
2094
2783
  vite.httpServer?.on("upgrade", (request, socket, head) => {
2095
2784
  if (!request.url) {
@@ -2099,22 +2788,48 @@ function setupBrowserRpc(server) {
2099
2788
  if (pathname !== BROWSER_API_PATH) {
2100
2789
  return;
2101
2790
  }
2102
- const type = searchParams.get("type") ?? "tester";
2103
- const sessionId = searchParams.get("sessionId") ?? "0";
2791
+ const type = searchParams.get("type");
2792
+ const rpcId = searchParams.get("rpcId");
2793
+ const sessionId = searchParams.get("sessionId");
2794
+ const projectName = searchParams.get("projectName");
2795
+ if (type !== "tester" && type !== "orchestrator") {
2796
+ return error(
2797
+ new Error(`[vitest] Type query in ${request.url} is invalid. Type should be either "tester" or "orchestrator".`)
2798
+ );
2799
+ }
2800
+ if (!sessionId || !rpcId || projectName == null) {
2801
+ return error(
2802
+ new Error(`[vitest] Invalid URL ${request.url}. "projectName", "sessionId" and "rpcId" queries are required.`)
2803
+ );
2804
+ }
2805
+ if (type === "orchestrator") {
2806
+ const session = vitest._browserSessions.getSession(sessionId);
2807
+ session?.connected();
2808
+ }
2809
+ const project = vitest.getProjectByName(projectName);
2810
+ if (!project) {
2811
+ return error(
2812
+ new Error(`[vitest] Project "${projectName}" not found.`)
2813
+ );
2814
+ }
2104
2815
  wss.handleUpgrade(request, socket, head, (ws) => {
2105
2816
  wss.emit("connection", ws, request);
2106
- const rpc = setupClient(sessionId, ws);
2107
- const state = server.state;
2817
+ const rpc = setupClient(project, rpcId, ws);
2818
+ const state = project.browser.state;
2108
2819
  const clients = type === "tester" ? state.testers : state.orchestrators;
2109
- clients.set(sessionId, rpc);
2110
- debug$1?.("[%s] Browser API connected to %s", sessionId, type);
2820
+ clients.set(rpcId, rpc);
2821
+ debug$1?.("[%s] Browser API connected to %s", rpcId, type);
2111
2822
  ws.on("close", () => {
2112
- debug$1?.("[%s] Browser API disconnected from %s", sessionId, type);
2113
- clients.delete(sessionId);
2114
- server.state.removeCDPHandler(sessionId);
2823
+ debug$1?.("[%s] Browser API disconnected from %s", rpcId, type);
2824
+ clients.delete(rpcId);
2825
+ globalServer.removeCDPHandler(rpcId);
2115
2826
  });
2116
2827
  });
2117
2828
  });
2829
+ function error(err) {
2830
+ console.error(err);
2831
+ vitest.state.catchError(err, "RPC Error");
2832
+ }
2118
2833
  function checkFileAccess(path) {
2119
2834
  if (!isFileServingAllowed(path, vite)) {
2120
2835
  throw new Error(
@@ -2122,43 +2837,48 @@ function setupBrowserRpc(server) {
2122
2837
  );
2123
2838
  }
2124
2839
  }
2125
- function setupClient(sessionId, ws) {
2126
- const mockResolver = new ServerMockResolver(server.vite, {
2840
+ function setupClient(project, rpcId, ws) {
2841
+ const mockResolver = new ServerMockResolver(globalServer.vite, {
2127
2842
  moduleDirectories: project.config.server?.deps?.moduleDirectories
2128
2843
  });
2129
2844
  const rpc = createBirpc(
2130
2845
  {
2131
- async onUnhandledError(error, type) {
2132
- if (error && typeof error === "object") {
2133
- const _error = error;
2134
- _error.stacks = server.parseErrorStacktrace(_error);
2846
+ async onUnhandledError(error2, type) {
2847
+ if (error2 && typeof error2 === "object") {
2848
+ const _error = error2;
2849
+ _error.stacks = globalServer.parseErrorStacktrace(_error);
2135
2850
  }
2136
- ctx.state.catchError(error, type);
2851
+ vitest.state.catchError(error2, type);
2852
+ },
2853
+ async onQueued(file) {
2854
+ vitest.state.collectFiles(project, [file]);
2855
+ const testModule = vitest.state.getReportedEntity(file);
2856
+ await vitest.report("onTestModuleQueued", testModule);
2137
2857
  },
2138
2858
  async onCollected(files) {
2139
- ctx.state.collectFiles(project, files);
2140
- await ctx.report("onCollected", files);
2859
+ vitest.state.collectFiles(project, files);
2860
+ await vitest.report("onCollected", files);
2141
2861
  },
2142
2862
  async onTaskUpdate(packs) {
2143
- ctx.state.updateTasks(packs);
2144
- await ctx.report("onTaskUpdate", packs);
2863
+ vitest.state.updateTasks(packs);
2864
+ await vitest.report("onTaskUpdate", packs);
2145
2865
  },
2146
2866
  onAfterSuiteRun(meta) {
2147
- ctx.coverageProvider?.onAfterSuiteRun(meta);
2867
+ vitest.coverageProvider?.onAfterSuiteRun(meta);
2148
2868
  },
2149
2869
  sendLog(log) {
2150
- return ctx.report("onUserConsoleLog", log);
2870
+ return vitest.report("onUserConsoleLog", log);
2151
2871
  },
2152
2872
  resolveSnapshotPath(testPath) {
2153
- return ctx.snapshot.resolvePath(testPath, {
2154
- config: project.getSerializableConfig()
2873
+ return vitest.snapshot.resolvePath(testPath, {
2874
+ config: project.serializedConfig
2155
2875
  });
2156
2876
  },
2157
2877
  resolveSnapshotRawPath(testPath, rawPath) {
2158
- return ctx.snapshot.resolveRawPath(testPath, rawPath);
2878
+ return vitest.snapshot.resolveRawPath(testPath, rawPath);
2159
2879
  },
2160
2880
  snapshotSaved(snapshot) {
2161
- ctx.snapshot.add(snapshot);
2881
+ vitest.snapshot.add(snapshot);
2162
2882
  },
2163
2883
  async readSnapshotFile(snapshotPath) {
2164
2884
  checkFileAccess(snapshotPath);
@@ -2180,56 +2900,53 @@ function setupBrowserRpc(server) {
2180
2900
  return promises.unlink(id);
2181
2901
  },
2182
2902
  getBrowserFileSourceMap(id) {
2183
- const mod = server.vite.moduleGraph.getModuleById(id);
2903
+ const mod = globalServer.vite.moduleGraph.getModuleById(id);
2184
2904
  return mod?.transformResult?.map;
2185
2905
  },
2186
2906
  onCancel(reason) {
2187
- ctx.cancelCurrentRun(reason);
2907
+ vitest.cancelCurrentRun(reason);
2188
2908
  },
2189
2909
  async resolveId(id, importer) {
2190
2910
  return mockResolver.resolveId(id, importer);
2191
2911
  },
2192
2912
  debug(...args) {
2193
- ctx.logger.console.debug(...args);
2913
+ vitest.logger.console.debug(...args);
2194
2914
  },
2195
2915
  getCountOfFailedTests() {
2196
- return ctx.state.getCountOfFailedTests();
2916
+ return vitest.state.getCountOfFailedTests();
2197
2917
  },
2198
- async triggerCommand(contextId, command, testPath, payload) {
2199
- debug$1?.('[%s] Triggering command "%s"', contextId, command);
2200
- const provider = server.provider;
2918
+ async triggerCommand(sessionId, command, testPath, payload) {
2919
+ debug$1?.('[%s] Triggering command "%s"', sessionId, command);
2920
+ const provider = project.browser.provider;
2201
2921
  if (!provider) {
2202
2922
  throw new Error("Commands are only available for browser tests.");
2203
2923
  }
2204
- const commands = project.config.browser?.commands;
2924
+ const commands = globalServer.commands;
2205
2925
  if (!commands || !commands[command]) {
2206
2926
  throw new Error(`Unknown command "${command}".`);
2207
2927
  }
2208
- if (provider.beforeCommand) {
2209
- await provider.beforeCommand(command, payload);
2210
- }
2928
+ await provider.beforeCommand?.(command, payload);
2211
2929
  const context = Object.assign(
2212
2930
  {
2213
2931
  testPath,
2214
2932
  project,
2215
2933
  provider,
2216
- contextId
2934
+ contextId: sessionId,
2935
+ sessionId
2217
2936
  },
2218
- provider.getCommandsContext(contextId)
2937
+ provider.getCommandsContext(sessionId)
2219
2938
  );
2220
2939
  let result;
2221
2940
  try {
2222
2941
  result = await commands[command](context, ...payload);
2223
2942
  } finally {
2224
- if (provider.afterCommand) {
2225
- await provider.afterCommand(command, payload);
2226
- }
2943
+ await provider.afterCommand?.(command, payload);
2227
2944
  }
2228
2945
  return result;
2229
2946
  },
2230
- finishBrowserTests(contextId) {
2231
- debug$1?.("[%s] Finishing browser tests for context", contextId);
2232
- return server.state.getContext(contextId)?.resolve();
2947
+ finishBrowserTests(sessionId) {
2948
+ debug$1?.("[%s] Finishing browser tests for session", sessionId);
2949
+ return vitest._browserSessions.getSession(sessionId)?.resolve();
2233
2950
  },
2234
2951
  resolveMock(rawId, importer, options) {
2235
2952
  return mockResolver.resolveMock(rawId, importer, options);
@@ -2238,12 +2955,12 @@ function setupBrowserRpc(server) {
2238
2955
  return mockResolver.invalidate(ids);
2239
2956
  },
2240
2957
  // CDP
2241
- async sendCdpEvent(contextId, event, payload) {
2242
- const cdp = await server.ensureCDPHandler(contextId, sessionId);
2958
+ async sendCdpEvent(sessionId, event, payload) {
2959
+ const cdp = await globalServer.ensureCDPHandler(sessionId, rpcId);
2243
2960
  return cdp.send(event, payload);
2244
2961
  },
2245
- async trackCdpEvent(contextId, type, event, listenerId) {
2246
- const cdp = await server.ensureCDPHandler(contextId, sessionId);
2962
+ async trackCdpEvent(sessionId, type, event, listenerId) {
2963
+ const cdp = await globalServer.ensureCDPHandler(sessionId, rpcId);
2247
2964
  cdp[type](event, listenerId);
2248
2965
  }
2249
2966
  },
@@ -2258,7 +2975,7 @@ function setupBrowserRpc(server) {
2258
2975
  }
2259
2976
  }
2260
2977
  );
2261
- ctx.onCancel((reason) => rpc.onCancel(reason));
2978
+ vitest.onCancel((reason) => rpc.onCancel(reason));
2262
2979
  return rpc;
2263
2980
  }
2264
2981
  }
@@ -2285,275 +3002,15 @@ function stringifyReplace(key, value) {
2285
3002
  }
2286
3003
  }
2287
3004
 
2288
- class BrowserServerCDPHandler {
2289
- constructor(session, tester) {
2290
- this.session = session;
2291
- this.tester = tester;
2292
- }
2293
- listenerIds = {};
2294
- listeners = {};
2295
- send(method, params) {
2296
- return this.session.send(method, params);
2297
- }
2298
- on(event, id, once = false) {
2299
- if (!this.listenerIds[event]) {
2300
- this.listenerIds[event] = [];
2301
- }
2302
- this.listenerIds[event].push(id);
2303
- if (!this.listeners[event]) {
2304
- this.listeners[event] = (payload) => {
2305
- this.tester.cdpEvent(
2306
- event,
2307
- payload
2308
- );
2309
- if (once) {
2310
- this.off(event, id);
2311
- }
2312
- };
2313
- this.session.on(event, this.listeners[event]);
2314
- }
2315
- }
2316
- off(event, id) {
2317
- if (!this.listenerIds[event]) {
2318
- this.listenerIds[event] = [];
2319
- }
2320
- this.listenerIds[event] = this.listenerIds[event].filter((l) => l !== id);
2321
- if (!this.listenerIds[event].length) {
2322
- this.session.off(event, this.listeners[event]);
2323
- delete this.listeners[event];
2324
- }
2325
- }
2326
- once(event, listener) {
2327
- this.on(event, listener, true);
2328
- }
2329
- }
2330
-
2331
- class BrowserServerState {
2332
- orchestrators = /* @__PURE__ */ new Map();
2333
- testers = /* @__PURE__ */ new Map();
2334
- cdps = /* @__PURE__ */ new Map();
2335
- contexts = /* @__PURE__ */ new Map();
2336
- getContext(contextId) {
2337
- return this.contexts.get(contextId);
2338
- }
2339
- createAsyncContext(method, contextId, files) {
2340
- const defer = createDefer();
2341
- this.contexts.set(contextId, {
2342
- files,
2343
- method,
2344
- resolve: () => {
2345
- defer.resolve();
2346
- this.contexts.delete(contextId);
2347
- },
2348
- reject: defer.reject
2349
- });
2350
- return defer;
2351
- }
2352
- async removeCDPHandler(sessionId) {
2353
- this.cdps.delete(sessionId);
2354
- }
2355
- }
2356
-
2357
- class BrowserServer {
2358
- constructor(project, base) {
2359
- this.project = project;
2360
- this.base = base;
2361
- this.stackTraceOptions = {
2362
- frameFilter: project.config.onStackTrace,
2363
- getSourceMap: (id) => {
2364
- const result = this.vite.moduleGraph.getModuleById(id)?.transformResult;
2365
- return result?.map;
2366
- },
2367
- getFileName: (id) => {
2368
- const mod = this.vite.moduleGraph.getModuleById(id);
2369
- if (mod?.file) {
2370
- return mod.file;
2371
- }
2372
- const modUrl = this.vite.moduleGraph.urlToModuleMap.get(id);
2373
- if (modUrl?.file) {
2374
- return modUrl.file;
2375
- }
2376
- return id;
2377
- }
2378
- };
2379
- this.state = new BrowserServerState();
2380
- const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
2381
- const distRoot = resolve(pkgRoot, "dist");
2382
- this.prefixTesterUrl = `${base}__vitest_test__/__test__/`;
2383
- this.faviconUrl = `${base}__vitest__/favicon.svg`;
2384
- this.manifest = (async () => {
2385
- return JSON.parse(
2386
- await readFile$1(`${distRoot}/client/.vite/manifest.json`, "utf8")
2387
- );
2388
- })().then((manifest) => this.manifest = manifest);
2389
- const testerHtmlPath = project.config.browser.testerHtmlPath ? resolve(project.config.root, project.config.browser.testerHtmlPath) : resolve(distRoot, "client/tester/tester.html");
2390
- if (!existsSync(testerHtmlPath)) {
2391
- throw new Error(`Tester HTML file "${testerHtmlPath}" doesn't exist.`);
2392
- }
2393
- this.testerFilepath = testerHtmlPath;
2394
- this.testerHtml = readFile$1(
2395
- testerHtmlPath,
2396
- "utf8"
2397
- ).then((html) => this.testerHtml = html);
2398
- this.orchestratorHtml = (project.config.browser.ui ? readFile$1(resolve(distRoot, "client/__vitest__/index.html"), "utf8") : readFile$1(resolve(distRoot, "client/orchestrator.html"), "utf8")).then((html) => this.orchestratorHtml = html);
2399
- this.injectorJs = readFile$1(
2400
- resolve(distRoot, "client/esm-client-injector.js"),
2401
- "utf8"
2402
- ).then((js) => this.injectorJs = js);
2403
- this.errorCatcherUrl = join("/@fs/", resolve(distRoot, "client/error-catcher.js"));
2404
- const builtinProviders = ["playwright", "webdriverio", "preview"];
2405
- const providerName = project.config.browser.provider || "preview";
2406
- if (builtinProviders.includes(providerName)) {
2407
- this.locatorsUrl = join("/@fs/", distRoot, "locators", `${providerName}.js`);
2408
- }
2409
- this.stateJs = readFile$1(
2410
- resolve(distRoot, "state.js"),
2411
- "utf-8"
2412
- ).then((js) => this.stateJs = js);
2413
- }
2414
- faviconUrl;
2415
- prefixTesterUrl;
2416
- orchestratorScripts;
2417
- testerScripts;
2418
- manifest;
2419
- testerHtml;
2420
- testerFilepath;
2421
- orchestratorHtml;
2422
- injectorJs;
2423
- errorCatcherUrl;
2424
- locatorsUrl;
2425
- stateJs;
2426
- state;
2427
- provider;
2428
- vite;
2429
- stackTraceOptions;
2430
- setServer(server) {
2431
- this.vite = server;
2432
- }
2433
- getSerializableConfig() {
2434
- const config = wrapConfig(this.project.getSerializableConfig());
2435
- config.env ??= {};
2436
- config.env.VITEST_BROWSER_DEBUG = process.env.VITEST_BROWSER_DEBUG || "";
2437
- return config;
2438
- }
2439
- resolveTesterUrl(pathname) {
2440
- const [contextId, testFile] = pathname.slice(this.prefixTesterUrl.length).split("/");
2441
- const decodedTestFile = decodeURIComponent(testFile);
2442
- return { contextId, testFile: decodedTestFile };
2443
- }
2444
- async formatScripts(scripts) {
2445
- if (!scripts?.length) {
2446
- return [];
2447
- }
2448
- const server = this.vite;
2449
- const promises = scripts.map(
2450
- async ({ content, src, async, id, type = "module" }, index) => {
2451
- const srcLink = (src ? (await server.pluginContainer.resolveId(src))?.id : void 0) || src;
2452
- const transformId = srcLink || join(server.config.root, `virtual__${id || `injected-${index}.js`}`);
2453
- await server.moduleGraph.ensureEntryFromUrl(transformId);
2454
- const contentProcessed = content && type === "module" ? (await server.pluginContainer.transform(content, transformId)).code : content;
2455
- return {
2456
- tag: "script",
2457
- attrs: {
2458
- type,
2459
- ...async ? { async: "" } : {},
2460
- ...srcLink ? {
2461
- src: srcLink.startsWith("http") ? srcLink : slash(`/@fs/${srcLink}`)
2462
- } : {}
2463
- },
2464
- injectTo: "head",
2465
- children: contentProcessed || ""
2466
- };
2467
- }
2468
- );
2469
- return await Promise.all(promises);
2470
- }
2471
- async initBrowserProvider() {
2472
- if (this.provider) {
2473
- return;
2474
- }
2475
- const Provider = await getBrowserProvider(this.project.config.browser, this.project);
2476
- this.provider = new Provider();
2477
- const browser = this.project.config.browser.name;
2478
- if (!browser) {
2479
- throw new Error(
2480
- `[${this.project.name}] Browser name is required. Please, set \`test.browser.name\` option manually.`
2481
- );
2482
- }
2483
- const supportedBrowsers = this.provider.getSupportedBrowsers();
2484
- if (supportedBrowsers.length && !supportedBrowsers.includes(browser)) {
2485
- throw new Error(
2486
- `[${this.project.name}] Browser "${browser}" is not supported by the browser provider "${this.provider.name}". Supported browsers: ${supportedBrowsers.join(", ")}.`
2487
- );
2488
- }
2489
- const providerOptions = this.project.config.browser.providerOptions;
2490
- await this.provider.initialize(this.project, {
2491
- browser,
2492
- options: providerOptions
2493
- });
2494
- }
2495
- parseErrorStacktrace(e, options = {}) {
2496
- return parseErrorStacktrace(e, {
2497
- ...this.stackTraceOptions,
2498
- ...options
2499
- });
2500
- }
2501
- parseStacktrace(trace, options = {}) {
2502
- return parseStacktrace(trace, {
2503
- ...this.stackTraceOptions,
2504
- ...options
2505
- });
2506
- }
2507
- cdpSessionsPromises = /* @__PURE__ */ new Map();
2508
- async ensureCDPHandler(contextId, sessionId) {
2509
- const cachedHandler = this.state.cdps.get(sessionId);
2510
- if (cachedHandler) {
2511
- return cachedHandler;
2512
- }
2513
- const provider = this.provider;
2514
- if (!provider.getCDPSession) {
2515
- throw new Error(`CDP is not supported by the provider "${provider.name}".`);
2516
- }
2517
- const promise = this.cdpSessionsPromises.get(sessionId) ?? await (async () => {
2518
- const promise2 = provider.getCDPSession(contextId).finally(() => {
2519
- this.cdpSessionsPromises.delete(sessionId);
2520
- });
2521
- this.cdpSessionsPromises.set(sessionId, promise2);
2522
- return promise2;
2523
- })();
2524
- const session = await promise;
2525
- const rpc = this.state.testers.get(sessionId);
2526
- if (!rpc) {
2527
- throw new Error(`Tester RPC "${sessionId}" was not established.`);
2528
- }
2529
- const handler = new BrowserServerCDPHandler(session, rpc);
2530
- this.state.cdps.set(
2531
- sessionId,
2532
- handler
2533
- );
2534
- return handler;
2535
- }
2536
- async close() {
2537
- await this.vite.close();
2538
- }
2539
- }
2540
- function wrapConfig(config) {
2541
- return {
2542
- ...config,
2543
- // workaround RegExp serialization
2544
- testNamePattern: config.testNamePattern ? config.testNamePattern.toString() : void 0
2545
- };
2546
- }
2547
-
2548
3005
  const debug = createDebugger("vitest:browser:pool");
2549
- async function waitForTests(method, contextId, project, files) {
2550
- const context = project.browser.state.createAsyncContext(method, contextId, files);
3006
+ async function waitForTests(method, sessionId, project, files) {
3007
+ const context = project.vitest._browserSessions.createAsyncSession(method, sessionId, files, project);
2551
3008
  return await context;
2552
3009
  }
2553
- function createBrowserPool(ctx) {
3010
+ function createBrowserPool(vitest) {
2554
3011
  const providers = /* @__PURE__ */ new Set();
2555
3012
  const executeTests = async (method, project, files) => {
2556
- ctx.state.clearFiles(project, files);
3013
+ vitest.state.clearFiles(project, files);
2557
3014
  const browser = project.browser;
2558
3015
  const threadsCount = getThreadsCount(project);
2559
3016
  const provider = browser.provider;
@@ -2565,14 +3022,14 @@ function createBrowserPool(ctx) {
2565
3022
  `Can't find browser origin URL for project "${project.name}" when running tests for files "${files.join('", "')}"`
2566
3023
  );
2567
3024
  }
2568
- async function setBreakpoint(contextId, file) {
3025
+ async function setBreakpoint(sessionId, file) {
2569
3026
  if (!project.config.inspector.waitForDebugger) {
2570
3027
  return;
2571
3028
  }
2572
3029
  if (!provider.getCDPSession) {
2573
3030
  throw new Error("Unable to set breakpoint, CDP not supported");
2574
3031
  }
2575
- const session = await provider.getCDPSession(contextId);
3032
+ const session = await provider.getCDPSession(sessionId);
2576
3033
  await session.send("Debugger.enable", {});
2577
3034
  await session.send("Debugger.setBreakpointByUrl", {
2578
3035
  lineNumber: 0,
@@ -2596,13 +3053,13 @@ function createBrowserPool(ctx) {
2596
3053
  const promises = [];
2597
3054
  chunks.forEach((files2, index) => {
2598
3055
  if (orchestrators[index]) {
2599
- const [contextId, orchestrator] = orchestrators[index];
3056
+ const [sessionId, orchestrator] = orchestrators[index];
2600
3057
  debug?.(
2601
- "Reusing orchestrator (context %s) for files: %s",
2602
- contextId,
3058
+ "Reusing orchestrator (session %s) for files: %s",
3059
+ sessionId,
2603
3060
  [...files2.map((f) => relative(project.config.root, f))].join(", ")
2604
3061
  );
2605
- const promise = waitForTests(method, contextId, project, files2);
3062
+ const promise = waitForTests(method, sessionId, project, files2);
2606
3063
  const tester = orchestrator.createTesters(files2).catch((error) => {
2607
3064
  if (error instanceof Error && error.message.startsWith("[birpc] rpc is closed")) {
2608
3065
  return;
@@ -2611,16 +3068,16 @@ function createBrowserPool(ctx) {
2611
3068
  });
2612
3069
  promises.push(promise, tester);
2613
3070
  } else {
2614
- const contextId = crypto.randomUUID();
2615
- const waitPromise = waitForTests(method, contextId, project, files2);
3071
+ const sessionId = crypto.randomUUID();
3072
+ const waitPromise = waitForTests(method, sessionId, project, files2);
2616
3073
  debug?.(
2617
- "Opening a new context %s for files: %s",
2618
- contextId,
3074
+ "Opening a new session %s for files: %s",
3075
+ sessionId,
2619
3076
  [...files2.map((f) => relative(project.config.root, f))].join(", ")
2620
3077
  );
2621
3078
  const url = new URL("/", origin);
2622
- url.searchParams.set("contextId", contextId);
2623
- const page = provider.openPage(contextId, url.toString(), () => setBreakpoint(contextId, files2[0]));
3079
+ url.searchParams.set("sessionId", sessionId);
3080
+ const page = provider.openPage(sessionId, url.toString(), () => setBreakpoint(sessionId, files2[0]));
2624
3081
  promises.push(page, waitPromise);
2625
3082
  }
2626
3083
  });
@@ -2634,7 +3091,7 @@ function createBrowserPool(ctx) {
2634
3091
  groupedFiles.set(project, files);
2635
3092
  }
2636
3093
  let isCancelled = false;
2637
- ctx.onCancel(() => {
3094
+ vitest.onCancel(() => {
2638
3095
  isCancelled = true;
2639
3096
  });
2640
3097
  for (const [project, files] of groupedFiles.entries()) {
@@ -2654,14 +3111,14 @@ function createBrowserPool(ctx) {
2654
3111
  if (!config.fileParallelism) {
2655
3112
  return 1;
2656
3113
  }
2657
- return ctx.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
3114
+ return vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1);
2658
3115
  }
2659
3116
  return {
2660
3117
  name: "browser",
2661
3118
  async close() {
2662
3119
  await Promise.all([...providers].map((provider) => provider.close()));
2663
3120
  providers.clear();
2664
- ctx.resolvedProjects.forEach((project) => {
3121
+ vitest.resolvedProjects.forEach((project) => {
2665
3122
  project.browser?.state.orchestrators.forEach((orchestrator) => {
2666
3123
  orchestrator.$close();
2667
3124
  });
@@ -2676,19 +3133,19 @@ function escapePathToRegexp(path) {
2676
3133
  }
2677
3134
 
2678
3135
  async function createBrowserServer(project, configFile, prePlugins = [], postPlugins = []) {
2679
- if (project.ctx.version !== version) {
2680
- project.ctx.logger.warn(
3136
+ if (project.vitest.version !== version) {
3137
+ project.vitest.logger.warn(
2681
3138
  c.yellow(
2682
- `Loaded ${c.inverse(c.yellow(` vitest@${project.ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/browser@${version} `))}.
3139
+ `Loaded ${c.inverse(c.yellow(` vitest@${project.vitest.version} `))} and ${c.inverse(c.yellow(` @vitest/browser@${version} `))}.
2683
3140
  Running mixed versions is not supported and may lead into bugs
2684
3141
  Update your dependencies and make sure the versions match.`
2685
3142
  )
2686
3143
  );
2687
3144
  }
2688
- const server = new BrowserServer(project, "/");
3145
+ const server = new ParentBrowserProject(project, "/");
2689
3146
  const configPath = typeof configFile === "string" ? configFile : false;
2690
3147
  const logLevel = process.env.VITEST_BROWSER_DEBUG ?? "info";
2691
- const logger = createViteLogger(project.logger, logLevel, {
3148
+ const logger = createViteLogger(project.vitest.logger, logLevel, {
2692
3149
  allowClearScreen: false
2693
3150
  });
2694
3151
  const vite = await createViteServer({