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