@vitest/browser 3.0.0-beta.1 → 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/context.d.ts +17 -0
- package/dist/client/.vite/manifest.json +2 -2
- package/dist/client/__vitest__/assets/{index-DYFkX02J.css → index-D1v_Nqq1.css} +1 -1
- package/dist/client/__vitest__/assets/{index-DgyW9gjj.js → index-JmEkKNR0.js} +27 -27
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/{orchestrator-DnP17K36.js → orchestrator-vOivV83Y.js} +7 -5
- package/dist/client/__vitest_browser__/{tester-D_NUSQO8.js → tester-CDBn6hqf.js} +19 -10
- package/dist/client/esm-client-injector.js +1 -1
- package/dist/client/orchestrator.html +1 -1
- package/dist/client/tester/tester.html +1 -1
- package/dist/client.js +4 -4
- package/dist/context.js +88 -23
- package/dist/{index-CKtADM3n.js → index-VFFcOojA.js} +8 -2
- package/dist/index.d.ts +52 -34
- package/dist/index.js +2417 -1960
- package/dist/locators/index.d.ts +2 -0
- package/dist/locators/index.js +1 -1
- package/dist/locators/playwright.js +1 -1
- package/dist/locators/preview.js +11 -34
- package/dist/locators/webdriverio.js +1 -1
- package/dist/providers.js +3 -3
- package/dist/state.js +1 -1
- package/dist/{webdriver-JzwxG3Ek.js → webdriver-dkCg9pjp.js} +22 -22
- package/package.json +14 -14
- package/providers/webdriverio.d.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import c from 'tinyrainbow';
|
|
2
|
-
import {
|
|
3
|
-
import 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
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
var mime = new Mime(types)._freeze();
|
|
431
|
+
return after;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
377
434
|
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
-
|
|
392
|
-
};
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
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
|
-
|
|
468
|
-
(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
|
|
557
|
-
(
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
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
|
+
}
|
|
704
798
|
},
|
|
705
799
|
{
|
|
706
|
-
|
|
707
|
-
|
|
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
|
+
}
|
|
708
808
|
},
|
|
709
809
|
{
|
|
710
|
-
|
|
711
|
-
|
|
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
|
+
}
|
|
712
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
|
+
}),
|
|
713
839
|
{
|
|
714
|
-
|
|
715
|
-
|
|
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
|
+
}
|
|
716
875
|
},
|
|
717
|
-
// Special keys that are not part of a default US-layout but included for specific behavior
|
|
718
876
|
{
|
|
719
|
-
|
|
720
|
-
|
|
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
|
+
}
|
|
721
893
|
},
|
|
722
894
|
{
|
|
723
|
-
|
|
724
|
-
|
|
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
|
+
}
|
|
725
906
|
},
|
|
726
907
|
{
|
|
727
|
-
|
|
728
|
-
|
|
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();
|
|
753
|
-
}
|
|
754
|
-
return def.key === descriptor;
|
|
755
|
-
})) !== null && _keyboardMap_find !== void 0 ? _keyboardMap_find : {
|
|
756
|
-
key: 'Unknown',
|
|
757
|
-
code: 'Unknown',
|
|
758
|
-
[type === '[' ? 'code' : 'key']: descriptor
|
|
759
|
-
};
|
|
760
|
-
defs.push({
|
|
761
|
-
keyDef,
|
|
762
|
-
releasePrevious,
|
|
763
|
-
releaseSelf,
|
|
764
|
-
repeat
|
|
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;
|
|
765
913
|
});
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
return defs;
|
|
769
|
-
}
|
|
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);
|
|
777
|
-
}
|
|
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
|
|
795
|
-
);
|
|
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);
|
|
806
|
-
}
|
|
807
|
-
} else if (provider instanceof WebdriverBrowserProvider) {
|
|
808
|
-
const keyboard2 = provider.browser.action("key");
|
|
809
|
-
for (const key of state.unreleased) {
|
|
810
|
-
keyboard2.up(key);
|
|
811
|
-
}
|
|
812
|
-
await keyboard2.perform();
|
|
813
|
-
} else {
|
|
814
|
-
throw new TypeError(`Provider "${context.provider.name}" does not support keyboard api`);
|
|
815
|
-
}
|
|
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;
|
|
914
|
+
if (!projectBrowser) {
|
|
915
|
+
return;
|
|
834
916
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
}
|
|
917
|
+
if (!parentServer.testerScripts) {
|
|
918
|
+
const testerScripts = await parentServer.formatScripts(
|
|
919
|
+
parentServer.config.browser.testerScripts
|
|
920
|
+
);
|
|
921
|
+
parentServer.testerScripts = testerScripts;
|
|
841
922
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
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
|
+
}
|
|
845
953
|
}
|
|
846
954
|
} else {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
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
|
+
});
|
|
855
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);
|
|
856
1009
|
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
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
|
-
}
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
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
|
+
]
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
889
1034
|
}
|
|
890
1035
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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
|
+
}
|
|
897
1045
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1046
|
+
let _require;
|
|
1047
|
+
function getRequire() {
|
|
1048
|
+
if (!_require) {
|
|
1049
|
+
_require = createRequire(import.meta.url);
|
|
901
1050
|
}
|
|
1051
|
+
return _require;
|
|
902
1052
|
}
|
|
903
|
-
function
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
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;
|
|
907
1063
|
}
|
|
1064
|
+
const root = resolve(
|
|
1065
|
+
options.root || process.cwd(),
|
|
1066
|
+
options.coverage.reportsDirectory || coverageConfigDefaults.reportsDirectory
|
|
1067
|
+
);
|
|
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, "");
|
|
908
1077
|
}
|
|
909
1078
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1079
|
+
class BrowserServerCDPHandler {
|
|
1080
|
+
constructor(session, tester) {
|
|
1081
|
+
this.session = session;
|
|
1082
|
+
this.tester = tester;
|
|
913
1083
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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({
|
|
932
|
-
...options,
|
|
933
|
-
path: savePath
|
|
934
|
-
});
|
|
935
|
-
return returnResult(options, path, buffer);
|
|
1084
|
+
listenerIds = {};
|
|
1085
|
+
listeners = {};
|
|
1086
|
+
send(method, params) {
|
|
1087
|
+
return this.session.send(method, params);
|
|
936
1088
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1089
|
+
on(event, id, once = false) {
|
|
1090
|
+
if (!this.listenerIds[event]) {
|
|
1091
|
+
this.listenerIds[event] = [];
|
|
1092
|
+
}
|
|
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]);
|
|
943
1105
|
}
|
|
944
|
-
const element = await page.$(`${options.element}`);
|
|
945
|
-
const buffer = await element.saveScreenshot(savePath);
|
|
946
|
-
return returnResult(options, path, buffer);
|
|
947
1106
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
config.browser.screenshotDirectory,
|
|
958
|
-
relative(config.root, dir),
|
|
959
|
-
base,
|
|
960
|
-
name
|
|
961
|
-
);
|
|
1107
|
+
off(event, id) {
|
|
1108
|
+
if (!this.listenerIds[event]) {
|
|
1109
|
+
this.listenerIds[event] = [];
|
|
1110
|
+
}
|
|
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];
|
|
1115
|
+
}
|
|
962
1116
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
function returnResult(options, path, buffer) {
|
|
966
|
-
if (options.base64) {
|
|
967
|
-
return { path, base64: buffer.toString("base64") };
|
|
1117
|
+
once(event, listener) {
|
|
1118
|
+
this.on(event, listener, true);
|
|
968
1119
|
}
|
|
969
|
-
return path;
|
|
970
1120
|
}
|
|
971
1121
|
|
|
972
|
-
const
|
|
1122
|
+
const clear = async (context, selector) => {
|
|
973
1123
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
974
|
-
const value = userValues;
|
|
975
1124
|
const { iframe } = context;
|
|
976
|
-
const
|
|
977
|
-
|
|
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);
|
|
1125
|
+
const element = iframe.locator(selector);
|
|
1126
|
+
await element.clear();
|
|
988
1127
|
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
989
|
-
const values = userValues;
|
|
990
|
-
if (!values.length) {
|
|
991
|
-
return;
|
|
992
|
-
}
|
|
993
1128
|
const browser = context.browser;
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
await selectElement.selectByIndex(values[0].index);
|
|
997
|
-
} else {
|
|
998
|
-
throw new Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);
|
|
999
|
-
}
|
|
1129
|
+
const element = await browser.$(selector);
|
|
1130
|
+
await element.clearValue();
|
|
1000
1131
|
} else {
|
|
1001
|
-
throw new TypeError(`Provider "${context.provider.name}"
|
|
1132
|
+
throw new TypeError(`Provider "${context.provider.name}" does not support clearing elements`);
|
|
1002
1133
|
}
|
|
1003
1134
|
};
|
|
1004
1135
|
|
|
1005
|
-
const
|
|
1136
|
+
const click = async (context, selector, options = {}) => {
|
|
1006
1137
|
const provider = context.provider;
|
|
1007
1138
|
if (provider instanceof PlaywrightBrowserProvider) {
|
|
1008
|
-
const
|
|
1009
|
-
await
|
|
1010
|
-
|
|
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`);
|
|
1011
1146
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
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) {
|
|
1014
1154
|
const browser = context.browser;
|
|
1015
|
-
await browser.
|
|
1016
|
-
|
|
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({
|
|
1165
|
+
...options,
|
|
1166
|
+
clickCount: 3
|
|
1167
|
+
});
|
|
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`);
|
|
1017
1173
|
}
|
|
1018
|
-
throw new Error(`Provider "${provider.name}" doesn't support tab command`);
|
|
1019
1174
|
};
|
|
1020
1175
|
|
|
1021
|
-
const
|
|
1022
|
-
const { skipClick = false, skipAutoClose = false } = options;
|
|
1023
|
-
const unreleased = new Set(Reflect.get(options, "unreleased") ?? []);
|
|
1176
|
+
const dragAndDrop = async (context, source, target, options_) => {
|
|
1024
1177
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
await keyboardImplementation(
|
|
1031
|
-
unreleased,
|
|
1032
|
-
context.provider,
|
|
1033
|
-
context.contextId,
|
|
1034
|
-
text,
|
|
1035
|
-
() => element.selectText(),
|
|
1036
|
-
skipAutoClose
|
|
1178
|
+
const frame = await context.frame();
|
|
1179
|
+
await frame.dragAndDrop(
|
|
1180
|
+
source,
|
|
1181
|
+
target,
|
|
1182
|
+
options_
|
|
1037
1183
|
);
|
|
1038
1184
|
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
1039
|
-
const
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
}
|
|
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();
|
|
1053
|
-
}
|
|
1054
|
-
}),
|
|
1055
|
-
skipAutoClose
|
|
1056
|
-
);
|
|
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();
|
|
1057
1190
|
} else {
|
|
1058
|
-
throw new TypeError(`Provider "${context.provider.name}" does not support
|
|
1191
|
+
throw new TypeError(`Provider "${context.provider.name}" does not support dragging elements`);
|
|
1059
1192
|
}
|
|
1060
|
-
return {
|
|
1061
|
-
unreleased: Array.from(unreleased)
|
|
1062
|
-
};
|
|
1063
1193
|
};
|
|
1064
1194
|
|
|
1065
|
-
const
|
|
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);
|
|
1195
|
+
const fill = async (context, selector, text, options = {}) => {
|
|
1071
1196
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1072
1197
|
const { iframe } = context;
|
|
1073
|
-
const
|
|
1074
|
-
|
|
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);
|
|
1198
|
+
const element = iframe.locator(selector);
|
|
1199
|
+
await element.fill(text, options);
|
|
1084
1200
|
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
1085
|
-
|
|
1086
|
-
|
|
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
|
-
}
|
|
1201
|
+
const browser = context.browser;
|
|
1202
|
+
await browser.$(selector).setValue(text);
|
|
1096
1203
|
} else {
|
|
1097
|
-
throw new TypeError(`Provider "${context.provider.name}" does not support
|
|
1204
|
+
throw new TypeError(`Provider "${context.provider.name}" does not support clearing elements`);
|
|
1098
1205
|
}
|
|
1099
1206
|
};
|
|
1100
1207
|
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
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'],
|
|
1120
1559
|
};
|
|
1560
|
+
Object.freeze(types);
|
|
1121
1561
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
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
|
+
}
|
|
1136
1576
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
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;
|
|
1604
|
+
}
|
|
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);
|
|
1634
|
+
}
|
|
1635
|
+
return this;
|
|
1636
|
+
}
|
|
1637
|
+
_getTestState() {
|
|
1638
|
+
return {
|
|
1639
|
+
types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
|
|
1640
|
+
extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f"),
|
|
1641
|
+
};
|
|
1150
1642
|
}
|
|
1151
|
-
};
|
|
1152
1643
|
}
|
|
1153
|
-
|
|
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
|
|
1644
|
+
_Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _Mime_typeToExtensions = new WeakMap();
|
|
1171
1645
|
|
|
1172
|
-
|
|
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
|
-
}
|
|
1646
|
+
var mime = new Mime(types)._freeze();
|
|
1199
1647
|
|
|
1200
|
-
function
|
|
1201
|
-
|
|
1202
|
-
}
|
|
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.runner.executeId(
|
|
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) {
|
|
1648
|
+
function assertFileAccess(path, project) {
|
|
1649
|
+
if (!isFileServingAllowed(path, project.vite) && !isFileServingAllowed(path, project.vitest.server)) {
|
|
1222
1650
|
throw new Error(
|
|
1223
|
-
`
|
|
1651
|
+
`Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`
|
|
1224
1652
|
);
|
|
1225
1653
|
}
|
|
1226
|
-
return customProviderModule.default;
|
|
1227
1654
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
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");
|
|
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";
|
|
1262
1660
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
"{__VITEST_INJECTOR__}",
|
|
1272
|
-
"{__VITEST_ERROR_CATCHER__}",
|
|
1273
|
-
"{__VITEST_SCRIPTS__}",
|
|
1274
|
-
`<script type="module" crossorigin src="${base}${jsEntry}"><\/script>`
|
|
1275
|
-
].join("\n")
|
|
1276
|
-
);
|
|
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 });
|
|
1277
1669
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
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
|
-
);
|
|
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");
|
|
1681
|
+
return {
|
|
1682
|
+
content,
|
|
1683
|
+
basename: basename$1(filepath),
|
|
1684
|
+
mime: mime.getType(filepath)
|
|
1685
|
+
};
|
|
1686
|
+
};
|
|
1310
1687
|
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
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));
|
|
1688
|
+
const hover = async (context, selector, options = {}) => {
|
|
1689
|
+
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1690
|
+
await context.iframe.locator(selector).hover(options);
|
|
1691
|
+
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
1692
|
+
const browser = context.browser;
|
|
1693
|
+
await browser.$(selector).moveTo(options);
|
|
1694
|
+
} else {
|
|
1695
|
+
throw new TypeError(`Provider "${context.provider.name}" does not support hover`);
|
|
1332
1696
|
}
|
|
1333
|
-
return output;
|
|
1334
1697
|
};
|
|
1335
1698
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
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 = {}));
|
|
1341
1710
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
};
|
|
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 = {}));
|
|
1726
|
+
|
|
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 = {}));
|
|
1357
1736
|
|
|
1737
|
+
var bracketDict;
|
|
1738
|
+
(function(bracketDict) {
|
|
1739
|
+
bracketDict["{"] = "}";
|
|
1740
|
+
bracketDict["["] = "]";
|
|
1741
|
+
})(bracketDict || (bracketDict = {}));
|
|
1358
1742
|
/**
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
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
|
+
};
|
|
1762
|
+
}
|
|
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
|
+
};
|
|
1774
|
+
}
|
|
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));
|
|
1383
1797
|
}
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
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));
|
|
1390
1810
|
}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
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.`;
|
|
1824
|
+
}
|
|
1394
1825
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
csp.replace(/frame-ancestors [^;]+/, "frame-ancestors *")
|
|
1401
|
-
);
|
|
1402
|
-
}
|
|
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
|
-
}
|
|
1826
|
+
var ApiLevel;
|
|
1827
|
+
(function(ApiLevel) {
|
|
1828
|
+
ApiLevel[ApiLevel["Trigger"] = 2] = "Trigger";
|
|
1829
|
+
ApiLevel[ApiLevel["Call"] = 1] = "Call";
|
|
1830
|
+
})(ApiLevel || (ApiLevel = {}));
|
|
1444
1831
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
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 = {}));
|
|
1842
|
+
|
|
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 = {}));
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
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
|
|
1454
1874
|
{
|
|
1455
|
-
|
|
1456
|
-
|
|
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
|
-
});
|
|
1573
|
-
}
|
|
1875
|
+
code: 'Space',
|
|
1876
|
+
key: ' '
|
|
1574
1877
|
},
|
|
1575
1878
|
{
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
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;
|
|
1588
|
-
}
|
|
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);
|
|
1622
|
-
}
|
|
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);
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
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");
|
|
1655
|
-
}
|
|
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
|
-
}
|
|
1879
|
+
code: 'AltLeft',
|
|
1880
|
+
key: 'Alt',
|
|
1881
|
+
location: DOM_KEY_LOCATION.LEFT
|
|
1685
1882
|
},
|
|
1686
1883
|
{
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
return this.resolve("msw/mockServiceWorker.js", distRoot, {
|
|
1691
|
-
skipSelf: true
|
|
1692
|
-
});
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1884
|
+
code: 'AltRight',
|
|
1885
|
+
key: 'Alt',
|
|
1886
|
+
location: DOM_KEY_LOCATION.RIGHT
|
|
1695
1887
|
},
|
|
1696
1888
|
{
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
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
|
-
}
|
|
1714
|
-
}
|
|
1889
|
+
code: 'ShiftLeft',
|
|
1890
|
+
key: 'Shift',
|
|
1891
|
+
location: DOM_KEY_LOCATION.LEFT
|
|
1715
1892
|
},
|
|
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;
|
|
1724
|
-
}
|
|
1725
|
-
}),
|
|
1726
1893
|
{
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
// Enables using ignore hint for coverage providers with @preserve keyword
|
|
1731
|
-
if (viteConfig.esbuild !== false) {
|
|
1732
|
-
viteConfig.esbuild ||= {};
|
|
1733
|
-
viteConfig.esbuild.legalComments = "inline";
|
|
1734
|
-
}
|
|
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
|
-
}
|
|
1894
|
+
code: 'ShiftRight',
|
|
1895
|
+
key: 'Shift',
|
|
1896
|
+
location: DOM_KEY_LOCATION.RIGHT
|
|
1762
1897
|
},
|
|
1763
1898
|
{
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
return;
|
|
1768
|
-
}
|
|
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
|
-
}
|
|
1899
|
+
code: 'ControlLeft',
|
|
1900
|
+
key: 'Control',
|
|
1901
|
+
location: DOM_KEY_LOCATION.LEFT
|
|
1779
1902
|
},
|
|
1780
1903
|
{
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
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
|
-
};
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1904
|
+
code: 'ControlRight',
|
|
1905
|
+
key: 'Control',
|
|
1906
|
+
location: DOM_KEY_LOCATION.RIGHT
|
|
1792
1907
|
},
|
|
1793
1908
|
{
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
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
|
+
];
|
|
2001
|
+
|
|
2002
|
+
/**
|
|
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
|
+
}
|
|
2040
|
+
|
|
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);
|
|
2047
|
+
}
|
|
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`);
|
|
2062
|
+
}
|
|
2063
|
+
},
|
|
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);
|
|
2097
|
+
}
|
|
2098
|
+
pressed.delete(key);
|
|
2099
|
+
}
|
|
2100
|
+
if (!releasePrevious) {
|
|
2101
|
+
if (key === "selectall") {
|
|
2102
|
+
await selectAll2();
|
|
2103
|
+
continue;
|
|
2104
|
+
}
|
|
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);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
if (releaseSelf) {
|
|
2113
|
+
if (VALID_KEYS.has(key)) {
|
|
2114
|
+
await page.keyboard.up(key);
|
|
2115
|
+
}
|
|
2116
|
+
} else {
|
|
2117
|
+
pressed.add(key);
|
|
2118
|
+
}
|
|
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);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
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;
|
|
2139
|
+
}
|
|
2140
|
+
if (pressed.has(key)) {
|
|
2141
|
+
keyboard2.up(key);
|
|
2142
|
+
pressed.delete(key);
|
|
2143
|
+
}
|
|
2144
|
+
if (!releasePrevious) {
|
|
2145
|
+
if (key === "selectall") {
|
|
2146
|
+
await keyboard2.perform();
|
|
2147
|
+
keyboard2 = browser.action("key");
|
|
2148
|
+
await selectAll2();
|
|
2149
|
+
continue;
|
|
2150
|
+
}
|
|
2151
|
+
for (let i = 1; i <= repeat; i++) {
|
|
2152
|
+
keyboard2.down(key);
|
|
2153
|
+
}
|
|
2154
|
+
if (releaseSelf) {
|
|
2155
|
+
keyboard2.up(key);
|
|
2156
|
+
} else {
|
|
2157
|
+
pressed.add(key);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
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
|
+
};
|
|
2167
|
+
}
|
|
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();
|
|
2323
|
+
}
|
|
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
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
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
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
}
|
|
1926
|
-
|
|
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
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
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
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
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
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
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
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
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(
|
|
2090
|
-
const
|
|
2091
|
-
const
|
|
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")
|
|
2103
|
-
const
|
|
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(
|
|
2107
|
-
const 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(
|
|
2110
|
-
debug$1?.("[%s] Browser API connected to %s",
|
|
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",
|
|
2113
|
-
clients.delete(
|
|
2114
|
-
|
|
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(
|
|
2126
|
-
const mockResolver = new ServerMockResolver(
|
|
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(
|
|
2132
|
-
if (
|
|
2133
|
-
const _error =
|
|
2134
|
-
_error.stacks =
|
|
2846
|
+
async onUnhandledError(error2, type) {
|
|
2847
|
+
if (error2 && typeof error2 === "object") {
|
|
2848
|
+
const _error = error2;
|
|
2849
|
+
_error.stacks = globalServer.parseErrorStacktrace(_error);
|
|
2135
2850
|
}
|
|
2136
|
-
|
|
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
|
-
|
|
2140
|
-
await
|
|
2859
|
+
vitest.state.collectFiles(project, files);
|
|
2860
|
+
await vitest.report("onCollected", files);
|
|
2141
2861
|
},
|
|
2142
2862
|
async onTaskUpdate(packs) {
|
|
2143
|
-
|
|
2144
|
-
await
|
|
2863
|
+
vitest.state.updateTasks(packs);
|
|
2864
|
+
await vitest.report("onTaskUpdate", packs);
|
|
2145
2865
|
},
|
|
2146
2866
|
onAfterSuiteRun(meta) {
|
|
2147
|
-
|
|
2867
|
+
vitest.coverageProvider?.onAfterSuiteRun(meta);
|
|
2148
2868
|
},
|
|
2149
2869
|
sendLog(log) {
|
|
2150
|
-
return
|
|
2870
|
+
return vitest.report("onUserConsoleLog", log);
|
|
2151
2871
|
},
|
|
2152
2872
|
resolveSnapshotPath(testPath) {
|
|
2153
|
-
return
|
|
2154
|
-
config: project.
|
|
2873
|
+
return vitest.snapshot.resolvePath(testPath, {
|
|
2874
|
+
config: project.serializedConfig
|
|
2155
2875
|
});
|
|
2156
2876
|
},
|
|
2157
2877
|
resolveSnapshotRawPath(testPath, rawPath) {
|
|
2158
|
-
return
|
|
2878
|
+
return vitest.snapshot.resolveRawPath(testPath, rawPath);
|
|
2159
2879
|
},
|
|
2160
2880
|
snapshotSaved(snapshot) {
|
|
2161
|
-
|
|
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 =
|
|
2903
|
+
const mod = globalServer.vite.moduleGraph.getModuleById(id);
|
|
2184
2904
|
return mod?.transformResult?.map;
|
|
2185
2905
|
},
|
|
2186
2906
|
onCancel(reason) {
|
|
2187
|
-
|
|
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
|
-
|
|
2913
|
+
vitest.logger.console.debug(...args);
|
|
2194
2914
|
},
|
|
2195
2915
|
getCountOfFailedTests() {
|
|
2196
|
-
return
|
|
2916
|
+
return vitest.state.getCountOfFailedTests();
|
|
2197
2917
|
},
|
|
2198
|
-
async triggerCommand(
|
|
2199
|
-
debug$1?.('[%s] Triggering command "%s"',
|
|
2200
|
-
const 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 =
|
|
2924
|
+
const commands = globalServer.commands;
|
|
2205
2925
|
if (!commands || !commands[command]) {
|
|
2206
2926
|
throw new Error(`Unknown command "${command}".`);
|
|
2207
2927
|
}
|
|
2208
|
-
|
|
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(
|
|
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
|
-
|
|
2225
|
-
await provider.afterCommand(command, payload);
|
|
2226
|
-
}
|
|
2943
|
+
await provider.afterCommand?.(command, payload);
|
|
2227
2944
|
}
|
|
2228
2945
|
return result;
|
|
2229
2946
|
},
|
|
2230
|
-
finishBrowserTests(
|
|
2231
|
-
debug$1?.("[%s] Finishing browser tests for
|
|
2232
|
-
return
|
|
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(
|
|
2242
|
-
const cdp = await
|
|
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(
|
|
2246
|
-
const cdp = await
|
|
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
|
-
|
|
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,
|
|
2550
|
-
const context = project.
|
|
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(
|
|
3010
|
+
function createBrowserPool(vitest) {
|
|
2554
3011
|
const providers = /* @__PURE__ */ new Set();
|
|
2555
3012
|
const executeTests = async (method, project, files) => {
|
|
2556
|
-
|
|
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(
|
|
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(
|
|
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 [
|
|
3056
|
+
const [sessionId, orchestrator] = orchestrators[index];
|
|
2600
3057
|
debug?.(
|
|
2601
|
-
"Reusing orchestrator (
|
|
2602
|
-
|
|
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,
|
|
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
|
|
2615
|
-
const waitPromise = waitForTests(method,
|
|
3071
|
+
const sessionId = crypto.randomUUID();
|
|
3072
|
+
const waitPromise = waitForTests(method, sessionId, project, files2);
|
|
2616
3073
|
debug?.(
|
|
2617
|
-
"Opening a new
|
|
2618
|
-
|
|
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("
|
|
2623
|
-
const page = provider.openPage(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
2680
|
-
project.
|
|
3136
|
+
if (project.vitest.version !== version) {
|
|
3137
|
+
project.vitest.logger.warn(
|
|
2681
3138
|
c.yellow(
|
|
2682
|
-
`Loaded ${c.inverse(c.yellow(` vitest@${project.
|
|
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
|
|
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({
|