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