var __defProp = Object.defineProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); var __privateWrapper = (obj, member, setter, getter) => ({ set _(value) { __privateSet(obj, member, value, setter); }, get _() { return __privateGet(obj, member, getter); } }); // src/browser.ts import logger6 from "@wdio/logger"; // 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 { constructor(options) { // mask the text parameter value of the command __publicField(this, "mask"); 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 _id, _ws, _waitForConnected, _resolveWaitForConnected, _webSocketUrl, _clientOptions, _pendingCommands, _BidiCore_instances, handleResponse_fn; var BidiCore = class { constructor(webSocketUrl, opts) { __privateAdd(this, _BidiCore_instances); __privateAdd(this, _id, 0); __privateAdd(this, _ws); __privateAdd(this, _waitForConnected); __privateAdd(this, _resolveWaitForConnected); __privateAdd(this, _webSocketUrl); __privateAdd(this, _clientOptions); __privateAdd(this, _pendingCommands, /* @__PURE__ */ new Map()); __publicField(this, "client"); /** * @private */ __publicField(this, "_isConnected", false); __privateSet(this, _webSocketUrl, webSocketUrl); __privateSet(this, _clientOptions, opts); __privateSet(this, _resolveWaitForConnected, () => { }); __privateSet(this, _waitForConnected, new Promise((resolve) => { __privateSet(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 ".concat(__privateGet(this, _webSocketUrl))); __privateSet(this, _ws, await environment.value.createBidiConnection(__privateGet(this, _webSocketUrl), __privateGet(this, _clientOptions))); this._isConnected = Boolean(__privateGet(this, _ws)); __privateGet(this, _resolveWaitForConnected).call(this, this._isConnected); if (__privateGet(this, _ws)) { __privateGet(this, _ws).on("message", __privateMethod(this, _BidiCore_instances, handleResponse_fn).bind(this)); } return this._isConnected; } close() { if (!this._isConnected) { return; } log.info("Close Bidi connection to ".concat(__privateGet(this, _webSocketUrl))); this._isConnected = false; if (__privateGet(this, _ws)) { __privateGet(this, _ws).off("message", __privateMethod(this, _BidiCore_instances, handleResponse_fn).bind(this)); __privateGet(this, _ws).close(); __privateGet(this, _ws).terminate(); __privateSet(this, _ws, void 0); } } reconnect(webSocketUrl, opts) { log.info("Reconnect to new Bidi session at ".concat(webSocketUrl)); this.close(); __privateSet(this, _webSocketUrl, webSocketUrl); __privateSet(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 __privateGet(this, _waitForConnected); } get socket() { return __privateGet(this, _ws); } get isConnected() { return this._isConnected; } /** * for testing purposes only * @internal */ get __handleResponse() { return __privateMethod(this, _BidiCore_instances, handleResponse_fn).bind(this); } async send(params) { const id = this.sendAsync(params); const failError = new Error('WebDriver Bidi command "'.concat(params.method, '" failed')); const payload = await new Promise((resolve, reject) => { const t = setTimeout(() => { reject(new Error("Command ".concat(params.method, " with id ").concat(id, " (with the following parameter: ").concat(JSON.stringify(params.params), ") timed out"))); __privateGet(this, _pendingCommands).delete(id); }, RESPONSE_TIMEOUT); __privateGet(this, _pendingCommands).set(id, (payload2) => { clearTimeout(t); resolve(payload2); }); }); if (payload.type === "error" || "error" in payload) { const error = payload; failError.message += " with error: ".concat(payload.error, " - ").concat(error.message); if (error.stacktrace && typeof error.stacktrace === "string") { const driverStack = error.stacktrace.split("\n").filter(Boolean).map((line) => " at ".concat(line)).join("\n"); failError.stack += "\n\nDriver Stack:\n".concat(driverStack); } throw failError; } return payload; } sendAsync(params) { var _a; if (!__privateGet(this, _ws) || !this._isConnected) { throw new Error("No connection to WebDriver Bidi was established"); } log.info("BIDI COMMAND", ...parseBidiCommand(params)); const id = ++__privateWrapper(this, _id)._; (_a = this.client) == null ? void 0 : _a.emit("bidiCommand", params); __privateGet(this, _ws).send(JSON.stringify({ id, ...params })); return id; } }; _id = new WeakMap(); _ws = new WeakMap(); _waitForConnected = new WeakMap(); _resolveWaitForConnected = new WeakMap(); _webSocketUrl = new WeakMap(); _clientOptions = new WeakMap(); _pendingCommands = new WeakMap(); _BidiCore_instances = new WeakSet(); handleResponse_fn = function(data) { var _a; 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 [".concat(payload.result.data.length, " chars]") }); } log.info("BIDI RESULT", resultLog); (_a = this.client) == null ? void 0 : _a.emit("bidiResult", payload); const resolve = __privateGet(this, _pendingCommands).get(payload.id); if (!resolve) { log.error("Couldn't resolve command with id ".concat(payload.id)); return; } __privateGet(this, _pendingCommands).delete(payload.id); resolve(payload); } catch (err) { const error = err instanceof Error ? err : new Error("Failed parse message: ".concat(String(err))); log.error("Failed parse message: ".concat(error.message)); } }; function parseBidiCommand(params) { const commandName = params.method; if (commandName === "script.addPreloadScript") { const param = params.params; const logString = "{ functionDeclaration: , contexts: ").concat(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: "") }); 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` **/ 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` **/ 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` **/ 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.SessionSubscriptionRequest` {@link https://w3c.github.io/webdriver-bidi/#command-session-subscribe | command parameter} * @returns `Promise` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ async browserSetClientWindowState(params) { const result = await this.send({ method: "browser.setClientWindowState", 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ async browsingContextReload(params) { const result = await this.send({ method: "browsingContext.reload", 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` **/ 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` **/ async browsingContextTraverseHistory(params) { const result = await this.send({ method: "browsingContext.traverseHistory", 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` **/ async emulationSetGeolocationOverride(params) { const result = await this.send({ method: "emulation.setGeolocationOverride", 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` **/ 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` **/ 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` **/ 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` **/ async networkContinueWithAuth(params) { const result = await this.send({ method: "network.continueWithAuth", 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` **/ async networkFailRequest(params) { const result = await this.send({ method: "network.failRequest", 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` **/ async networkProvideResponse(params) { const result = await this.send({ method: "network.provideResponse", 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` **/ 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` **/ async networkSetCacheBehavior(params) { const result = await this.send({ method: "network.setCacheBehavior", 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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` **/ 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 keysToNormalize) { const alwaysVal = capabilities.alwaysMatch[key]; if (alwaysVal === void 0) { continue; } const hasConflict = capabilities.firstMatch.some( (match) => key in match && !deepEqual(match[key], alwaysVal) ); if (hasConflict) { delete capabilities.alwaysMatch[key]; capabilities.firstMatch.forEach((match) => { if (!(key in match)) { match[key] = alwaysVal; } }); } else { capabilities.firstMatch.forEach((match) => { if (key in match) { delete match[key]; } }); } } } const sessionRequest = new environment.value.Request( "POST", "/session", { capabilities } ); let response; try { response = await sessionRequest.makeRequest(params); } catch (err) { log2.error(err); const message = getSessionError(err, params); throw new Error(message); } const sessionId = response.value.sessionId || response.sessionId; params.capabilities = response.value.capabilities || response.value; return { sessionId, capabilities: params.capabilities }; } function validateCapabilities(capabilities) { var _a; const chromeArgs = ((_a = capabilities["goog:chromeOptions"]) == null ? void 0 : _a.args) || []; if (chromeArgs.includes("incognito") || chromeArgs.includes("--incognito")) { throw new Error( 'Please remove "incognito" from `"goog:chromeOptions".args` as it is not supported running Chrome with WebDriver. WebDriver sessions are always incognito mode and do not persist across browser sessions.' ); } if (capabilities) { const extensionCaps = Object.keys(capabilities).filter((cap) => cap.includes(":")); const invalidWebDriverCaps = Object.keys(capabilities).filter((cap) => !CAPABILITY_KEYS.includes(cap) && !cap.includes(":")); if (extensionCaps.length && invalidWebDriverCaps.length) { throw new Error( 'Invalid or unsupported WebDriver capabilities found ("'.concat(invalidWebDriverCaps.join('", "'), '"). ') + 'Ensure to only use valid W3C WebDriver capabilities (see https://w3c.github.io/webdriver/#capabilities).If you run your tests on a remote vendor, like Sauce Labs or BrowserStack, make sure that you put them into vendor specific capabilities, e.g. "sauce:options" or "bstack:options". Please reach out to your vendor support team if you have further questions.' ); } } } function isSuccessfulResponse(statusCode, body) { if (!body || typeof body !== "object" || !("value" in body) || typeof body.value === "undefined") { log2.debug("request failed due to missing body"); return false; } if ("status" in body && body.status === 7 && body.value && typeof body.value === "object" && "message" in body.value && body.value.message && typeof body.value.message === "string" && (body.value.message.toLowerCase().startsWith("no such element") || // Appium body.value.message === "An element could not be located on the page using the given search parameters." || // Internet Explorer body.value.message.toLowerCase().startsWith("unable to find element"))) { return true; } if ("status" in body && body.status && body.status !== 0) { log2.debug("request failed due to status ".concat(body.status)); return false; } const hasErrorResponse = body.value && (typeof body.value === "object" && "error" in body.value && body.value.error || typeof body.value === "object" && "stackTrace" in body.value && body.value.stackTrace || typeof body.value === "object" && "stacktrace" in body.value && body.value.stacktrace); if (statusCode === 200 && !hasErrorResponse) { return true; } if (statusCode === 404 && typeof body.value === "object" && body.value && "error" in body.value && body.value.error === "no such element") { return true; } if (hasErrorResponse) { const errMsg = typeof body.value === "object" && body.value && "error" in body.value ? body.value.error : body.value; log2.debug("request failed due to response error:", errMsg); return false; } return true; } function getPrototype({ isW3C, isChromium, isFirefox, isMobile, isSauce, isSeleniumStandalone }) { const prototype = {}; const ProtocolCommands = deepmerge( /** * if mobile apply JSONWire and WebDriver protocol because * some legacy JSONWire commands are still used in Appium * (e.g. set/get geolocation) */ isMobile ? deepmerge(AppiumProtocol, WebDriverProtocol) : WebDriverProtocol, /** * enable Bidi protocol for W3C sessions */ isW3C ? WebDriverBidiProtocol : {}, /** * only apply mobile protocol if session is actually for mobile */ // eslint-disable-next-line @typescript-eslint/no-explicit-any isMobile ? deepmerge(MJsonWProtocol, AppiumProtocol) : {}, /** * only apply special Chromium commands if session is using Chrome or Edge */ isChromium ? ChromiumProtocol : {}, /** * only apply special Firefox commands if session is using Firefox */ isFirefox ? GeckoProtocol : {}, /** * only Sauce Labs specific vendor commands */ isSauce ? SauceLabsProtocol : {}, /** * only apply special commands when running tests using * Selenium Grid or Selenium Standalone server */ isSeleniumStandalone ? SeleniumProtocol : {}, {} ); for (const [endpoint, methods] of Object.entries(ProtocolCommands)) { for (const [method, commandData] of Object.entries(methods)) { prototype[commandData.command] = { value: command_default(method, endpoint, commandData, isSeleniumStandalone) }; } } return prototype; } function getEnvironmentVars({ isW3C, isMobile, isIOS, isAndroid, isFirefox, isSauce, isSeleniumStandalone, isChromium, isWindowsApp, isMacApp }) { return { isW3C: { value: isW3C }, isMobile: { value: isMobile }, isIOS: { value: isIOS }, isAndroid: { value: isAndroid }, isFirefox: { value: isFirefox }, isSauce: { value: isSauce }, isSeleniumStandalone: { value: isSeleniumStandalone }, isBidi: { /** * Return the value of this flag dynamically based on whether the * BidiHandler was able to connect to the `webSocketUrl` url provided * by the session response. */ get: function() { var _a; return Boolean((_a = this._bidiHandler) == null ? void 0 : _a.isConnected); } }, isChromium: { value: isChromium }, isWindowsApp: { value: isWindowsApp }, isMacApp: { value: isMacApp } }; } function setupDirectConnect(client) { const capabilities = client.capabilities; const directConnectProtocol = capabilities["appium:directConnectProtocol"]; const directConnectHost = capabilities["appium:directConnectHost"]; const directConnectPath = capabilities["appium:directConnectPath"]; const directConnectPort = capabilities["appium:directConnectPort"]; if (directConnectProtocol && directConnectHost && directConnectPort && (directConnectPath || directConnectPath === "")) { log2.info("Found direct connect information in new session response. " + "Will connect to server at ".concat(directConnectProtocol, "://") + "".concat(directConnectHost, ":").concat(directConnectPort).concat(directConnectPath)); client.options.protocol = directConnectProtocol; client.options.hostname = directConnectHost; client.options.port = directConnectPort; client.options.path = directConnectPath; } } var getSessionError = (err, params = {}) => { var _a; if (err.code === "ECONNREFUSED") { return 'Unable to connect to "'.concat(params.protocol, "://").concat(params.hostname, ":").concat(params.port).concat(params.path, '", make sure browser driver is running on that address.') + "\nIt seems like the service failed to start or is rejecting any connections."; } if (err.message === "unhandled request") { return 'The browser driver couldn\'t start the session. Make sure you have set the "path" correctly!'; } if (!err.message) { return "See wdio.* logs for more information."; } if (err.message.includes("Whoops! The URL specified routes to this help page.")) { return "It seems you are running a Selenium Standalone server and point to a wrong path. Please set `path: '/wd/hub'` in your wdio.conf.js!"; } if (BROWSER_DRIVER_ERRORS.some((m) => err && err.message && err.message.includes(m))) { return "Make sure to set `path: '/'` in your wdio.conf.js!"; } if (err.message.includes("Bad Request - Invalid Hostname") && err.message.includes("HTTP Error 400")) { return "Run edge driver on 127.0.0.1 instead of localhost, ex: --host=127.0.0.1, or set `hostname: 'localhost'` in your wdio.conf.js"; } const w3cCapMessage = '\nMake sure to add vendor prefix like "goog:", "appium:", "moz:", etc to non W3C capabilities.\nSee more https://www.w3.org/TR/webdriver/#capabilities'; if (err.message.includes("Illegal key values seen in w3c capabilities")) { return err.message + w3cCapMessage; } if (err.message === "Response has empty body") { return "Make sure to connect to valid hostname:port or the port is not in use.\nIf you use a grid server " + w3cCapMessage; } if (err.message.includes("failed serving request POST /wd/hub/session: Unauthorized") && (params.hostname === "saucelabs.com" || ((_a = params.hostname) == null ? void 0 : _a.endsWith(".saucelabs.com")))) { return "Session request was not authorized because you either did provide a wrong access key or tried to run in a region that has not been enabled for your user. If have registered a free trial account it is connected to a specific region. Ensure this region is set in your configuration (https://webdriver.io/docs/options.html#region)."; } return err.message; }; function initiateBidi(socketUrl, strictSSL = true, userHeaders) { const isUnitTesting = environment.value.variables.WDIO_UNIT_TESTS; if (isUnitTesting) { log2.info("Skip connecting to WebDriver Bidi interface due to unit tests"); return { _bidiHandler: { value: { isConnected: true, waitForConnected: () => Promise.resolve(), socket: { on: () => { }, off: () => { } } } } }; } socketUrl = socketUrl.replace("localhost", "127.0.0.1"); const bidiReqOpts = strictSSL ? {} : { rejectUnauthorized: false }; if (userHeaders) { bidiReqOpts.headers = userHeaders; } const handler = new BidiHandler(socketUrl, bidiReqOpts); handler.connect().then((isConnected) => isConnected && log2.info("Connected to WebDriver Bidi interface at ".concat(socketUrl))); return { _bidiHandler: { value: handler }, ...Object.values(WebDriverBidiProtocol).map((def) => def.socket).reduce((acc, cur) => { acc[cur.command] = { value: function(...args) { const bidiFn = handler[cur.command]; handler.attachClient(this); this.emit(cur.command, args); return bidiFn == null ? void 0 : bidiFn.apply(handler, args); } }; return acc; }, {}) }; } function parseBidiMessage(data) { try { const payload = JSON.parse(data.toString()); if (payload.type !== "event") { return; } this.emit(payload.method, payload.params); } catch (err) { log2.error("Failed parse WebDriver Bidi message: ".concat(err.message)); } } function mask(commandInfo, options, body, args) { var _a, _b, _c, _d; const unmaskedResult = { maskedBody: body, maskedArgs: args, isMasked: false }; if (!options.mask) { return unmaskedResult; } const textValueParamIndex = commandInfo.parameters.findIndex((param) => param.name === "text"); if (textValueParamIndex === -1) { return unmaskedResult; } const textValueIndexInArgs = ((_b = (_a = commandInfo.variables) == null ? void 0 : _a.length) != null ? _b : 0) + textValueParamIndex; const text = args[textValueIndexInArgs]; if (typeof text !== "string" || !text) { return unmaskedResult; } const maskedBody = { ...body, text: SENSITIVE_DATA_REPLACER }; const textValueArgsIndex = textValueParamIndex + ((_d = (_c = commandInfo.variables) == null ? void 0 : _c.length) != null ? _d : 0); const maskedArgs = args.slice(0, textValueArgsIndex).concat(SENSITIVE_DATA_REPLACER).concat(args.slice(textValueArgsIndex + 1)); return { maskedBody, maskedArgs, isMasked: true }; } // src/command.ts var log3 = logger3("webdriver"); var BIDI_COMMANDS = Object.values(WebDriverBidiProtocol2).map((def) => def.socket.command); var sessionAbortListeners = /* @__PURE__ */ new Map(); function command_default(method, endpointUri, commandInfo, doubleEncodeVariables = false) { const { command, deprecated, ref, parameters, variables = [], isHubCommand = false } = commandInfo; return async function protocolCommand(...unmaskedArgs) { let runtimeOptions = {}; if (unmaskedArgs.length > 0 && unmaskedArgs[unmaskedArgs.length - 1] instanceof CommandRuntimeOptions) { runtimeOptions = unmaskedArgs.pop(); } const isBidiCommand = BIDI_COMMANDS.includes(command); let endpoint = endpointUri; const commandParams = [...variables.map((v) => Object.assign(v, { /** * url variables are: */ required: true, // always required as they are part of the endpoint type: "string" // have to be always type of string })), ...parameters]; const commandUsage = "".concat(command, "(").concat(commandParams.map((p) => p.name).join(", "), ")"); const moreInfo = "\n\nFor more info see ".concat(ref, "\n"); const DISABLE_WEBDRIVERIO_DEPRECATION_WARNINGS = globalThis.process && globalThis.process.env ? globalThis.process.env.DISABLE_WEBDRIVERIO_DEPRECATION_WARNINGS : void 0; if (typeof deprecated === "string" && !DISABLE_WEBDRIVERIO_DEPRECATION_WARNINGS) { const warning = deprecated.replace("This command", 'The "'.concat(command, '" command')); log3.warn(warning); console.warn("\u26A0\uFE0F [WEBDRIVERIO DEPRECATION NOTICE] ".concat(warning)); } if (isBidiCommand) { throw new Error( 'Failed to execute WebDriver Bidi command "'.concat(command, '" as no Bidi session ') + 'was established. Make sure you enable it by setting "webSocketUrl: true" in your capabilities and verify that your environment and browser supports it.' ); } const minAllowedParams = commandParams.filter((param) => param.required).length; if (unmaskedArgs.length < minAllowedParams || unmaskedArgs.length > commandParams.length) { const parameterDescription = commandParams.length ? "\n\nProperty Description:\n".concat(commandParams.map((p) => ' "'.concat(p.name, '" (').concat(p.type, "): ").concat(p.description)).join("\n")) : ""; throw new Error( "Wrong parameters applied for ".concat(command, "\n") + "Usage: ".concat(commandUsage) + parameterDescription + moreInfo ); } const unmaskedBody = {}; for (const [it, arg] of Object.entries(unmaskedArgs)) { if (isBidiCommand) { break; } const i = parseInt(it, 10); const commandParam = commandParams[i]; if (!isValidParameter(arg, commandParam.type)) { if (typeof arg === "undefined" && !commandParam.required) { continue; } const actual = commandParam.type.endsWith("[]") ? "(".concat((Array.isArray(arg) ? arg : [arg]).map((a) => getArgumentType(a)), ")[]") : getArgumentType(arg); throw new Error( 'Malformed type for "'.concat(commandParam.name, '" parameter of command ').concat(command, "\n") + "Expected: ".concat(commandParam.type, "\n") + "Actual: ".concat(actual) + moreInfo ); } if (i < variables.length) { const encodedArg = doubleEncodeVariables ? encodeURIComponent(encodeURIComponent(arg)) : encodeURIComponent(arg); endpoint = endpoint.replace(":".concat(commandParams[i].name), encodedArg); continue; } unmaskedBody[commandParams[i].name] = arg; } const { maskedBody, maskedArgs, isMasked } = mask(commandInfo, runtimeOptions, unmaskedBody, unmaskedArgs); const { isAborted, abortSignal, cleanup } = manageSessionAbortions.call(this); const requiresSession = endpointUri.includes("/:sessionId/"); if (isAborted && command !== "deleteSession" && requiresSession) { throw new Error('Trying to run command "'.concat(commandCallStructure(command, maskedArgs), '" after session has been deleted, aborting request without executing it')); } const request = new environment.value.Request(method, endpoint, unmaskedBody, abortSignal, isHubCommand, { onPerformance: (data) => this.emit("request.performance", { ...data, request: { ...data.request, body: isMasked ? maskedBody : data.request.body } }), onRequest: (data) => this.emit("request.start", { ...data, body: isMasked ? maskedBody : data.body }), onResponse: (data) => this.emit("request.end", data), onRetry: (data) => this.emit("request.retry", data), onLogData: (data) => log3.info("DATA", transformCommandLogResult(isMasked ? maskedBody : data)) }); this.emit("command", { command, method, endpoint, body: maskedBody }); log3.info("COMMAND", commandCallStructure(command, maskedArgs)); const options = isMasked ? { ...this.options, headers: { ...this.options.headers, ...APPIUM_MASKING_HEADER } } : this.options; return request.makeRequest(options, this.sessionId).then((result) => { var _a, _b; if (typeof result.value !== "undefined") { let resultLog = result.value; if (/screenshot|recording/i.test(command) && typeof result.value === "string" && result.value.length > 64) { resultLog = "".concat(result.value.slice(0, 61), "..."); } else if (command === "executeScript" && typeof maskedBody.script === "string" && maskedBody.script.includes("(() => window.__wdioEvents__)")) { resultLog = "[".concat(result.value.length, " framework events captured]"); } log3.info("RESULT", resultLog); } this.emit("result", { command, method, endpoint, body: maskedBody, result }); if (command === "deleteSession") { const browser = this; (_a = browser._bidiHandler) == null ? void 0 : _a.close(); const shutdownDriver = ((_b = maskedBody.deleteSessionOpts) == null ? void 0 : _b.shutdownDriver) !== false; environment.value.killDriverProcess(this.capabilities, shutdownDriver); if (!environment.value.variables.WDIO_WORKER_ID) { logger3.clearLogger(); } } return result.value; }).catch((error) => { this.emit("result", { command, method, endpoint, body: maskedBody, result: { error } }); throw error; }).finally(() => { cleanup(); }); }; } function manageSessionAbortions() { const abort = new AbortController(); const abortOnSessionEnd = (result) => { if (result.command !== "deleteSession") { return; } const abortListeners = sessionAbortListeners.get(this.sessionId); if (abortListeners) { for (const abortListener of abortListeners) { abortListener.abort(); } abortListeners.clear(); sessionAbortListeners.set(this.sessionId, null); } }; let abortListenerForCurrentSession = sessionAbortListeners.get(this.sessionId); if (typeof abortListenerForCurrentSession === "undefined") { abortListenerForCurrentSession = /* @__PURE__ */ new Set(); sessionAbortListeners.set(this.sessionId, abortListenerForCurrentSession); this.on("result", abortOnSessionEnd); } if (abortListenerForCurrentSession === null) { return { isAborted: true, abortSignal: void 0, cleanup: () => { } }; } abortListenerForCurrentSession.add(abort); return { isAborted: false, abortSignal: abort.signal, cleanup: () => { this.off("result", abortOnSessionEnd); abortListenerForCurrentSession == null ? void 0 : abortListenerForCurrentSession.delete(abort); } }; } // src/bidi/localTypes.ts var localTypes_exports = {}; // src/bidi/remoteTypes.ts var remoteTypes_exports = {}; // src/index.ts var log4 = logger4("webdriver"); var WebDriver = class _WebDriver { static async newSession(options, modifier, userPrototype = {}, customCommandWrapper, implicitWaitExclusionList = []) { var _a; const envLogLevel = environment.value.variables.WDIO_LOG_LEVEL; options.logLevel = envLogLevel != null ? envLogLevel : options.logLevel; const params = validateConfig(DEFAULTS, options); if (params.logLevel && (!options.logLevels || !options.logLevels.webdriver)) { logger4.setLevel("webdriver", params.logLevel); } log4.info("Initiate new session using the WebDriver protocol"); const driverProcess = await startWebDriver(params); const requestedCapabilities = { ...params.capabilities }; const { sessionId, capabilities } = await startWebDriverSession(params); const environment2 = sessionEnvironmentDetector({ capabilities, requestedCapabilities }); const environmentPrototype = getEnvironmentVars(environment2); const protocolCommands = getPrototype(environment2); if (driverProcess == null ? void 0 : driverProcess.pid) { capabilities["wdio:driverPID"] = driverProcess.pid; } const bidiPrototype = {}; if (isBidi(capabilities)) { log4.info("Register BiDi handler for session with id ".concat(sessionId)); Object.assign(bidiPrototype, initiateBidi( capabilities.webSocketUrl, options.strictSSL, options.headers )); } const monad = webdriverMonad( { ...params, requestedCapabilities }, modifier, { ...protocolCommands, ...environmentPrototype, ...userPrototype, ...bidiPrototype } ); const client = monad(sessionId, customCommandWrapper, implicitWaitExclusionList); if (isBidi(capabilities)) { if (await client._bidiHandler.waitForConnected()) { (_a = client._bidiHandler.socket) == null ? void 0 : _a.on("message", parseBidiMessage.bind(client)); } } if (params.enableDirectConnect) { setupDirectConnect(client); } return client; } /** * allows user to attach to existing sessions */ static attachToSession(options, modifier, userPrototype = {}, commandWrapper) { var _a, _b; if (!options || typeof options.sessionId !== "string") { throw new Error("sessionId is required to attach to existing session"); } if (options.logLevel) { logger4.setLevel("webdriver", options.logLevel); } options.capabilities = options.capabilities || {}; options.isW3C = options.isW3C === false ? false : true; options.protocol = options.protocol || DEFAULTS.protocol.default; options.hostname = options.hostname || DEFAULTS.hostname.default; options.port = options.port || DEFAULTS.port.default; options.path = options.path || DEFAULTS.path.default; const environment2 = sessionEnvironmentDetector({ capabilities: options.capabilities, requestedCapabilities: options.capabilities }); options = Object.assign(environment2, options); const environmentPrototype = getEnvironmentVars(options); const protocolCommands = getPrototype(options); const bidiPrototype = {}; if (isBidi(options.capabilities || {})) { const webSocketUrl = (_a = options.capabilities) == null ? void 0 : _a.webSocketUrl; log4.info("Register BiDi handler for session with id ".concat(options.sessionId)); Object.assign(bidiPrototype, initiateBidi( webSocketUrl, options.strictSSL, options.headers )); } const prototype = { ...protocolCommands, ...environmentPrototype, ...userPrototype, ...bidiPrototype }; const monad = webdriverMonad(options, modifier, prototype); const client = monad(options.sessionId, commandWrapper); if (isBidi(options.capabilities || {})) { (_b = client._bidiHandler) == null ? void 0 : _b.waitForConnected().then(() => { var _a2; (_a2 = client._bidiHandler) == null ? void 0 : _a2.socket.on("message", parseBidiMessage.bind(client)); }); } return client; } /** * Changes The instance session id and browser capabilities for the new session * directly into the passed in browser object * * @param {object} instance the object we get from a new browser session. * @returns {string} the new session id of the browser */ static async reloadSession(instance, newCapabilities) { var _a, _b, _c; const capabilities = newCapabilities ? newCapabilities : Object.assign({}, instance.requestedCapabilities); let params = { ...instance.options, capabilities }; for (const prop of ["protocol", "hostname", "port", "path", "queryParams", "user", "key"]) { if (prop in capabilities) { params = { ...params, [prop]: capabilities[prop] }; delete capabilities[prop]; } } let driverProcess; if (params.hostname === "localhost" && (newCapabilities == null ? void 0 : newCapabilities.browserName)) { delete params.port; delete params.hostname; driverProcess = await startWebDriver(params); } const { sessionId, capabilities: newSessionCapabilities } = await startWebDriverSession(params); if (driverProcess == null ? void 0 : driverProcess.pid) { newSessionCapabilities["wdio:driverPID"] = driverProcess.pid; } for (const prop of ["protocol", "hostname", "port", "path", "queryParams", "user", "key"]) { if (prop in params) { instance.options[prop] = params[prop]; } } for (const prop in instance.requestedCapabilities) { delete instance.requestedCapabilities[prop]; } const driverPid = instance.capabilities["wdio:driverPID"]; instance.sessionId = sessionId; instance.capabilities = newSessionCapabilities; instance.capabilities["wdio:driverPID"] = driverPid; Object.assign(instance.requestedCapabilities, capabilities); if (isBidi(instance.capabilities || {})) { const bidiReqOpts = instance.options.strictSSL ? {} : { rejectUnauthorized: false }; await ((_a = instance._bidiHandler) == null ? void 0 : _a.reconnect(newSessionCapabilities.webSocketUrl, bidiReqOpts)); (_c = (_b = instance._bidiHandler) == null ? void 0 : _b.socket) == null ? void 0 : _c.on("message", parseBidiMessage.bind(instance)); } return sessionId; } static get WebDriver() { return _WebDriver; } }; // src/bidi/socket.ts var _callbacks, _ws2; var BrowserSocket = class { constructor(wsUrl, _opts) { __privateAdd(this, _callbacks, /* @__PURE__ */ new Set()); __privateAdd(this, _ws2); __privateSet(this, _ws2, new globalThis.WebSocket(wsUrl)); __privateGet(this, _ws2).onmessage = this.handleMessage.bind(this); } handleMessage(event) { for (const callback of __privateGet(this, _callbacks)) { callback(event.data); } } send(data) { __privateGet(this, _ws2).send(data); } on(event, callback) { if (event === "open") { __privateGet(this, _ws2).onopen = callback; } else if (event === "close") { __privateGet(this, _ws2).onclose = callback; } else if (event === "error") { __privateGet(this, _ws2).onerror = callback; } else { __privateGet(this, _callbacks).add(callback); } return this; } off(_event, callback) { __privateGet(this, _callbacks).delete(callback); return this; } close() { __privateGet(this, _ws2).close(); } }; _callbacks = new WeakMap(); _ws2 = new WeakMap(); // src/request/request.ts import logger5 from "@wdio/logger"; import { sleep } from "@wdio/utils"; // src/request/error.ts import { transformCommandLogResult as transformCommandLogResult2 } from "@wdio/utils"; // src/request/constants.ts var RETRYABLE_STATUS_CODES = [408, 413, 429, 500, 502, 503, 504]; var RETRYABLE_ERROR_CODES = [ "ETIMEDOUT", "ECONNRESET", "EADDRINUSE", "ECONNREFUSED", "EPIPE", "ENOTFOUND", "ENETUNREACH", "EAI_AGAIN", // additional error codes we like to retry "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_SOCKET" ]; var REG_EXPS = { commandName: /.*\/session\/[0-9a-f-]+\/(.*)/, execFn: /return \(([\s\S]*)\)\.apply\(null, arguments\)/ }; // src/request/error.ts var _WebDriverError_instances, getExecCmdName_fn, getExecCmdArgs_fn; var WebDriverError = class extends Error { constructor() { super(...arguments); __privateAdd(this, _WebDriverError_instances); } /** * return timeout error with information about the executing command on which the test hangs */ computeErrorMessage() { const cmdName = __privateMethod(this, _WebDriverError_instances, getExecCmdName_fn).call(this); const cmdArgs = __privateMethod(this, _WebDriverError_instances, getExecCmdArgs_fn).call(this, this.opts); const cmdInfoMsg = 'when running "'.concat(cmdName, '" with method "').concat(this.opts.method, '"'); const cmdArgsMsg = cmdArgs ? " and args ".concat(cmdArgs) : ""; return "WebDriverError: ".concat(this.message, " ").concat(cmdInfoMsg).concat(cmdArgsMsg); } }; _WebDriverError_instances = new WeakSet(); getExecCmdName_fn = function() { const { href } = this.url; const res = href.match(REG_EXPS.commandName) || []; return res[1] || href; }; getExecCmdArgs_fn = function(requestOptions) { const { body: cmdJson } = requestOptions; if (typeof cmdJson !== "object") { return ""; } const transformedRes = transformCommandLogResult2(cmdJson); if (typeof transformedRes === "string") { return transformedRes; } if (typeof cmdJson.script === "string") { const scriptRes = cmdJson.script.match(REG_EXPS.execFn) || []; return '"'.concat(scriptRes[1] || cmdJson.script, '"'); } return Object.keys(cmdJson).length ? '"'.concat(JSON.stringify(cmdJson), '"') : ""; }; var WebDriverRequestError = class extends WebDriverError { constructor(err, url, opts) { let message = err.message; if (err.message === "fetch failed") { message = "Failed to fetch [".concat(opts.method, "] ").concat(url.href, ": please make sure you have a WebDriver compatible server running on ").concat(url.origin); } super(message); __publicField(this, "url"); __publicField(this, "opts"); __publicField(this, "statusCode"); __publicField(this, "body"); __publicField(this, "code"); this.url = url; this.opts = opts; const errorCode = typeof err.cause === "object" && err.cause && "code" in err.cause && typeof err.cause.code === "string" ? err.cause.code : "code" in err && typeof err.code === "string" ? err.code : void 0; if (errorCode) { this.code = errorCode; this.message = errorCode === "UND_ERR_CONNECT_TIMEOUT" ? 'Request timed out! Consider increasing the "connectionRetryTimeout" option.' : "Request failed with error code " + errorCode; } if (typeof err.cause === "object" && err.cause) { this.statusCode = "statusCode" in err.cause && typeof err.cause.statusCode === "number" ? err.cause.statusCode : void 0; this.body = "body" in err.cause ? err.cause.body : void 0; } this.message = this.computeErrorMessage(); } }; var WebDriverResponseError = class _WebDriverResponseError extends WebDriverError { constructor(response, url, opts) { const errorObj = !response || typeof response !== "object" || !("body" in response) || !response.body ? new Error("Response has empty body") : typeof response.body === "string" && response.body.length ? new Error(response.body) : typeof response.body !== "object" ? new Error("Unknown error") : "value" in response.body && response.body.value ? response.body.value : response.body; let errorMessage = errorObj.message || errorObj.error || errorObj.class || "unknown error"; if (typeof errorMessage === "string" && errorMessage.includes("invalid locator")) { const requestOptions = opts.body; errorMessage = 'The selector "'.concat(requestOptions.value, '" used with strategy "').concat(requestOptions.using, '" is invalid!'); } super(errorMessage); __publicField(this, "url"); __publicField(this, "opts"); if (errorObj.error) { this.name = errorObj.error; } else if (errorMessage && errorMessage.includes("stale element reference")) { this.name = "stale element reference"; } else { this.name = errorObj.name || "WebDriver Error"; } Error.captureStackTrace(this, _WebDriverResponseError); this.url = url; this.opts = opts; this.message = this.computeErrorMessage(); } }; // package.json var package_default = { name: "webdriver", version: "9.24.0", description: "A Node.js bindings implementation for the W3C WebDriver and Mobile JSONWire Protocol", author: "Christian Bromann ", homepage: "https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver", license: "MIT", type: "module", main: "./build/index.cjs", module: "./build/index.js", exports: { ".": { types: "./build/index.d.ts", browserSource: "./src/browser.js", browser: "./build/index.js", importSource: "./src/node.ts", import: "./build/node.js", requireSource: "./src/index.cts", require: "./build/index.cjs" } }, types: "./build/index.d.ts", typeScriptVersion: "3.8.3", engines: { node: ">=18.20.0" }, repository: { type: "git", url: "git+https://github.com/webdriverio/webdriverio.git", directory: "packages/webdriver" }, keywords: [ "webdriver" ], bugs: { url: "https://github.com/webdriverio/webdriverio/issues" }, dependencies: { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", "@wdio/config": "workspace:*", "@wdio/logger": "workspace:*", "@wdio/protocols": "workspace:*", "@wdio/types": "workspace:*", "@wdio/utils": "workspace:*", "deepmerge-ts": "^7.0.3", "https-proxy-agent": "^7.0.6", undici: "^6.21.3", ws: "^8.8.0" } }; // src/request/polyfill.ts if (!AbortSignal.any) { AbortSignal.any = function(signals) { if (!signals || !Array.isArray(signals)) { throw new TypeError("AbortSignal.any requires an array of AbortSignal objects"); } const controller = new AbortController(); if (signals.some((signal) => signal.aborted)) { controller.abort(); return controller.signal; } const listeners = signals.map((signal) => { const listener = () => { if ("reason" in signal && signal.reason !== void 0) { controller.abort(signal.reason); } else { controller.abort(); } cleanup(); }; signal.addEventListener("abort", listener); return { signal, listener }; }); const cleanup = () => { listeners.forEach(({ signal, listener }) => { signal.removeEventListener("abort", listener); }); }; controller.signal.addEventListener("abort", cleanup); return controller.signal; }; } // src/request/request.ts var ERRORS_TO_EXCLUDE_FROM_RETRY = [ "detached shadow root", "move target out of bounds" ]; var DEFAULT_HEADERS = { "Content-Type": "application/json; charset=utf-8", "Connection": "keep-alive", "Accept": "application/json", "User-Agent": "webdriver/" + package_default.version }; var log5 = logger5("webdriver"); var WebDriverRequest = class { constructor(method, endpoint, body, abortSignal, isHubCommand = false, eventHandler = {}) { __publicField(this, "body"); __publicField(this, "method"); __publicField(this, "endpoint"); __publicField(this, "isHubCommand"); __publicField(this, "requiresSessionId"); __publicField(this, "eventHandler"); __publicField(this, "abortSignal"); this.body = body; this.method = method; this.endpoint = endpoint; this.isHubCommand = isHubCommand; this.requiresSessionId = Boolean(this.endpoint.match(/:sessionId/)); this.eventHandler = eventHandler; this.abortSignal = abortSignal; } async makeRequest(options, sessionId) { var _a, _b; const { url, requestOptions } = await this.createOptions(options, sessionId); (_b = (_a = this.eventHandler).onRequest) == null ? void 0 : _b.call(_a, requestOptions); return this._request(url, requestOptions, options.transformResponse, options.connectionRetryCount, 0); } async createOptions(options, sessionId, isBrowser = false) { const timeout = options.connectionRetryTimeout || DEFAULTS.connectionRetryTimeout.default; const requestOptions = { method: this.method, redirect: "follow", signal: AbortSignal.any([ AbortSignal.timeout(timeout), ...this.abortSignal ? [this.abortSignal] : [] ]) }; const requestHeaders = new Headers({ ...DEFAULT_HEADERS, ...typeof options.headers === "object" ? options.headers : {} }); const searchParams = isBrowser ? void 0 : typeof options.queryParams === "object" ? options.queryParams : void 0; if (this.body && (Object.keys(this.body).length || this.method === "POST")) { requestOptions.body = JSON.stringify(this.body); const contentLength = new TextEncoder().encode(requestOptions.body).length; requestHeaders.set("Content-Length", "".concat(contentLength)); } let endpoint = this.endpoint; if (this.requiresSessionId) { if (!sessionId) { throw new Error("A sessionId is required for this command"); } endpoint = endpoint.replace(":sessionId", sessionId); } const url = new URL("".concat(options.protocol, "://").concat(options.hostname, ":").concat(options.port).concat(this.isHubCommand ? this.endpoint : "".concat(options.path || "", "/").concat(endpoint).replace(/(\/){2,}/g, "/"))); if (searchParams) { url.search = new URLSearchParams(searchParams).toString(); } if (this.endpoint === "/session" && options.user && options.key) { requestHeaders.set("Authorization", "Basic " + btoa(options.user + ":" + options.key)); } requestOptions.headers = requestHeaders; return { url, requestOptions: typeof options.transformRequest === "function" ? options.transformRequest(requestOptions) : requestOptions }; } async _libRequest(url, opts) { try { const response = await this.fetch(url, opts); return await this.parseResponse(response); } catch (err) { if (!(err instanceof Error)) { throw new WebDriverRequestError( new Error("Failed to fetch ".concat(url.href, ": ").concat(err.message || err || "Unknown error")), url, opts ); } throw new WebDriverRequestError(err, url, opts); } } async parseResponse(response) { const rawBody = await response.text(); try { return { statusCode: response.status, body: rawBody ? JSON.parse(rawBody) : {} }; } catch { throw new Error('Could not parse response body: "'.concat(rawBody, '"'), { cause: { statusCode: response.status, body: rawBody } }); } } async _request(url, fullRequestOptions, transformResponse, totalRetryCount = 0, retryCount = 0) { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n; log5.info("[".concat(fullRequestOptions.method, "] ").concat(url.href)); if (fullRequestOptions.body && Object.keys(fullRequestOptions.body).length) { (_b = (_a = this.eventHandler).onLogData) == null ? void 0 : _b.call(_a, fullRequestOptions.body); } const { ...requestLibOptions } = fullRequestOptions; const startTime = performance.now(); let response = await this._libRequest(url, requestLibOptions).catch((err) => err); const durationMillisecond = performance.now() - startTime; const retry = async (error2) => { var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2; if (retryCount >= totalRetryCount || error2.message.includes("invalid session id")) { log5.error(error2.message); (_b2 = (_a2 = this.eventHandler).onResponse) == null ? void 0 : _b2.call(_a2, { error: error2 }); (_d2 = (_c2 = this.eventHandler).onPerformance) == null ? void 0 : _d2.call(_c2, { request: fullRequestOptions, durationMillisecond, success: false, error: error2, retryCount }); throw error2; } if (retryCount > 0) { await sleep(Math.min(1e4, 250 * Math.pow(2, retryCount))); } ++retryCount; (_f2 = (_e2 = this.eventHandler).onRetry) == null ? void 0 : _f2.call(_e2, { error: error2, retryCount }); (_h2 = (_g2 = this.eventHandler).onPerformance) == null ? void 0 : _h2.call(_g2, { request: fullRequestOptions, durationMillisecond, success: false, error: error2, retryCount }); log5.warn(error2.message); log5.info("Retrying ".concat(retryCount, "/").concat(totalRetryCount)); return this._request(url, fullRequestOptions, transformResponse, totalRetryCount, retryCount); }; if (response instanceof Error) { const resError = response; if (!(this.abortSignal && this.abortSignal.aborted) && (resError.code && RETRYABLE_ERROR_CODES.includes(resError.code) || resError.statusCode && RETRYABLE_STATUS_CODES.includes(resError.statusCode))) { return retry(resError); } (_d = (_c = this.eventHandler).onPerformance) == null ? void 0 : _d.call(_c, { request: fullRequestOptions, durationMillisecond, success: false, error: response, retryCount }); throw response; } if (typeof transformResponse === "function") { response = transformResponse(response, fullRequestOptions); } if (isSuccessfulResponse(response.statusCode, response.body)) { (_f = (_e = this.eventHandler).onResponse) == null ? void 0 : _f.call(_e, { result: response.body }); (_h = (_g = this.eventHandler).onPerformance) == null ? void 0 : _h.call(_g, { request: fullRequestOptions, durationMillisecond, success: true, retryCount }); return response.body; } const error = new WebDriverResponseError(response, url, fullRequestOptions); if (this.isHubCommand) { if (typeof response.body === "string" && response.body.startsWith("")) { (_j = (_i = this.eventHandler).onPerformance) == null ? void 0 : _j.call(_i, { request: fullRequestOptions, durationMillisecond, success: false, error, retryCount }); return Promise.reject(new Error("Command can only be called to a Selenium Hub")); } return { value: response.body || null }; } if (error.name === "stale element reference") { log5.warn("Request encountered a stale element - terminating request"); (_l = (_k = this.eventHandler).onResponse) == null ? void 0 : _l.call(_k, { error }); (_n = (_m = this.eventHandler).onPerformance) == null ? void 0 : _n.call(_m, { request: fullRequestOptions, durationMillisecond, success: false, error, retryCount }); throw error; } if (ERRORS_TO_EXCLUDE_FROM_RETRY.includes(error.name)) { throw error; } return retry(error); } }; // src/request/web.ts var FetchRequest = class extends WebDriverRequest { fetch(url, opts) { return fetch(url, opts); } }; // src/browser.ts var browser_default = WebDriver; var log6 = logger6("webdriver"); environment.value = { Request: FetchRequest, Socket: BrowserSocket, killDriverProcess: () => { }, createBidiConnection: (webSocketUrl, options) => { log6.info("Connecting to webSocketUrl ".concat(webSocketUrl)); const ws = new BrowserSocket(webSocketUrl, options); return new Promise((resolve) => { ws.on("open", () => { log6.info("Connected session to Bidi protocol"); resolve(ws); }); ws.on("error", (err) => { const error = err instanceof Error ? err : new Error(String(err)); log6.warn("Couldn't connect to Bidi protocol: ".concat(error.message)); resolve(void 0); }); }); }, variables: {} }; export { APPIUM_MASKING_HEADER, BASE_64_REGEX, BASE_64_SAFE_STRING_TO_PROCESS_LENGTH, BidiHandler, CommandRuntimeOptions, DEFAULTS, ELEMENT_KEY, SHADOW_ELEMENT_KEY, WebDriver, command_default as command, browser_default as default, getEnvironmentVars, getPrototype, initiateBidi, localTypes_exports as local, parseBidiMessage, remoteTypes_exports as remote };