@vitest/browser 4.0.0-beta.11 → 4.0.0-beta.13
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 +6 -6
- package/dist/client/__vitest__/assets/index-C15NF4dG.js +53 -0
- package/dist/client/__vitest__/assets/index-CjTcNCIc.css +1 -0
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/{orchestrator-DOxlOAkk.js → orchestrator-Pdu7HCGX.js} +55 -38
- package/dist/client/__vitest_browser__/{tester-B7fynsGK.js → tester-DYNLfPFH.js} +135 -92
- package/dist/client/__vitest_browser__/{utils-CPmDBIKG.js → utils-uxqdqUz8.js} +48 -20
- package/dist/client/orchestrator.html +2 -2
- package/dist/client/tester/tester.html +2 -2
- package/dist/expect-element.js +10 -10
- package/dist/index-BPDFwkoW.js +1 -0
- package/dist/index.js +131 -12
- 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/playwright.d.ts +4 -2
- package/dist/providers/playwright.js +24 -3
- package/dist/providers/preview.js +1 -0
- package/dist/providers/webdriverio.d.ts +3 -2
- package/dist/providers/webdriverio.js +35 -0
- package/dist/public-utils-B6exS8fl.js +6 -0
- package/dist/utils.js +1 -1
- package/matchers.d.ts +1 -1
- package/package.json +9 -9
- package/dist/client/__vitest__/assets/index-CCvbyxW7.css +0 -1
- package/dist/client/__vitest__/assets/index-CYIziQD6.js +0 -53
- package/dist/index-DDlvjJVO.js +0 -1
- package/dist/public-utils-Kx5DUGWa.js +0 -6
package/dist/index.js
CHANGED
|
@@ -4,13 +4,13 @@ import c from 'tinyrainbow';
|
|
|
4
4
|
import { isValidApiRequest, isFileServingAllowed, distDir, resolveApiServerConfig, resolveFsAllow, rolldownVersion, createDebugger, createViteLogger, createViteServer } from 'vitest/node';
|
|
5
5
|
import fs, { readFileSync, lstatSync, createReadStream, promises, existsSync } from 'node:fs';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
|
-
import { slash as slash$1, toArray, deepMerge, createDefer } from '@vitest/utils/helpers';
|
|
7
|
+
import { slash as slash$1, toArray, nanoid as nanoid$1, deepMerge, createDefer } from '@vitest/utils/helpers';
|
|
8
8
|
import MagicString from 'magic-string';
|
|
9
9
|
import sirv from 'sirv';
|
|
10
10
|
import { coverageConfigDefaults } from 'vitest/config';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
12
|
import crypto from 'node:crypto';
|
|
13
|
-
import { mkdir, rm, readFile as readFile$1, writeFile as writeFile$1 } from 'node:fs/promises';
|
|
13
|
+
import { mkdir, rm, readFile as readFile$1, writeFile as writeFile$1, unlink } from 'node:fs/promises';
|
|
14
14
|
import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
|
|
15
15
|
import { PlaywrightBrowserProvider } from './providers/playwright.js';
|
|
16
16
|
import { WebdriverBrowserProvider } from './providers/webdriverio.js';
|
|
@@ -22,7 +22,7 @@ import pm from 'pixelmatch';
|
|
|
22
22
|
import { WebSocketServer } from 'ws';
|
|
23
23
|
import { performance } from 'node:perf_hooks';
|
|
24
24
|
|
|
25
|
-
var version = "4.0.0-beta.
|
|
25
|
+
var version = "4.0.0-beta.13";
|
|
26
26
|
|
|
27
27
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
28
28
|
function normalizeWindowsPath(input = "") {
|
|
@@ -339,7 +339,7 @@ async function getBrowserProvider(options, project) {
|
|
|
339
339
|
if (!(name in providers)) {
|
|
340
340
|
throw new Error(`Unknown browser provider "${name}". Available providers: ${Object.keys(providers).join(", ")}.`);
|
|
341
341
|
}
|
|
342
|
-
return providers[name]().factory(project);
|
|
342
|
+
return providers[name](options.provider?.options).factory(project);
|
|
343
343
|
}
|
|
344
344
|
const supportedBrowsers = options.provider.supportedBrowser || [];
|
|
345
345
|
if (supportedBrowsers.length && !supportedBrowsers.includes(browser)) {
|
|
@@ -773,8 +773,6 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
773
773
|
"vitest > expect-type",
|
|
774
774
|
"vitest > @vitest/snapshot > magic-string",
|
|
775
775
|
"vitest > @vitest/expect > chai",
|
|
776
|
-
"vitest > @vitest/expect > chai > loupe",
|
|
777
|
-
"vitest > @vitest/utils > loupe",
|
|
778
776
|
"@vitest/browser > @testing-library/user-event",
|
|
779
777
|
"@vitest/browser > @testing-library/dom"
|
|
780
778
|
];
|
|
@@ -2396,8 +2394,12 @@ async function takeScreenshot(context, name, options) {
|
|
|
2396
2394
|
throw new Error(`Cannot take a screenshot without a test path`);
|
|
2397
2395
|
}
|
|
2398
2396
|
const path = resolveScreenshotPath(context.testPath, name, context.project.config, options.path);
|
|
2399
|
-
|
|
2400
|
-
|
|
2397
|
+
// playwright does not need a screenshot path if we don't intend to save it
|
|
2398
|
+
let savePath;
|
|
2399
|
+
if (options.save) {
|
|
2400
|
+
savePath = normalize(path);
|
|
2401
|
+
await mkdir(dirname(savePath), { recursive: true });
|
|
2402
|
+
}
|
|
2401
2403
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
2402
2404
|
const mask = options.mask?.map((selector) => context.iframe.locator(selector));
|
|
2403
2405
|
if (options.element) {
|
|
@@ -2406,7 +2408,7 @@ async function takeScreenshot(context, name, options) {
|
|
|
2406
2408
|
const buffer = await element.screenshot({
|
|
2407
2409
|
...config,
|
|
2408
2410
|
mask,
|
|
2409
|
-
path:
|
|
2411
|
+
path: savePath
|
|
2410
2412
|
});
|
|
2411
2413
|
return {
|
|
2412
2414
|
buffer,
|
|
@@ -2416,7 +2418,7 @@ async function takeScreenshot(context, name, options) {
|
|
|
2416
2418
|
const buffer = await context.iframe.locator("body").screenshot({
|
|
2417
2419
|
...options,
|
|
2418
2420
|
mask,
|
|
2419
|
-
path:
|
|
2421
|
+
path: savePath
|
|
2420
2422
|
});
|
|
2421
2423
|
return {
|
|
2422
2424
|
buffer,
|
|
@@ -2424,11 +2426,17 @@ async function takeScreenshot(context, name, options) {
|
|
|
2424
2426
|
};
|
|
2425
2427
|
}
|
|
2426
2428
|
if (context.provider instanceof WebdriverBrowserProvider) {
|
|
2429
|
+
// webdriverio needs a path, so if one is not already set we create a temporary one
|
|
2430
|
+
if (savePath === undefined) {
|
|
2431
|
+
savePath = resolve(context.project.tmpDir, nanoid$1());
|
|
2432
|
+
await mkdir(context.project.tmpDir, { recursive: true });
|
|
2433
|
+
}
|
|
2427
2434
|
const page = context.provider.browser;
|
|
2428
2435
|
const element = !options.element ? await page.$("body") : await page.$(`${options.element}`);
|
|
2429
2436
|
// webdriverio expects the path to contain the extension and only works with PNG files
|
|
2430
2437
|
const savePathWithExtension = savePath.endsWith(".png") ? savePath : `${savePath}.png`;
|
|
2431
|
-
|
|
2438
|
+
// there seems to be a bug in webdriverio, `X:/` gets appended to cwd, so we convert to `X:\`
|
|
2439
|
+
const buffer = await element.saveScreenshot(normalize$1(savePathWithExtension));
|
|
2432
2440
|
if (!options.save) {
|
|
2433
2441
|
await rm(savePathWithExtension, { force: true });
|
|
2434
2442
|
}
|
|
@@ -2907,6 +2915,101 @@ const tab = async (context, options = {}) => {
|
|
|
2907
2915
|
throw new Error(`Provider "${provider.name}" doesn't support tab command`);
|
|
2908
2916
|
};
|
|
2909
2917
|
|
|
2918
|
+
const startTracing = async ({ context, project, provider, sessionId }) => {
|
|
2919
|
+
if (provider instanceof PlaywrightBrowserProvider) {
|
|
2920
|
+
if (provider.tracingContexts.has(sessionId)) {
|
|
2921
|
+
return;
|
|
2922
|
+
}
|
|
2923
|
+
provider.tracingContexts.add(sessionId);
|
|
2924
|
+
const options = project.config.browser.trace;
|
|
2925
|
+
await context.tracing.start({
|
|
2926
|
+
screenshots: options.screenshots ?? true,
|
|
2927
|
+
snapshots: options.snapshots ?? true,
|
|
2928
|
+
sources: false
|
|
2929
|
+
}).catch(() => {
|
|
2930
|
+
provider.tracingContexts.delete(sessionId);
|
|
2931
|
+
});
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
throw new TypeError(`The ${provider.name} provider does not support tracing.`);
|
|
2935
|
+
};
|
|
2936
|
+
const startChunkTrace = async (command, { name, title }) => {
|
|
2937
|
+
const { provider, sessionId, testPath, context } = command;
|
|
2938
|
+
if (!testPath) {
|
|
2939
|
+
throw new Error(`stopChunkTrace cannot be called outside of the test file.`);
|
|
2940
|
+
}
|
|
2941
|
+
if (provider instanceof PlaywrightBrowserProvider) {
|
|
2942
|
+
if (!provider.tracingContexts.has(sessionId)) {
|
|
2943
|
+
await startTracing(command);
|
|
2944
|
+
}
|
|
2945
|
+
const path = resolveTracesPath(command, name);
|
|
2946
|
+
provider.pendingTraces.set(path, sessionId);
|
|
2947
|
+
await context.tracing.startChunk({
|
|
2948
|
+
name,
|
|
2949
|
+
title
|
|
2950
|
+
});
|
|
2951
|
+
return;
|
|
2952
|
+
}
|
|
2953
|
+
throw new TypeError(`The ${provider.name} provider does not support tracing.`);
|
|
2954
|
+
};
|
|
2955
|
+
const stopChunkTrace = async (context, { name }) => {
|
|
2956
|
+
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
2957
|
+
const path = resolveTracesPath(context, name);
|
|
2958
|
+
context.provider.pendingTraces.delete(path);
|
|
2959
|
+
await context.context.tracing.stopChunk({ path });
|
|
2960
|
+
return { tracePath: path };
|
|
2961
|
+
}
|
|
2962
|
+
throw new TypeError(`The ${context.provider.name} provider does not support tracing.`);
|
|
2963
|
+
};
|
|
2964
|
+
function resolveTracesPath({ testPath, project }, name) {
|
|
2965
|
+
if (!testPath) {
|
|
2966
|
+
throw new Error(`This command can only be called inside a test file.`);
|
|
2967
|
+
}
|
|
2968
|
+
const options = project.config.browser.trace;
|
|
2969
|
+
const sanitizedName = `${project.name.replace(/[^a-z0-9]/gi, "-")}-${name}.trace.zip`;
|
|
2970
|
+
if (options.tracesDir) {
|
|
2971
|
+
return resolve(options.tracesDir, sanitizedName);
|
|
2972
|
+
}
|
|
2973
|
+
const dir = dirname(testPath);
|
|
2974
|
+
const base = basename(testPath);
|
|
2975
|
+
return resolve(dir, "__traces__", base, `${project.name.replace(/[^a-z0-9]/gi, "-")}-${name}.trace.zip`);
|
|
2976
|
+
}
|
|
2977
|
+
const deleteTracing = async (context, { traces }) => {
|
|
2978
|
+
if (!context.testPath) {
|
|
2979
|
+
throw new Error(`stopChunkTrace cannot be called outside of the test file.`);
|
|
2980
|
+
}
|
|
2981
|
+
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
2982
|
+
return Promise.all(traces.map((trace) => unlink(trace).catch((err) => {
|
|
2983
|
+
if (err.code === "ENOENT") {
|
|
2984
|
+
// Ignore the error if the file doesn't exist
|
|
2985
|
+
return;
|
|
2986
|
+
}
|
|
2987
|
+
// Re-throw other errors
|
|
2988
|
+
throw err;
|
|
2989
|
+
})));
|
|
2990
|
+
}
|
|
2991
|
+
throw new Error(`provider ${context.provider.name} is not supported`);
|
|
2992
|
+
};
|
|
2993
|
+
const annotateTraces = async ({ project }, { testId, traces }) => {
|
|
2994
|
+
const vitest = project.vitest;
|
|
2995
|
+
await Promise.all(traces.map((trace) => {
|
|
2996
|
+
const entity = vitest.state.getReportedEntityById(testId);
|
|
2997
|
+
return vitest._testRun.annotate(testId, {
|
|
2998
|
+
message: relative(project.config.root, trace),
|
|
2999
|
+
type: "traces",
|
|
3000
|
+
attachment: {
|
|
3001
|
+
path: trace,
|
|
3002
|
+
contentType: "application/octet-stream"
|
|
3003
|
+
},
|
|
3004
|
+
location: entity?.location ? {
|
|
3005
|
+
file: entity.module.moduleId,
|
|
3006
|
+
line: entity.location.line,
|
|
3007
|
+
column: entity.location.column
|
|
3008
|
+
} : undefined
|
|
3009
|
+
});
|
|
3010
|
+
}));
|
|
3011
|
+
};
|
|
3012
|
+
|
|
2910
3013
|
const type = async (context, selector, text, options = {}) => {
|
|
2911
3014
|
const { skipClick = false, skipAutoClose = false } = options;
|
|
2912
3015
|
const unreleased = new Set(Reflect.get(options, "unreleased") ?? []);
|
|
@@ -2999,7 +3102,12 @@ var builtinCommands = {
|
|
|
2999
3102
|
__vitest_hover: hover,
|
|
3000
3103
|
__vitest_cleanup: keyboardCleanup,
|
|
3001
3104
|
__vitest_viewport: viewport,
|
|
3002
|
-
__vitest_screenshotMatcher: screenshotMatcher
|
|
3105
|
+
__vitest_screenshotMatcher: screenshotMatcher,
|
|
3106
|
+
__vitest_deleteTracing: deleteTracing,
|
|
3107
|
+
__vitest_startChunkTrace: startChunkTrace,
|
|
3108
|
+
__vitest_startTracing: startTracing,
|
|
3109
|
+
__vitest_stopChunkTrace: stopChunkTrace,
|
|
3110
|
+
__vitest_annotateTraces: annotateTraces
|
|
3003
3111
|
};
|
|
3004
3112
|
|
|
3005
3113
|
class BrowserServerState {
|
|
@@ -3984,6 +4092,11 @@ class BrowserPool {
|
|
|
3984
4092
|
return;
|
|
3985
4093
|
}
|
|
3986
4094
|
const provider = this.project.browser.provider;
|
|
4095
|
+
const browser = this.project.config.browser.name;
|
|
4096
|
+
if (shouldIgnoreDebugger(provider.name, browser)) {
|
|
4097
|
+
debug?.("[$s] ignoring debugger in %s browser because it is not supported", sessionId, browser);
|
|
4098
|
+
return;
|
|
4099
|
+
}
|
|
3987
4100
|
if (!provider.getCDPSession) {
|
|
3988
4101
|
throw new Error("Unable to set breakpoint, CDP not supported");
|
|
3989
4102
|
}
|
|
@@ -3996,6 +4109,12 @@ class BrowserPool {
|
|
|
3996
4109
|
});
|
|
3997
4110
|
}
|
|
3998
4111
|
}
|
|
4112
|
+
function shouldIgnoreDebugger(provider, browser) {
|
|
4113
|
+
if (provider === "webdriverio") {
|
|
4114
|
+
return browser !== "chrome" && browser !== "edge";
|
|
4115
|
+
}
|
|
4116
|
+
return browser !== "chromium";
|
|
4117
|
+
}
|
|
3999
4118
|
|
|
4000
4119
|
async function createBrowserServer(project, configFile, prePlugins = [], postPlugins = []) {
|
|
4001
4120
|
if (project.vitest.version !== version) {
|
package/dist/locators/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"@vitest/browser/context";import"../public-utils-
|
|
1
|
+
import"@vitest/browser/context";import"../public-utils-B6exS8fl.js";export{L as Locator,s as selectorEngine}from"../index-BPDFwkoW.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-B6exS8fl.js";import{s as selectorEngine,L as Locator,p as processTimeoutOptions,g as getIframeScale}from"../index-BPDFwkoW.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)},frameLocator(e){return new PlaywrightLocator(`${e.selector} >> internal:control=enter-frame`)}});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-B6exS8fl.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector}from"../index-BPDFwkoW.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-B6exS8fl.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector,a as getBrowserState,g as getIframeScale}from"../index-BPDFwkoW.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);let g=!1,_=e.map(e=>e.startsWith(`>>>`)?(g=!0,e.slice(3)):e);return(g?`>>>`:``)+_.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()}
|
|
@@ -10,7 +10,7 @@ interface PlaywrightProviderOptions {
|
|
|
10
10
|
* The options passed down to [`playwright.connect`](https://playwright.dev/docs/api/class-browsertype#browser-type-launch) method.
|
|
11
11
|
* @see {@link https://playwright.dev/docs/api/class-browsertype#browser-type-launch}
|
|
12
12
|
*/
|
|
13
|
-
launchOptions?: LaunchOptions
|
|
13
|
+
launchOptions?: Omit<LaunchOptions, "tracesDir">;
|
|
14
14
|
/**
|
|
15
15
|
* The options passed down to [`playwright.connect`](https://playwright.dev/docs/api/class-browsertype#browser-type-connect) method.
|
|
16
16
|
*
|
|
@@ -31,7 +31,7 @@ interface PlaywrightProviderOptions {
|
|
|
31
31
|
*/
|
|
32
32
|
actionTimeout?: number;
|
|
33
33
|
}
|
|
34
|
-
declare function playwright(options?: PlaywrightProviderOptions): BrowserProviderOption
|
|
34
|
+
declare function playwright(options?: PlaywrightProviderOptions): BrowserProviderOption<PlaywrightProviderOptions>;
|
|
35
35
|
declare class PlaywrightBrowserProvider implements BrowserProvider {
|
|
36
36
|
private project;
|
|
37
37
|
private options;
|
|
@@ -44,6 +44,8 @@ declare class PlaywrightBrowserProvider implements BrowserProvider {
|
|
|
44
44
|
browserName: PlaywrightBrowser;
|
|
45
45
|
private browserPromise;
|
|
46
46
|
private closing;
|
|
47
|
+
tracingContexts: Set<string>;
|
|
48
|
+
pendingTraces: Map<string, string>;
|
|
47
49
|
constructor(project: TestProject, options: PlaywrightProviderOptions);
|
|
48
50
|
private openBrowser;
|
|
49
51
|
private createMocker;
|
|
@@ -12,6 +12,7 @@ function playwright(options = {}) {
|
|
|
12
12
|
return {
|
|
13
13
|
name: "playwright",
|
|
14
14
|
supportedBrowser: playwrightBrowsers,
|
|
15
|
+
options,
|
|
15
16
|
factory(project) {
|
|
16
17
|
return new PlaywrightBrowserProvider(project, options);
|
|
17
18
|
},
|
|
@@ -28,11 +29,27 @@ class PlaywrightBrowserProvider {
|
|
|
28
29
|
browserName;
|
|
29
30
|
browserPromise = null;
|
|
30
31
|
closing = false;
|
|
32
|
+
tracingContexts = new Set();
|
|
33
|
+
pendingTraces = new Map();
|
|
31
34
|
constructor(project, options) {
|
|
32
35
|
this.project = project;
|
|
33
36
|
this.options = options;
|
|
34
37
|
this.browserName = project.config.browser.name;
|
|
35
38
|
this.mocker = this.createMocker();
|
|
39
|
+
// make sure the traces are finished if the test hangs
|
|
40
|
+
process.on("SIGTERM", () => {
|
|
41
|
+
if (!this.browser) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const promises = [];
|
|
45
|
+
for (const [trace, contextId] of this.pendingTraces.entries()) {
|
|
46
|
+
promises.push((() => {
|
|
47
|
+
const context = this.contexts.get(contextId);
|
|
48
|
+
return context?.tracing.stopChunk({ path: trace });
|
|
49
|
+
})());
|
|
50
|
+
}
|
|
51
|
+
return Promise.allSettled(promises);
|
|
52
|
+
});
|
|
36
53
|
}
|
|
37
54
|
async openBrowser() {
|
|
38
55
|
await this._throwIfClosing();
|
|
@@ -62,10 +79,14 @@ class PlaywrightBrowserProvider {
|
|
|
62
79
|
...this.options.launchOptions,
|
|
63
80
|
headless: options.headless
|
|
64
81
|
};
|
|
65
|
-
if (
|
|
82
|
+
if (typeof options.trace === "object" && options.trace.tracesDir) {
|
|
83
|
+
launchOptions.tracesDir = options.trace?.tracesDir;
|
|
84
|
+
}
|
|
85
|
+
const inspector = this.project.vitest.config.inspector;
|
|
86
|
+
if (inspector.enabled) {
|
|
66
87
|
// NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
|
|
67
|
-
const port =
|
|
68
|
-
const host =
|
|
88
|
+
const port = inspector.port || 9229;
|
|
89
|
+
const host = inspector.host || "127.0.0.1";
|
|
69
90
|
launchOptions.args ||= [];
|
|
70
91
|
launchOptions.args.push(`--remote-debugging-port=${port}`);
|
|
71
92
|
launchOptions.args.push(`--remote-debugging-address=${host}`);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ScreenshotMatcherOptions, ScreenshotComparatorRegistry } from '@vitest/browser/context';
|
|
2
|
-
import { BrowserProviderOption, BrowserProvider, TestProject } from 'vitest/node';
|
|
2
|
+
import { BrowserProviderOption, BrowserProvider, TestProject, CDPSession } from 'vitest/node';
|
|
3
3
|
import { ClickOptions, DragAndDropOptions, remote } from 'webdriverio';
|
|
4
4
|
|
|
5
5
|
interface WebdriverProviderOptions extends Partial<Parameters<typeof remote>[0]> {}
|
|
6
|
-
declare function webdriverio(options?: WebdriverProviderOptions): BrowserProviderOption
|
|
6
|
+
declare function webdriverio(options?: WebdriverProviderOptions): BrowserProviderOption<WebdriverProviderOptions>;
|
|
7
7
|
declare class WebdriverBrowserProvider implements BrowserProvider {
|
|
8
8
|
name: "webdriverio";
|
|
9
9
|
supportsParallelism: boolean;
|
|
@@ -31,6 +31,7 @@ declare class WebdriverBrowserProvider implements BrowserProvider {
|
|
|
31
31
|
openPage(sessionId: string, url: string): Promise<void>;
|
|
32
32
|
private _throwIfClosing;
|
|
33
33
|
close(): Promise<void>;
|
|
34
|
+
getCDPSession(_sessionId: string): Promise<CDPSession>;
|
|
34
35
|
}
|
|
35
36
|
declare module "vitest/node" {
|
|
36
37
|
interface UserEventClickOptions extends ClickOptions {}
|
|
@@ -11,6 +11,7 @@ function webdriverio(options = {}) {
|
|
|
11
11
|
return {
|
|
12
12
|
name: "webdriverio",
|
|
13
13
|
supportedBrowser: webdriverBrowsers,
|
|
14
|
+
options,
|
|
14
15
|
factory(project) {
|
|
15
16
|
return new WebdriverBrowserProvider(project, options);
|
|
16
17
|
},
|
|
@@ -135,6 +136,19 @@ class WebdriverBrowserProvider {
|
|
|
135
136
|
capabilities[key] ??= {};
|
|
136
137
|
capabilities[key].args = args;
|
|
137
138
|
}
|
|
139
|
+
const inspector = this.project.vitest.config.inspector;
|
|
140
|
+
if (inspector.enabled && (browser === "chrome" || browser === "edge")) {
|
|
141
|
+
const key = browser === "chrome" ? "goog:chromeOptions" : "ms:edgeOptions";
|
|
142
|
+
const args = capabilities[key]?.args || [];
|
|
143
|
+
// NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
|
|
144
|
+
const port = inspector.port || 9229;
|
|
145
|
+
const host = inspector.host || "127.0.0.1";
|
|
146
|
+
args.push(`--remote-debugging-port=${port}`);
|
|
147
|
+
args.push(`--remote-debugging-address=${host}`);
|
|
148
|
+
this.project.vitest.logger.log(`Debugger listening on ws://${host}:${port}`);
|
|
149
|
+
capabilities[key] ??= {};
|
|
150
|
+
capabilities[key].args = args;
|
|
151
|
+
}
|
|
138
152
|
return capabilities;
|
|
139
153
|
}
|
|
140
154
|
async openPage(sessionId, url) {
|
|
@@ -166,6 +180,27 @@ class WebdriverBrowserProvider {
|
|
|
166
180
|
browser.sessionId = undefined;
|
|
167
181
|
this.browser = null;
|
|
168
182
|
}
|
|
183
|
+
async getCDPSession(_sessionId) {
|
|
184
|
+
return {
|
|
185
|
+
send: (method, params) => {
|
|
186
|
+
if (!this.browser) {
|
|
187
|
+
throw new Error(`The environment was torn down.`);
|
|
188
|
+
}
|
|
189
|
+
return this.browser.sendCommandAndGetResult(method, params ?? {}).catch((error) => {
|
|
190
|
+
return Promise.reject(new Error(`Failed to execute "${method}" command.`, { cause: error }));
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
on: () => {
|
|
194
|
+
throw new Error(`webdriverio provider doesn't support cdp.on()`);
|
|
195
|
+
},
|
|
196
|
+
once: () => {
|
|
197
|
+
throw new Error(`webdriverio provider doesn't support cdp.once()`);
|
|
198
|
+
},
|
|
199
|
+
off: () => {
|
|
200
|
+
throw new Error(`webdriverio provider doesn't support cdp.off()`);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
169
204
|
}
|
|
170
205
|
|
|
171
206
|
export { WebdriverBrowserProvider, webdriverio };
|