@vitest/browser 3.2.0-beta.1 → 3.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/context.d.ts +23 -2
- package/context.js +1 -0
- package/dist/client/.vite/manifest.json +2 -2
- package/dist/client/__vitest__/assets/index-C03hLyIS.js +52 -0
- package/dist/client/__vitest__/assets/{index-DJfrXR3P.css → index-CVSF215x.css} +1 -1
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/{orchestrator-CuTjqoE1.js → orchestrator-Bsc_nLaw.js} +6 -2
- package/dist/client/__vitest_browser__/{tester-D-yxPeOx.js → tester-BV-CSJ5v.js} +7 -3
- package/dist/client/orchestrator.html +1 -1
- package/dist/client/tester/tester.html +1 -1
- package/dist/client.js +5 -0
- package/dist/context.js +48 -2
- package/dist/expect-element.js +1 -1
- package/dist/{index-C3ICQ6zz.js → index-D0pxULUR.js} +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +125 -23
- package/dist/locators/index.d.ts +1 -0
- package/dist/locators/index.js +1 -1
- package/dist/locators/playwright.js +1 -1
- package/dist/locators/preview.js +1 -1
- package/dist/locators/webdriverio.js +1 -1
- package/dist/providers.js +2 -1
- package/dist/{public-utils-DUr23h1p.js → public-utils-DJ-T0CfF.js} +1 -1
- package/dist/state.js +3 -0
- package/dist/utils.js +1 -1
- package/dist/{webdriver-D7k26Na7.js → webdriver-B1QbgqhC.js} +52 -13
- package/package.json +12 -12
- package/utils.d.ts +1 -1
- package/dist/client/__vitest__/assets/index-BZjudRZr.js +0 -52
package/dist/index.js
CHANGED
|
@@ -11,14 +11,14 @@ import * as vite from 'vite';
|
|
|
11
11
|
import { coverageConfigDefaults } from 'vitest/config';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import crypto from 'node:crypto';
|
|
14
|
-
import { mkdir, readFile as readFile$1 } from 'node:fs/promises';
|
|
14
|
+
import { mkdir, rm, readFile as readFile$1 } from 'node:fs/promises';
|
|
15
15
|
import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
|
|
16
|
-
import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-
|
|
16
|
+
import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-B1QbgqhC.js';
|
|
17
17
|
import { resolve as resolve$1, basename as basename$1, dirname as dirname$1, normalize as normalize$1 } from 'node:path';
|
|
18
18
|
import { WebSocketServer } from 'ws';
|
|
19
19
|
import * as nodeos from 'node:os';
|
|
20
20
|
|
|
21
|
-
var version = "3.2.0-beta.
|
|
21
|
+
var version = "3.2.0-beta.3";
|
|
22
22
|
|
|
23
23
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
24
24
|
function normalizeWindowsPath(input = "") {
|
|
@@ -351,15 +351,19 @@ function slash(path) {
|
|
|
351
351
|
|
|
352
352
|
async function resolveOrchestrator(globalServer, url, res) {
|
|
353
353
|
let sessionId = url.searchParams.get("sessionId");
|
|
354
|
+
// it's possible to open the page without a context
|
|
354
355
|
if (!sessionId) {
|
|
355
356
|
const contexts = [...globalServer.children].flatMap((p) => [...p.state.orchestrators.keys()]);
|
|
356
357
|
sessionId = contexts[contexts.length - 1] ?? "none";
|
|
357
358
|
}
|
|
359
|
+
// it's ok to not have a session here, especially in the preview provider
|
|
360
|
+
// because the user could refresh the page which would remove the session id from the url
|
|
358
361
|
const session = globalServer.vitest._browserSessions.getSession(sessionId);
|
|
359
362
|
const browserProject = session?.project.browser || [...globalServer.children][0];
|
|
360
363
|
if (!browserProject) {
|
|
361
364
|
return;
|
|
362
365
|
}
|
|
366
|
+
// ignore uknown pages
|
|
363
367
|
if (sessionId && sessionId !== "none" && !globalServer.vitest._browserSessions.sessionIds.has(sessionId)) {
|
|
364
368
|
return;
|
|
365
369
|
}
|
|
@@ -375,6 +379,7 @@ async function resolveOrchestrator(globalServer, url, res) {
|
|
|
375
379
|
__VITEST_PROVIDED_CONTEXT__: JSON.stringify(stringify(browserProject.project.getProvidedContext())),
|
|
376
380
|
__VITEST_API_TOKEN__: JSON.stringify(globalServer.vitest.config.api.token)
|
|
377
381
|
});
|
|
382
|
+
// disable CSP for the orchestrator as we are the ones controlling it
|
|
378
383
|
res.removeHeader("Content-Security-Policy");
|
|
379
384
|
if (!globalServer.orchestratorScripts) {
|
|
380
385
|
globalServer.orchestratorScripts = (await globalServer.formatScripts(globalServer.config.browser.orchestratorScripts)).map((script) => {
|
|
@@ -387,6 +392,7 @@ async function resolveOrchestrator(globalServer, url, res) {
|
|
|
387
392
|
}).join("\n");
|
|
388
393
|
}
|
|
389
394
|
let baseHtml = typeof globalServer.orchestratorHtml === "string" ? globalServer.orchestratorHtml : await globalServer.orchestratorHtml;
|
|
395
|
+
// if UI is enabled, use UI HTML and inject the orchestrator script
|
|
390
396
|
if (globalServer.config.browser.ui) {
|
|
391
397
|
const manifestContent = globalServer.manifest instanceof Promise ? await globalServer.manifest : globalServer.manifest;
|
|
392
398
|
const jsEntry = manifestContent["orchestrator.html"].file;
|
|
@@ -413,6 +419,7 @@ function disableCache(res) {
|
|
|
413
419
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
414
420
|
}
|
|
415
421
|
function allowIframes(res) {
|
|
422
|
+
// remove custom iframe related headers to allow the iframe to load
|
|
416
423
|
res.removeHeader("X-Frame-Options");
|
|
417
424
|
}
|
|
418
425
|
|
|
@@ -438,6 +445,8 @@ function createOrchestratorMiddleware(parentServer) {
|
|
|
438
445
|
async function resolveTester(globalServer, url, res, next) {
|
|
439
446
|
const csp = res.getHeader("Content-Security-Policy");
|
|
440
447
|
if (typeof csp === "string") {
|
|
448
|
+
// add frame-ancestors to allow the iframe to be loaded by Vitest,
|
|
449
|
+
// but keep the rest of the CSP
|
|
441
450
|
res.setHeader("Content-Security-Policy", csp.replace(/frame-ancestors [^;]+/, "frame-ancestors *"));
|
|
442
451
|
}
|
|
443
452
|
const sessionId = url.searchParams.get("sessionId") || "none";
|
|
@@ -529,7 +538,7 @@ async function generateContextFile(globalServer) {
|
|
|
529
538
|
const userEventNonProviderImport = await getUserEventImport(providerName, this.resolve.bind(this));
|
|
530
539
|
const distContextPath = slash$1(`/@fs/${resolve(__dirname, "context.js")}`);
|
|
531
540
|
return `
|
|
532
|
-
import { page, createUserEvent, cdp } from '${distContextPath}'
|
|
541
|
+
import { page, createUserEvent, cdp, locators } from '${distContextPath}'
|
|
533
542
|
${userEventNonProviderImport}
|
|
534
543
|
|
|
535
544
|
export const server = {
|
|
@@ -544,7 +553,7 @@ export const server = {
|
|
|
544
553
|
}
|
|
545
554
|
export const commands = server.commands
|
|
546
555
|
export const userEvent = createUserEvent(_userEventSetup)
|
|
547
|
-
export { page, cdp }
|
|
556
|
+
export { page, cdp, locators }
|
|
548
557
|
`;
|
|
549
558
|
}
|
|
550
559
|
async function getUserEventImport(provider, resolve) {
|
|
@@ -572,6 +581,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
572
581
|
name: "vitest:browser",
|
|
573
582
|
async configureServer(server) {
|
|
574
583
|
parentServer.setServer(server);
|
|
584
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
575
585
|
server.middlewares.use(function vitestHeaders(_req, res, next) {
|
|
576
586
|
const headers = server.config.server.headers;
|
|
577
587
|
if (headers) {
|
|
@@ -604,6 +614,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
604
614
|
}
|
|
605
615
|
const uiEnabled = parentServer.config.browser.ui;
|
|
606
616
|
if (uiEnabled) {
|
|
617
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
607
618
|
server.middlewares.use(`${base}__screenshot-error`, function vitestBrowserScreenshotError(req, res) {
|
|
608
619
|
if (!req.url) {
|
|
609
620
|
res.statusCode = 404;
|
|
@@ -642,6 +653,11 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
642
653
|
});
|
|
643
654
|
}
|
|
644
655
|
server.middlewares.use((req, res, next) => {
|
|
656
|
+
// 9000 mega head move
|
|
657
|
+
// Vite always caches optimized dependencies, but users might mock
|
|
658
|
+
// them in _some_ tests, while keeping original modules in others
|
|
659
|
+
// there is no way to configure that in Vite, so we patch it here
|
|
660
|
+
// to always ignore the cache-control set by Vite in the next middleware
|
|
645
661
|
if (req.url && versionRegexp.test(req.url) && !req.url.includes("chunk-")) {
|
|
646
662
|
res.setHeader("Cache-Control", "no-cache");
|
|
647
663
|
const setHeader = res.setHeader.bind(res);
|
|
@@ -660,10 +676,13 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
660
676
|
name: "vitest:browser:tests",
|
|
661
677
|
enforce: "pre",
|
|
662
678
|
async config() {
|
|
679
|
+
// this plugin can be used in different projects, but all of them
|
|
680
|
+
// have the same `include` pattern, so it doesn't matter which project we use
|
|
663
681
|
const project = parentServer.project;
|
|
664
682
|
const { testFiles: allTestFiles } = await project.globTestFiles();
|
|
665
683
|
const browserTestFiles = allTestFiles.filter((file) => getFilePoolName(project, file) === "browser");
|
|
666
684
|
const setupFiles = toArray(project.config.setupFiles);
|
|
685
|
+
// replace env values - cannot be reassign at runtime
|
|
667
686
|
const define = {};
|
|
668
687
|
for (const env in project.config.env || {}) {
|
|
669
688
|
const stringValue = JSON.stringify(project.config.env[env]);
|
|
@@ -680,8 +699,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
680
699
|
];
|
|
681
700
|
const exclude = [
|
|
682
701
|
"vitest",
|
|
683
|
-
"vitest/
|
|
684
|
-
"vitest/browser",
|
|
702
|
+
"vitest/internal/browser",
|
|
685
703
|
"vitest/runners",
|
|
686
704
|
"@vitest/browser",
|
|
687
705
|
"@vitest/browser/client",
|
|
@@ -736,8 +754,10 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
736
754
|
if (svelte) {
|
|
737
755
|
exclude.push("vitest-browser-svelte");
|
|
738
756
|
}
|
|
757
|
+
// since we override the resolution in the esbuild plugin, Vite can no longer optimizer it
|
|
739
758
|
const vue = isPackageExists("vitest-browser-vue", fileRoot);
|
|
740
759
|
if (vue) {
|
|
760
|
+
// we override them in the esbuild plugin so optimizer can no longer intercept it
|
|
741
761
|
include.push("vitest-browser-vue", "vitest-browser-vue > @vue/test-utils", "vitest-browser-vue > @vue/test-utils > @vue/compiler-core");
|
|
742
762
|
}
|
|
743
763
|
const vueTestUtils = isPackageExists("@vue/test-utils", fileRoot);
|
|
@@ -788,6 +808,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
788
808
|
},
|
|
789
809
|
transform(code, id) {
|
|
790
810
|
if (id.includes(parentServer.vite.config.cacheDir) && id.includes("loupe.js")) {
|
|
811
|
+
// loupe bundle has a nastry require('util') call that leaves a warning in the console
|
|
791
812
|
const utilRequire = "nodeUtil = require_util();";
|
|
792
813
|
return code.replace(utilRequire, " ".repeat(utilRequire.length));
|
|
793
814
|
}
|
|
@@ -830,11 +851,12 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
830
851
|
{
|
|
831
852
|
name: "vitest:browser:in-source-tests",
|
|
832
853
|
transform(code, id) {
|
|
854
|
+
const filename = cleanUrl(id);
|
|
833
855
|
const project = parentServer.vitest.getProjectByName(parentServer.config.name);
|
|
834
|
-
if (!project._isCachedTestFile(
|
|
856
|
+
if (!project._isCachedTestFile(filename) || !code.includes("import.meta.vitest")) {
|
|
835
857
|
return;
|
|
836
858
|
}
|
|
837
|
-
const s = new MagicString(code, { filename
|
|
859
|
+
const s = new MagicString(code, { filename });
|
|
838
860
|
s.prepend(`import.meta.vitest = __vitest_index__;\n`);
|
|
839
861
|
return {
|
|
840
862
|
code: s.toString(),
|
|
@@ -845,6 +867,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
845
867
|
{
|
|
846
868
|
name: "vitest:browser:worker",
|
|
847
869
|
transform(code, id, _options) {
|
|
870
|
+
// https://github.com/vitejs/vite/blob/ba56cf43b5480f8519349f7d7fe60718e9af5f1a/packages/vite/src/node/plugins/worker.ts#L46
|
|
848
871
|
if (/(?:\?|&)worker_file&type=\w+(?:&|$)/.test(id)) {
|
|
849
872
|
const s = new MagicString(code);
|
|
850
873
|
s.prepend("globalThis.__vitest_browser_runner__ = { wrapDynamicImport: f => f() };\n");
|
|
@@ -899,6 +922,8 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
899
922
|
}
|
|
900
923
|
}
|
|
901
924
|
} else {
|
|
925
|
+
// inject the reset style only in the default template,
|
|
926
|
+
// allowing users to customize the style in their own template
|
|
902
927
|
testerTags.push({
|
|
903
928
|
tag: "style",
|
|
904
929
|
children: `
|
|
@@ -970,6 +995,8 @@ body {
|
|
|
970
995
|
const esbuildPlugin = {
|
|
971
996
|
name: "test-utils-rewrite",
|
|
972
997
|
setup(build) {
|
|
998
|
+
// test-utils: resolve to CJS instead of the browser because the browser version expects a global Vue object
|
|
999
|
+
// compiler-core: only CJS version allows slots as strings
|
|
973
1000
|
build.onResolve({ filter: /^@vue\/(test-utils|compiler-core)$/ }, (args) => {
|
|
974
1001
|
const resolved = getRequire().resolve(args.path, { paths: [args.importer] });
|
|
975
1002
|
return { path: resolved };
|
|
@@ -1007,6 +1034,7 @@ function resolveCoverageFolder(vitest) {
|
|
|
1007
1034
|
if (!htmlReporter) {
|
|
1008
1035
|
return undefined;
|
|
1009
1036
|
}
|
|
1037
|
+
// reportsDirectory not resolved yet
|
|
1010
1038
|
const root = resolve(options.root || process.cwd(), options.coverage.reportsDirectory || coverageConfigDefaults.reportsDirectory);
|
|
1011
1039
|
const subdir = Array.isArray(htmlReporter) && htmlReporter.length > 1 && "subdir" in htmlReporter[1] ? htmlReporter[1].subdir : undefined;
|
|
1012
1040
|
if (!subdir || typeof subdir !== "string") {
|
|
@@ -1122,6 +1150,7 @@ const dragAndDrop = async (context, source, target, options_) => {
|
|
|
1122
1150
|
const $target = context.browser.$(target);
|
|
1123
1151
|
const options = options_ || {};
|
|
1124
1152
|
const duration = options.duration ?? 10;
|
|
1153
|
+
// https://github.com/webdriverio/webdriverio/issues/8022#issuecomment-1700919670
|
|
1125
1154
|
await context.browser.action("pointer").move({
|
|
1126
1155
|
duration: 0,
|
|
1127
1156
|
origin: $source,
|
|
@@ -1626,6 +1655,7 @@ function assertFileAccess(path, project) {
|
|
|
1626
1655
|
const readFile = async ({ project }, path, options = {}) => {
|
|
1627
1656
|
const filepath = resolve$1(project.config.root, path);
|
|
1628
1657
|
assertFileAccess(filepath, project);
|
|
1658
|
+
// never return a Buffer
|
|
1629
1659
|
if (typeof options === "object" && !options.encoding) {
|
|
1630
1660
|
options.encoding = "utf-8";
|
|
1631
1661
|
}
|
|
@@ -2016,6 +2046,8 @@ const keyboardCleanup = async (context, state) => {
|
|
|
2016
2046
|
throw new TypeError(`Provider "${context.provider.name}" does not support keyboard api`);
|
|
2017
2047
|
}
|
|
2018
2048
|
};
|
|
2049
|
+
// fallback to insertText for non US key
|
|
2050
|
+
// https://github.com/microsoft/playwright/blob/50775698ae13642742f2a1e8983d1d686d7f192d/packages/playwright-core/src/server/input.ts#L95
|
|
2019
2051
|
const VALID_KEYS = new Set([
|
|
2020
2052
|
"Escape",
|
|
2021
2053
|
"F1",
|
|
@@ -2231,6 +2263,9 @@ async function keyboardImplementation(pressed, provider, sessionId, text, select
|
|
|
2231
2263
|
const actions = parseKeyDef(defaultKeyMap, text);
|
|
2232
2264
|
for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) {
|
|
2233
2265
|
const key = keyDef.key;
|
|
2266
|
+
// TODO: instead of calling down/up for each key, join non special
|
|
2267
|
+
// together, and call `type` once for all non special keys,
|
|
2268
|
+
// and then `press` for special keys
|
|
2234
2269
|
if (pressed.has(key)) {
|
|
2235
2270
|
if (VALID_KEYS.has(key)) {
|
|
2236
2271
|
await page.keyboard.up(key);
|
|
@@ -2297,6 +2332,7 @@ async function keyboardImplementation(pressed, provider, sessionId, text, select
|
|
|
2297
2332
|
}
|
|
2298
2333
|
}
|
|
2299
2334
|
}
|
|
2335
|
+
// seems like webdriverio doesn't release keys automatically if skipRelease is true and all events are keyUp
|
|
2300
2336
|
const allRelease = keyboard.toJSON().actions.every((action) => action.type === "keyUp");
|
|
2301
2337
|
await keyboard.perform(allRelease ? false : skipRelease);
|
|
2302
2338
|
}
|
|
@@ -2318,6 +2354,10 @@ const screenshot = async (context, name, options = {}) => {
|
|
|
2318
2354
|
if (!context.testPath) {
|
|
2319
2355
|
throw new Error(`Cannot take a screenshot without a test path`);
|
|
2320
2356
|
}
|
|
2357
|
+
options.save ??= true;
|
|
2358
|
+
if (!options.save) {
|
|
2359
|
+
options.base64 = true;
|
|
2360
|
+
}
|
|
2321
2361
|
const path = options.path ? resolve(dirname(context.testPath), options.path) : resolveScreenshotPath(context.testPath, name, context.project.config);
|
|
2322
2362
|
const savePath = normalize$1(path);
|
|
2323
2363
|
await mkdir(dirname(path), { recursive: true });
|
|
@@ -2327,25 +2367,23 @@ const screenshot = async (context, name, options = {}) => {
|
|
|
2327
2367
|
const element = context.iframe.locator(`${selector}`);
|
|
2328
2368
|
const buffer = await element.screenshot({
|
|
2329
2369
|
...config,
|
|
2330
|
-
path: savePath
|
|
2370
|
+
path: options.save ? savePath : undefined
|
|
2331
2371
|
});
|
|
2332
2372
|
return returnResult(options, path, buffer);
|
|
2333
2373
|
}
|
|
2334
2374
|
const buffer = await context.iframe.locator("body").screenshot({
|
|
2335
2375
|
...options,
|
|
2336
|
-
path: savePath
|
|
2376
|
+
path: options.save ? savePath : undefined
|
|
2337
2377
|
});
|
|
2338
2378
|
return returnResult(options, path, buffer);
|
|
2339
2379
|
}
|
|
2340
2380
|
if (context.provider instanceof WebdriverBrowserProvider) {
|
|
2341
2381
|
const page = context.provider.browser;
|
|
2342
|
-
|
|
2343
|
-
const body = await page.$("body");
|
|
2344
|
-
const buffer = await body.saveScreenshot(savePath);
|
|
2345
|
-
return returnResult(options, path, buffer);
|
|
2346
|
-
}
|
|
2347
|
-
const element = await page.$(`${options.element}`);
|
|
2382
|
+
const element = !options.element ? await page.$("body") : await page.$(`${options.element}`);
|
|
2348
2383
|
const buffer = await element.saveScreenshot(savePath);
|
|
2384
|
+
if (!options.save) {
|
|
2385
|
+
await rm(savePath, { force: true });
|
|
2386
|
+
}
|
|
2349
2387
|
return returnResult(options, path, buffer);
|
|
2350
2388
|
}
|
|
2351
2389
|
throw new Error(`Provider "${context.provider.name}" does not support screenshots`);
|
|
@@ -2359,6 +2397,9 @@ function resolveScreenshotPath(testPath, name, config) {
|
|
|
2359
2397
|
return resolve(dir, "__screenshots__", base, name);
|
|
2360
2398
|
}
|
|
2361
2399
|
function returnResult(options, path, buffer) {
|
|
2400
|
+
if (!options.save) {
|
|
2401
|
+
return buffer.toString("base64");
|
|
2402
|
+
}
|
|
2362
2403
|
if (options.base64) {
|
|
2363
2404
|
return {
|
|
2364
2405
|
path,
|
|
@@ -2450,12 +2491,12 @@ const upload = async (context, selector, files, options) => {
|
|
|
2450
2491
|
if (!testPath) {
|
|
2451
2492
|
throw new Error(`Cannot upload files outside of a test`);
|
|
2452
2493
|
}
|
|
2453
|
-
const
|
|
2494
|
+
const root = context.project.config.root;
|
|
2454
2495
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
2455
2496
|
const { iframe } = context;
|
|
2456
2497
|
const playwrightFiles = files.map((file) => {
|
|
2457
2498
|
if (typeof file === "string") {
|
|
2458
|
-
return resolve(
|
|
2499
|
+
return resolve(root, file);
|
|
2459
2500
|
}
|
|
2460
2501
|
return {
|
|
2461
2502
|
name: file.name,
|
|
@@ -2472,7 +2513,7 @@ const upload = async (context, selector, files, options) => {
|
|
|
2472
2513
|
}
|
|
2473
2514
|
const element = context.browser.$(selector);
|
|
2474
2515
|
for (const file of files) {
|
|
2475
|
-
const filepath = resolve(
|
|
2516
|
+
const filepath = resolve(root, file);
|
|
2476
2517
|
const remoteFilePath = await context.browser.uploadFile(filepath);
|
|
2477
2518
|
await element.addValue(remoteFilePath);
|
|
2478
2519
|
}
|
|
@@ -2481,6 +2522,14 @@ const upload = async (context, selector, files, options) => {
|
|
|
2481
2522
|
}
|
|
2482
2523
|
};
|
|
2483
2524
|
|
|
2525
|
+
const viewport = async (context, options) => {
|
|
2526
|
+
if (context.provider instanceof WebdriverBrowserProvider) {
|
|
2527
|
+
await context.provider.setViewport(options);
|
|
2528
|
+
} else {
|
|
2529
|
+
throw new TypeError(`Provider ${context.provider.name} doesn't support "viewport" command`);
|
|
2530
|
+
}
|
|
2531
|
+
};
|
|
2532
|
+
|
|
2484
2533
|
var builtinCommands = {
|
|
2485
2534
|
readFile,
|
|
2486
2535
|
removeFile,
|
|
@@ -2499,7 +2548,8 @@ var builtinCommands = {
|
|
|
2499
2548
|
__vitest_selectOptions: selectOptions,
|
|
2500
2549
|
__vitest_dragAndDrop: dragAndDrop,
|
|
2501
2550
|
__vitest_hover: hover,
|
|
2502
|
-
__vitest_cleanup: keyboardCleanup
|
|
2551
|
+
__vitest_cleanup: keyboardCleanup,
|
|
2552
|
+
__vitest_viewport: viewport
|
|
2503
2553
|
};
|
|
2504
2554
|
|
|
2505
2555
|
class BrowserServerState {
|
|
@@ -2595,6 +2645,7 @@ class ParentBrowserProject {
|
|
|
2595
2645
|
children = new Set();
|
|
2596
2646
|
vitest;
|
|
2597
2647
|
config;
|
|
2648
|
+
// cache for non-vite source maps
|
|
2598
2649
|
sourceMapCache = new Map();
|
|
2599
2650
|
constructor(project, base) {
|
|
2600
2651
|
this.project = project;
|
|
@@ -2608,6 +2659,7 @@ class ParentBrowserProject {
|
|
|
2608
2659
|
return this.sourceMapCache.get(id);
|
|
2609
2660
|
}
|
|
2610
2661
|
const result = this.vite.moduleGraph.getModuleById(id)?.transformResult;
|
|
2662
|
+
// this can happen for bundled dependencies in node_modules/.vite
|
|
2611
2663
|
if (result && !result.map) {
|
|
2612
2664
|
const sourceMapUrl = this.retrieveSourceMapURL(result.code);
|
|
2613
2665
|
if (!sourceMapUrl) {
|
|
@@ -2631,6 +2683,8 @@ class ParentBrowserProject {
|
|
|
2631
2683
|
if (modUrl) {
|
|
2632
2684
|
return resolvedPath;
|
|
2633
2685
|
}
|
|
2686
|
+
// some browsers (looking at you, safari) don't report queries in stack traces
|
|
2687
|
+
// the next best thing is to try the first id that this file resolves to
|
|
2634
2688
|
const files = this.vite.moduleGraph.getModulesByFile(resolvedPath);
|
|
2635
2689
|
if (files && files.size) {
|
|
2636
2690
|
return files.values().next().value.id;
|
|
@@ -2641,6 +2695,7 @@ class ParentBrowserProject {
|
|
|
2641
2695
|
for (const [name, command] of Object.entries(builtinCommands)) {
|
|
2642
2696
|
this.commands[name] ??= command;
|
|
2643
2697
|
}
|
|
2698
|
+
// validate names because they can't be used as identifiers
|
|
2644
2699
|
for (const command in project.config.browser.commands) {
|
|
2645
2700
|
if (!/^[a-z_$][\w$]*$/i.test(command)) {
|
|
2646
2701
|
throw new Error(`Invalid command name "${command}". Only alphanumeric characters, $ and _ are allowed.`);
|
|
@@ -2761,7 +2816,10 @@ class ParentBrowserProject {
|
|
|
2761
2816
|
}
|
|
2762
2817
|
retrieveSourceMapURL(source) {
|
|
2763
2818
|
const re = /\/\/[@#]\s*sourceMappingURL=([^\s'"]+)\s*$|\/\*[@#]\s*sourceMappingURL=[^\s*'"]+\s*\*\/\s*$/gm;
|
|
2819
|
+
// Keep executing the search to find the *last* sourceMappingURL to avoid
|
|
2820
|
+
// picking up sourceMappingURLs from comments, strings, etc.
|
|
2764
2821
|
let lastMatch, match;
|
|
2822
|
+
// eslint-disable-next-line no-cond-assign
|
|
2765
2823
|
while (match = re.exec(source)) {
|
|
2766
2824
|
lastMatch = match;
|
|
2767
2825
|
}
|
|
@@ -2960,6 +3018,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
2960
3018
|
}
|
|
2961
3019
|
if (type === "orchestrator") {
|
|
2962
3020
|
const session = vitest._browserSessions.getSession(sessionId);
|
|
3021
|
+
// it's possible the session was already resolved by the preview provider
|
|
2963
3022
|
session?.connected();
|
|
2964
3023
|
}
|
|
2965
3024
|
const project = vitest.getProjectByName(projectName);
|
|
@@ -2980,10 +3039,12 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
2980
3039
|
if (type === "orchestrator") {
|
|
2981
3040
|
vitest._browserSessions.destroySession(sessionId);
|
|
2982
3041
|
}
|
|
3042
|
+
// this will reject any hanging methods if there are any
|
|
2983
3043
|
rpc.$close(new Error(`[vitest] Browser connection was closed while running tests. Was the page closed unexpectedly?`));
|
|
2984
3044
|
});
|
|
2985
3045
|
});
|
|
2986
3046
|
});
|
|
3047
|
+
// we don't throw an error inside a stream because this can segfault the process
|
|
2987
3048
|
function error(err) {
|
|
2988
3049
|
console.error(err);
|
|
2989
3050
|
vitest.state.catchError(err, "RPC Error");
|
|
@@ -3120,6 +3181,8 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3120
3181
|
},
|
|
3121
3182
|
async registerMock(sessionId, module) {
|
|
3122
3183
|
if (!mocker) {
|
|
3184
|
+
// make sure modules are not processed yet in case they were imported before
|
|
3185
|
+
// and were not mocked
|
|
3123
3186
|
mockResolver.invalidate([module.id]);
|
|
3124
3187
|
if (module.type === "manual") {
|
|
3125
3188
|
const mock = ManualMockedModule.fromJSON(module, async () => {
|
|
@@ -3190,7 +3253,10 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3190
3253
|
return rpc;
|
|
3191
3254
|
}
|
|
3192
3255
|
}
|
|
3256
|
+
// Serialization support utils.
|
|
3193
3257
|
function cloneByOwnProperties(value) {
|
|
3258
|
+
// Clones the value's properties into a new Object. The simpler approach of
|
|
3259
|
+
// Object.assign() won't work in the case that properties are not enumerable.
|
|
3194
3260
|
return Object.getOwnPropertyNames(value).reduce((clone, prop) => ({
|
|
3195
3261
|
...clone,
|
|
3196
3262
|
[prop]: value[prop]
|
|
@@ -3251,7 +3317,7 @@ function createBrowserPool(vitest) {
|
|
|
3251
3317
|
vitest.onCancel(() => {
|
|
3252
3318
|
isCancelled = true;
|
|
3253
3319
|
});
|
|
3254
|
-
await Promise.all([...groupedFiles.entries()].map(async ([project, files]) => {
|
|
3320
|
+
const initialisedPools = await Promise.all([...groupedFiles.entries()].map(async ([project, files]) => {
|
|
3255
3321
|
await project._initBrowserProvider();
|
|
3256
3322
|
if (!project.browser) {
|
|
3257
3323
|
throw new TypeError(`The browser server was not initialized${project.name ? ` for the "${project.name}" project` : ""}. This is a bug in Vitest. Please, open a new issue with reproduction.`);
|
|
@@ -3263,8 +3329,34 @@ function createBrowserPool(vitest) {
|
|
|
3263
3329
|
const pool = ensurePool(project);
|
|
3264
3330
|
vitest.state.clearFiles(project, files);
|
|
3265
3331
|
providers.add(project.browser.provider);
|
|
3266
|
-
|
|
3332
|
+
return {
|
|
3333
|
+
pool,
|
|
3334
|
+
provider: project.browser.provider,
|
|
3335
|
+
runTests: () => pool.runTests(method, files)
|
|
3336
|
+
};
|
|
3267
3337
|
}));
|
|
3338
|
+
if (isCancelled) {
|
|
3339
|
+
return;
|
|
3340
|
+
}
|
|
3341
|
+
const parallelPools = [];
|
|
3342
|
+
const nonParallelPools = [];
|
|
3343
|
+
for (const result of initialisedPools) {
|
|
3344
|
+
if (!result) {
|
|
3345
|
+
return;
|
|
3346
|
+
}
|
|
3347
|
+
if (result.provider.mocker && result.provider.supportsParallelism) {
|
|
3348
|
+
parallelPools.push(result.runTests);
|
|
3349
|
+
} else {
|
|
3350
|
+
nonParallelPools.push(result.runTests);
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
await Promise.all(parallelPools.map((runTests) => runTests()));
|
|
3354
|
+
for (const runTests of nonParallelPools) {
|
|
3355
|
+
if (isCancelled) {
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
await runTests();
|
|
3359
|
+
}
|
|
3268
3360
|
};
|
|
3269
3361
|
function getThreadsCount(project) {
|
|
3270
3362
|
const config = project.config.browser;
|
|
@@ -3335,6 +3427,8 @@ class BrowserPool {
|
|
|
3335
3427
|
debug?.("all orchestrators are ready, not creating more");
|
|
3336
3428
|
return this._promise;
|
|
3337
3429
|
}
|
|
3430
|
+
// open the minimum amount of tabs
|
|
3431
|
+
// if there is only 1 file running, we don't need 8 tabs running
|
|
3338
3432
|
const workerCount = Math.min(this.options.maxWorkers - this.orchestrators.size, files.length);
|
|
3339
3433
|
const promises = [];
|
|
3340
3434
|
for (let i = 0; i < workerCount; i++) {
|
|
@@ -3343,6 +3437,7 @@ class BrowserPool {
|
|
|
3343
3437
|
const project = this.project.name;
|
|
3344
3438
|
debug?.("[%s] creating session for %s", sessionId, project);
|
|
3345
3439
|
const page = this.openPage(sessionId).then(() => {
|
|
3440
|
+
// start running tests on the page when it's ready
|
|
3346
3441
|
this.runNextTest(method, sessionId);
|
|
3347
3442
|
});
|
|
3348
3443
|
promises.push(page);
|
|
@@ -3367,6 +3462,7 @@ class BrowserPool {
|
|
|
3367
3462
|
}
|
|
3368
3463
|
finishSession(sessionId) {
|
|
3369
3464
|
this.readySessions.add(sessionId);
|
|
3465
|
+
// the last worker finished running tests
|
|
3370
3466
|
if (this.readySessions.size === this.orchestrators.size) {
|
|
3371
3467
|
this._promise?.resolve();
|
|
3372
3468
|
this._promise = undefined;
|
|
@@ -3380,10 +3476,14 @@ class BrowserPool {
|
|
|
3380
3476
|
if (!file) {
|
|
3381
3477
|
debug?.("[%s] no more tests to run", sessionId);
|
|
3382
3478
|
const isolate = this.project.config.browser.isolate;
|
|
3479
|
+
// we don't need to cleanup testers if isolation is enabled,
|
|
3480
|
+
// because cleanup is done at the end of every test
|
|
3383
3481
|
if (isolate) {
|
|
3384
3482
|
this.finishSession(sessionId);
|
|
3385
3483
|
return;
|
|
3386
3484
|
}
|
|
3485
|
+
// we need to cleanup testers first because there is only
|
|
3486
|
+
// one iframe and it does the cleanup only after everything is completed
|
|
3387
3487
|
const orchestrator = this.getOrchestrator(sessionId);
|
|
3388
3488
|
orchestrator.cleanupTesters().catch((error) => this.reject(error)).finally(() => this.finishSession(sessionId));
|
|
3389
3489
|
return;
|
|
@@ -3394,6 +3494,7 @@ class BrowserPool {
|
|
|
3394
3494
|
const orchestrator = this.getOrchestrator(sessionId);
|
|
3395
3495
|
debug?.("[%s] run test %s", sessionId, file);
|
|
3396
3496
|
this.setBreakpoint(sessionId, file).then(() => {
|
|
3497
|
+
// this starts running tests inside the orchestrator
|
|
3397
3498
|
orchestrator.createTesters({
|
|
3398
3499
|
method,
|
|
3399
3500
|
files: [file],
|
|
@@ -3402,6 +3503,7 @@ class BrowserPool {
|
|
|
3402
3503
|
debug?.("[%s] test %s finished running", sessionId, file);
|
|
3403
3504
|
this.runNextTest(method, sessionId);
|
|
3404
3505
|
}).catch((error) => {
|
|
3506
|
+
// if user cancells the test run manually, ignore the error and exit gracefully
|
|
3405
3507
|
if (this.project.vitest.isCancelling && error instanceof Error && error.message.startsWith("Browser connection was closed while running tests")) {
|
|
3406
3508
|
this.cancel();
|
|
3407
3509
|
this._promise?.resolve();
|
package/dist/locators/index.d.ts
CHANGED
|
@@ -278,6 +278,7 @@ interface SelectorEngine {
|
|
|
278
278
|
queryAll: (root: SelectorRoot, selector: string | any) => Element[];
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
// we prefer using playwright locators because they are more powerful and support Shadow DOM
|
|
281
282
|
declare const selectorEngine: Ivya;
|
|
282
283
|
declare abstract class Locator {
|
|
283
284
|
abstract selector: string;
|
package/dist/locators/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"@vitest/browser/context";import"../public-utils-
|
|
1
|
+
import"@vitest/browser/context";import"../public-utils-DJ-T0CfF.js";export{L as Locator,s as selectorEngine}from"../index-D0pxULUR.js";import"vitest/internal/browser";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{page,server}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector}from"../public-utils-
|
|
1
|
+
import{page,server}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector}from"../public-utils-DJ-T0CfF.js";import{s as selectorEngine,L as Locator,p as processTimeoutOptions,g as getIframeScale}from"../index-D0pxULUR.js";import"vitest/internal/browser";page.extend({getByLabelText(e,_){return new PlaywrightLocator(getByLabelSelector(e,_))},getByRole(e,_){return new PlaywrightLocator(getByRoleSelector(e,_))},getByTestId(e){return new PlaywrightLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,_){return new PlaywrightLocator(getByAltTextSelector(e,_))},getByPlaceholder(e,_){return new PlaywrightLocator(getByPlaceholderSelector(e,_))},getByText(e,_){return new PlaywrightLocator(getByTextSelector(e,_))},getByTitle(e,_){return new PlaywrightLocator(getByTitleSelector(e,_))},_createLocator(e){return new PlaywrightLocator(e)},elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}});class PlaywrightLocator extends Locator{constructor(e,_){super(),this.selector=e,this._container=_}click(e){return super.click(processTimeoutOptions(processClickOptions(e)))}dblClick(e){return super.dblClick(processTimeoutOptions(processClickOptions(e)))}tripleClick(e){return super.tripleClick(processTimeoutOptions(processClickOptions(e)))}selectOptions(e,_){return super.selectOptions(e,processTimeoutOptions(_))}clear(e){return super.clear(processTimeoutOptions(e))}hover(e){return super.hover(processTimeoutOptions(processHoverOptions(e)))}upload(e,_){return super.upload(e,processTimeoutOptions(_))}fill(e,_){return super.fill(e,processTimeoutOptions(_))}dropTo(e,_){return super.dropTo(e,processTimeoutOptions(processDragAndDropOptions(_)))}locator(e){return new PlaywrightLocator(`${this.selector} >> ${e}`,this._container)}elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}}function processDragAndDropOptions(e){if(!e)return e;let _=e;return _.sourcePosition&&=processPlaywrightPosition(_.sourcePosition),_.targetPosition&&=processPlaywrightPosition(_.targetPosition),e}function processHoverOptions(e){if(!e)return e;let _=e;return _.position&&=processPlaywrightPosition(_.position),e}function processClickOptions(e){if(!e)return e;let _=e;return _.position&&=processPlaywrightPosition(_.position),_}function processPlaywrightPosition(e){let _=getIframeScale();return e.x!=null&&(e.x*=_),e.y!=null&&(e.y*=_),e}
|
package/dist/locators/preview.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{page,server,userEvent}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector,h as getElementError}from"../public-utils-
|
|
1
|
+
import{page,server,userEvent}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector,h as getElementError}from"../public-utils-DJ-T0CfF.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector}from"../index-D0pxULUR.js";import"vitest/internal/browser";page.extend({getByLabelText(e,m){return new PreviewLocator(getByLabelSelector(e,m))},getByRole(e,m){return new PreviewLocator(getByRoleSelector(e,m))},getByTestId(e){return new PreviewLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,m){return new PreviewLocator(getByAltTextSelector(e,m))},getByPlaceholder(e,m){return new PreviewLocator(getByPlaceholderSelector(e,m))},getByText(e,m){return new PreviewLocator(getByTextSelector(e,m))},getByTitle(e,m){return new PreviewLocator(getByTitleSelector(e,m))},_createLocator(e){return new PreviewLocator(e)},elementLocator(e){return new PreviewLocator(selectorEngine.generateSelectorSimple(e),e)}});class PreviewLocator extends Locator{constructor(e,m){super(),this._pwSelector=e,this._container=m}get selector(){let e=this.elements().map(e=>convertElementToCssSelector(e));if(!e.length)throw getElementError(this._pwSelector,this._container||document.body);return e.join(`, `)}click(){return userEvent.click(this.element())}dblClick(){return userEvent.dblClick(this.element())}tripleClick(){return userEvent.tripleClick(this.element())}hover(){return userEvent.hover(this.element())}unhover(){return userEvent.unhover(this.element())}async fill(e){return userEvent.fill(this.element(),e)}async upload(e){return userEvent.upload(this.element(),e)}selectOptions(e){return userEvent.selectOptions(this.element(),e)}clear(){return userEvent.clear(this.element())}locator(e){return new PreviewLocator(`${this._pwSelector} >> ${e}`,this._container)}elementLocator(e){return new PreviewLocator(selectorEngine.generateSelectorSimple(e),e)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{page,server}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector,h as getElementError}from"../public-utils-
|
|
1
|
+
import{page,server}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector,h as getElementError}from"../public-utils-DJ-T0CfF.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector,a as getBrowserState,g as getIframeScale}from"../index-D0pxULUR.js";import"vitest/internal/browser";page.extend({getByLabelText(e,g){return new WebdriverIOLocator(getByLabelSelector(e,g))},getByRole(e,g){return new WebdriverIOLocator(getByRoleSelector(e,g))},getByTestId(e){return new WebdriverIOLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,g){return new WebdriverIOLocator(getByAltTextSelector(e,g))},getByPlaceholder(e,g){return new WebdriverIOLocator(getByPlaceholderSelector(e,g))},getByText(e,g){return new WebdriverIOLocator(getByTextSelector(e,g))},getByTitle(e,g){return new WebdriverIOLocator(getByTitleSelector(e,g))},_createLocator(e){return new WebdriverIOLocator(e)},elementLocator(e){return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(e))}});class WebdriverIOLocator extends Locator{constructor(e,g){super(),this._pwSelector=e,this._container=g}get selector(){let e=this.elements().map(e=>convertElementToCssSelector(e));if(!e.length)throw getElementError(this._pwSelector,this._container||document.body);return e.join(`, `)}click(e){return super.click(processClickOptions(e))}dblClick(e){return super.dblClick(processClickOptions(e))}tripleClick(e){return super.tripleClick(processClickOptions(e))}selectOptions(e,g){let _=getWebdriverioSelectOptions(this.element(),e);return this.triggerCommand(`__vitest_selectOptions`,this.selector,_,g)}hover(e){return super.hover(processHoverOptions(e))}dropTo(e,g){return super.dropTo(e,processDragAndDropOptions(g))}locator(e){return new WebdriverIOLocator(`${this._pwSelector} >> ${e}`,this._container)}elementLocator(e){return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(e),e)}}function getWebdriverioSelectOptions(e,g){let _=[...e.querySelectorAll(`option`)],v=Array.isArray(g)?g:[g];if(!v.length)return[];if(v.length>1)throw Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);let y=v[0];if(typeof y!=`string`){let e=`element`in y?y.element():y,g=_.indexOf(e);if(g===-1)throw Error(`The element ${selectorEngine.previewNode(e)} was not found in the "select" options.`);return[{index:g}]}let b=_.findIndex(e=>e.value===y);if(b!==-1)return[{index:b}];let x=_.findIndex(e=>e.textContent?.trim()===y||e.ariaLabel===y);if(x===-1)throw Error(`The option "${y}" was not found in the "select" options.`);return[{index:x}]}function processClickOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g=e;if(g.x!=null||g.y!=null){let e={};g.x!=null&&(g.x=scaleCoordinate(g.x,e)),g.y!=null&&(g.y=scaleCoordinate(g.y,e))}return e}function processHoverOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g=e,_={};return g.xOffset!=null&&(g.xOffset=scaleCoordinate(g.xOffset,_)),g.yOffset!=null&&(g.yOffset=scaleCoordinate(g.yOffset,_)),e}function processDragAndDropOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g={},_=e;return _.sourceX!=null&&(_.sourceX=scaleCoordinate(_.sourceX,g)),_.sourceY!=null&&(_.sourceY=scaleCoordinate(_.sourceY,g)),_.targetX!=null&&(_.targetX=scaleCoordinate(_.targetX,g)),_.targetY!=null&&(_.targetY=scaleCoordinate(_.targetY,g)),e}function scaleCoordinate(e,g){return Math.round(e*getCachedScale(g))}function getCachedScale(e){return e.scale??=getIframeScale()}
|
package/dist/providers.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as WebdriverBrowserProvider, P as PlaywrightBrowserProvider } from './webdriver-
|
|
1
|
+
import { W as WebdriverBrowserProvider, P as PlaywrightBrowserProvider } from './webdriver-B1QbgqhC.js';
|
|
2
2
|
import '@vitest/mocker/node';
|
|
3
3
|
import 'tinyrainbow';
|
|
4
4
|
import 'vitest/node';
|
|
@@ -9,6 +9,7 @@ class PreviewBrowserProvider {
|
|
|
9
9
|
project;
|
|
10
10
|
open = false;
|
|
11
11
|
getSupportedBrowsers() {
|
|
12
|
+
// `none` is not restricted to certain browsers.
|
|
12
13
|
return [];
|
|
13
14
|
}
|
|
14
15
|
isOpen() {
|