webdriver
Version:
A Node.js bindings implementation for the W3C WebDriver and Mobile JSONWire Protocol
1,300 lines (1,288 loc) • 98.1 kB
JavaScript
// src/node.ts
import os from "node:os";
import ws from "ws";
// src/index.ts
import logger4 from "@wdio/logger";
import { webdriverMonad, sessionEnvironmentDetector, startWebDriver, isBidi } from "@wdio/utils";
import { validateConfig } from "@wdio/config";
// src/command.ts
import logger3 from "@wdio/logger";
import { commandCallStructure, isValidParameter, getArgumentType, transformCommandLogResult } from "@wdio/utils";
import { WebDriverBidiProtocol as WebDriverBidiProtocol2 } from "@wdio/protocols";
// src/environment.ts
var isNode = !!(typeof process !== "undefined" && process.version);
var environment = {
value: {
get Request() {
throw new Error("Request is not available in this environment");
},
get Socket() {
throw new Error("Socket is not available in this environment");
},
get createBidiConnection() {
throw new Error("createBidiConnection is not available in this environment");
},
get killDriverProcess() {
throw new Error("killDriverProcess is not available in this environment");
},
get variables() {
return {};
}
}
};
// src/types.ts
var CommandRuntimeOptions = class {
// mask the text parameter value of the command
mask;
constructor(options) {
this.mask = options.mask;
}
};
// src/utils.ts
import { deepmergeCustom } from "deepmerge-ts";
import logger2, { SENSITIVE_DATA_REPLACER } from "@wdio/logger";
import {
WebDriverProtocol,
MJsonWProtocol,
AppiumProtocol,
ChromiumProtocol,
SauceLabsProtocol,
SeleniumProtocol,
GeckoProtocol,
WebDriverBidiProtocol
} from "@wdio/protocols";
import { CAPABILITY_KEYS } from "@wdio/protocols";
// src/bidi/core.ts
import logger from "@wdio/logger";
// src/constants.ts
var DEFAULTS = {
/**
* protocol of automation driver
*/
protocol: {
type: "string",
default: "http",
match: /(http|https)/
},
/**
* hostname of automation driver
*/
hostname: {
type: "string",
default: "localhost"
},
/**
* port of automation driver
*/
port: {
type: "number"
},
/**
* path to WebDriver endpoints
*/
path: {
type: "string",
validate: (path) => {
if (!path.startsWith("/")) {
throw new TypeError('The option "path" needs to start with a "/"');
}
return true;
},
default: "/"
},
/**
* A key-value store of query parameters to be added to every selenium request
*/
queryParams: {
type: "object"
},
/**
* cloud user if applicable
*/
user: {
type: "string"
},
/**
* access key to user
*/
key: {
type: "string"
},
/**
* capability of WebDriver session
*/
capabilities: {
type: "object",
required: true
},
/**
* Level of logging verbosity
*/
logLevel: {
type: "string",
default: "info",
match: /(trace|debug|info|warn|error|silent)/
},
/**
* directory for log files
*/
outputDir: {
type: "string"
},
/**
* Timeout for any WebDriver request to a driver or grid
*/
connectionRetryTimeout: {
type: "number",
default: 12e4
},
/**
* Count of request retries to the Selenium server
*/
connectionRetryCount: {
type: "number",
default: 3
},
/**
* Override default agent
*/
logLevels: {
type: "object"
},
/**
* Pass custom headers
*/
headers: {
type: "object"
},
/**
* Function transforming the request options before the request is made
*/
transformRequest: {
type: "function",
default: (requestOptions) => requestOptions
},
/**
* Function transforming the response object after it is received
*/
transformResponse: {
type: "function",
default: (response) => response
},
/**
* Appium direct connect options server (https://appiumpro.com/editions/86-connecting-directly-to-appium-hosts-in-distributed-environments)
* Whether to allow direct connect caps to adjust endpoint details (Appium only)
*/
enableDirectConnect: {
type: "boolean",
default: true
},
/**
* Whether it requires SSL certificates to be valid in HTTP/s requests
* for an environment which cannot get process environment well.
*/
strictSSL: {
type: "boolean",
default: true
},
/**
* The path to the root of the cache directory. This directory is used to store all drivers that are downloaded
* when attempting to start a session.
*/
cacheDir: {
type: "string",
default: environment.value.variables.WEBDRIVER_CACHE_DIR
},
/**
* Mask sensitive data in logs by replacing matching string or all captured groups for the provided regular expressions as string
*/
maskingPatterns: {
type: "string",
default: void 0
}
};
var ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf";
var SHADOW_ELEMENT_KEY = "shadow-6066-11e4-a52e-4f735466cecf";
var BASE_64_REGEX = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/;
var BASE_64_SAFE_STRING_TO_PROCESS_LENGTH = 2e5;
var APPIUM_MASKING_HEADER = { "x-appium-is-sensitive": "true" };
// src/bidi/utils.ts
function isBase64Safe(str) {
if (typeof str !== "string") {
return false;
}
if (str.length === 0) {
return true;
}
if (str.length % 4 !== 0) {
return false;
}
const length = str.length;
const digitCount = length.toString().length;
if (length > BASE_64_SAFE_STRING_TO_PROCESS_LENGTH) {
const chunkSize = Math.floor(length / digitCount / 4) * 4;
for (let i = 0; i < length; i += chunkSize) {
const chunk = str.slice(i, i + chunkSize);
if (!BASE_64_REGEX.test(chunk)) {
return false;
}
}
return true;
}
return BASE_64_REGEX.test(str);
}
// src/bidi/core.ts
var SCRIPT_PREFIX = "/* __wdio script__ */";
var SCRIPT_SUFFIX = "/* __wdio script end__ */";
var log = logger("webdriver");
var RESPONSE_TIMEOUT = 1e3 * 60;
var BidiCore = class {
#id = 0;
#ws;
#waitForConnected;
#resolveWaitForConnected;
#webSocketUrl;
#clientOptions;
#pendingCommands = /* @__PURE__ */ new Map();
client;
/**
* @private
*/
_isConnected = false;
constructor(webSocketUrl, opts) {
this.#webSocketUrl = webSocketUrl;
this.#clientOptions = opts;
this.#resolveWaitForConnected = () => {
};
this.#waitForConnected = new Promise((resolve) => {
this.#resolveWaitForConnected = resolve;
});
}
/**
* We initiate the Bidi instance before a WebdriverIO instance is created.
* In order to emit Bidi events we have to attach the WebdriverIO instance
* to the Bidi instance afterwards.
*/
attachClient(client) {
this.client = client;
}
async connect() {
log.info(`Connecting to webSocketUrl ${this.#webSocketUrl}`);
this.#ws = await environment.value.createBidiConnection(this.#webSocketUrl, this.#clientOptions);
this._isConnected = Boolean(this.#ws);
this.#resolveWaitForConnected(this._isConnected);
if (this.#ws) {
this.#ws.on("message", this.#handleResponse.bind(this));
}
return this._isConnected;
}
close() {
if (!this._isConnected) {
return;
}
log.info(`Close Bidi connection to ${this.#webSocketUrl}`);
this._isConnected = false;
if (this.#ws) {
this.#ws.off("message", this.#handleResponse.bind(this));
this.#ws.close();
this.#ws.terminate();
this.#ws = void 0;
}
}
reconnect(webSocketUrl, opts) {
log.info(`Reconnect to new Bidi session at ${webSocketUrl}`);
this.close();
this.#webSocketUrl = webSocketUrl;
this.#clientOptions = opts;
return this.connect();
}
/**
* Helper function that allows to wait until Bidi connection establishes
* @returns a promise that resolves once the connection to WebDriver Bidi protocol was established
*/
waitForConnected() {
return this.#waitForConnected;
}
get socket() {
return this.#ws;
}
get isConnected() {
return this._isConnected;
}
/**
* for testing purposes only
* @internal
*/
get __handleResponse() {
return this.#handleResponse.bind(this);
}
#handleResponse(data) {
try {
const payload = JSON.parse(data.toString());
if (!payload.id) {
return;
}
let resultLog = data.toString();
if (typeof payload.result === "object" && payload.result && "data" in payload.result && typeof payload.result.data === "string" && isBase64Safe(payload.result.data)) {
resultLog = JSON.stringify({
...payload.result,
data: `Base64 string [${payload.result.data.length} chars]`
});
}
log.info("BIDI RESULT", resultLog);
this.client?.emit("bidiResult", payload);
const resolve = this.#pendingCommands.get(payload.id);
if (!resolve) {
log.error(`Couldn't resolve command with id ${payload.id}`);
return;
}
this.#pendingCommands.delete(payload.id);
resolve(payload);
} catch (err) {
const error = err instanceof Error ? err : new Error(`Failed parse message: ${String(err)}`);
log.error(`Failed parse message: ${error.message}`);
}
}
async send(params) {
const id = this.sendAsync(params);
const failError = new Error(`WebDriver Bidi command "${params.method}" failed`);
const payload = await new Promise((resolve, reject) => {
const t = setTimeout(() => {
reject(new Error(`Command ${params.method} with id ${id} (with the following parameter: ${JSON.stringify(params.params)}) timed out`));
this.#pendingCommands.delete(id);
}, RESPONSE_TIMEOUT);
this.#pendingCommands.set(id, (payload2) => {
clearTimeout(t);
resolve(payload2);
});
});
if (payload.type === "error" || "error" in payload) {
const error = payload;
failError.message += ` with error: ${payload.error} - ${error.message}`;
if (error.stacktrace && typeof error.stacktrace === "string") {
const driverStack = error.stacktrace.split("\n").filter(Boolean).map((line) => ` at ${line}`).join("\n");
failError.stack += `
Driver Stack:
${driverStack}`;
}
throw failError;
}
return payload;
}
sendAsync(params) {
if (!this.#ws || !this._isConnected) {
throw new Error("No connection to WebDriver Bidi was established");
}
log.info("BIDI COMMAND", ...parseBidiCommand(params));
const id = ++this.#id;
this.client?.emit("bidiCommand", params);
this.#ws.send(JSON.stringify({ id, ...params }));
return id;
}
};
function parseBidiCommand(params) {
const commandName = params.method;
if (commandName === "script.addPreloadScript") {
const param = params.params;
const logString = `{ functionDeclaration: <PreloadScript[${new TextEncoder().encode(param.functionDeclaration).length} bytes]>, contexts: ${JSON.stringify(param.contexts)} }`;
return [commandName, logString];
} else if (commandName === "script.callFunction") {
const param = params.params;
const fn = param.functionDeclaration;
let fnName = "";
if (fn.includes(SCRIPT_PREFIX)) {
const internalFn = fn.slice(
fn.indexOf(SCRIPT_PREFIX) + SCRIPT_PREFIX.length,
fn.indexOf(SCRIPT_SUFFIX)
);
const functionPrefix = "function ";
if (internalFn.startsWith(functionPrefix)) {
fnName = internalFn.slice(
internalFn.indexOf(functionPrefix) + functionPrefix.length,
internalFn.indexOf("(")
);
}
}
const logString = JSON.stringify({
...param,
functionDeclaration: `<Function[${new TextEncoder().encode(param.functionDeclaration).length} bytes] ${fnName || "anonymous"}>`
});
return [commandName, logString];
}
return [commandName, JSON.stringify(params.params)];
}
// src/bidi/handler.ts
var BidiHandler = class extends BidiCore {
/**
* WebDriver Bidi command to send command method "session.status" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-session-status
* @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-session-status | command parameter}
* @returns `Promise<local.SessionStatusResult>`
**/
async sessionStatus(params) {
const result = await this.send({
method: "session.status",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "session.new" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-session-new
* @param params `remote.SessionNewParameters` {@link https://w3c.github.io/webdriver-bidi/#command-session-new | command parameter}
* @returns `Promise<local.SessionNewResult>`
**/
async sessionNew(params) {
const result = await this.send({
method: "session.new",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "session.end" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-session-end
* @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-session-end | command parameter}
* @returns `Promise<local.SessionEndResult>`
**/
async sessionEnd(params) {
const result = await this.send({
method: "session.end",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "session.subscribe" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-session-subscribe
* @param params `remote.SessionSubscribeParameters` {@link https://w3c.github.io/webdriver-bidi/#command-session-subscribe | command parameter}
* @returns `Promise<local.SessionSubscribeResult>`
**/
async sessionSubscribe(params) {
const result = await this.send({
method: "session.subscribe",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "session.unsubscribe" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe
* @param params `remote.SessionUnsubscribeParameters` {@link https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe | command parameter}
* @returns `Promise<local.SessionUnsubscribeResult>`
**/
async sessionUnsubscribe(params) {
const result = await this.send({
method: "session.unsubscribe",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.close" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-close
* @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-browser-close | command parameter}
* @returns `Promise<local.BrowserCloseResult>`
**/
async browserClose(params) {
const result = await this.send({
method: "browser.close",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.createUserContext" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-createUserContext
* @param params `remote.BrowserCreateUserContextParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browser-createUserContext | command parameter}
* @returns `Promise<local.BrowserCreateUserContextResult>`
**/
async browserCreateUserContext(params) {
const result = await this.send({
method: "browser.createUserContext",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.getClientWindows" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-getClientWindows
* @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-browser-getClientWindows | command parameter}
* @returns `Promise<local.BrowserGetClientWindowsResult>`
**/
async browserGetClientWindows(params) {
const result = await this.send({
method: "browser.getClientWindows",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.getUserContexts" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-getUserContexts
* @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-browser-getUserContexts | command parameter}
* @returns `Promise<local.BrowserGetUserContextsResult>`
**/
async browserGetUserContexts(params) {
const result = await this.send({
method: "browser.getUserContexts",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.removeUserContext" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-removeUserContext
* @param params `remote.BrowserRemoveUserContextParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browser-removeUserContext | command parameter}
* @returns `Promise<local.BrowserRemoveUserContextResult>`
**/
async browserRemoveUserContext(params) {
const result = await this.send({
method: "browser.removeUserContext",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.setClientWindowState" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-setClientWindowState
* @param params `remote.BrowserSetClientWindowStateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browser-setClientWindowState | command parameter}
* @returns `Promise<local.BrowserSetClientWindowStateResult>`
**/
async browserSetClientWindowState(params) {
const result = await this.send({
method: "browser.setClientWindowState",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browser.setDownloadBehavior" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browser-setDownloadBehavior
* @param params `remote.BrowserSetDownloadBehaviorParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browser-setDownloadBehavior | command parameter}
* @returns `Promise<local.BrowserSetDownloadBehaviorResult>`
**/
async browserSetDownloadBehavior(params) {
const result = await this.send({
method: "browser.setDownloadBehavior",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.activate" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-activate
* @param params `remote.BrowsingContextActivateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-activate | command parameter}
* @returns `Promise<local.BrowsingContextActivateResult>`
**/
async browsingContextActivate(params) {
const result = await this.send({
method: "browsingContext.activate",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.captureScreenshot" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-captureScreenshot
* @param params `remote.BrowsingContextCaptureScreenshotParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-captureScreenshot | command parameter}
* @returns `Promise<local.BrowsingContextCaptureScreenshotResult>`
**/
async browsingContextCaptureScreenshot(params) {
const result = await this.send({
method: "browsingContext.captureScreenshot",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.close" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-close
* @param params `remote.BrowsingContextCloseParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-close | command parameter}
* @returns `Promise<local.BrowsingContextCloseResult>`
**/
async browsingContextClose(params) {
const result = await this.send({
method: "browsingContext.close",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.create" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-create
* @param params `remote.BrowsingContextCreateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-create | command parameter}
* @returns `Promise<local.BrowsingContextCreateResult>`
**/
async browsingContextCreate(params) {
const result = await this.send({
method: "browsingContext.create",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.getTree" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-getTree
* @param params `remote.BrowsingContextGetTreeParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-getTree | command parameter}
* @returns `Promise<local.BrowsingContextGetTreeResult>`
**/
async browsingContextGetTree(params) {
const result = await this.send({
method: "browsingContext.getTree",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.handleUserPrompt" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-handleUserPrompt
* @param params `remote.BrowsingContextHandleUserPromptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-handleUserPrompt | command parameter}
* @returns `Promise<local.BrowsingContextHandleUserPromptResult>`
**/
async browsingContextHandleUserPrompt(params) {
const result = await this.send({
method: "browsingContext.handleUserPrompt",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.locateNodes" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-locateNodes
* @param params `remote.BrowsingContextLocateNodesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-locateNodes | command parameter}
* @returns `Promise<local.BrowsingContextLocateNodesResult>`
**/
async browsingContextLocateNodes(params) {
const result = await this.send({
method: "browsingContext.locateNodes",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.navigate" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-navigate
* @param params `remote.BrowsingContextNavigateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-navigate | command parameter}
* @returns `Promise<local.BrowsingContextNavigateResult>`
**/
async browsingContextNavigate(params) {
const result = await this.send({
method: "browsingContext.navigate",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.print" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-print
* @param params `remote.BrowsingContextPrintParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-print | command parameter}
* @returns `Promise<local.BrowsingContextPrintResult>`
**/
async browsingContextPrint(params) {
const result = await this.send({
method: "browsingContext.print",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.reload" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-reload
* @param params `remote.BrowsingContextReloadParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-reload | command parameter}
* @returns `Promise<local.BrowsingContextReloadResult>`
**/
async browsingContextReload(params) {
const result = await this.send({
method: "browsingContext.reload",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.setBypassCSP" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-setBypassCSP
* @param params `remote.BrowsingContextSetBypassCspParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-setBypassCSP | command parameter}
* @returns `Promise<local.BrowsingContextSetBypassCspResult>`
**/
async browsingContextSetBypassCsp(params) {
const result = await this.send({
method: "browsingContext.setBypassCSP",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.setViewport" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-setViewport
* @param params `remote.BrowsingContextSetViewportParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-setViewport | command parameter}
* @returns `Promise<local.BrowsingContextSetViewportResult>`
**/
async browsingContextSetViewport(params) {
const result = await this.send({
method: "browsingContext.setViewport",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "browsingContext.traverseHistory" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-traverseHistory
* @param params `remote.BrowsingContextTraverseHistoryParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-traverseHistory | command parameter}
* @returns `Promise<local.BrowsingContextTraverseHistoryResult>`
**/
async browsingContextTraverseHistory(params) {
const result = await this.send({
method: "browsingContext.traverseHistory",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setForcedColorsModeThemeOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setForcedColorsModeThemeOverride
* @param params `remote.EmulationSetForcedColorsModeThemeOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setForcedColorsModeThemeOverride | command parameter}
* @returns `Promise<local.EmulationSetForcedColorsModeThemeOverrideResult>`
**/
async emulationSetForcedColorsModeThemeOverride(params) {
const result = await this.send({
method: "emulation.setForcedColorsModeThemeOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setGeolocationOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setGeolocationOverride
* @param params `remote.EmulationSetGeolocationOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setGeolocationOverride | command parameter}
* @returns `Promise<local.EmulationSetGeolocationOverrideResult>`
**/
async emulationSetGeolocationOverride(params) {
const result = await this.send({
method: "emulation.setGeolocationOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setLocaleOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setLocaleOverride
* @param params `remote.EmulationSetLocaleOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setLocaleOverride | command parameter}
* @returns `Promise<local.EmulationSetLocaleOverrideResult>`
**/
async emulationSetLocaleOverride(params) {
const result = await this.send({
method: "emulation.setLocaleOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setNetworkConditions" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setNetworkConditions
* @param params `remote.EmulationSetNetworkConditionsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setNetworkConditions | command parameter}
* @returns `Promise<local.EmulationSetNetworkConditionsResult>`
**/
async emulationSetNetworkConditions(params) {
const result = await this.send({
method: "emulation.setNetworkConditions",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setScreenSettingsOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setScreenSettingsOverride
* @param params `remote.EmulationSetScreenSettingsOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setScreenSettingsOverride | command parameter}
* @returns `Promise<local.EmulationSetScreenSettingsOverrideResult>`
**/
async emulationSetScreenSettingsOverride(params) {
const result = await this.send({
method: "emulation.setScreenSettingsOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setScreenOrientationOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setScreenOrientationOverride
* @param params `remote.EmulationSetScreenOrientationOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setScreenOrientationOverride | command parameter}
* @returns `Promise<local.EmulationSetScreenOrientationOverrideResult>`
**/
async emulationSetScreenOrientationOverride(params) {
const result = await this.send({
method: "emulation.setScreenOrientationOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setUserAgentOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setUserAgentOverride
* @param params `remote.EmulationSetUserAgentOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setUserAgentOverride | command parameter}
* @returns `Promise<local.EmulationSetUserAgentOverrideResult>`
**/
async emulationSetUserAgentOverride(params) {
const result = await this.send({
method: "emulation.setUserAgentOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setScriptingEnabled" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setScriptingEnabled
* @param params `remote.EmulationSetScriptingEnabledParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setScriptingEnabled | command parameter}
* @returns `Promise<local.EmulationSetScriptingEnabledResult>`
**/
async emulationSetScriptingEnabled(params) {
const result = await this.send({
method: "emulation.setScriptingEnabled",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setScrollbarTypeOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setScrollbarTypeOverride
* @param params `remote.EmulationSetScrollbarTypeOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setScrollbarTypeOverride | command parameter}
* @returns `Promise<local.EmulationSetScrollbarTypeOverrideResult>`
**/
async emulationSetScrollbarTypeOverride(params) {
const result = await this.send({
method: "emulation.setScrollbarTypeOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setTimezoneOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setTimezoneOverride
* @param params `remote.EmulationSetTimezoneOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setTimezoneOverride | command parameter}
* @returns `Promise<local.EmulationSetTimezoneOverrideResult>`
**/
async emulationSetTimezoneOverride(params) {
const result = await this.send({
method: "emulation.setTimezoneOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "emulation.setTouchOverride" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-emulation-setTouchOverride
* @param params `remote.EmulationSetTouchOverrideParameters` {@link https://w3c.github.io/webdriver-bidi/#command-emulation-setTouchOverride | command parameter}
* @returns `Promise<local.EmulationSetTouchOverrideResult>`
**/
async emulationSetTouchOverride(params) {
const result = await this.send({
method: "emulation.setTouchOverride",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.addDataCollector" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-addDataCollector
* @param params `remote.NetworkAddDataCollectorParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-addDataCollector | command parameter}
* @returns `Promise<local.NetworkAddDataCollectorResult>`
**/
async networkAddDataCollector(params) {
const result = await this.send({
method: "network.addDataCollector",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.addIntercept" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-addIntercept
* @param params `remote.NetworkAddInterceptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-addIntercept | command parameter}
* @returns `Promise<local.NetworkAddInterceptResult>`
**/
async networkAddIntercept(params) {
const result = await this.send({
method: "network.addIntercept",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.continueRequest" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-continueRequest
* @param params `remote.NetworkContinueRequestParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-continueRequest | command parameter}
* @returns `Promise<local.NetworkContinueRequestResult>`
**/
async networkContinueRequest(params) {
const result = await this.send({
method: "network.continueRequest",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.continueResponse" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-continueResponse
* @param params `remote.NetworkContinueResponseParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-continueResponse | command parameter}
* @returns `Promise<local.NetworkContinueResponseResult>`
**/
async networkContinueResponse(params) {
const result = await this.send({
method: "network.continueResponse",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.continueWithAuth" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-continueWithAuth
* @param params `remote.NetworkContinueWithAuthParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-continueWithAuth | command parameter}
* @returns `Promise<local.NetworkContinueWithAuthResult>`
**/
async networkContinueWithAuth(params) {
const result = await this.send({
method: "network.continueWithAuth",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.disownData" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-disownData
* @param params `remote.NetworkDisownDataParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-disownData | command parameter}
* @returns `Promise<local.NetworkDisownDataResult>`
**/
async networkDisownData(params) {
const result = await this.send({
method: "network.disownData",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.failRequest" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-failRequest
* @param params `remote.NetworkFailRequestParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-failRequest | command parameter}
* @returns `Promise<local.NetworkFailRequestResult>`
**/
async networkFailRequest(params) {
const result = await this.send({
method: "network.failRequest",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.getData" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-getData
* @param params `remote.NetworkGetDataParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-getData | command parameter}
* @returns `Promise<local.NetworkGetDataResult>`
**/
async networkGetData(params) {
const result = await this.send({
method: "network.getData",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.provideResponse" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-provideResponse
* @param params `remote.NetworkProvideResponseParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-provideResponse | command parameter}
* @returns `Promise<local.NetworkProvideResponseResult>`
**/
async networkProvideResponse(params) {
const result = await this.send({
method: "network.provideResponse",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.removeDataCollector" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-removeDataCollector
* @param params `remote.NetworkRemoveDataCollectorParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-removeDataCollector | command parameter}
* @returns `Promise<local.NetworkRemoveDataCollectorResult>`
**/
async networkRemoveDataCollector(params) {
const result = await this.send({
method: "network.removeDataCollector",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.removeIntercept" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-removeIntercept
* @param params `remote.NetworkRemoveInterceptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-removeIntercept | command parameter}
* @returns `Promise<local.NetworkRemoveInterceptResult>`
**/
async networkRemoveIntercept(params) {
const result = await this.send({
method: "network.removeIntercept",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.setCacheBehavior" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-setCacheBehavior
* @param params `remote.NetworkSetCacheBehaviorParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-setCacheBehavior | command parameter}
* @returns `Promise<local.NetworkSetCacheBehaviorResult>`
**/
async networkSetCacheBehavior(params) {
const result = await this.send({
method: "network.setCacheBehavior",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "network.setExtraHeaders" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-network-setExtraHeaders
* @param params `remote.NetworkSetExtraHeadersParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-setExtraHeaders | command parameter}
* @returns `Promise<local.NetworkSetExtraHeadersResult>`
**/
async networkSetExtraHeaders(params) {
const result = await this.send({
method: "network.setExtraHeaders",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "script.addPreloadScript" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-script-addPreloadScript
* @param params `remote.ScriptAddPreloadScriptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-addPreloadScript | command parameter}
* @returns `Promise<local.ScriptAddPreloadScriptResult>`
**/
async scriptAddPreloadScript(params) {
const result = await this.send({
method: "script.addPreloadScript",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "script.disown" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-script-disown
* @param params `remote.ScriptDisownParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-disown | command parameter}
* @returns `Promise<local.ScriptDisownResult>`
**/
async scriptDisown(params) {
const result = await this.send({
method: "script.disown",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "script.callFunction" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-script-callFunction
* @param params `remote.ScriptCallFunctionParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-callFunction | command parameter}
* @returns `Promise<local.ScriptCallFunctionResult>`
**/
async scriptCallFunction(params) {
const result = await this.send({
method: "script.callFunction",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "script.evaluate" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-script-evaluate
* @param params `remote.ScriptEvaluateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-evaluate | command parameter}
* @returns `Promise<local.ScriptEvaluateResult>`
**/
async scriptEvaluate(params) {
const result = await this.send({
method: "script.evaluate",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "script.getRealms" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-script-getRealms
* @param params `remote.ScriptGetRealmsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-getRealms | command parameter}
* @returns `Promise<local.ScriptGetRealmsResult>`
**/
async scriptGetRealms(params) {
const result = await this.send({
method: "script.getRealms",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "script.removePreloadScript" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-script-removePreloadScript
* @param params `remote.ScriptRemovePreloadScriptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-removePreloadScript | command parameter}
* @returns `Promise<local.ScriptRemovePreloadScriptResult>`
**/
async scriptRemovePreloadScript(params) {
const result = await this.send({
method: "script.removePreloadScript",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "storage.getCookies" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-storage-getCookies
* @param params `remote.StorageGetCookiesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-storage-getCookies | command parameter}
* @returns `Promise<local.StorageGetCookiesResult>`
**/
async storageGetCookies(params) {
const result = await this.send({
method: "storage.getCookies",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "storage.setCookie" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-storage-setCookie
* @param params `remote.StorageSetCookieParameters` {@link https://w3c.github.io/webdriver-bidi/#command-storage-setCookie | command parameter}
* @returns `Promise<local.StorageSetCookieResult>`
**/
async storageSetCookie(params) {
const result = await this.send({
method: "storage.setCookie",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "storage.deleteCookies" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-storage-deleteCookies
* @param params `remote.StorageDeleteCookiesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-storage-deleteCookies | command parameter}
* @returns `Promise<local.StorageDeleteCookiesResult>`
**/
async storageDeleteCookies(params) {
const result = await this.send({
method: "storage.deleteCookies",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "input.performActions" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-input-performActions
* @param params `remote.InputPerformActionsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-input-performActions | command parameter}
* @returns `Promise<local.InputPerformActionsResult>`
**/
async inputPerformActions(params) {
const result = await this.send({
method: "input.performActions",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "input.releaseActions" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-input-releaseActions
* @param params `remote.InputReleaseActionsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-input-releaseActions | command parameter}
* @returns `Promise<local.InputReleaseActionsResult>`
**/
async inputReleaseActions(params) {
const result = await this.send({
method: "input.releaseActions",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "input.setFiles" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-input-setFiles
* @param params `remote.InputSetFilesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-input-setFiles | command parameter}
* @returns `Promise<local.InputSetFilesResult>`
**/
async inputSetFiles(params) {
const result = await this.send({
method: "input.setFiles",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "webExtension.install" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-webExtension-install
* @param params `remote.WebExtensionInstallParameters` {@link https://w3c.github.io/webdriver-bidi/#command-webExtension-install | command parameter}
* @returns `Promise<local.WebExtensionInstallResult>`
**/
async webExtensionInstall(params) {
const result = await this.send({
method: "webExtension.install",
params
});
return result.result;
}
/**
* WebDriver Bidi command to send command method "webExtension.uninstall" with parameters.
* @url https://w3c.github.io/webdriver-bidi/#command-webExtension-uninstall
* @param params `remote.WebExtensionUninstallParameters` {@link https://w3c.github.io/webdriver-bidi/#command-webExtension-uninstall | command parameter}
* @returns `Promise<local.WebExtensionUninstallResult>`
**/
async webExtensionUninstall(params) {
const result = await this.send({
method: "webExtension.uninstall",
params
});
return result.result;
}
};
// src/utils.ts
var log2 = logger2("webdriver");
var deepmerge = deepmergeCustom({ mergeArrays: false });
function deepEqual(a, b) {
if (a === b) {
return true;
}
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
return false;
}
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) {
return false;
}
for (const key of keysA) {
if (!keysB.includes(key) || !deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}
var BROWSER_DRIVER_ERRORS = [
"unknown command: wd/hub/session",
// chromedriver
"HTTP method not allowed",
// geckodriver
"'POST /wd/hub/session' was not found.",
// safaridriver
"Command not found"
// iedriver
];
async function startWebDriverSession(params) {
const capabilities = params.capabilities && "alwaysMatch" in params.capabilities ? params.capabilities : { alwaysMatch: params.capabilities, firstMatch: [{}] };
if (
/**
* except, if user does not want to opt-in
*/
!capabilities.alwaysMatch["wdio:enforceWebDriverClassic"] && /**
* or user requests a Safari session which does not support Bidi
*/
typeof capabilities.alwaysMatch.browserName === "string" && capabilities.alwaysMatch.browserName.toLowerCase() !== "safari"
) {
capabilities.alwaysMatch.webSocketUrl = true;
capabilities.alwaysMatch.unhandledPromptBehavior = "ignore";
}
validateCapabilities(capabilities.alwaysMatch);
const keysToNormalize = new Set(Object.keys(capabilities.alwaysMatch));
if (capabilities.firstMatch) {
capabilities.firstMatch.forEach((match) => {
Object.keys(match).forEach((key) => keysToNormalize.add(key));
});
for (const key of keysToNorma