UNPKG

webdriverio

Version:

Next-gen browser and mobile automation test framework for Node.js

17,672 lines • 720 kB
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res, err) => function __init() {
  if (err) throw err[0];
  try {
    return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
  } catch (e) {
    throw err = [e], e;
  }
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};

// src/environment.ts
var isNode, environment;
var init_environment = __esm({
  "src/environment.ts"() {
    "use strict";
    isNode = !!(typeof process !== "undefined" && process.version);
    environment = {
      value: {
        get readFileSync() {
          throw new Error("Can't read files form file system in this environment");
        },
        get downloadFile() {
          throw new Error("The `downloadFile` command is not available in this environment");
        },
        get savePDF() {
          throw new Error("The `savePDF` command is not available in this environment");
        },
        get saveRecordingScreen() {
          throw new Error("The `saveRecordingScreen` command is not available in this environment");
        },
        get extensionDataFromPath() {
          throw new Error("installExtension cannot read extension paths in this environment");
        },
        get saveScreenshot() {
          throw new Error("The `saveScreenshot` command for WebdriverIO.Browser is not available in this environment");
        },
        get saveElementScreenshot() {
          throw new Error("The `saveScreenshot` command for WebdriverIO.Element is not available in this environment");
        },
        get osType() {
          return () => "browser";
        },
        get variables() {
          return isNode ? process.env : {};
        }
      }
    };
  }
});

// src/session/session.ts
var sessionManager, listenerRegisteredSession, SessionManager;
var init_session = __esm({
  "src/session/session.ts"() {
    "use strict";
    init_environment();
    sessionManager = /* @__PURE__ */ new Map();
    listenerRegisteredSession = /* @__PURE__ */ new Set();
    SessionManager = class {
      #browser;
      #scope;
      /**
       * the marker this instance added, or undefined when another instance
       * already owned the key and this one registered no listener
       */
      #ownedRegistrationId;
      /**
       * SessionManager constructor
       * Logic in here should be executed for all session singletons, e.g. remove instance
       * of itself when a session was deleted.
       * @param browser WebdriverIO.Browser
       * @param scope   scope of the session manager, e.g. context, network etc.
       */
      constructor(browser, scope) {
        this.#browser = browser;
        this.#scope = scope;
        const registrationId = `${this.#browser.sessionId}-${this.#scope}`;
        if (!listenerRegisteredSession.has(registrationId)) {
          this.#browser.on("command", this.#onCommandListener);
          listenerRegisteredSession.add(registrationId);
          this.#ownedRegistrationId = registrationId;
        }
      }
      #onCommandListener = this.#onCommand.bind(this);
      #onCommand(ev) {
        if (ev.command === "deleteSession") {
          const sessionManagerInstances = sessionManager.get(this.#scope);
          const sessionManagerInstance = sessionManagerInstances?.get(this.#browser);
          if (sessionManagerInstance && sessionManagerInstances) {
            sessionManagerInstance.removeListeners();
            sessionManagerInstances.delete(this.#browser);
          }
        }
      }
      removeListeners() {
        this.#browser.off("command", this.#onCommandListener);
        if (this.#ownedRegistrationId) {
          listenerRegisteredSession.delete(this.#ownedRegistrationId);
          this.#ownedRegistrationId = void 0;
        }
      }
      initialize() {
        return void 0;
      }
      /**
       * check if session manager should be enabled, if
       */
      isEnabled() {
        return (
          // we are in a Bidi session
          this.#browser.isBidi && // we are not running unit tests
          !environment.value.variables.WDIO_UNIT_TESTS
        );
      }
      static getSessionManager(browser, Manager) {
        const scope = Manager.name;
        let sessionManagerInstances = sessionManager.get(scope);
        if (!sessionManagerInstances) {
          sessionManagerInstances = /* @__PURE__ */ new Map();
          sessionManager.set(scope, sessionManagerInstances);
        }
        let sessionManagerInstance = sessionManagerInstances.get(browser);
        if (!sessionManagerInstance) {
          sessionManagerInstance = new Manager(browser);
          sessionManagerInstances.set(browser, sessionManagerInstance);
        }
        return sessionManagerInstance;
      }
    };
  }
});

// src/utils/mobile.ts
function isUnknownMethodError(err) {
  if (!(err instanceof Error)) {
    return false;
  }
  const msg = err.message.toLowerCase();
  return msg.includes("unknown method") || msg.includes("unknown command");
}
async function executeMobile(browser, script, args) {
  try {
    return await browser.executeScript(
      script,
      args === void 0 ? [] : [args]
    );
  } catch (err) {
    if (!isUnknownMethodError(err)) {
      throw err;
    }
    const original = err instanceof Error ? err.message : String(err);
    throw new Error(
      `The \`${script}\` execute method is not supported by your Appium driver (${original}). ${APPIUM3_UPGRADE_HINT} If you are already on Appium 3 with current drivers, this platform may not implement \`${script}\`.`
    );
  }
}
function getNativeContext({ capabilities, isMobile }) {
  if (!capabilities || typeof capabilities !== "object" || !isMobile) {
    return false;
  }
  const isBrowserNameFalse = !!capabilities?.browserName === false;
  const isAutoWebviewFalse = !// @ts-expect-error
  (capabilities?.autoWebview === true || capabilities["appium:autoWebview"] === true || capabilities["appium:options"]?.autoWebview === true || capabilities["lt:options"]?.autoWebview === true);
  return isBrowserNameFalse && isMobile && isAutoWebviewFalse;
}
function getMobileContext({ capabilities, isAndroid, isNativeContext }) {
  return isNativeContext ? "NATIVE_APP" : (
    // Android webviews are always WEBVIEW_<package_name>, Chrome will always be CHROMIUM
    // We can only determine it for Android and Chrome, for all other, including iOS, we return undefined
    isAndroid && capabilities?.browserName?.toLowerCase() === "chrome" ? "CHROMIUM" : void 0
  );
}
function calculateAndroidPinchAndZoomSpeed({ browser, duration, scale }) {
  const deviceScreenSize = (browser.capabilities?.deviceScreenSize || "1080x2400").split("x").reduce((a, b) => a * b);
  const baseDistance = Math.sqrt(deviceScreenSize);
  const gestureDistance = Math.max(baseDistance * Math.abs(scale), baseDistance * 0.1);
  const durationSeconds = duration / 1e3;
  return Math.floor(gestureDistance / durationSeconds);
}
function validatePinchAndZoomOptions({ browser, gesture, options }) {
  if (typeof options !== "undefined" && (typeof options !== "object" || Array.isArray(options))) {
    throw new TypeError("Options must be an object");
  }
  const DEFAULT_SCALE = 0.5;
  const DEFAULT_DURATION = browser.isIOS ? 1.5 : 1500;
  const MIN_SCALE = 0;
  const MAX_SCALE = 1;
  const MIN_DURATION_MS = 500;
  const MAX_DURATION_MS = 1e4;
  const { scale: scaleOption, duration: durationOption } = options;
  const scale = typeof scaleOption === "number" ? scaleOption >= MIN_SCALE && scaleOption <= MAX_SCALE ? scaleOption : (() => {
    throw new Error(`The 'scale' option must be a number between ${MIN_SCALE} and ${MAX_SCALE}`);
  })() : DEFAULT_SCALE;
  const duration = typeof durationOption === "number" ? durationOption >= MIN_DURATION_MS && durationOption <= MAX_DURATION_MS ? browser.isIOS ? durationOption / 1e3 : durationOption : (() => {
    throw new Error(`The 'duration' option must be between ${MIN_DURATION_MS} and ${MAX_DURATION_MS} ms (${MIN_DURATION_MS / 1e3} and ${MAX_DURATION_MS / 1e3}  seconds)`);
  })() : DEFAULT_DURATION;
  return {
    duration,
    scale: browser.isIOS && gesture === "zoom" ? scale * 10 : scale
  };
}
var APPIUM3_UPGRADE_HINT;
var init_mobile = __esm({
  "src/utils/mobile.ts"() {
    "use strict";
    APPIUM3_UPGRADE_HINT = "WebdriverIO 10 requires Appium 3 and a current official driver. Install or upgrade with `npm i -D appium@^3`, then run `appium driver update installed`. Stay on WebdriverIO 9 if you cannot upgrade the server.";
  }
});

// src/utils/sessionEnded.ts
import { isSessionEndedError, isBidiConnectionClosed } from "webdriver";
function logBackgroundError(log29, message, err, browser) {
  const reason = err instanceof Error ? err.message : String(err);
  if (isSessionEndedError(err) || isBidiConnectionClosed(browser)) {
    log29.debug(`${message}, the session ended: ${reason}`);
    return;
  }
  log29.warn(`${message}: ${reason}`);
}
var init_sessionEnded = __esm({
  "src/utils/sessionEnded.ts"() {
    "use strict";
  }
});

// src/session/context.ts
import logger2 from "@wdio/logger";
function parallelModeError(command) {
  if (SESSION_GLOBAL_COMMANDS.includes(command)) {
    return `${command} cannot run inside a parallel test: it changes the session that all concurrently running tests share (browser.reloadSession() sends deleteSession, browser.setTimeout() sends setTimeouts). Call it outside the test, e.g. in the \`before\` config hook.`;
  }
  if (ALERT_COMMANDS.includes(command)) {
    return `${command} is not supported in parallel mode: alerts belong to a browsing context. Use the per-context API instead on the context \`browser.url()\` returns, e.g. \`const page = await browser.url(url); await page.acceptAlert()\` (also \`dismissAlert()\` and \`getAlertText()\` on the BrowsingContext).`;
  }
  if (COMPUTED_A11Y_COMMANDS.includes(command)) {
    return `${command} is not supported in parallel mode: WebDriver BiDi has no command to read an element's computed role or label.`;
  }
  return `${command} is not supported in parallel mode \u2014 WebDriver Classic commands act on the session's focused window, which concurrent tests share. If you did not call ${command} yourself, a WebdriverIO command fell back to WebDriver Classic \u2014 please report it.`;
}
function setParallelContextStore(store) {
  parallelContextStore = store;
}
function isParallelContext(contextId) {
  return parallelContexts.has(contextId);
}
function getParallelContextStore() {
  return parallelContextStore;
}
function getContextManager(browser) {
  return SessionManager.getSessionManager(browser, ContextManager);
}
function byUrl(context, url2) {
  return context.url === url2;
}
function byUrlContaining(context, url2) {
  return context.url.includes(url2);
}
function byContextId(context, contextId) {
  return context.context === contextId;
}
var log2, COMMANDS_REQUIRING_RESET, PARALLEL_SAFE_CLASSIC_COMMANDS, SESSION_GLOBAL_COMMANDS, ALERT_COMMANDS, COMPUTED_A11Y_COMMANDS, PARALLEL_CONTEXT_STORE_KEY, PARALLEL_CONTEXTS_KEY, noopParallelContextStore, parallelContextStore, parallelContexts, ContextManager;
var init_context = __esm({
  "src/session/context.ts"() {
    "use strict";
    init_session();
    init_mobile();
    init_environment();
    init_sessionEnded();
    log2 = logger2("webdriverio:context");
    COMMANDS_REQUIRING_RESET = ["deleteSession", "refresh", "switchToParentFrame"];
    PARALLEL_SAFE_CLASSIC_COMMANDS = ["status", "getTimeouts", "getWindowHandles"];
    SESSION_GLOBAL_COMMANDS = ["deleteSession", "newSession", "setTimeouts"];
    ALERT_COMMANDS = ["acceptAlert", "dismissAlert", "getAlertText", "sendAlertText"];
    COMPUTED_A11Y_COMMANDS = ["getElementComputedRole", "getElementComputedLabel"];
    PARALLEL_CONTEXT_STORE_KEY = "__parallelContextStore";
    PARALLEL_CONTEXTS_KEY = "__parallelContexts";
    noopParallelContextStore = {
      getStore: () => void 0,
      run: (_contextId, fn) => fn()
    };
    parallelContextStore = noopParallelContextStore;
    parallelContexts = /* @__PURE__ */ new Set();
    ContextManager = class _ContextManager extends SessionManager {
      #browser;
      #currentContext;
      #mobileContext;
      #isNativeContext;
      #getContextSupport = true;
      #currentWindowHandle;
      #onCommandResultBidiAndClassicListener;
      #onCommandListener;
      #onCommandResultMobileListener;
      #navigationStartedListener;
      #destroyedListener;
      constructor(browser) {
        super(browser, _ContextManager.name);
        this.#browser = browser;
        const capabilities = this.#browser.capabilities;
        browser[PARALLEL_CONTEXT_STORE_KEY] = parallelContextStore;
        browser[PARALLEL_CONTEXTS_KEY] = parallelContexts;
        const reqCaps = browser.requestedCapabilities;
        const sessCaps = browser.capabilities;
        browser.__bidiCommandsEnabled = !!(reqCaps?.["wdio:experimentalBiDiCommands"] || sessCaps?.["wdio:experimentalBiDiCommands"]);
        this.#isNativeContext = getNativeContext({ capabilities, isMobile: this.#browser.isMobile });
        this.#mobileContext = getMobileContext({
          capabilities,
          isAndroid: this.#browser.isAndroid,
          isNativeContext: this.#isNativeContext
        });
        this.#onCommandResultBidiAndClassicListener = this.#onCommandResultBidiAndClassic.bind(this);
        this.#onCommandListener = this.#onCommand.bind(this);
        this.#onCommandResultMobileListener = this.#onCommandResultMobile.bind(this);
        this.#navigationStartedListener = this.#navigationStarted.bind(this);
        this.#destroyedListener = this.#contextDestroyed.bind(this);
        this.#browser.on("result", this.#onCommandResultBidiAndClassicListener);
        if (!this.isEnabled() && !this.#browser.isMobile) {
          return;
        }
        this.#browser.on("command", this.#onCommandListener);
        if (this.#browser.isMobile) {
          this.#browser.on("result", this.#onCommandResultMobileListener);
        } else {
          this.#browser.sessionSubscribe({
            events: ["browsingContext.navigationStarted", "browsingContext.contextDestroyed"]
          }).catch((err) => logBackgroundError(log2, "Failed to subscribe to the navigation events of the context manager", err, this.#browser));
          this.#browser.on("browsingContext.navigationStarted", this.#navigationStartedListener);
          this.#browser.on("browsingContext.contextDestroyed", this.#destroyedListener);
        }
      }
      removeListeners() {
        super.removeListeners();
        this.#browser.off("result", this.#onCommandResultBidiAndClassicListener);
        this.#browser.off("command", this.#onCommandListener);
        if (this.#browser.isMobile) {
          this.#browser.off("result", this.#onCommandResultMobileListener);
        } else {
          this.#browser.off("browsingContext.navigationStarted", this.#navigationStartedListener);
          this.#browser.off("browsingContext.contextDestroyed", this.#destroyedListener);
        }
      }
      async #navigationStarted(nav) {
        if (!this.#currentContext || nav.context === this.#currentContext) {
          return;
        }
        if (isParallelContext(nav.context)) {
          return;
        }
        try {
          const { contexts } = await this.#browser.browsingContextGetTree({});
          const hasContext = this.findContext(this.#currentContext, contexts, "byContextId");
          const newContext = contexts.find((context) => context.context === nav.context);
          if (!hasContext && newContext) {
            this.setCurrentContext(newContext.context);
            await this.#browser.switchToWindow(this.#currentContext);
            return;
          }
        } catch (err) {
          logBackgroundError(log2, `Failed to update the context after a navigation in "${nav.context}"`, err, this.#browser);
        }
      }
      async #contextDestroyed(destroyed) {
        if (!this.#currentContext || destroyed.context !== this.#currentContext) {
          return;
        }
        this.#currentWindowHandle = void 0;
        this.#currentContext = void 0;
        let handle;
        try {
          if (destroyed.parent) {
            handle = await this.#getTopLevelContext(destroyed.parent);
          }
          if (!handle) {
            const windowHandles = await this.#browser.getWindowHandles();
            handle = windowHandles.find((windowHandle) => windowHandle !== destroyed.context) ?? windowHandles[0];
          }
          if (!handle) {
            return;
          }
          if (this.#currentContext) {
            return;
          }
          await this.#browser.switchToWindow(handle);
          if (this.#currentContext && this.#currentContext !== handle) {
            return;
          }
          this.setCurrentContext(handle);
        } catch (err) {
          if (!this.#currentContext || this.#currentContext === handle) {
            this.#currentContext = void 0;
            this.#currentWindowHandle = void 0;
          }
          logBackgroundError(log2, `Failed to switch context after "${destroyed.context}" was destroyed`, err, this.#browser);
        }
      }
      /**
       * Resolve the top-level context of a given context id, e.g. the top-level
       * browsing context a child frame belongs to.
       * @param contextId the context id to resolve the top-level context for
       * @returns the top-level context id, or undefined if it can't be found
       */
      async #getTopLevelContext(contextId) {
        const { contexts } = await this.#browser.browsingContextGetTree({});
        return contexts.find(
          (context) => this.findContext(contextId, [context], "byContextId")
        )?.context;
      }
      #onCommandResultBidiAndClassic(event) {
        if (event.command === "closeWindow") {
          this.#currentWindowHandle = void 0;
          const windowHandles = event.result.value || [];
          if (windowHandles.length === 0) {
            throw new Error("All window handles were removed, causing WebdriverIO to close the session.");
          }
          this.#currentContext = windowHandles[0];
          return this.#browser.switchToWindow(this.#currentContext).catch((err) => logBackgroundError(log2, `Failed to switch to window "${windowHandles[0]}" after closeWindow`, err, this.#browser));
        }
        if (event.command === "getWindowHandle") {
          const windowHandle = event.result.value || void 0;
          this.#currentWindowHandle = windowHandle;
        }
        if (event.command === "switchToWindow") {
          const err = event.result.error || void 0;
          if (!err) {
            const windowHandle = event.body.handle || void 0;
            this.#currentWindowHandle = windowHandle;
          }
        }
      }
      #onCommand(event) {
        if (typeof event.endpoint === "string" && parallelContextStore.getStore() && !PARALLEL_SAFE_CLASSIC_COMMANDS.includes(event.command)) {
          throw new Error(parallelModeError(event.command));
        }
        if (event.command === "switchToParentFrame") {
          if (!this.#currentContext) {
            return;
          }
          return this.#browser.browsingContextGetTree({}).then(({ contexts }) => {
            const parentContext = this.findParentContext(this.#currentContext, contexts);
            if (!parentContext) {
              const stillInTree = this.findContext(this.#currentContext, contexts, "byContextId");
              if (stillInTree) {
                return;
              }
              this.#currentContext = void 0;
              this.#currentWindowHandle = void 0;
              return;
            }
            this.setCurrentContext(parentContext.context);
          }).catch((err) => {
            logBackgroundError(log2, "Failed to update the context after switchToParentFrame", err, this.#browser);
          });
        }
        if (event.command === "switchToWindow") {
          this.setCurrentContext(event.body.handle);
        }
        if (COMMANDS_REQUIRING_RESET.includes(event.command)) {
          this.#currentContext = void 0;
        }
        if (this.#browser.isMobile && event.command === "switchAppiumContext") {
          this.#mobileContext = event.body.name;
        }
      }
      #onCommandResultMobile(event) {
        if (event.command === "getAppiumContext") {
          this.#setAppiumContext(event.result.value);
        }
        if (event.command === "switchAppiumContext" && event.result.value === null && this.#mobileContext) {
          this.#setAppiumContext(this.#mobileContext, true);
        }
      }
      /**
       * Track the Appium context name (`NATIVE_APP`, `CHROMIUM`, `WEBVIEW_<pkg>`).
       * In a BiDi session that name is not a browsing context id, so it does not
       * become the current context: when the Appium context changes, the current
       * context is reset and `getCurrentContext()` resolves the window handle again.
       */
      #setAppiumContext(name, switched = false) {
        if (!this.#browser.isBidi) {
          return this.setCurrentContext(name);
        }
        const changed = switched || name !== this.#mobileContext;
        this.#isNativeContext = name ? name === "NATIVE_APP" : this.#isNativeContext;
        this.#mobileContext = name || void 0;
        if (changed) {
          this.#currentContext = void 0;
        }
      }
      /**
       * set context at the start of the session
       */
      async initialize() {
        if (environment.value.variables.WDIO_UNIT_TESTS) {
          return "";
        }
        if (this.#browser.isMobile && !this.#isNativeContext && !this.#mobileContext && this.#getContextSupport) {
          const context = await this.#browser.getContext().catch((err) => {
            log2.warn(
              `Error getting context: ${err}

WebDriver capabilities: ${JSON.stringify(this.#browser.capabilities)}
Requested WebDriver capabilities: ${JSON.stringify(this.#browser.requestedCapabilities)}`
            );
            if (err.message.includes("Request failed with status code 405")) {
              this.#getContextSupport = false;
            }
            return void 0;
          });
          this.#mobileContext = typeof context === "string" ? context : typeof context === "object" ? context.id : void 0;
        }
        const useWindowHandle = this.#browser.isBidi && !this.#isNativeContext;
        const windowHandle = !useWindowHandle && this.#mobileContext || await this.#browser.getWindowHandle();
        this.setCurrentContext(windowHandle);
        return windowHandle;
      }
      /**
       * Set the context that BiDi commands target. In a BiDi session this is a
       * browsing context id (window handle), never an Appium context name, so it
       * does not change the tracked Appium context.
       */
      setCurrentContext(context) {
        this.#currentContext = context;
        if (this.#browser.isMobile && !this.#browser.isBidi) {
          this.#isNativeContext = context ? context === "NATIVE_APP" : this.#isNativeContext;
          this.#mobileContext = context || void 0;
        }
      }
      async getCurrentContext() {
        const parallelCtx = parallelContextStore.getStore();
        if (parallelCtx) {
          return parallelCtx;
        }
        if (!this.#currentContext) {
          return this.initialize();
        }
        return this.#currentContext;
      }
      /**
       * Browsing context id the emulation commands target. Several BiDi emulation
       * commands reject a call that is not aimed at a top-level traversable, and
       * a child frame id is not one. Resolve the frame the user is in to the
       * top-level context that contains it.
       */
      async getCurrentTopLevelContext() {
        const current = await this.getCurrentContext();
        if (!current) {
          return current;
        }
        return await this.#getTopLevelContext(current) ?? current;
      }
      /**
       * Sets the cached current window handle value.
       * @param handle current window handle to set
       */
      setCurrentWindowHandle(handle) {
        this.#currentWindowHandle = handle;
      }
      /**
       * Returns the cached window handle.
       *
       * @returns the current window handle, or undefined if the current window is closed.
       */
      getCurrentWindowHandle() {
        return this.#currentWindowHandle;
      }
      get isNativeContext() {
        return this.#isNativeContext;
      }
      get mobileContext() {
        return this.#mobileContext;
      }
      /**
       * Get the flat context tree for the current session
       * @returns a flat list of all contexts in the current session
       */
      async getFlatContextTree() {
        const tree = await this.#browser.browsingContextGetTree({});
        const mapContext = (context) => [
          context.context,
          ...(context.children || []).map(mapContext).flat(Infinity)
        ];
        const allContexts = tree.contexts.map(mapContext).flat(Infinity).reduce((acc, ctx) => {
          const context = this.findContext(ctx, tree.contexts, "byContextId");
          acc[ctx] = context;
          return acc;
        }, {});
        return allContexts;
      }
      /**
       * Find the parent context of a given context id
       * @param contextId the context id you want to find the parent of
       * @param contexts  the list of contexts to search through returned from `browsingContextGetTree`
       * @returns         the parent context of the context with the given id
       */
      findParentContext(contextId, contexts) {
        for (const context of contexts) {
          if (context.children?.some((child) => child.context === contextId)) {
            return context;
          }
          if (Array.isArray(context.children) && context.children.length > 0) {
            const result = this.findParentContext(contextId, context.children);
            if (result) {
              return result;
            }
          }
        }
        return void 0;
      }
      /**
       * Find a context by URL or ID
       * @param urlOrId     The URL or ID of the context to find
       * @param contexts    The list of contexts to search through returned from `browsingContextGetTree`
       * @param matcherType The type of matcher to use to find the context
       * @returns           The context with the given URL or ID
       */
      findContext(urlOrId, contexts, matcherType) {
        const matcher = {
          byUrl,
          byUrlContaining,
          byContextId
        }[matcherType];
        for (const context of contexts || []) {
          if (matcher(context, urlOrId)) {
            return context;
          }
          if (Array.isArray(context.children) && context.children.length > 0) {
            const result = this.findContext(urlOrId, context.children, matcherType);
            if (result) {
              return result;
            }
          }
        }
        return void 0;
      }
    };
  }
});

// src/session/browsingContext.ts
import { getBrowserObject, getWdioKind } from "@wdio/utils";
function isBrowsingContext(value) {
  return getWdioKind(value) === "browsing-context";
}
async function contextIdOf(scope) {
  let current = scope;
  const seen = /* @__PURE__ */ new Set();
  while (current && typeof current === "object" && !seen.has(current)) {
    seen.add(current);
    if (isBrowsingContext(current)) {
      return current.contextId;
    }
    const parent = current.parent;
    if (!parent || parent === current) {
      break;
    }
    current = parent;
  }
  const browser = getBrowserObject(scope);
  return getContextManager(browser).getCurrentContext();
}
function contextIdValue(value) {
  if (typeof value === "string" && value) {
    return value;
  }
  if (value && typeof value === "object" && typeof value.context === "string") {
    return value.context;
  }
  throw new Error("A browsing context id is required");
}
function heldBrowsingContext(scope) {
  let current = scope;
  const seen = /* @__PURE__ */ new Set();
  while (current && typeof current === "object" && !seen.has(current)) {
    seen.add(current);
    if (isBrowsingContext(current)) {
      return current;
    }
    const parent = current.parent;
    if (!parent || parent === current) {
      break;
    }
    current = parent;
  }
  return void 0;
}
async function foreignContextId(scope) {
  const held = heldBrowsingContext(scope);
  if (!held) {
    return void 0;
  }
  const current = contextIdValue(await getContextManager(held.browser).getCurrentContext());
  return held.contextId === current ? void 0 : held.contextId;
}
function assertTopLevel(context, command) {
  if (context.isFrame) {
    throw new Error(`\`${command}\` is only available on a top-level browsing context`);
  }
}
function containsContext(nodes, contextId) {
  return nodes.some((node) => node.context === contextId || containsContext(node.children ?? [], contextId));
}
async function assertFrameAttached(frame2) {
  let top = frame2;
  while (top.parent) {
    top = top.parent;
  }
  const { contexts } = await frame2.browser.browsingContextGetTree({ root: top.contextId });
  if (!containsContext(contexts, frame2.contextId)) {
    throw new Error(`no such frame: the frame "${frame2.contextId}" was discarded because the page it belongs to navigated away`);
  }
}
var init_browsingContext = __esm({
  "src/session/browsingContext.ts"() {
    "use strict";
    init_context();
  }
});

// src/utils/frameOffset.ts
async function frameRect(parent, contextId) {
  const frames = await parent.$$("iframe, frame");
  for (const frame2 of frames) {
    const element = await frame2.getElement();
    const win = await parent.execute(
      (node) => node.contentWindow,
      element
    );
    if (win?.context !== contextId) {
      continue;
    }
    return parent.execute((node) => {
      const rect = node.getBoundingClientRect();
      return {
        x: Math.round(rect.x + node.clientLeft),
        y: Math.round(rect.y + node.clientTop),
        width: Math.round(rect.width),
        height: Math.round(rect.height)
      };
    }, element);
  }
  throw new Error(`Could not find a frame element for browsing context ${contextId}`);
}
async function frameOffset(frame2) {
  let top = frame2;
  const chain = [];
  while (top.parent) {
    chain.unshift(top);
    top = top.parent;
  }
  let x = 0;
  let y = 0;
  let parent = top;
  for (const child of chain) {
    const rect = await frameRect(parent, child.contextId);
    x += rect.x;
    y += rect.y;
    parent = child;
  }
  return { top, x, y };
}
var init_frameOffset = __esm({
  "src/utils/frameOffset.ts"() {
    "use strict";
  }
});

// src/utils/screenshotEvents.ts
async function withScreenshotEvents(browser, command, capture, elementId) {
  const event = {
    command,
    method: "GET",
    endpoint: command === "takeElementScreenshot" ? `/session/:sessionId/element/${elementId}/screenshot` : "/session/:sessionId/screenshot",
    body: {}
  };
  browser.emit("command", event);
  try {
    const data = await capture();
    browser.emit("result", { ...event, result: { value: data } });
    return data;
  } catch (error) {
    browser.emit("result", { ...event, result: { error } });
    throw error;
  }
}
var init_screenshotEvents = __esm({
  "src/utils/screenshotEvents.ts"() {
    "use strict";
  }
});

// src/utils/thirdParty/getVisibleText.ts
var GET_VISIBLE_TEXT;
var init_getVisibleText = __esm({
  "src/utils/thirdParty/getVisibleText.ts"() {
    "use strict";
    GET_VISIBLE_TEXT = `function(){return (function(){var h=this||self;
function aa(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"==
b&&"undefined"==typeof a.call)return"object";return b}function ba(a,b){function c(){}c.prototype=b.prototype;a.prototype=new c;a.prototype.constructor=a};var ca=Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b,void 0)}:function(a,b){if("string"===typeof a)return"string"!==typeof b||1!=b.length?-1:a.indexOf(b,0);for(var c=0;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},m=Array.prototype.forEach?function(a,b){Array.prototype.forEach.call(a,b,void 0)}:function(a,b){for(var c=a.length,d="string"===typeof a?a.split(""):a,e=0;e<c;e++)e in d&&b.call(void 0,d[e],e,a)},da=Array.prototype.map?function(a,b){return Array.prototype.map.call(a,
b,void 0)}:function(a,b){for(var c=a.length,d=Array(c),e="string"===typeof a?a.split(""):a,f=0;f<c;f++)f in e&&(d[f]=b.call(void 0,e[f],f,a));return d},fa=Array.prototype.some?function(a,b){return Array.prototype.some.call(a,b,void 0)}:function(a,b){for(var c=a.length,d="string"===typeof a?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a))return!0;return!1},ha=Array.prototype.every?function(a,b){return Array.prototype.every.call(a,b,void 0)}:function(a,b){for(var c=a.length,d="string"===
typeof a?a.split(""):a,e=0;e<c;e++)if(e in d&&!b.call(void 0,d[e],e,a))return!1;return!0};var ia={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",
darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",
ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",
lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",
moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",
seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};var ja="backgroundColor borderTopColor borderRightColor borderBottomColor borderLeftColor color outlineColor".split(" "),ka=/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/,la=/^#(?:[0-9a-f]{3}){1,2}$/i,ma=/^(?:rgba)?\\((\\d{1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*)\\)$/i,na=/^(?:rgb)?\\((0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2})\\)$/i;function p(a,b){this.code=a;this.a=q[a]||u;this.message=b||"";a=this.a.replace(/((?:^|\\s+)[a-z])/g,function(c){return c.toUpperCase().replace(/^[\\s\\xa0]+/g,"")});b=a.length-5;if(0>b||a.indexOf("Error",b)!=b)a+="Error";this.name=a;a=Error(this.message);a.name=this.name;this.stack=a.stack||""}ba(p,Error);var u="unknown error",q={15:"element not selectable",11:"element not visible"};q[31]=u;q[30]=u;q[24]="invalid cookie domain";q[29]="invalid element coordinates";q[12]="invalid element state";
q[32]="invalid selector";q[51]="invalid selector";q[52]="invalid selector";q[17]="javascript error";q[405]="unsupported operation";q[34]="move target out of bounds";q[27]="no such alert";q[7]="no such element";q[8]="no such frame";q[23]="no such window";q[28]="script timeout";q[33]="session not created";q[10]="stale element reference";q[21]="timeout";q[25]="unable to set cookie";q[26]="unexpected alert open";q[13]=u;q[9]="unknown command";function oa(a){var b=a.length-1;return 0<=b&&a.indexOf(" ",b)==b}var v=String.prototype.trim?function(a){return a.trim()}:function(a){return/^[\\s\\xa0]*([\\s\\S]*?)[\\s\\xa0]*$/.exec(a)[1]};
function pa(a,b){var c=0;a=v(String(a)).split(".");b=v(String(b)).split(".");for(var d=Math.max(a.length,b.length),e=0;0==c&&e<d;e++){var f=a[e]||"",g=b[e]||"";do{f=/(\\d*)(\\D*)(.*)/.exec(f)||["","","",""];g=/(\\d*)(\\D*)(.*)/.exec(g)||["","","",""];if(0==f[0].length&&0==g[0].length)break;c=w(0==f[1].length?0:parseInt(f[1],10),0==g[1].length?0:parseInt(g[1],10))||w(0==f[2].length,0==g[2].length)||w(f[2],g[2]);f=f[3];g=g[3]}while(0==c)}return c}function w(a,b){return a<b?-1:a>b?1:0};var x;a:{var qa=h.navigator;if(qa){var ra=qa.userAgent;if(ra){x=ra;break a}}x=""}function z(a){return-1!=x.indexOf(a)};function B(){return z("Firefox")||z("FxiOS")}function C(){return(z("Chrome")||z("CriOS"))&&!z("Edge")};function sa(a){return String(a).replace(/\\-([a-z])/g,function(b,c){return c.toUpperCase()})};function D(){return z("iPhone")&&!z("iPod")&&!z("iPad")};function ta(a,b){var c=ua;return Object.prototype.hasOwnProperty.call(c,a)?c[a]:c[a]=b(a)};var va=z("Opera"),E=z("Trident")||z("MSIE"),ya=z("Edge"),za=z("Gecko")&&!(-1!=x.toLowerCase().indexOf("webkit")&&!z("Edge"))&&!(z("Trident")||z("MSIE"))&&!z("Edge"),Aa=-1!=x.toLowerCase().indexOf("webkit")&&!z("Edge");function Ba(){var a=h.document;return a?a.documentMode:void 0}var F;
a:{var G="",I=function(){var a=x;if(za)return/rv:([^\\);]+)(\\)|;)/.exec(a);if(ya)return/Edge\\/([\\d\\.]+)/.exec(a);if(E)return/\\b(?:MSIE|rv)[: ]([^\\);]+)(\\)|;)/.exec(a);if(Aa)return/WebKit\\/(\\S+)/.exec(a);if(va)return/(?:Version)[ \\/]?(\\S+)/.exec(a)}();I&&(G=I?I[1]:"");if(E){var J=Ba();if(null!=J&&J>parseFloat(G)){F=String(J);break a}}F=G}var ua={};function Ca(a){return ta(a,function(){return 0<=pa(F,a)})}var Da;Da=h.document&&E?Ba():void 0;var Ea=B(),Fa=D()||z("iPod"),Ga=z("iPad"),Ha=z("Android")&&!(C()||B()||z("Opera")||z("Silk")),Ia=C(),Ja=z("Safari")&&!(C()||z("Coast")||z("Opera")||z("Edge")||z("Edg/")||z("OPR")||B()||z("Silk")||z("Android"))&&!(D()||z("iPad")||z("iPod"));function K(a){return(a=a.exec(x))?a[1]:""}(function(){if(Ea)return K(/Firefox\\/([0-9.]+)/);if(E||ya||va)return F;if(Ia)return D()||z("iPad")||z("iPod")?K(/CriOS\\/([0-9.]+)/):K(/Chrome\\/([0-9.]+)/);if(Ja&&!(D()||z("iPad")||z("iPod")))return K(/Version\\/([0-9.]+)/);if(Fa||Ga){var a=/Version\\/(\\S+).*Mobile\\/(\\S+)/.exec(x);if(a)return a[1]+"."+a[2]}else if(Ha)return(a=K(/Android\\s+([0-9.]+)/))?a:K(/Version\\/([0-9.]+)/);return""})();var Ka;if(Ka=E)Ka=!(9<=Number(Da));var La=Ka;function L(a,b){this.x=void 0!==a?a:0;this.y=void 0!==b?b:0}L.prototype.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};L.prototype.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};L.prototype.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};function M(a,b){this.width=a;this.height=b}M.prototype.aspectRatio=function(){return this.width/this.height};M.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};M.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};M.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};function Ma(a){for(;a&&1!=a.nodeType;)a=a.previousSibling;return a}function N(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function Na(a,b){a&&(a=a.parentNode);for(var c=0;a;){if(b(a))return a;a=a.parentNode;c++}return null}function Oa(a){this.a=a||h.document||document};function O(a,b){b&&"string"!==typeof b&&(b=b.toString());return a instanceof HTMLFormElement?!!a&&1==a.nodeType&&(!b||"FORM"==b):!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)};function P(a,b,c,d){this.f=a;this.a=b;this.b=c;this.c=d}P.prototype.ceil=function(){this.f=Math.ceil(this.f);this.a=Math.ceil(this.a);this.b=Math.ceil(this.b);this.c=Math.ceil(this.c);return this};P.prototype.floor=function(){this.f=Math.floor(this.f);this.a=Math.floor(this.a);this.b=Math.floor(this.b);this.c=Math.floor(this.c);return this};P.prototype.round=function(){this.f=Math.round(this.f);this.a=Math.round(this.a);this.b=Math.round(this.b);this.c=Math.round(this.c);return this};function R(a,b,c,d){this.a=a;this.b=b;this.width=c;this.height=d}R.prototype.ceil=function(){this.a=Math.ceil(this.a);this.b=Math.ceil(this.b);this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};R.prototype.floor=function(){this.a=Math.floor(this.a);this.b=Math.floor(this.b);this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};
R.prototype.round=function(){this.a=Math.round(this.a);this.b=Math.round(this.b);this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var Pa="function"===typeof ShadowRoot;function S(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return O(a)?a:null}
function T(a,b){b=sa(b);if("float"==b||"cssFloat"==b||"styleFloat"==b)b=La?"styleFloat":"cssFloat";a:{var c=b;var d=N(a);if(d.defaultView&&d.defaultView.getComputedStyle&&(d=d.defaultView.getComputedStyle(a,null))){c=d[c]||d.getPropertyValue(c)||"";break a}c=""}a=c||Qa(a,b);if(null===a)a=null;else if(0<=ca(ja,b)){b:{var e=a.match(ma);if(e&&(b=Number(e[1]),c=Number(e[2]),d=Number(e[3]),e=Number(e[4]),0<=b&&255>=b&&0<=c&&255>=c&&0<=d&&255>=d&&0<=e&&1>=e)){b=[b,c,d,e];break b}b=null}if(!b)b:{if(d=a.match(na))if(b=
Number(d[1]),c=Number(d[2]),d=Number(d[3]),0<=b&&255>=b&&0<=c&&255>=c&&0<=d&&255>=d){b=[b,c,d,1];break b}b=null}if(!b)b:{b=a.toLowerCase();c=ia[b.toLowerCase()];if(!c&&(c="#"==b.charAt(0)?b:"#"+b,4==c.length&&(c=c.replace(ka,"#$1$1$2$2$3$3")),!la.test(c))){b=null;break b}b=[parseInt(c.substr(1,2),16),parseInt(c.substr(3,2),16),parseInt(c.substr(5,2),16),1]}a=b?"rgba("+b.join(", ")+")":a}return a}
function Qa(a,b){var c=a.currentStyle||a.style,d=c[b];void 0===d&&"function"==aa(c.getPropertyValue)&&(d=c.getPropertyValue(b));return"inherit"!=d?void 0!==d?d:null:(a=S(a))?Qa(a,b):null}
function Ra(a,b,c){function d(g){var k=U(g);return 0<k.height&&0<k.width?!0:O(g,"PATH")&&(0<k.height||0<k.width)?(g=T(g,"stroke-width"),!!g&&0<parseInt(g,10)):"hidden"!=T(g,"overflow")&&fa(g.childNodes,function(y){return 3==y.nodeType||O(y)&&d(y)})}function e(g){return Sa(g)==V&&ha(g.childNodes,function(k){return!O(k)||e(k)||!d(k)})}if(!O(a))throw Error("Argument to isShown must be of type Element");if(O(a,"BODY"))return!0;if(O(a,"OPTION")||O(a,"OPTGROUP"))return a=Na(a,function(g){return O(g,"SELECT")}),
!!a&&Ra(a,!0,c);var f=Ta(a);if(f)return!!f.image&&0<f.rect.width&&0<f.rect.height&&Ra(f.image,b,c);if(O(a,"INPUT")&&"hidden"==a.type.toLowerCase()||O(a,"NOSCRIPT"))return!1;f=T(a,"visibility");return"collapse"!=f&&"hidden"!=f&&c(a)&&(b||0!=Ua(a))&&d(a)?!e(a):!1}
function Va(a){function b(c){if(O(c)&&("none"==T(c,"display")||"hidden"==T(c,"content-visibility")))return!1;var d;if((d=c.parentNode)&&d.shadowRoot&&void 0!==c.assignedSlot)d=c.assignedSlot?c.assignedSlot.parentNode:null;else if(c.getDestinationInsertionPoints){var e=c.getDestinationInsertionPoints();0<e.length&&(d=e[e.length-1])}if(Pa&&d instanceof ShadowRoot){if(d.host.shadowRoot&&d.host.shadowRoot!==d)return!1;d=d.host}return!d||9!=d.nodeType&&11!=d.nodeType?d&&O(d,"DETAILS")&&!d.open&&!O(c,"SUMMARY")?
!1:!!d&&b(d):!0}return Ra(a,!1,b)}var V="hidden";
function Sa(a){function b(l){function n(ea){if(ea==g)return!0;var wa=T(ea,"display");return 0==wa.lastIndexOf("inline",0)||"contents"==wa||"absolute"==xa&&"static"==T(ea,"position")?!1:!0}var xa=T(l,"position");if("fixed"==xa)return H=!0,l==g?null:g;for(l=S(l);l&&!n(l);)l=S(l);return l}function c(l){var n=l;if("visible"==y)if(l==g&&k)n=k;else if(l==k)return{x:"visible",y:"visible"};n={x:T(n,"overflow-x"),y:T(n,"overflow-y")};l==g&&(n.x="visible"==n.x?"auto":n.x,n.y="visible"==n.y?"auto":n.y);return n}
function d(l){if(l==g){var n=(new Oa(f)).a;l=n.scrollingElement?n.scrollingElement:Aa||"CSS1Compat"!=n.compatMode?n.body||n.documentElement:n.documentElement;n=n.parentWindow||n.defaultView;l=E&&Ca("10")&&n.pageYOffset!=l.scrollTop?new L(l.scrollLeft,l.scrollTop):new L(n.pageXOffset||l.scrollLeft,n.pageYOffset||l.scrollTop)}else l=new L(l.scrollLeft,l.scrollTop);return l}var e=Wa(a),f=N(a),g=f.documentElement,k=f.body,y=T(g,"overflow"),H;for(a=b(a);a;a=b(a)){var r=c(a);if("visible"!=r.x||"visible"!=
r.y){var t=U(a);if(0==t.width||0==t.height)return V;var A=e.a<t.a,Q=e.b<t.b;if(A&&"hidden"==r.x||Q&&"hidden"==r.y)return V;if(A&&"visible"!=r.x||Q&&"visible"!=r.y){A=d(a);Q=e.b<t.b-A.y;if(e.a<t.a-A.x&&"visible"!=r.x||Q&&"visible"!=r.x)return V;e=Sa(a);return e==V?V:"scroll"}A=e.c>=t.a+t.width;t=e.f>=t.b+t.height;if(A&&"hidden"==r.x||t&&"hidden"==r.y)return V;if(A&&"visible"!=r.x||t&&"visible"!=r.y){if(H&&(r=d(a),e.c>=g.scrollWidth-r.x||e.a>=g.scrollHeight-r.y))return V;e=Sa(a);return e==V?V:"scroll"}}}return"none"}
function U(a){var b=Ta(a);if(b)return b.rect;if(O(a,"HTML"))return a=N(a),a=((a?a.parentWindow||a.defaultView:window)||window).document,a="CSS1Compat"==a.compatMode?a.documentElement:a.body,a=new M(a.clientWidth,a.clientHeight),new R(0,0,a.width,a.height);try{var c=a.getBoundingClientRect()}catch(d){return new R(0,0,0,0)}b=new R(c.left,c.top,c.right-c.left,c.bottom-c.top);E&&a.ownerDocument.body&&(a=N(a),b.a-=a.documentElement.clientLeft+a.body.clientLeft,b.b-=a.documentElement.clientTop+a.body.clientTop);
return b}
function Ta(a){var b=O(a,"MAP");if(!b&&!O(a,"AREA"))return null;var c=b?a:O(a.parentNode,"MAP")?a.parentNode:null,d=null,e=null;if(c&&c.name){d='*[usemap="#'+c.name+'"]';c=N(c);var f;if(f="function"!=aa(c.querySelector)&&E&&(E?0<=pa(Da,8):Ca(8))){f=c.querySelector;var g=typeof f;f=!("object"==g&&null!=f||"function"==g)}if(f)throw Error("CSS selection is not supported");if(!d)throw new p(32,"No selector specified");d=v(d);try{var k=c.querySelector(d)}catch(y){throw new p(32,"An invalid or illegal selector was specified");}if(d=
k&&1==k.nodeType?k:null)e=U(d),b||"default"==a.shape.toLowerCase()||(a=Xa(a),b=Math.min(Math.max(a.a,0),e.width),k=Math.min(Math.max(a.b,0),e.height),e=new R(b+e.a,k+e.b,Math.min(a.width,e.width-b),Math.min(a.height,e.height-k)))}return{image:d,rect:e||new R(0,0,0,0)}}
function Xa(a){var b=a.shape.toLowerCase();a=a.coords.split(",");if("rect"==b&&4==a.length){b=a[0];var c=a[1];return new R(b,c,a[2]-b,a[3]-c)}if("circle"==b&&3==a.length)return b=a[2],new R(a[0]-b,a[1]-b,2*b,2*b);if("poly"==b&&2<a.length){b=a[0];c=a[1];for(var d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new R(b,c,d-b,e-c)}return new R(0,0,0,0)}function Wa(a){a=U(a);return new P(a.b,a.a+a.width,a.b+a.height,a.a)}
function Ya(a){return a.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g,"")}
function Za(a,b,c){if(O(a,"BR"))b.push("");else{var d=O(a,"TD"),e=T(a,"display"),f=!d&&!(0<=ca($a,e)),g=void 0!==a.previousElementSibling?a.previousElementSibling:Ma(a.previousSibling);g=g?T(g,"display"):"";var k=T(a,"float")||T(a,"cssFloat")||T(a,"styleFloat");!f||"run-in"==g&&"none"==k||/^[\\s\\xa0]*$/.test(b[b.length-1]||"")||b.push("");var y=Va(a),H=null,r=null;y&&(H=T(a,"white-space"),r=T(a,"text-transform"));m(a.childNodes,function(t){c(t,b,y,H,r)});a=b[b.length-1]||"";!d&&"table-cell"!=e||!a||
oa(a)||(b[b.length-1]+=" ");f&&"run-in"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push("")}}function ab(a,b){Za(a,b,function(c,d,e,f,g){3==c.nodeType&&e?bb(c,d,f,g):O(c)&&ab(c,d)})}var $a="inline inline-block inline-table none table-cell table-column table-column-group".split(" ");
function bb(a,b,c,d){a=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,"");a=a.replace(/(\\r\\n|\\r|\\n)/g,"\\n");if("normal"==c||"nowrap"==c)a=a.replace(/\\n/g," ");a="pre"==c||"pre-wrap"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]/g,"\\u00a0"):a.replace(/[ \\f\\t\\v\\u2028\\u2029]+/g," ");"capitalize"==d?(c=/(^|[^'_0-9A-Za-z\\u00C0-\\u02AF\\u1E00-\\u1EFF\\u24B6-\\u24E9\\u0300-\\u036F\\u1AB0-\\u1AFF\\u1DC0-\\u1DFF])([A-Za-z\\u00C0-\\u02AF\\u1E00-\\u1EFF\\u24B6-\\u24E9])/g,a=a.replace(c,function(e,f,g){return f+g.toUpperCase()}),c=/(^|[^'_0-9A-Za-z\\u00C0-\\u02AF\\u1E00-\\u1EFF\\u24B6-\\u24E9])([_*])([A-Za-z\\u00C0-\\u02AF\\u1E00-\\u1EFF\\u24D0-\\u24E9])/g,
a=a.replace(c,function(e,f,g,k){return f+g+k.toUpperCase()})):"uppercase"==d?a=a.toUpperCase():"lowercase"==d&&(a=a.toLowerCase());c=b.pop()||"";oa(c)&&0==a.lastIndexOf(" ",0)&&(a=a.substr(1));b.push(c+a)}function Ua(a){if(La){if("relative"==T(a,"position"))return 1;a=T(a,"filter");return(a=a.match(/^alpha\\(opacity=(\\d*)\\)/)||a.match(/^progid:DXImageTransform.Microsoft.Alpha\\(Opacity=(\\d*)\\)/))?Number(a[1])/100:1}return cb(a)}
function cb(a){var b=1,c=T(a,"opacity");c&&(b=Number(c));(a=S(a))&&(b*=cb(a));return b}
function W(a,b,c,d,e){if(3==a.nodeType&&c)bb(a,b,d,e);else if(O(a))if(O(a,"CONTENT")||O(a,"SLOT")){for(var f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(f=O(a,"CONTENT")?a.getDistributedNodes():a.assignedNodes(),m(0<f.length?f:a.childNodes,function(g){W(g,b,c,d,e)})):db(a,b)}else if(O(a,"SHADOW")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)m(a.childNodes,function(g){W(g,b,c,d,e)}),a=a.olderShadowRoot}else db(a,b)}
function db(a,b){a.shadowRoot&&m(a.shadowRoot.childNodes,function(c){W(c,b,!0,null,null)});Za(a,b,function(c,d,e,f,g){var k=null;1==c.nodeType?k=c:3==c.nodeType&&(k=c);null!=k&&(null!=k.assignedSlot||k.getDestinationInsertionPoints&&0<k.getDestinationInsertionPoints().length)||W(c,d,e,f,g)})};function eb(a){var b=[];Pa?db(a,b):ab(a,b);a=da(b,Ya);return Ya(a.join("\\n")).replace(/\\xa0/g," ")}var X=["se_exportedFunctionSymbol"],Y=h;X[0]in Y||"undefined"==typeof Y.execScript||Y.execScript("var "+X[0]);for(var Z;X.length&&(Z=X.shift());)X.length||void 0===eb?Y[Z]&&Y[Z]!==Object.prototype[Z]?Y=Y[Z]:Y=Y[Z]={}:Y[Z]=eb;; return this.se_exportedFunctionSymbol.apply(null,arguments);}).apply(window, arguments);}
`;
  }
});

// src/utils/bidi/elementCommands.ts
import { BIDI_MASK, ELEMENT_KEY } from "webdriver";
import { getBrowserObject as getBrowserObject4 } from "@wdio/utils";
function isBidiCommandsEnabled(browser) {
  return !!(browser.isBidi && browser.__bidiCommandsEnabled === true);
}
function exec(element, fn, ...args) {
  const el = element;
  const target = el.__bidiBrowser || heldBrowsingContext(element) || getBrowserObject4(element);
  el.__bidiBrowser = target;
  const rawEl = { [ELEMENT_KEY]: element.elementId };
  return target.execute(fn, rawEl, ...args).catch(nameNotInteractable);
}
function nameNotInteractable(err) {
  if (err instanceof Error && err.message.includes(NOT_INTERACTABLE)) {
    err.name = NOT_INTERACTABLE;
  }
  throw err;
}
function bidiClearValue(element) {
  return exec(element, withEditableGuard(function(el) {
    el.scrollIntoView({ block: "center", inline: "center" });
    el.focus();
    if (el.isContentEditable) {
      el.textContent = "";
    } else {
      setNativeValue(el, "");
    }
    el.dispatchEvent(new Event("input", { bubbles: true }));
    el.dispatchEvent(new Event("change", { bubbles: true }));
  }));
}
function withEditableGuard(body) {
  return new Function(
    "el",
    "value",
    `const setNativeValue = ${setNativeValue}; (${assertEditableTarget})(el); return (${body})(el, value)`
  );
}
function bidiAddValue(element, value) {
  if (SPECIAL_KEY.test(value)) {
    return typeKeys(element, value, false);
  }
  return exec(element, withEditableGuard(function(el, val) {
    const wasActive = document.activeElement === el;
    if (!wasActive) {
      el.scrollIntoView({ block: "center", inline: "center" });
      el.focus();
    }
    const v = el.value;
    const vLen = typeof v === "string" ? v.length : (el.textContent || "").length;
    const s = wasActive && typeof el.selectionStart === "number" ? el.selectionStart : vLen;
    const e2 = wasActive && typeof el.selectionEnd === "number" ? el.selectionEnd : vLen;
    if (el.isContentEditable) {
      el.textContent = (el.textContent || "").substring(0, s) + val + (el.textContent || "").substring(e2);
    } else {
      setNativeValue(el, v.substring(0, s) + val + v.substring(e2));
    }
    el.dispatchEvent(new Event("input", { bubbles: true }));
    el.dispatchEvent(new Event("change", { bubbles: true }));
  }), value);
}
function bidiAddMaskedValue(element, value) {
  return typeKeys(element, value, true);
}
async function typeKeys(element, value, mask) {
  await exec(element, withEditableGuard(function(el) {
    if (el.ownerDocument.activeElement !== el) {
      el.scrollIntoView({ block: "center", inline: "center" });
      el.focus();
      if (el.isContentEditable) {
        el.ownerDocument.getSelection().setPosition(el, el.childNodes.length);
      } else if (typeof el.value === "string") {
        try {
          el.setSelectionRange(el.value.length, el.value.length);
        } catch {
        }
      }
    }
    const root = el.getRootNode();
    const active = root && root.activeElement || el.ownerDocument.activeElement;
    if (!active || active !== el && !el.contains(active) && !(el.shadowRoot && el.shadowRoot.contains(active))) {
      throw new Error("element not interactable: element could not receive focus");
    }
  }));
  if (!value) {
    return;
  }
  const held = heldBrowsingContext(element);
  const browser = held ? held.browser : getBrowserObject4(element);
  const context = held?.contextId ?? getParallelContextStore().getStore() ?? contextIdValue(await getContextManager(browser).getCurrentContext());
  const params = {
    context,
    actions: [{
      id: "keyboard",
      type: "key",
      actions: Array.from(value).flatMap((key) => [
        { type: "keyDown", value: key },
        { type: "keyUp", value: key }
      ])
    }]
  };
  await browser.inputPerformActions(mask ? Object.assign(params, { [BIDI_MASK]: true }) : params);
  await browser.inputReleaseActions({ context });
}
async function bidiAssertClickable(element) {
  const result = await exec(element, function(el) {
    const describe = (node) => {
      let out = "<" + node.tagName.toLowerCase();
      if (node.id) {
        out += ' id="' + node.id + '"';
      }
      const cls = node.getAttribute("class");
      if (cls) {
        out += ' class="' + cls + '"';
      }
      return out + ">";
    };
    const rect = el.getClientRects()[0];
    if (!rect) {
      return { ok: false, x: 0, y: 0, target: describe(el), hit: "null", notInteractable: "element is not displayed" };
    }
    if (!rect.width || !rect.height) {
      return { ok: false, x: 0, y: 0, target: describe(el), hit: "null", notInteractable: "element has zero size" };
    }
    const center = () => {
      const r = el.getClientRects()[0] || el.getBoundingClientRect();
      return { x: Math.floor(r.left + r.width / 2), y: Math.floor(r.top + r.height / 2) };
    };
    let p = center();
    if (p.x < 0 || p.y < 0 || p.x >= window.innerWidth || p.y >= window.innerHeight) {
      el.scrollIntoView({ block: "center", inline: "center" });
      p = center();
    }
    const root = el.getRootNode();
    const hit = (root && typeof root.elementFromPoint === "function" ? root : document).elementFromPoint(p.x, p.y);
    const ok = !!hit && (hit === el || el.contains(hit) || !!el.shadowRoot && el.shadowRoot.contains(hit));
    return { ok, x: p.x, y: p.y, target: describe(el), hit: hit ? describe(hit) : "null" };
  });
  if (result.notInteractable) {
    const error = new Error(`element not interactable: ${result.notInteractable}`);
    error.name = "element not interactable";
    throw error;
  }
  if (!result.ok) {
    const error = new Error(
      `element click intercepted: Element ${result.target} is not clickable at point (${result.x}, ${result.y}). Other element would receive the click: ${result.hit}`
    );
    error.name = "element click intercepted";
    throw error;
  }
}
function bidiGetText(element) {
  const fn = new Function("el", `return (${GET_VISIBLE_TEXT}).call(null, el)`);
  return exec(element, fn);
}
function bidiGetValue(element) {
  return exec(element, function(el) {
    const v = el.value;
    return typeof v === "string" ? v : el.getAttribute("value") || "";
  });
}
function bidiGetAttribute(element, name) {
  return exec(element, function(el, attrName) {
    const BOOLEAN_PROPS = /* @__PURE__ */ new Set([
      "allowfullscreen",
      "allowpaymentrequest",
      "allowusermedia",
      "async",
      "autofocus",
      "autoplay",
      "checked",
      "compact",
      "complete",
      "controls",
      "declare",
      "default",
      "defaultchecked",
      "defaultselected",
      "defer",
      "disabled",
      "ended",
      "formnovalidate",
      "hidden",
      "indeterminate",
      "iscontenteditable",
      "ismap",
      "itemscope",
      "loop",
      "multiple",
      "muted",
      "nohref",
      "nomodule",
      "noresize",
      "noshade",
      "novalidate",
      "nowrap",
      "open",
      "paused",
      "playsinline",
      "pubdate",
      "readonly",
      "required",
      "reversed",
      "scoped",
      "seamless",
      "seeking",
      "selected",
      "truespeed",
      "typemustmatch",
      "willvalidate"
    ]);
    if (BOOLEAN_PROPS.has(attrName.toLowerCase())) {
      return el.hasAttribute(attrName) ? "true" : null;
    }
    return el.getAttribute(attrName);
  }, name);
}
function bidiGetTagName(element) {
  return exec(element, function(el) {
    return el.tagName.toLowerCase();
  });
}
function bidiGetProperty(element, property) {
  return exec(element, function(el, prop) {
    return el[prop];
  }, property);
}
function bidiGetRect(element) {
  return exec(element, function(el) {
    const rect = el.getBoundingClientRect();
    const view = el.ownerDocument.defaultView;
    return {
      x: rect.x + (view ? view.scrollX : 0),
      y: rect.y + (view ? view.scrollY : 0),
      width: rect.width,
      height: rect.height
    };
  });
}
function bidiGetCSSProperty(element, cssProperty) {
  return exec(element, function(el, prop) {
    return window.getComputedStyle(el)[prop];
  }, cssProperty);
}
function selectInPage(element, match, first, second) {
  return exec(element, function(selectEl, kind, a, b) {
    const normalize = (value) => (value || "").replace(/\s+/g, " ").trim();
    const normalizeSpace = (value) => (value ?? "").replace(/^[ \t\r\n]+|[ \t\r\n]+$/g, "").replace(/[ \t\r\n]+/g, " ");
    const options = selectEl.options;
    const count = options.length;
    let option = null;
    if (kind === "index") {
      option = options[a] || null;
    } else {
      for (let i = 0; i < count && !option; i++) {
        const opt = options[i];
        const matches = kind === "text" ? normalize(opt.textContent) === a || normalize(opt.label) === a : normalizeSpace(opt.getAttribute(a.trim())) === b.trim();
        if (matches) {
          option = opt;
        }
      }
    }
    if (!option) {
      return { selected: false, count };
    }
    let disabled = null;
    if (selectEl.disabled) {
      disabled = "select";
    } else if (option.disabled) {
      disabled = "option";
    } else if (option.closest("optgroup[disabled]")) {
      disabled = "optgroup";
    }
    if (disabled) {
      return { selected: false, count, disabled };
    }
    option.selected = true;
    selectEl.dispatchEvent(new Event("change", { bubbles: true }));
    return { selected: true, count };
  }, match, first, second);
}
function bidiSelectByVisibleText(element, text) {
  return selectInPage(element, "text", text);
}
function bidiSelectByAttribute(element, attribute, value) {
  return selectInPage(element, "attribute", attribute, value);
}
function bidiSelectByIndex(element, index) {
  return selectInPage(element, "index", index);
}
function bidiDisabledSelectError(command, option, source) {
  return new Error(
    `${command} cannot select ${option}: ${DISABLED_SOURCE_LABEL[source]} A user cannot select a disabled option, so this action is impossible and the test would pass on something that cannot happen. This error comes from the BiDi select implementation enabled by the "wdio:experimentalBiDiCommands" capability. To fix it, enable the element in the page before selecting, or select a different option.`
  );
}
function bidiIsSelected(element) {
  return exec(element, function(el) {
    return !!(el.selected || el.checked);
  });
}
function bidiIsEnabled(element) {
  return exec(element, function(el) {
    if (el.disabled) {
      return false;
    }
    const fs9 = el.closest("fieldset[disabled]");
    if (fs9) {
      const legend = fs9.querySelector(":scope > legend:first-of-type");
      if (!legend || !legend.contains(el)) {
        return false;
      }
    }
    return true;
  });
}
var NOT_INTERACTABLE, SPECIAL_KEY, assertEditableTarget, setNativeValue, DISABLED_SOURCE_LABEL;
var init_elementCommands = __esm({
  "src/utils/bidi/elementCommands.ts"() {
    "use strict";
    init_browsingContext();
    init_context();
    init_getVisibleText();
    NOT_INTERACTABLE = "element not interactable";
    SPECIAL_KEY = /[\uE000-\uE05D]/;
    assertEditableTarget = function(el) {
      if (el.disabled || el.readOnly) {
        throw new Error("element not interactable");
      }
      const tag = el.tagName.toLowerCase();
      const editable = tag === "input" || tag === "textarea" || tag === "select" || el.isContentEditable;
      if (!editable) {
        throw new Error("element not editable");
      }
      const style = window.getComputedStyle(el);
      if (style.display === "none" || style.visibility === "hidden") {
        throw new Error("element not interactable");
      }
    };
    setNativeValue = function(el, newValue) {
      const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), "value");
      if (descriptor && descriptor.set) {
        descriptor.set.call(el, newValue);
      } else {
        el.value = newValue;
      }
    };
    DISABLED_SOURCE_LABEL = {
      option: "The option itself is disabled.",
      optgroup: "The option sits in a disabled <optgroup>.",
      select: "The <select> element is disabled."
    };
  }
});

// src/utils/foreignContext.ts
import { BIDI_MASK as BIDI_MASK2, ELEMENT_KEY as ELEMENT_KEY2 } from "webdriver";
async function foreignContext(scope) {
  const held = heldBrowsingContext(scope);
  if (!held) {
    return void 0;
  }
  const current = contextIdValue(await getContextManager(held.browser).getCurrentContext());
  return held.contextId === current ? void 0 : held;
}
function driverError(code, message) {
  const error = new Error(`${code}: ${message}`);
  error.name = code;
  return error;
}
function throwOnFailure(result) {
  if (isFailure(result)) {
    throw driverError(result.error, result.message);
  }
  return result;
}
async function prepareInteraction(el, mode, isFrame) {
  const describe = (node) => {
    const html = node.outerHTML;
    const end = html.indexOf(">");
    return end === -1 ? html : html.slice(0, end + 1);
  };
  const failure = (error, message) => ({ error, message });
  const isDisabled = (node) => {
    if (["option", "optgroup"].includes(node.localName) && !node.disabled) {
      const parent = node.parentElement?.closest("optgroup,select");
      return parent ? isDisabled(parent) : false;
    }
    return node.matches(":disabled");
  };
  const isReadOnly = (node) => ["input", "textarea"].includes(node.localName) && node.readOnly;
  const MUTABLE_INPUT_TYPES = ["color", "date", "datetime-local", "email", "file", "month", "number", "password", "range", "search", "tel", "text", "time", "url", "week"];
  const isMutableFormControl = (node) => !isReadOnly(node) && !isDisabled(node) && (node.localName === "textarea" || node.localName === "input" && MUTABLE_INPUT_TYPES.includes(node.type));
  const isEditingHost = (node) => node.isContentEditable || node.ownerDocument.designMode === "on";
  const paintTree = (node) => {
    if (!node.isConnected) {
      return { tree: [] };
    }
    const rects = Array.from(node.getClientRects());
    if (rects.length === 0) {
      return { tree: [] };
    }
    const rect = rects.find((r) => r.width > 0 && r.height > 0) || rects[0];
    const view = node.ownerDocument.defaultView;
    const left = Math.max(0, Math.min(rect.x, rect.x + rect.width));
    const right = Math.min(view.innerWidth, Math.max(rect.x, rect.x + rect.width));
    const top = Math.max(0, Math.min(rect.y, rect.y + rect.height));
    const bottom = Math.min(view.innerHeight, Math.max(rect.y, rect.y + rect.height));
    const point = { x: Math.floor((left + right) / 2), y: Math.floor((top + bottom) / 2) };
    const root = node.getRootNode();
    return { tree: root.elementsFromPoint(point.x, point.y), point };
  };
  const isInView = (node) => {
    const pointerEvents = node.style.pointerEvents;
    const style = node.getAttribute("style");
    try {
      node.style.pointerEvents = "auto";
      const { tree } = paintTree(node);
      const row = node;
      if (node.localName === "tr" && row.cells?.length) {
        return tree.includes(row.cells[0]);
      }
      return tree.includes(node);
    } finally {
      node.style.pointerEvents = pointerEvents;
      if (style === null) {
        node.removeAttribute("style");
      } else if (node.getAttribute("style") !== style) {
        node.setAttribute("style", style);
      }
    }
  };
  const visibleInTopLevelViewport = (node) => new Promise((resolve) => {
    const timeout = setTimeout(() => {
      observer.disconnect();
      resolve(true);
    }, 100);
    const observer = new IntersectionObserver(([entry]) => {
      clearTimeout(timeout);
      observer.disconnect();
      resolve(entry.intersectionRatio >= 1);
    });
    observer.observe(node);
  });
  const scrollIntoView2 = async (node) => {
    if (!isInView(node)) {
      node.scrollIntoView({ behavior: "instant", block: "end", inline: "nearest" });
    }
    if (isFrame && !await visibleInTopLevelViewport(node)) {
      node.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
    }
  };
  const container = ["option", "optgroup"].includes(el.localName) && el.closest("datalist,select") || el;
  if (mode === "screenshot") {
    await scrollIntoView2(el);
    return null;
  }
  if (mode === "clear") {
    if (isReadOnly(el) || isDisabled(el) || !(isMutableFormControl(el) || isEditingHost(el))) {
      return failure("invalid element state", `Element ${describe(el)} is not editable, so it can not be cleared`);
    }
    await scrollIntoView2(el);
    if (!isInView(el)) {
      return failure("element not interactable", `Element ${describe(el)} could not be scrolled into view`);
    }
    return null;
  }
  if (mode === "click") {
    if (el.localName === "input" && el.type === "file") {
      return failure("invalid argument", `Cannot click ${describe(el)}, use \`setValue()\` or \`addValue()\` to upload files`);
    }
    await scrollIntoView2(container);
    if (!isInView(container)) {
      return failure("element not interactable", `Element ${describe(el)} could not be scrolled into view`);
    }
    const { tree, point } = paintTree(container);
    if (!tree[0] || !container.contains(tree[0])) {
      return failure(
        "element click intercepted",
        `Element ${describe(el)} is not clickable at point (${point?.x}, ${point?.y}). Other element would receive the click: ${tree[0] ? describe(tree[0]) : "none"}`
      );
    }
    return null;
  }
  if (el.localName === "input" && el.type === "file") {
    return null;
  }
  await scrollIntoView2(container);
  const doc = container.ownerDocument;
  if (container !== doc.body && container !== doc.documentElement) {
    if (doc.activeElement !== container) {
      container.focus();
    }
    if (doc.activeElement !== container) {
      return failure("element not interactable", `Element ${describe(el)} is not reachable by keyboard`);
    }
  }
  return null;
}
async function findInContext(held, elementId, using, value, maxNodeCount) {
  if (using === "link text" || using === "partial link text") {
    return findLinksInContext(held, using, value, elementId, maxNodeCount);
  }
  if (using === "xpath") {
    const found = await held.execute((root, expression) => {
      let result;
      try {
        result = root.ownerDocument.evaluate(expression, root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      } catch (err) {
        return { error: "invalid selector", message: `Unable to locate an element with the xpath expression ${expression}: ${err.message}` };
      }
      return Array.from({ length: result.snapshotLength }, (_, i) => result.snapshotItem(i)).filter((node) => node?.nodeType === Node.ELEMENT_NODE);
    }, ref(elementId), value);
    return throwOnFailure(found).slice(0, maxNodeCount);
  }
  const locator = using === "css selector" || using === "tag name" ? { type: "css", value } : void 0;
  if (!locator) {
    throw driverError("invalid argument", `Locator strategy "${using}" is not supported for an element of another browsing context`);
  }
  const { nodes } = await held.browser.browsingContextLocateNodes({
    context: held.contextId,
    locator,
    startNodes: [sharedRef(elementId)],
    ...maxNodeCount ? { maxNodeCount } : {}
  });
  return nodes.filter((node) => node.sharedId).map((node) => ({ [ELEMENT_KEY2]: node.sharedId }));
}
async function findLinksInContext(held, using, value, elementId, maxNodeCount) {
  const found = await held.execute(
    `const getVisibleText = ${GET_VISIBLE_TEXT}
        const [root, partial, value] = arguments
        return Array.from((root || document).querySelectorAll('a')).filter((a) => {
            const text = getVisibleText(a).trim()
            return partial ? text.includes(value) : text === value
        })`,
    elementId ? ref(elementId) : null,
    using === "partial link text",
    value
  );
  return found.slice(0, maxNodeCount);
}
function screenshotInContext(held, elementId) {
  return withScreenshotEvents(held.browser, "takeElementScreenshot", () => captureInContext(held, elementId), elementId);
}
async function captureInContext(held, elementId) {
  await held.execute(prepareInteraction, ref(elementId), "screenshot", held.isFrame);
  const rect = await held.execute((el) => {
    const { x: x2, y: y2, width, height } = el.getBoundingClientRect();
    return { x: x2, y: y2, width, height };
  }, ref(elementId));
  const { top, x, y } = held.isFrame ? await frameOffset(held) : { top: held, x: 0, y: 0 };
  const scroll2 = await top.execute(() => ({ x: window.scrollX, y: window.scrollY }));
  const { data } = await held.browser.browsingContextCaptureScreenshot({
    context: top.contextId,
    origin: "document",
    clip: { type: "box", x: scroll2.x + x + rect.x, y: scroll2.y + y + rect.y, width: rect.width, height: rect.height }
  });
  return data;
}
async function clickInContext(held, elementId) {
  throwOnFailure(await held.execute(prepareInteraction, ref(elementId), "click", held.isFrame));
  const isOption = await held.execute((el) => {
    if (el.localName !== "option") {
      return false;
    }
    const option = el;
    const parent = option.closest("datalist,select") || option;
    const fire = (type) => parent.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, view: window }));
    fire("mouseover");
    fire("mousemove");
    fire("mousedown");
    parent.focus();
    const isDisabled = (node) => {
      if (["option", "optgroup"].includes(node.localName) && !node.disabled) {
        const ancestor = node.parentElement?.closest("optgroup,select");
        return ancestor ? isDisabled(ancestor) : false;
      }
      return node.matches(":disabled");
    };
    if (!isDisabled(option)) {
      const previous = option.selected;
      option.selected = parent.multiple ? !option.selected : true;
      parent.dispatchEvent(new Event("input", { bubbles: true }));
      if (option.selected !== previous) {
        parent.dispatchEvent(new Event("change", { bubbles: true }));
      }
    }
    fire("mouseup");
    fire("click");
    return true;
  }, ref(elementId));
  if (isOption) {
    return null;
  }
  await held.browser.inputPerformActions({
    context: held.contextId,
    actions: [{
      id: "pointer",
      type: "pointer",
      parameters: { pointerType: "mouse" },
      actions: [
        { type: "pointerMove", duration: 0, x: 0, y: 0, origin: { type: "element", element: sharedRef(elementId) } },
        { type: "pointerDown", button: 0 },
        { type: "pointerUp", button: 0 }
      ]
    }]
  });
  await held.browser.inputReleaseActions({ context: held.contextId }).catch((err) => {
    if (!err.message.includes("no such frame")) {
      throw err;
    }
  });
  return null;
}
async function clearInContext(held, elementId) {
  throwOnFailure(await held.execute(prepareInteraction, ref(elementId), "clear", held.isFrame));
  await held.execute((el) => {
    if (el.isContentEditable || el.ownerDocument.designMode === "on") {
      if (el.innerHTML === "") {
        return;
      }
      el.focus();
      el.innerHTML = "";
      el.blur();
      return;
    }
    const field = el;
    const isEmpty = field.type === "file" ? !field.files?.length : field.value === "";
    if (field.validity.valid && isEmpty) {
      return;
    }
    field.focus();
    field.value = "";
    field.dispatchEvent(new Event("change", { bubbles: true }));
    field.blur();
  }, ref(elementId));
  return null;
}
async function sendKeysInContext(held, elementId, text, options = {}) {
  const kind = await held.execute((el) => {
    const input = el;
    if (el.localName !== "input") {
      return "text";
    }
    if (input.type === "file") {
      return input.hasAttribute("multiple") ? "files" : "file";
    }
    return input.type === "date" || input.type === "time" ? "value" : "text";
  }, ref(elementId));
  if (kind === "file" || kind === "files") {
    const files = text.split("\n");
    if (files.length === 0 || files.some((file) => file === "")) {
      throw driverError("invalid argument", "Expected one or more newline separated file paths");
    }
    if (kind === "file" && files.length > 1) {
      throw driverError("invalid argument", "The file input does not accept multiple files");
    }
    await held.browser.inputSetFiles({ context: held.contextId, element: sharedRef(elementId), files });
    return null;
  }
  const hadFocus = await held.execute((el) => el.ownerDocument.activeElement === el, ref(elementId));
  throwOnFailure(await held.execute(prepareInteraction, ref(elementId), "keys", held.isFrame));
  if (kind === "value") {
    throwOnFailure(await held.execute((el, value) => {
      if (el.readOnly || el.disabled) {
        return { error: "element not interactable", message: "The element is not mutable" };
      }
      el.value = value;
      el.dispatchEvent(new Event("input", { bubbles: true }));
      el.dispatchEvent(new Event("change", { bubbles: true }));
      return null;
    }, ref(elementId), text));
    return null;
  }
  if (!hadFocus) {
    await held.execute((el) => {
      if (el.isContentEditable) {
        const selection = el.ownerDocument.getSelection();
        selection?.setPosition(el, el.childNodes.length);
        return;
      }
      const field = el;
      if (typeof field.value === "string") {
        try {
          field.setSelectionRange(field.value.length, field.value.length);
        } catch {
        }
      }
    }, ref(elementId));
  }
  if (text.length === 0) {
    return null;
  }
  const params = {
    context: held.contextId,
    actions: [{
      id: "keyboard",
      type: "key",
      actions: Array.from(text).flatMap((key) => [
        { type: "keyDown", value: key },
        { type: "keyUp", value: key }
      ])
    }]
  };
  if (options.mask) {
    Object.assign(params, { [BIDI_MASK2]: true });
  }
  await held.browser.inputPerformActions(params);
  await held.browser.inputReleaseActions({ context: held.contextId });
  return null;
}
function unsupported(endpoint) {
  return async () => {
    throw new Error(
      `\`${endpoint}\` is not supported for an element of another browsing context: WebDriver BiDi has no equivalent. Run it on an element of the session's current context.`
    );
  };
}
function routeElementEndpoints(properties) {
  for (const [name, endpoint] of Object.entries(FOREIGN_ELEMENT_ENDPOINTS)) {
    const classic = properties[name]?.value;
    if (typeof classic !== "function") {
      continue;
    }
    properties[name] = {
      ...properties[name],
      value: async function(elementId, ...args) {
        const held = await foreignContext(this);
        if (held) {
          return endpoint(held, elementId, ...args);
        }
        return classic.call(this, elementId, ...args);
      }
    };
  }
  return properties;
}
var ref, sharedRef, isFailure, BOOLEAN_ATTRIBUTES, FOREIGN_ELEMENT_ENDPOINTS;
var init_foreignContext = __esm({
  "src/utils/foreignContext.ts"() {
    "use strict";
    init_context();
    init_browsingContext();
    init_frameOffset();
    init_screenshotEvents();
    init_getVisibleText();
    ref = (elementId) => ({ [ELEMENT_KEY2]: elementId });
    sharedRef = (elementId) => ({ sharedId: elementId });
    isFailure = (result) => Boolean(result) && typeof result === "object" && typeof result.error === "string";
    BOOLEAN_ATTRIBUTES = {
      audio: ["autoplay", "controls", "loop", "muted"],
      button: ["autofocus", "disabled", "formnovalidate"],
      details: ["open"],
      dialog: ["open"],
      fieldset: ["disabled"],
      form: ["novalidate"],
      iframe: ["allowfullscreen"],
      img: ["ismap"],
      input: ["autofocus", "checked", "disabled", "formnovalidate", "multiple", "readonly", "required"],
      ol: ["reversed"],
      optgroup: ["disabled"],
      option: ["disabled", "selected"],
      script: ["async", "defer"],
      select: ["autofocus", "disabled", "multiple", "required"],
      textarea: ["autofocus", "disabled", "readonly", "required"],
      track: ["default"],
      video: ["autoplay", "controls", "loop", "muted"]
    };
    FOREIGN_ELEMENT_ENDPOINTS = {
      async findElementFromElement(held, elementId, using, value) {
        const [first] = await findInContext(held, elementId, using, value, 1);
        if (!first) {
          throw driverError("no such element", `Unable to locate element: {"method":"${using}","selector":"${value}"}`);
        }
        return first;
      },
      findElementsFromElement: (held, elementId, using, value) => findInContext(held, elementId, using, value),
      isElementSelected: (held, elementId) => held.execute((el) => {
        if (el.localName === "option") {
          return el.selected;
        }
        const type = el.localName === "input" ? el.type : "";
        return (type === "checkbox" || type === "radio") && el.checked;
      }, ref(elementId)),
      /**
       * An `<option>` or `<optgroup>` in a disabled `<optgroup>` or `<select>`
       * counts as disabled, like the drivers report it. An XML document has no
       * enabled form controls.
       */
      isElementEnabled: (held, elementId) => held.execute((el) => {
        if (["text/xml", "application/xml"].includes(el.ownerDocument.contentType)) {
          return false;
        }
        const isDisabled = (node) => {
          if (["option", "optgroup"].includes(node.localName) && !node.disabled) {
            const parent = node.parentElement?.closest("optgroup,select");
            return parent ? isDisabled(parent) : false;
          }
          return node.matches(":disabled");
        };
        return !isDisabled(el);
      }, ref(elementId)),
      getElementAttribute: (held, elementId, name) => held.execute(
        (el, name2, booleanAttributes) => {
          const isHTML = el.namespaceURI === "http://www.w3.org/1999/xhtml" && !["text/xml", "application/xml"].includes(el.ownerDocument.contentType);
          const lowerName = name2.toLowerCase();
          const isCustomElement = el.localName.includes("-");
          const isBoolean = isHTML && ((lowerName === "hidden" || lowerName === "itemscope") && !isCustomElement || (booleanAttributes[el.localName] || []).includes(lowerName));
          if (isBoolean) {
            return el.hasAttribute(name2) ? "true" : null;
          }
          return el.getAttribute(name2);
        },
        ref(elementId),
        name,
        BOOLEAN_ATTRIBUTES
      ),
      getElementProperty: (held, elementId, name) => held.execute(
        (el, name2) => {
          const value = el[name2];
          return value === void 0 ? null : value;
        },
        ref(elementId),
        name
      ),
      /**
       * The computed value, or `""` in an XML document. chromedriver reports
       * colors as `rgba(r, g, b, a)`, so in Chromium `rgb()` gets an alpha of 1.
       */
      getElementCSSValue: async (held, elementId, name) => {
        const value = await held.execute(
          (el, name2) => ["text/xml", "application/xml"].includes(el.ownerDocument.contentType) ? "" : getComputedStyle(el).getPropertyValue(name2),
          ref(elementId),
          name
        );
        const browserName = (held.browser.capabilities.browserName || "").toLowerCase();
        const isChromium = held.browser.isChromium || ["chrome", "chromium", "chrome-headless-shell", "msedge", "microsoftedge"].includes(browserName);
        return isChromium ? value.replace(/rgb\((\s*\d+\s*),(\s*\d+\s*),(\s*\d+\s*)\)/g, "rgba($1,$2,$3, 1)") : value;
      },
      getElementText: (held, elementId) => held.execute(
        `return (${GET_VISIBLE_TEXT}).apply(null, arguments)`,
        ref(elementId)
      ),
      getElementTagName: (held, elementId) => held.execute((el) => el.tagName.toLowerCase(), ref(elementId)),
      getElementRect: (held, elementId) => held.execute((el) => {
        const rect = el.getBoundingClientRect();
        const view = el.ownerDocument.defaultView;
        return {
          x: rect.x + (view?.scrollX ?? 0),
          y: rect.y + (view?.scrollY ?? 0),
          width: rect.width,
          height: rect.height
        };
      }, ref(elementId)),
      elementClick: (held, elementId) => clickInContext(held, elementId),
      elementClear: (held, elementId) => clearInContext(held, elementId),
      elementSendKeys: (held, elementId, text, runtime) => sendKeysInContext(held, elementId, String(text), {
        mask: runtime?.mask
      }),
      takeElementScreenshot: (held, elementId) => screenshotInContext(held, elementId),
      getElementComputedRole: unsupported("getElementComputedRole"),
      getElementComputedLabel: unsupported("getElementComputedLabel")
    };
  }
});

// src/utils/strictSelectorError.ts
function selectorToString(selector) {
  if (typeof selector === "function") {
    return selector.toString();
  }
  return JSON.stringify(selector);
}
var StrictSelectorError;
var init_strictSelectorError = __esm({
  "src/utils/strictSelectorError.ts"() {
    "use strict";
    StrictSelectorError = class extends Error {
      /**
       * amount of elements the selector resolved to
       */
      matches;
      /**
       * selector that was used to query the elements
       */
      selector;
      constructor(selector, matches) {
        const printable = selectorToString(selector);
        super(
          `strict mode violation: \`$(${printable})\` resolved to ${matches} elements, expected 1.
Use \`$$(${printable})\` to work with all matches, \`$$(${printable})[0]\` if you explicitly want the first one, or narrow down the selector so it matches a single element.
Opt out for a single call with \`$(${printable}, { strict: false })\` or globally by setting \`strictSelectors: false\` in your WebdriverIO config.`
        );
        this.name = "StrictSelectorError";
        this.matches = matches;
        this.selector = selector;
      }
    };
  }
});

// src/utils/findElementAgain.ts
import isPlainObject from "is-plain-obj";
import { ELEMENT_KEY as ELEMENT_KEY3 } from "webdriver";
import { getBrowserObject as getBrowserObject6, getWdioKind as getWdioKind2 } from "@wdio/utils";
function canFindAgain(element) {
  const { selector } = element;
  return typeof selector === "string" || typeof selector === "function" || isPlainObject(selector) && typeof selector[ELEMENT_KEY3] !== "string";
}
function selectorIn(element, parent) {
  const selector = element.selector;
  if (!isPlainObject(selector) || typeof selector.strategy !== "function" || getWdioKind2(element.parent) !== "element") {
    return element.selector;
  }
  return { ...selector, strategyArguments: [...selector.strategyArguments.slice(0, -1), parent] };
}
function itemOf(foundWith, selector, props, parent) {
  const flags = LIST_QUERIES.get(foundWith);
  if (!flags || selector === void 0 || Array.isArray(selector)) {
    return void 0;
  }
  if (foundWith === "custom$$") {
    const strategy = getBrowserObject6(parent).strategies?.get(selector);
    if (!strategy) {
      return void 0;
    }
    const strategyArguments = getWdioKind2(parent) === "element" ? [...props, parent] : props;
    const strategyRef = { strategy, strategyName: selector, strategyArguments };
    return { selector: strategyRef, props: { ...flags } };
  }
  return {
    selector,
    props: {
      ...flags,
      ...flags.isReactElement && props[0] ? { reactOptions: props[0] } : {}
    }
  };
}
function findAllAgain(element, parent = element.parent) {
  if (element.isReactElement) {
    return parent.react$$(element.selector, element[REACT_OPTIONS]);
  }
  if (element.isShadowElement) {
    return parent.shadow$$(element.selector);
  }
  return parent.$$(selectorIn(element, parent));
}
async function findElementAgain(element, { parent = element.parent, wait = false } = {}) {
  if (element.index !== void 0) {
    if (wait) {
      const item = await findAllAgain(element, parent)[element.index]?.getElement();
      if (item && !item.elementId && item.error) {
        throw item.error;
      }
      return item;
    }
    const elements = await findAllAgain(element, parent);
    return element.index < elements.length ? elements[element.index] : void 0;
  }
  if (element.isReactElement) {
    return parent.react$(element.selector, element[REACT_OPTIONS]).getElement();
  }
  if (element.isShadowElement) {
    return parent.shadow$(element.selector).getElement();
  }
  return parent.$(selectorIn(element, parent), { strict: element.strict }).getElement();
}
var REACT_OPTIONS, INDEX_NOT_FOUND, LIST_QUERIES;
var init_findElementAgain = __esm({
  "src/utils/findElementAgain.ts"() {
    "use strict";
    REACT_OPTIONS = /* @__PURE__ */ Symbol("wdio:reactOptions");
    INDEX_NOT_FOUND = /* @__PURE__ */ Symbol("wdio:indexNotFound");
    LIST_QUERIES = /* @__PURE__ */ new Map([
      ["$$", { isShadowElement: false, isReactElement: false }],
      ["shadow$$", { isShadowElement: true, isReactElement: false }],
      ["react$$", { isShadowElement: false, isReactElement: true }],
      ["custom$$", { isShadowElement: false, isReactElement: false }]
    ]);
  }
});

// src/utils/describeSelector.ts
import isPlainObject2 from "is-plain-obj";
function describeSelector(element) {
  const { selector } = element;
  if (isPlainObject2(selector)) {
    const { strategyName } = selector;
    if (typeof strategyName === "string") {
      return `${element.index === void 0 ? "custom$" : "custom$$"}(${strategyName})`;
    }
    try {
      return JSON.stringify(selector);
    } catch {
    }
  }
  return String(selector);
}
var init_describeSelector = __esm({
  "src/utils/describeSelector.ts"() {
    "use strict";
  }
});

// src/utils/errorCodes.ts
function hasCode(err, code) {
  return err instanceof Error && err.code === code;
}
var WAIT_UNTIL_TIMEOUT, TIMER_TIMEOUT, ELEMENT_NOT_FOUND_AGAIN;
var init_errorCodes = __esm({
  "src/utils/errorCodes.ts"() {
    "use strict";
    WAIT_UNTIL_TIMEOUT = "WAIT_UNTIL_TIMEOUT";
    TIMER_TIMEOUT = "TIMER_TIMEOUT";
    ELEMENT_NOT_FOUND_AGAIN = "ELEMENT_NOT_FOUND_AGAIN";
  }
});

// src/utils/elementNotFound.ts
function markWaited(err) {
  if (err && typeof err === "object" && !notFound.has(err)) {
    notFound.set(err, true);
  }
}
function waitedFor(err) {
  return Boolean(err && typeof err === "object" && notFound.has(err));
}
function isElementNotFoundAgain(err) {
  return hasCode(err, ELEMENT_NOT_FOUND_AGAIN);
}
function recordNotFound(err, el) {
  if (err && typeof err === "object") {
    notFound.set(err, el);
  }
}
function notFoundElement(err) {
  const el = err && typeof err === "object" ? notFound.get(err) : void 0;
  return el === true ? void 0 : el;
}
function nameNotFoundAgain(err, el, commandName, cause) {
  if (!Object.isExtensible(err)) {
    return;
  }
  if (cause !== void 0) {
    const withCause = err;
    withCause.cause ??= cause;
  }
  const firstLine = `${err.name}: ${err.message}`;
  const withCode = err;
  withCode.code = ELEMENT_NOT_FOUND_AGAIN;
  if (notFoundElement(err) === el) {
    err.message = err.message.replace(/^Can't call \S+ /, () => `Can't call ${commandName} `);
  }
  if (typeof err.stack === "string" && err.stack.startsWith(firstLine)) {
    err.stack = `${err.name}: ${err.message}` + err.stack.slice(firstLine.length);
  }
}
var notFound;
var init_elementNotFound = __esm({
  "src/utils/elementNotFound.ts"() {
    "use strict";
    init_errorCodes();
    notFound = /* @__PURE__ */ new WeakMap();
  }
});

// src/utils/implicitWait.ts
import logger3 from "@wdio/logger";
import { getBrowserObject as getBrowserObject7 } from "@wdio/utils";
async function implicitWait(currentElement, commandName) {
  const browser = getBrowserObject7(currentElement);
  const skipForMobileScroll = browser.isMobile && await browser.isNativeContext && (commandName === "scrollIntoView" || commandName === "tap");
  if (!currentElement.elementId && !/(waitUntil|waitFor|isExisting|is?\w+Displayed|is?\w+Clickable)/.test(commandName) && !skipForMobileScroll) {
    if (currentElement[INDEX_NOT_FOUND]) {
      const item = await findElementAgain(currentElement);
      if (!item?.elementId) {
        throw currentElement.error;
      }
      delete currentElement.error;
      return item;
    }
    log3.debug(
      `command ${commandName} was called on an element ("${describeSelector(currentElement)}") that wasn't found, waiting for it...`
    );
    try {
      await currentElement.waitForExist();
      const nextElement2 = await findElementAgain(currentElement, { wait: true });
      if (!nextElement2) {
        throw new Error(
          `element with selector "${describeSelector(currentElement)}" has no match at index ${currentElement.index}`
        );
      }
      return nextElement2;
    } catch (err) {
      if (err instanceof StrictSelectorError) {
        throw err;
      }
      const selector = currentElement.selector.toString();
      const index = currentElement.index === void 0 ? "" : ` at index ${currentElement.index}`;
      let message = `Can't call ${commandName} on element with selector "${describeSelector(currentElement)}"${index} because element wasn't found`;
      if (selector.includes("this.previousElementSibling")) {
        message = `Can't call ${commandName} on previous element of element with selector "${describeSelector(currentElement.parent)}" because sibling wasn't found`;
      } else if (selector.includes("this.nextElementSibling")) {
        message = `Can't call ${commandName} on next element of element with selector "${describeSelector(currentElement.parent)}" because sibling wasn't found`;
      } else if (selector.includes("this.parentElement")) {
        message = `Can't call ${commandName} on parent element of element with selector "${describeSelector(currentElement.parent)}" because it wasn't found`;
      }
      const notFound2 = new Error(message);
      if (hasCode(err, WAIT_UNTIL_TIMEOUT)) {
        markWaited(notFound2);
      }
      throw notFound2;
    }
  }
  return currentElement;
}
var log3;
var init_implicitWait = __esm({
  "src/utils/implicitWait.ts"() {
    "use strict";
    init_strictSelectorError();
    init_findElementAgain();
    init_describeSelector();
    init_elementNotFound();
    init_errorCodes();
    log3 = logger3("webdriverio");
  }
});

// src/element/array.ts
import { asyncIterators, chainElementPromise, ELEMENT_ARRAY_WRAP, getBrowserObject as getBrowserObject8, registerElementArrayFactory, WDIO_KIND } from "@wdio/utils";
function stateOf(array) {
  const state = states.get(array);
  if (!state) {
    throw new Error("Expected a WebdriverIO element array");
  }
  return state;
}
function normalizeSelector(selector) {
  if (typeof selector === "undefined") {
    return void 0;
  }
  if (!Array.isArray(selector)) {
    return selector;
  }
  const elements = selector;
  if (elements.length > 0 && elements.every((element) => element && element.selector && element.selector === elements[0].selector)) {
    return elements[0].selector;
  }
  return void 0;
}
function prepareMetadata(metadata) {
  metadata.selector = normalizeSelector(metadata.selector);
  metadata.props = metadata.props ?? [];
  metadata.foundWith = metadata.foundWith || "$$";
  return metadata;
}
function cloneMetadata(metadata) {
  return {
    ...metadata,
    props: [...metadata.props]
  };
}
function derivedMetadata(metadata) {
  return {
    ...cloneMetadata(metadata),
    refetch: false
  };
}
function fill(array, items) {
  const state = stateOf(array);
  array.splice(0, array.length, ...items);
  state.resolved = true;
}
async function load(array) {
  const state = stateOf(array);
  if (state.resolved) {
    return array;
  }
  if (!state.loading) {
    const base = async () => {
      const items = state.loader ? await state.loader() : [];
      fill(array, items);
      return items;
    };
    let run2 = base;
    for (const wrapper of state.wrappers) {
      const inner = run2;
      run2 = () => wrapper(inner);
    }
    state.loading = run2().then((items) => {
      if (!state.resolved) {
        fill(array, items);
      }
      return array;
    });
  }
  await state.loading;
  return array;
}
function listForIteration(array) {
  return stateOf(array).self ?? array;
}
function integerIndex(index) {
  const truncated = Math.trunc(index);
  return Number.isNaN(truncated) ? 0 : truncated;
}
function itemAt(items, index) {
  return items[index < 0 ? items.length + index : index];
}
function readIndex(array, index) {
  const normalized = integerIndex(index);
  const state = stateOf(array);
  const multiRemote2 = state.metadata.isMultiRemote === true;
  if (!state.resolved) {
    return chainElementPromise(elementAt(array, normalized), multiRemote2);
  }
  if (normalized < 0 || !Number.isFinite(normalized) || state.metadata.refetch === false) {
    return itemAt(array, normalized);
  }
  if (normalized < array.length) {
    return array[normalized];
  }
  return chainElementPromise(elementAt(array, normalized), multiRemote2);
}
async function elementAt(array, index) {
  const items = await load(array);
  if (index < 0) {
    return itemAt(items, index);
  }
  if (index < items.length) {
    return items[index];
  }
  const { parent, foundWith, selector, props, refetch, wrapMultiRemote } = stateOf(array).metadata;
  if (refetch === false || !parent) {
    return void 0;
  }
  const timeoutMsg = `Index out of bounds! $$(${String(selector)}) returned only ${items.length} elements.`;
  const findIn = async (target) => {
    const query = target[foundWith];
    if (typeof query !== "function") {
      return false;
    }
    const refetched = await query.call(target, selector, ...props);
    return refetched && refetched.length > index ? refetched[index] : false;
  };
  const itemIn = async (target) => {
    const browser = getBrowserObject8(target);
    try {
      return await browser.waitUntil(() => findIn(target), {
        timeout: browser.options?.waitforTimeout,
        timeoutMsg
      });
    } catch (err) {
      if (!(err instanceof Error) || err.message !== timeoutMsg) {
        throw err;
      }
      const item = itemOf(foundWith, selector, props, target);
      if (!item) {
        throw err;
      }
      const { getElements: getElements3 } = await Promise.resolve().then(() => (init_getElementObject(), getElementObject_exports));
      const [notFound2] = getElements3.call(target, item.selector, [err], item.props);
      notFound2.index = index;
      notFound2[INDEX_NOT_FOUND] = true;
      return notFound2;
    }
  };
  if (wrapMultiRemote) {
    const multiRemoteParent = parent;
    const elements = await Promise.all(multiRemoteParent.instances.map((name) => itemIn(multiRemoteParent.getInstance(name))));
    return wrapMultiRemote(elements);
  }
  return itemIn(parent);
}
function proxify(array, state) {
  const proxy = new Proxy(array, {
    get(target, prop, receiver) {
      const current = stateOf(target);
      if (prop === ELEMENT_ARRAY_WRAP) {
        return Reflect.get(target, prop);
      }
      if (prop === WDIO_KIND) {
        return "element-array";
      }
      if (prop === "then") {
        if (current.resolved) {
          return void 0;
        }
        return (onFulfilled, onRejected) => load(target).then(
          () => onFulfilled ? onFulfilled(current.self) : current.self,
          onRejected
        );
      }
      if ((prop === "catch" || prop === "finally") && !current.resolved) {
        return (handler) => {
          const settled = load(target).then(() => current.self);
          return prop === "catch" ? settled.catch(handler) : settled.finally(handler);
        };
      }
      if (prop === "length" && !current.resolved) {
        return load(target).then(() => target.length);
      }
      if (prop === "selector" || prop === "parent" || prop === "foundWith" || prop === "props") {
        return current.metadata[prop];
      }
      if (prop === "isMultiRemote") {
        return current.metadata.isMultiRemote === true;
      }
      if (typeof prop === "string" && /^\d+$/.test(prop)) {
        return readIndex(target, Number(prop));
      }
      if (prop === Symbol.iterator) {
        return function* iterator() {
          if (!stateOf(target).resolved) {
            throw new Error(
              "Cannot synchronously iterate over an element list that has not resolved yet. Use `for await (const el of $$('...')) { ... }` instead."
            );
          }
          yield* Array.prototype[Symbol.iterator].call(target);
        };
      }
      if (prop === Symbol.asyncIterator) {
        return async function* asyncIterator() {
          const items = await load(target);
          yield* items;
        };
      }
      if (typeof prop === "string" && RETURN_SELF.has(prop)) {
        return (...args) => {
          if (!stateOf(target).resolved) {
            throw new Error(`Cannot ${prop} an element list that has not resolved yet`);
          }
          const result = Array.prototype[prop].apply(target, args);
          return result === target ? current.self : result;
        };
      }
      if (typeof prop === "string" && Object.prototype.hasOwnProperty.call(methods, prop)) {
        return methods[prop].bind(target);
      }
      const value = Reflect.get(target, prop, receiver);
      return typeof value === "function" ? value.bind(target) : value;
    },
    /**
     * `parent`, `foundWith` and `getElements` live on the proxy, not the
     * raw array. `in` does not use the get trap, and expect-webdriverio
     * detects an element list with `'getElements' in elements`. Without
     * this, a resolved list looks like a plain array of elements and
     * `elements.map(fn).join()` calls the async map.
     */
    has(target, prop) {
      if (prop === WDIO_KIND || prop === "selector" || prop === "parent" || prop === "foundWith" || prop === "props" || prop === "isMultiRemote" || prop === "getElements") {
        return true;
      }
      if (typeof prop === "string" && (RETURN_SELF.has(prop) || Object.prototype.hasOwnProperty.call(methods, prop))) {
        return true;
      }
      return Reflect.has(target, prop);
    },
    set(target, prop, value) {
      if (prop === "parent" || prop === "selector" || prop === "foundWith" || prop === "props") {
        stateOf(target).metadata[prop] = value;
        return true;
      }
      if (prop === "isMultiRemote") {
        stateOf(target).metadata.isMultiRemote = Boolean(value);
        return true;
      }
      return Reflect.set(target, prop, value, target);
    }
  });
  state.self = proxy;
  proxyStates.set(proxy, state);
  return proxy;
}
function create(elements, loader, metadata) {
  const prepared = prepareMetadata(metadata);
  const array = elements ? [...elements] : [];
  const state = {
    metadata: prepared,
    resolved: Boolean(elements),
    loader,
    wrappers: []
  };
  states.set(array, state);
  Object.defineProperty(array, ELEMENT_ARRAY_WRAP, {
    configurable: false,
    enumerable: false,
    value: (wrapper) => {
      if (state.resolved || state.loading) {
        return;
      }
      state.wrappers.push(wrapper);
    }
  });
  return proxify(array, state);
}
function fromAsyncCallback(loader, metadata) {
  return ElementArray.fromAsyncCallback(loader, metadata);
}
function fromResolved(elements, metadata) {
  return ElementArray.fromResolved(elements, metadata);
}
var states, proxyStates, RETURN_SELF, methods, ElementArray;
var init_array = __esm({
  "src/element/array.ts"() {
    "use strict";
    init_findElementAgain();
    states = /* @__PURE__ */ new WeakMap();
    proxyStates = /* @__PURE__ */ new WeakMap();
    RETURN_SELF = /* @__PURE__ */ new Set(["reverse", "sort", "fill", "copyWithin"]);
    methods = {
      async map(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.map(listForIteration(items), callback, thisArg);
      },
      async mapSeries(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.mapSeries(listForIteration(items), callback, thisArg);
      },
      async filter(callback, thisArg) {
        const state = stateOf(this);
        const items = await load(this);
        const matched = await asyncIterators.filter(listForIteration(items), callback, thisArg);
        return fromResolved(matched, derivedMetadata(state.metadata));
      },
      async filterSeries(callback, thisArg) {
        const state = stateOf(this);
        const items = await load(this);
        const matched = await asyncIterators.filterSeries(listForIteration(items), callback, thisArg);
        return fromResolved(matched, derivedMetadata(state.metadata));
      },
      async forEach(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.forEach(listForIteration(items), callback, thisArg);
      },
      async forEachSeries(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.forEachSeries(listForIteration(items), callback, thisArg);
      },
      async find(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.find(listForIteration(items), callback, thisArg);
      },
      async findSeries(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.findSeries(listForIteration(items), callback, thisArg);
      },
      async findIndex(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.findIndex(listForIteration(items), callback, thisArg);
      },
      async findIndexSeries(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.findIndexSeries(listForIteration(items), callback, thisArg);
      },
      async some(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.some(listForIteration(items), callback, thisArg);
      },
      async someSeries(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.someSeries(listForIteration(items), callback, thisArg);
      },
      async every(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.every(listForIteration(items), callback, thisArg);
      },
      async everySeries(callback, thisArg) {
        const items = await load(this);
        return asyncIterators.everySeries(listForIteration(items), callback, thisArg);
      },
      async reduce(callback, initialValue) {
        const items = await load(this);
        return asyncIterators.reduce(listForIteration(items), callback, initialValue);
      },
      entries() {
        const array = this;
        return (async function* entries() {
          const items = await load(array);
          for (let index = 0; index < items.length; index++) {
            if (index in items) {
              yield [index, items[index]];
            }
          }
        })();
      },
      slice(start, end) {
        const state = stateOf(this);
        if (state.resolved) {
          return fromResolved(Array.prototype.slice.call(this, start, end), derivedMetadata(state.metadata));
        }
        return fromAsyncCallback(async () => {
          const items = await load(this);
          return items.slice(start, end);
        }, derivedMetadata(state.metadata));
      },
      at(index) {
        return readIndex(this, index);
      },
      async getElements() {
        await load(this);
        return stateOf(this).self;
      }
    };
    ElementArray = {
      fromAsyncCallback(loader, metadata) {
        return create(void 0, loader, metadata);
      },
      fromResolved(elements, metadata) {
        return create(elements, void 0, metadata);
      }
    };
    registerElementArrayFactory((loader, metadata) => {
      const chainedMetadata = metadata;
      return ElementArray.fromAsyncCallback(async () => {
        const items = await loader();
        chainedMetadata.wrapMultiRemote ??= proxyStates.get(items)?.metadata.wrapMultiRemote;
        return items;
      }, chainedMetadata);
    });
  }
});

// src/constants.ts
import { UNICODE_CHARACTERS, HOOK_DEFINITION } from "@wdio/utils";
var WDIO_DEFAULTS, FF_REMOTE_DEBUG_ARG, DEEP_SELECTOR, ARIA_SELECTOR, ROLE_SELECTOR, restoreFunctions, Key;
var init_constants = __esm({
  "src/constants.ts"() {
    "use strict";
    WDIO_DEFAULTS = {
      /**
       * allows to specify automation protocol
       */
      automationProtocol: {
        type: "string",
        default: "webdriver",
        validate: (param) => {
          if (typeof param !== "string") {
            throw new Error("automationProtocol should be a string");
          }
          if (typeof import.meta.resolve !== "function") {
            return;
          }
          try {
            import.meta.resolve(param);
          } catch (err) {
            const error = err instanceof Error ? err : new Error("unknown error");
            throw new Error(`Couldn't find automation protocol "${param}": ${error.message}`);
          }
        }
      },
      /**
       * capabilities of WebDriver sessions
       */
      capabilities: {
        type: "object",
        validate: (param) => {
          if (typeof param === "object") {
            return true;
          }
          throw new Error('the "capabilities" options needs to be an object or a list of objects');
        },
        required: true
      },
      /**
       * Shorten navigateTo command calls by setting a base url
       */
      baseUrl: {
        type: "string"
      },
      /**
       * Default interval for all waitFor* commands
       */
      waitforInterval: {
        type: "number",
        default: 100
      },
      /**
       * Default timeout for all waitFor* commands
       */
      waitforTimeout: {
        type: "number",
        default: 5e3
      },
      /**
       * Throw if `$` matches more than one element
       */
      strictSelectors: {
        type: "boolean",
        default: true
      },
      /**
       * Maximum size of the response body (in bytes) that `browser.mock` collects.
       * Use 0 to disable data collection of the spied response payload. Without
       * this entry, `remote()` drops the option in standalone mode.
       */
      maxSpyCollectedBodySize: {
        type: "number",
        validate: (param) => {
          if (!Number.isInteger(param) || param < 0) {
            throw new Error("maxSpyCollectedBodySize should be an integer of 0 or more");
          }
        }
      },
      /**
       * Hooks
       */
      onReload: HOOK_DEFINITION,
      beforeCommand: HOOK_DEFINITION,
      afterCommand: HOOK_DEFINITION
    };
    FF_REMOTE_DEBUG_ARG = "-remote-debugging-port";
    DEEP_SELECTOR = ">>>";
    ARIA_SELECTOR = "aria/";
    ROLE_SELECTOR = "role/";
    restoreFunctions = /* @__PURE__ */ new WeakMap();
    Key = {
      /**
       * Special control key that works cross browser for Mac, where it's the command key, and for
       * Windows or Linux, where it is the control key.
       */
      Ctrl: "WDIO_CONTROL",
      NULL: UNICODE_CHARACTERS.NULL,
      Cancel: UNICODE_CHARACTERS.Cancel,
      Help: UNICODE_CHARACTERS.Help,
      Backspace: UNICODE_CHARACTERS.Backspace,
      Tab: UNICODE_CHARACTERS.Tab,
      Clear: UNICODE_CHARACTERS.Clear,
      Return: UNICODE_CHARACTERS.Return,
      Enter: UNICODE_CHARACTERS.Enter,
      Shift: UNICODE_CHARACTERS.Shift,
      Control: UNICODE_CHARACTERS.Control,
      Alt: UNICODE_CHARACTERS.Alt,
      Pause: UNICODE_CHARACTERS.Pause,
      Escape: UNICODE_CHARACTERS.Escape,
      Space: UNICODE_CHARACTERS.Space,
      PageUp: UNICODE_CHARACTERS.PageUp,
      PageDown: UNICODE_CHARACTERS.PageDown,
      End: UNICODE_CHARACTERS.End,
      Home: UNICODE_CHARACTERS.Home,
      ArrowLeft: UNICODE_CHARACTERS.ArrowLeft,
      ArrowUp: UNICODE_CHARACTERS.ArrowUp,
      ArrowRight: UNICODE_CHARACTERS.ArrowRight,
      ArrowDown: UNICODE_CHARACTERS.ArrowDown,
      Insert: UNICODE_CHARACTERS.Insert,
      Delete: UNICODE_CHARACTERS.Delete,
      Semicolon: UNICODE_CHARACTERS.Semicolon,
      Equals: UNICODE_CHARACTERS.Equals,
      Numpad0: UNICODE_CHARACTERS["Numpad 0"],
      Numpad1: UNICODE_CHARACTERS["Numpad 1"],
      Numpad2: UNICODE_CHARACTERS["Numpad 2"],
      Numpad3: UNICODE_CHARACTERS["Numpad 3"],
      Numpad4: UNICODE_CHARACTERS["Numpad 4"],
      Numpad5: UNICODE_CHARACTERS["Numpad 5"],
      Numpad6: UNICODE_CHARACTERS["Numpad 6"],
      Numpad7: UNICODE_CHARACTERS["Numpad 7"],
      Numpad8: UNICODE_CHARACTERS["Numpad 8"],
      Numpad9: UNICODE_CHARACTERS["Numpad 9"],
      Multiply: UNICODE_CHARACTERS.Multiply,
      Add: UNICODE_CHARACTERS.Add,
      Separator: UNICODE_CHARACTERS.Separator,
      Subtract: UNICODE_CHARACTERS.Subtract,
      Decimal: UNICODE_CHARACTERS.Decimal,
      Divide: UNICODE_CHARACTERS.Divide,
      F1: UNICODE_CHARACTERS.F1,
      F2: UNICODE_CHARACTERS.F2,
      F3: UNICODE_CHARACTERS.F3,
      F4: UNICODE_CHARACTERS.F4,
      F5: UNICODE_CHARACTERS.F5,
      F6: UNICODE_CHARACTERS.F6,
      F7: UNICODE_CHARACTERS.F7,
      F8: UNICODE_CHARACTERS.F8,
      F9: UNICODE_CHARACTERS.F9,
      F10: UNICODE_CHARACTERS.F10,
      F11: UNICODE_CHARACTERS.F11,
      F12: UNICODE_CHARACTERS.F12,
      Command: UNICODE_CHARACTERS.Command,
      ZenkakuHankaku: UNICODE_CHARACTERS.ZenkakuHankaku
    };
  }
});

// src/commands/browser/$$.ts
function $$(selector) {
  const metadata = {
    selector,
    foundWith: "$$",
    parent: this,
    props: []
  };
  return ElementArray.fromAsyncCallback(async () => {
    if (this.isBidi && typeof selector === "string" && !selector.startsWith(DEEP_SELECTOR)) {
      if (globalThis.wdio?.execute) {
        const command = "$$";
        const res3 = "elementId" in this ? await globalThis.wdio.executeWithScope(command, this.elementId, selector) : await globalThis.wdio.execute(command, selector);
        const elements3 = await getElements.call(this, selector, res3);
        metadata.parent = this;
        return elements3;
      }
      const res2 = await findDeepElements.call(this, selector);
      const elements2 = await getElements.call(this, selector, res2);
      metadata.parent = getParent.call(this, res2);
      return elements2;
    }
    let res = Array.isArray(selector) ? selector : await findElements.call(this, selector);
    if (Array.isArray(selector) && isElement(selector[0])) {
      res = [];
      for (const el of selector) {
        const $el = await findElement.call(this, el);
        if ($el) {
          res.push($el);
        }
      }
    }
    const elements = await getElements.call(this, selector, res);
    metadata.parent = getParent.call(this, res);
    return elements;
  }, metadata);
}
function getParent(res) {
  let parent = res.length > 0 ? res[0].parent || this : this;
  if (typeof parent.$ === "undefined") {
    parent = "selector" in parent ? getElement.call(this, parent.selector, parent) : this;
  }
  return parent;
}
var init__ = __esm({
  "src/commands/browser/$$.ts"() {
    "use strict";
    init_utils2();
    init_getElementObject();
    init_utils2();
    init_array();
    init_constants();
  }
});

// src/utils/bidi/constants.ts
var init_constants2 = __esm({
  "src/utils/bidi/constants.ts"() {
    "use strict";
  }
});

// src/commands/constant.ts
var SCRIPT_PREFIX, SCRIPT_SUFFIX, reactScript, accessibilityScript;
var init_constant = __esm({
  "src/commands/constant.ts"() {
    "use strict";
    SCRIPT_PREFIX = "/* __wdio script__ */";
    SCRIPT_SUFFIX = "/* __wdio script end__ */";
    reactScript = '"use strict";(()=>{var l=e=>e instanceof HTMLElement||e instanceof Text,p=e=>typeof e=="object"&&!Array.isArray(e),u=e=>e!==null&&p(e),a=e=>Object.keys(e),b=e=>{var t;if(!e||typeof e=="string")return e;let n={};for(let o of Reflect.ownKeys(e))(t=Object.getOwnPropertyDescriptor(e,o))!=null&&t.enumerable&&(n[o]=e[o]);return delete n.children,n},k=e=>{if(e)return e.baseState||e},w=(e,n)=>Array.isArray(e)&&Array.isArray(n)&&e.some(t=>n.includes(t)),y=(e={},n={})=>{if(!a(e).length)return!0;if(n===null||!a(n).length)return!1;let t=e,o=n,s=a(t).filter(i=>a(o).includes(i)),r=[];for(let i of s)u(t[i])&&u(o[i])&&r.push(y(t[i],o[i])),(t[i]===o[i]||w(t[i],o[i]))&&r.push(o);return r.length>0&&r.filter(Boolean).length===s.length},m=e=>{let n={children:[]};if(!e)return n;let t=e.type;n.name=typeof t=="function"?t.displayName||t.name:t,n.props=b(e.memoizedProps),n.state=k(e.memoizedState);for(let o=e.child;o;o=o.sibling)n.children.push(m(o));return typeof e.type=="function"&&n.children.length>1?(n.node=n.children.flatMap(o=>o.node||[]),n.isFragment=!0):l(e.stateNode)?n.node=e.stateNode:n.node=e.child&&l(e.child.stateNode)?e.child.stateNode:null,n},N=e=>{for(;e.length;){let n=e.shift();if(n.node)return n.node;e.push(...n.children)}},F=(e,n)=>{let t=[...e],o=[];for(;t.length;)for(let s of t.shift().children)n(s)&&(s.node||(s.node=N([...s.children])),o.push(s)),t.push(s);return o},f=(e,n)=>{var s;let t=n;typeof t=="string"&&t.includes("(")&&(t=(s=t.split("(").find(r=>r.includes(")")))==null?void 0:s.replace(/\\)*/g,""));let o=e.split("*").map(r=>r.replace(/([.*+?^=!:${}()|[\\]/\\\\])/g,"\\\\$1")).join(".+");return new RegExp(`^${o}$`).test(t)},h=(e,n,t)=>typeof t=="function"?(console.warn("Functions are not supported as filter matchers"),[]):e.filter(o=>p(t)&&y(t,o[n])||Array.isArray(t)&&w(t,o[n])||o[n]===t),O=(e,n,t,o)=>{let r=e.split(" ").filter(Boolean).map(i=>i.trim()).reduce((i,d)=>F(i,c=>typeof c.name=="string"?f(d,c.name):c.name!==null&&typeof c.name=="object"&&f(d,c.name.displayName)),[m(o)]);return n&&a(n).length&&(r=h(r,"props",n)),t&&a(t).length&&(r=h(r,"state",t)),r},_=e=>e.startsWith("__reactFiber$")||e.startsWith("__reactInternalInstance$")||e.startsWith("__reactContainer$"),j=e=>!!e._reactRootContainer||Object.keys(e).some(n=>n.startsWith("__reactContainer$"));function*g(e){let n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT);for(let t=n.nextNode();t;t=n.nextNode())yield t,t.shadowRoot&&(yield*g(t.shadowRoot))}var E=e=>!!(e&&(e.child||e.alternate&&!e.stateNode.pendingLanes)),T=()=>{let e=[];for(let n of g(document)){let t=j(n)?R(n):void 0;t&&!e.includes(t)&&e.push(t)}return e},R=e=>{let n=e._reactRootContainer;if(n)return(n._internalRoot||n).current;let t=Object.keys(e),o=t.find(r=>r.startsWith("__reactContainer$"))||t.find(_),s=o?e[o]:void 0;for(;s&&s.return;)s=s.return;return s&&s.tag===3?s.stateNode.current:void 0},H=e=>{let n=R(e);if(!n||n.stateNode.containerInfo===e)return n;let t=[n];for(;t.length;){let o=t.pop();if(o.stateNode===e)return o;o.sibling&&t.push(o.sibling),o.child&&t.push(o.child)}};window.__wdioReact={findRoots:T,findFiber:H,isRendered:E,query:O};})();\n';
    accessibilityScript = `"use strict";(()=>{var ge=Object.prototype.toString;function W(e){return typeof e=="function"||ge.call(e)==="[object Function]"}function ve(e){var t=Number(e);return isNaN(t)?0:t===0||!isFinite(t)?t:(t>0?1:-1)*Math.floor(Math.abs(t))}var ye=Math.pow(2,53)-1;function he(e){var t=ve(e);return Math.min(Math.max(t,0),ye)}function c(e,t){var i=Array,n=Object(e);if(e==null)throw new TypeError("Array.from requires an array-like object - not null or undefined");if(typeof t<"u"&&!W(t))throw new TypeError("Array.from: when provided, the second argument must be a function");for(var o=he(n.length),b=W(i)?Object(new i(o)):new Array(o),f=0,d;f<o;)d=n[f],t?b[f]=t(d,f):b[f]=d,f+=1;return b.length=o,b}function N(e){"@babel/helpers - typeof";return N=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},N(e)}function we(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Q(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,X(n.key),n)}}function Se(e,t,i){return t&&Q(e.prototype,t),i&&Q(e,i),Object.defineProperty(e,"prototype",{writable:!1}),e}function Ee(e,t,i){return t=X(t),t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function X(e){var t=xe(e,"string");return N(t)=="symbol"?t:t+""}function xe(e,t){if(N(e)!="object"||!e)return e;var i=e[Symbol.toPrimitive];if(i!==void 0){var n=i.call(e,t||"default");if(N(n)!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}var Ae=(function(){function e(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[];we(this,e),Ee(this,"items",void 0),this.items=t}return Se(e,[{key:"add",value:function(i){return this.has(i)===!1&&this.items.push(i),this}},{key:"clear",value:function(){this.items=[]}},{key:"delete",value:function(i){var n=this.items.length;return this.items=this.items.filter(function(o){return o!==i}),n!==this.items.length}},{key:"forEach",value:function(i){var n=this;this.items.forEach(function(o){i(o,o,n)})}},{key:"has",value:function(i){return this.items.indexOf(i)!==-1}},{key:"size",get:function(){return this.items.length}}])})(),J=typeof Set>"u"?Set:Ae;function s(e){var t;return(t=e.localName)!==null&&t!==void 0?t:e.tagName.toLowerCase()}var Te={article:"article",aside:"complementary",button:"button",datalist:"listbox",dd:"definition",details:"group",dialog:"dialog",dt:"term",fieldset:"group",figure:"figure",form:"form",footer:"contentinfo",h1:"heading",h2:"heading",h3:"heading",h4:"heading",h5:"heading",h6:"heading",header:"banner",hr:"separator",html:"document",legend:"legend",li:"listitem",math:"math",main:"main",menu:"list",nav:"navigation",ol:"list",optgroup:"group",option:"option",output:"status",progress:"progressbar",section:"region",summary:"button",table:"table",tbody:"rowgroup",textarea:"textbox",tfoot:"rowgroup",td:"cell",th:"columnheader",thead:"rowgroup",tr:"row",ul:"list"},Le={caption:new Set(["aria-label","aria-labelledby"]),code:new Set(["aria-label","aria-labelledby"]),deletion:new Set(["aria-label","aria-labelledby"]),emphasis:new Set(["aria-label","aria-labelledby"]),generic:new Set(["aria-label","aria-labelledby","aria-roledescription"]),insertion:new Set(["aria-label","aria-labelledby"]),none:new Set(["aria-label","aria-labelledby"]),paragraph:new Set(["aria-label","aria-labelledby"]),presentation:new Set(["aria-label","aria-labelledby"]),strong:new Set(["aria-label","aria-labelledby"]),subscript:new Set(["aria-label","aria-labelledby"]),superscript:new Set(["aria-label","aria-labelledby"])};function Ne(e,t){return["aria-atomic","aria-busy","aria-controls","aria-current","aria-description","aria-describedby","aria-details","aria-dropeffect","aria-flowto","aria-grabbed","aria-hidden","aria-keyshortcuts","aria-label","aria-labelledby","aria-live","aria-owns","aria-relevant","aria-roledescription"].some(function(i){var n;return e.hasAttribute(i)&&!((n=Le[t])!==null&&n!==void 0&&n.has(i))})}function U(e,t){return Ne(e,t)}function T(e){var t=Re(e);if(t===null||O.indexOf(t)!==-1){var i=Oe(e);if(O.indexOf(t||"")===-1||U(e,i||""))return i}return t}function Oe(e){var t=Te[s(e)];if(t!==void 0)return t;switch(s(e)){case"a":case"area":case"link":if(e.hasAttribute("href"))return"link";break;case"img":return e.getAttribute("alt")===""&&!U(e,"img")?"presentation":"img";case"input":{var i=e,n=i.type;switch(n){case"button":case"image":case"reset":case"submit":return"button";case"checkbox":case"radio":return n;case"range":return"slider";case"email":case"tel":case"text":case"url":return e.hasAttribute("list")?"combobox":"textbox";case"search":return e.hasAttribute("list")?"combobox":"searchbox";case"number":return"spinbutton";default:return null}}case"select":return e.hasAttribute("multiple")||e.size>1?"listbox":"combobox"}return null}function Re(e){var t=e.getAttribute("role");if(t!==null){var i=t.trim().split(" ")[0];if(i.length>0)return i}return null}var O=["presentation","none"];function a(e){return e!==null&&e.nodeType===e.ELEMENT_NODE}function _(e){return a(e)&&s(e)==="caption"}function R(e){return a(e)&&s(e)==="input"}function Y(e){return a(e)&&s(e)==="optgroup"}function Z(e){return a(e)&&s(e)==="select"}function F(e){return a(e)&&s(e)==="table"}function ee(e){return a(e)&&s(e)==="textarea"}function te(e){var t=e.ownerDocument===null?e:e.ownerDocument,i=t.defaultView;if(i===null)throw new TypeError("no window available");return i}function re(e){return a(e)&&s(e)==="fieldset"}function ie(e){return a(e)&&s(e)==="legend"}function ne(e){return a(e)&&s(e)==="slot"}function Ie(e){return a(e)&&e.ownerSVGElement!==void 0}function ae(e){return a(e)&&s(e)==="svg"}function oe(e){return Ie(e)&&s(e)==="title"}function I(e,t){if(a(e)&&e.hasAttribute(t)){var i=e.getAttribute(t).split(" "),n=e.getRootNode?e.getRootNode():e.ownerDocument;return i.map(function(o){return n.getElementById(o)}).filter(function(o){return o!==null})}return[]}function p(e,t){return a(e)?t.indexOf(T(e))!==-1:!1}function Ce(e){return e.trim().replace(/\\s\\s+/g," ")}function Pe(e,t){if(!a(e))return!1;if(e.hasAttribute("hidden")||e.getAttribute("aria-hidden")==="true")return!0;var i=t(e);return i.getPropertyValue("display")==="none"||i.getPropertyValue("visibility")==="hidden"}function Me(e){return p(e,["button","combobox","listbox","textbox"])||se(e,"range")}function se(e,t){if(!a(e))return!1;if(t==="range")return p(e,["meter","progressbar","scrollbar","slider","spinbutton"]);throw new TypeError("No knowledge about abstract role '".concat(t,"'. This is likely a bug :("))}function ue(e,t){var i=c(e.querySelectorAll(t));return I(e,"aria-owns").forEach(function(n){i.push.apply(i,c(n.querySelectorAll(t)))}),i}function je(e){return Z(e)?e.selectedOptions||ue(e,"[selected]"):ue(e,'[aria-selected="true"]')}function _e(e){return p(e,O)}function He(e){return _(e)}function De(e){return p(e,["button","cell","checkbox","columnheader","gridcell","heading","label","legend","link","menuitem","menuitemcheckbox","menuitemradio","option","radio","row","rowheader","switch","tab","tooltip","treeitem"])}function ke(e){return!1}function Ve(e){return R(e)||ee(e)?e.value:e.textContent||""}function le(e){var t=e.getPropertyValue("content");return/^["'].*["']$/.test(t)?t.slice(1,-1):""}function fe(e){var t=s(e);return t==="button"||t==="input"&&e.getAttribute("type")!=="hidden"||t==="meter"||t==="output"||t==="progress"||t==="select"||t==="textarea"}function ce(e){if(fe(e))return e;var t=null;return e.childNodes.forEach(function(i){if(t===null&&a(i)){var n=ce(i);n!==null&&(t=n)}}),t}function Ge(e){if(e.control!==void 0)return e.control;var t=e.getAttribute("for");return t!==null?e.ownerDocument.getElementById(t):ce(e)}function $e(e){var t=e.labels;if(t===null)return t;if(t!==void 0)return c(t);if(!fe(e))return null;var i=e.ownerDocument;return c(i.querySelectorAll("label")).filter(function(n){return Ge(n)===e})}function qe(e){var t=e.assignedNodes();return t.length===0?c(e.childNodes):t}function H(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},i=new J,n=typeof Map>"u"?void 0:new Map,o=te(e),b=t.compute,f=b===void 0?"name":b,d=t.computedStyleSupportsPseudoElements,k=d===void 0?t.getComputedStyle!==void 0:d,V=t.getComputedStyle,C=V===void 0?o.getComputedStyle.bind(o):V,G=t.hidden,pe=G===void 0?!1:G,$=function(u,l){if(l!==void 0)throw new Error("use uncachedGetComputedStyle directly for pseudo elements");if(n===void 0)return C(u);var m=n.get(u);if(m)return m;var g=C(u,l);return n.set(u,g),g};function P(r,u){var l="";if(a(r)&&k){var m=C(r,"::before"),g=le(m);l="".concat(g," ").concat(l)}var y=ne(r)?qe(r):c(r.childNodes).concat(I(r,"aria-owns"));if(y.forEach(function(v){var x=w(v,{isEmbeddedInLabel:u.isEmbeddedInLabel,isReferenced:!1,recursion:!0}),h=a(v)?$(v).getPropertyValue("display"):"inline",L=h!=="inline"?" ":"";l+="".concat(L).concat(x).concat(L)}),a(r)&&k){var S=C(r,"::after"),E=le(S);l="".concat(l," ").concat(E)}return l.trim()}function A(r,u){var l=r.getAttributeNode(u);return l!==null&&!i.has(l)&&l.value.trim()!==""?(i.add(l),l.value):null}function be(r){return a(r)?A(r,"title"):null}function me(r){if(!a(r))return null;if(re(r)){i.add(r);for(var u=c(r.childNodes),l=0;l<u.length;l+=1){var m=u[l];if(ie(m))return w(m,{isEmbeddedInLabel:!1,isReferenced:!1,recursion:!1})}}else if(F(r)){i.add(r);for(var g=c(r.childNodes),y=0;y<g.length;y+=1){var S=g[y];if(_(S))return w(S,{isEmbeddedInLabel:!1,isReferenced:!1,recursion:!1})}}else if(ae(r)){i.add(r);for(var E=c(r.childNodes),v=0;v<E.length;v+=1){var x=E[v];if(oe(x))return x.textContent}return null}else if(s(r)==="img"||s(r)==="area"){var h=A(r,"alt");if(h!==null)return h}else if(Y(r)){var L=A(r,"label");if(L!==null)return L}if(R(r)&&(r.type==="button"||r.type==="submit"||r.type==="reset")){var q=A(r,"value");if(q!==null)return q;if(r.type==="submit")return"Submit";if(r.type==="reset")return"Reset"}var M=$e(r);if(M!==null&&M.length!==0)return i.add(r),c(M).map(function(j){return w(j,{isEmbeddedInLabel:!0,isReferenced:!1,recursion:!0})}).filter(function(j){return j.length>0}).join(" ");if(R(r)&&r.type==="image"){var B=A(r,"alt");if(B!==null)return B;var K=A(r,"title");return K!==null?K:"Submit Query"}if(p(r,["button"])){var z=P(r,{isEmbeddedInLabel:!1,isReferenced:!1});if(z!=="")return z}return null}function w(r,u){if(i.has(r))return"";if(!pe&&Pe(r,$)&&!u.isReferenced)return i.add(r),"";var l=a(r)?r.getAttributeNode("aria-labelledby"):null,m=l!==null&&!i.has(l)?I(r,"aria-labelledby"):[];if(f==="name"&&!u.isReferenced&&m.length>0)return i.add(l),m.map(function(h){return w(h,{isEmbeddedInLabel:u.isEmbeddedInLabel,isReferenced:!0,recursion:!1})}).join(" ");var g=u.recursion&&Me(r)&&f==="name";if(!g){var y=(a(r)&&r.getAttribute("aria-label")||"").trim();if(y!==""&&f==="name")return i.add(r),y;if(!_e(r)){var S=me(r);if(S!==null)return i.add(r),S}}if(p(r,["menu"]))return i.add(r),"";if(g||u.isEmbeddedInLabel||u.isReferenced){if(p(r,["combobox","listbox"])){i.add(r);var E=je(r);return E.length===0?R(r)?r.value:"":c(E).map(function(h){return w(h,{isEmbeddedInLabel:u.isEmbeddedInLabel,isReferenced:!1,recursion:!0})}).join(" ")}if(se(r,"range"))return i.add(r),r.hasAttribute("aria-valuetext")?r.getAttribute("aria-valuetext"):r.hasAttribute("aria-valuenow")?r.getAttribute("aria-valuenow"):r.getAttribute("value")||"";if(p(r,["textbox"]))return i.add(r),Ve(r)}if(De(r)||a(r)&&u.isReferenced||He(r)||ke(r)){var v=P(r,{isEmbeddedInLabel:u.isEmbeddedInLabel,isReferenced:!1});if(v!=="")return i.add(r),v}if(r.nodeType===r.TEXT_NODE)return i.add(r),r.textContent||"";if(u.recursion)return i.add(r),P(r,{isEmbeddedInLabel:u.isEmbeddedInLabel,isReferenced:!1});var x=be(r);return x!==null?(i.add(r),x):(i.add(r),"")}return Ce(w(e,{isEmbeddedInLabel:!1,isReferenced:f==="description",recursion:!1}))}function Be(e){return p(e,["caption","code","deletion","emphasis","generic","insertion","none","paragraph","presentation","strong","subscript","superscript"])}function D(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return Be(e)?"":H(e,t)}function de(e){var t,i=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=i.getComputedStyle,o=n===void 0?(t=e.ownerDocument.defaultView)===null||t===void 0?void 0:t.getComputedStyle:n,b=i.isSubtreeInaccessible,f=b===void 0?Ke:b;if(typeof o!="function")throw new TypeError("Owner document of the element needs to have an associated window.");if(o(e).visibility==="hidden")return!0;for(var d=e;d;){if(f(d,{getComputedStyle:o}))return!0;d=d.parentElement}return!1}function Ke(e){var t,i=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=i.getComputedStyle,o=n===void 0?(t=e.ownerDocument.defaultView)===null||t===void 0?void 0:t.getComputedStyle:n;if(typeof o!="function")throw new TypeError("Owner document of the element needs to have an associated window.");return e.hidden===!0||e.getAttribute("aria-hidden")==="true"||o(e).display==="none"}window.__wdioA11y={computeAccessibleName:D,getRole:T,isInaccessible:de};})();
`;
  }
});

// src/utils/bidi/error.ts
var WebdriverBidiExeception;
var init_error = __esm({
  "src/utils/bidi/error.ts"() {
    "use strict";
    init_constant();
    WebdriverBidiExeception = class extends Error {
      #params;
      #result;
      constructor(params, result) {
        super(result.exceptionDetails.text);
        this.name = "WebdriverBidiExeception";
        this.#params = params;
        this.#result = result;
        this.stack = this.#getCustomStack();
      }
      #getCustomStack() {
        const origStack = this.stack;
        const failureLine = this.#getFailureLine();
        const stack = origStack?.split("\n") || [];
        let wrapCommandIndex = -1;
        for (let i = stack.length - 1; i >= 0; i--) {
          if (stack[i].includes("Context.executeAsync")) {
            wrapCommandIndex = i;
            break;
          }
        }
        const executeLine = stack[wrapCommandIndex - 1];
        if (failureLine && executeLine) {
          const line = executeLine.replace("file://", "").split(":");
          const row = line.length > 3 ? line[2] : line[1];
          const [errorMessage2, ...restOfStack] = stack;
          const linePrefix = `      ${row} \u2502 `;
          const codeLine = [
            linePrefix + failureLine,
            " ".repeat(linePrefix.length - 2) + "\u2575 " + "~".repeat(failureLine.length),
            ""
          ];
          return [errorMessage2, executeLine, ...codeLine, ...restOfStack].join("\n");
        }
        return origStack;
      }
      /**
       * This is an attempt to identify the snippet of code that caused an execute(Async) function to
       * throw an exception
       * @param {string} script       script that executed in the browser
       * @param {number} columnNumber column in which the scrpt threw an exception
       * @returns the line of failure in which the code threw an exception or `undefined` if we could not find it
       */
      #getFailureLine() {
        const script = this.#params.functionDeclaration;
        const exceptionDetails = this.#result.exceptionDetails;
        const userScript = script.split("\n").find((l) => l.includes(SCRIPT_PREFIX));
        if (!userScript) {
          return;
        }
        let length = 0;
        const isMinified = script.split("\n").some((line) => line.includes(SCRIPT_PREFIX) && line.includes(SCRIPT_SUFFIX));
        if (isMinified) {
          for (const line of userScript.split(";")) {
            if (length + line.length >= exceptionDetails.columnNumber) {
              return line.includes(SCRIPT_SUFFIX) ? line.slice(0, line.indexOf(SCRIPT_SUFFIX)) : line;
            }
            length += line.length;
          }
        } else {
          const slicedScript = script.slice(
            script.indexOf(SCRIPT_PREFIX) + SCRIPT_PREFIX.length,
            script.indexOf(SCRIPT_SUFFIX)
          );
          const lineDiff = 9;
          const line = slicedScript.split("\n")[exceptionDetails.lineNumber - lineDiff]?.slice(exceptionDetails.columnNumber);
          return line;
        }
        return void 0;
      }
    };
  }
});

// src/utils/base64.ts
function encodeBase64(bytes) {
  if (typeof Buffer !== "undefined") {
    return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
  }
  let binary = "";
  for (let offset = 0; offset < bytes.length; offset += 32768) {
    binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
  }
  return btoa(binary);
}
function decodeBase64(value) {
  if (typeof Buffer !== "undefined") {
    return Buffer.from(value, "base64");
  }
  return Uint8Array.from(atob(value), (byte) => byte.charCodeAt(0));
}
var init_base64 = __esm({
  "src/utils/base64.ts"() {
    "use strict";
  }
});

// src/utils/bidi/serialize.ts
function createBidiFunctionDeclaration(script) {
  const userScript = typeof script === "string" ? new Function(script) : script;
  const declaration = new Function(
    `return (${SCRIPT_PREFIX}${userScript.toString()}${SCRIPT_SUFFIX}).apply(this, arguments);`
  ).toString();
  const markerIndex = declaration.indexOf(SCRIPT_PREFIX);
  const returnIndex = declaration.lastIndexOf("return (", markerIndex);
  const suffixIndex = declaration.indexOf(SCRIPT_SUFFIX);
  const applyToken = ").apply(this, arguments);";
  const applyIndex = declaration.indexOf(applyToken, suffixIndex);
  if (returnIndex === -1 || applyIndex === -1) {
    throw new Error("Unable to wrap BiDi execute script");
  }
  const resultPrefix = "const __wdioResult = (";
  const withResult = declaration.slice(0, returnIndex) + resultPrefix + declaration.slice(returnIndex + "return (".length);
  const applyEnd = applyIndex + (resultPrefix.length - "return (".length) + applyToken.length;
  return withResult.slice(0, applyEnd) + `
${SERIALIZER_HELPER}
return Promise.resolve(__wdioResult).then((value) => __wdioSerializeValue(value, new WeakSet()));
` + withResult.slice(applyEnd);
}
function decodedByteLength(data) {
  if (data.length === 0) {
    return 0;
  }
  const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
  return data.length / 4 * 3 - padding;
}
function isSerializedBlobValue(value) {
  if (typeof value !== "object" || value === null) {
    return false;
  }
  const serialized = value;
  if (serialized[SERIALIZED_BLOB_KEY] !== true) {
    return false;
  }
  if (serialized.kind !== SERIALIZED_BLOB_KIND_BLOB && serialized.kind !== SERIALIZED_BLOB_KIND_FILE) {
    return false;
  }
  const allowedKeys = serialized.kind === SERIALIZED_BLOB_KIND_FILE ? FILE_TRANSFER_KEYS : BLOB_TRANSFER_KEYS;
  if (!Object.keys(serialized).every((key) => allowedKeys.has(key))) {
    return false;
  }
  if (typeof serialized.data !== "string" || !BASE64_PATTERN.test(serialized.data)) {
    return false;
  }
  if (typeof serialized.type !== "string") {
    return false;
  }
  if (typeof serialized.size !== "number" || !Number.isInteger(serialized.size) || serialized.size < 0) {
    return false;
  }
  if (decodedByteLength(serialized.data) !== serialized.size) {
    return false;
  }
  if (serialized.name !== void 0 && typeof serialized.name !== "string") {
    return false;
  }
  if (serialized.lastModified !== void 0 && typeof serialized.lastModified !== "number") {
    return false;
  }
  if (serialized.props !== void 0) {
    if (typeof serialized.props !== "object" || serialized.props === null || Array.isArray(serialized.props)) {
      return false;
    }
  }
  return true;
}
function createBlobFromSerializedValue(value) {
  const bytes = decodeBase64(value.data);
  let blob;
  if (value.kind === SERIALIZED_BLOB_KIND_FILE && typeof File === "function") {
    blob = new File([bytes], value.name ?? "file", {
      type: value.type,
      lastModified: typeof value.lastModified === "number" ? value.lastModified : Date.now()
    });
  } else if (typeof Blob === "function") {
    blob = new Blob([bytes], { type: value.type });
  } else {
    blob = bytes;
  }
  if (value.props) {
    const target = blob;
    for (const [key, prop] of Object.entries(value.props)) {
      try {
        target[key] = prop;
      } catch {
      }
    }
  }
  return blob;
}
var SERIALIZED_BLOB_KEY, SERIALIZED_BLOB_KIND_BLOB, SERIALIZED_BLOB_KIND_FILE, BASE64_PATTERN, BLOB_TRANSFER_KEYS, FILE_TRANSFER_KEYS, BASE64_CHUNK_SIZE, SERIALIZER_HELPER;
var init_serialize = __esm({
  "src/utils/bidi/serialize.ts"() {
    "use strict";
    init_constant();
    init_base64();
    SERIALIZED_BLOB_KEY = "__wdioSerializedBlob__";
    SERIALIZED_BLOB_KIND_BLOB = "blob";
    SERIALIZED_BLOB_KIND_FILE = "file";
    BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
    BLOB_TRANSFER_KEYS = /* @__PURE__ */ new Set(["data", "type", "size", "kind", "props", SERIALIZED_BLOB_KEY]);
    FILE_TRANSFER_KEYS = /* @__PURE__ */ new Set([...BLOB_TRANSFER_KEYS, "name", "lastModified"]);
    BASE64_CHUNK_SIZE = 24576;
    SERIALIZER_HELPER = `
    const __wdioSerializedBlobKey = ${JSON.stringify(SERIALIZED_BLOB_KEY)};
    const __wdioSerializedBlobKindBlob = ${JSON.stringify(SERIALIZED_BLOB_KIND_BLOB)};
    const __wdioSerializedBlobKindFile = ${JSON.stringify(SERIALIZED_BLOB_KIND_FILE)};
    const __wdioCycle = Object.create(null);

    function __wdioTag(value) {
        return Object.prototype.toString.call(value);
    }

    function __wdioIsIndexKey(key) {
        return String(Number(key)) === key && Number.isInteger(Number(key)) && Number(key) >= 0;
    }

    function __wdioHostValue(value, key) {
        let proto = Object.getPrototypeOf(value);
        while (proto) {
            const desc = Object.getOwnPropertyDescriptor(proto, key);
            if (desc) {
                return typeof desc.get === 'function' ? desc.get.call(value) : desc.value;
            }
            proto = Object.getPrototypeOf(proto);
        }
        return value[key];
    }

    function __wdioIsBlob(value) {
        const tag = __wdioTag(value);
        if (tag !== '[object Blob]' && tag !== '[object File]') {
            return false;
        }
        if (typeof value.arrayBuffer !== 'function' || typeof value.size !== 'number' || typeof value.type !== 'string') {
            return false;
        }
        // A real Blob/File, including one from another realm, inherits its brand.
        // An object that sets the brand itself is user data.
        return !Object.prototype.hasOwnProperty.call(value, Symbol.toStringTag);
    }

    function __wdioIsFileList(value) {
        if (__wdioTag(value) !== '[object FileList]' || typeof value.length !== 'number') {
            return false;
        }
        return !Object.prototype.hasOwnProperty.call(value, Symbol.toStringTag);
    }

    function __wdioArrayBufferToBase64(buffer) {
        if (typeof btoa !== 'function') {
            throw new Error('Unable to encode Blob data: btoa is not available');
        }
        const bytes = new Uint8Array(buffer);
        const chunkSize = ${BASE64_CHUNK_SIZE};
        const parts = [];
        for (let offset = 0; offset < bytes.length; offset += chunkSize) {
            const chunk = bytes.subarray(offset, offset + chunkSize);
            const binary = Array.from(chunk, (byte) => String.fromCharCode(byte)).join('');
            parts.push(btoa(binary));
        }
        return parts.join('');
    }

    async function __wdioSerializeBlob(blob, seen) {
        const base64 = __wdioArrayBufferToBase64(await blob.arrayBuffer());
        const serialized = {
            [__wdioSerializedBlobKey]: true,
            data: base64,
            type: __wdioHostValue(blob, 'type') || '',
            size: __wdioHostValue(blob, 'size'),
            kind: __wdioSerializedBlobKindBlob
        };
        if (__wdioTag(blob) === '[object File]') {
            serialized.kind = __wdioSerializedBlobKindFile;
            serialized.name = __wdioHostValue(blob, 'name');
            serialized.lastModified = __wdioHostValue(blob, 'lastModified');
        }
        const propKeys = Object.keys(blob).filter((key) => (
            key !== 'size' && key !== 'type' &&
            (serialized.kind !== __wdioSerializedBlobKindFile || (key !== 'name' && key !== 'lastModified'))
        ));
        if (propKeys.length) {
            seen.add(blob);
            try {
                const props = {};
                for (const key of propKeys) {
                    const next = await __wdioSerializeValue(blob[key], seen);
                    props[key] = next === __wdioCycle ? null : next;
                }
                serialized.props = props;
            } finally {
                seen.delete(blob);
            }
        }
        return serialized;
    }

    function __wdioIsHostValue(value) {
        if (typeof Node !== 'undefined' && value instanceof Node) {
            return true;
        }
        if (typeof Window !== 'undefined' && value instanceof Window) {
            return true;
        }
        if (value instanceof Date || value instanceof RegExp) {
            return true;
        }
        if (typeof ArrayBuffer !== 'undefined' && (value instanceof ArrayBuffer || ArrayBuffer.isView(value))) {
            return true;
        }
        if (typeof Error !== 'undefined' && value instanceof Error) {
            return true;
        }
        if (typeof Promise !== 'undefined' && value instanceof Promise) {
            return true;
        }
        return false;
    }

    async function __wdioSerializeEntries(entries, seen) {
        let changed = false;
        const copy = [];
        for (const entry of entries) {
            const next = await __wdioSerializeValue(entry, seen);
            if (next === __wdioCycle) {
                copy.push(null);
                continue;
            }
            if (next !== entry) {
                changed = true;
            }
            copy.push(next);
        }
        return { changed, copy };
    }

    async function __wdioSerializeValue(value, seen) {
        if (value === null || typeof value !== 'object') {
            return value;
        }
        if (seen.has(value)) {
            return __wdioCycle;
        }
        if (__wdioIsBlob(value)) {
            return __wdioSerializeBlob(value, seen);
        }
        if (__wdioIsHostValue(value)) {
            return value;
        }

        seen.add(value);
        try {
            if (__wdioIsFileList(value)) {
                const listed = [];
                for (let i = 0; i < value.length; i++) {
                    listed.push(value[i]);
                }
                const { changed, copy } = await __wdioSerializeEntries(listed, seen);
                const extras = {};
                let hasExtras = false;
                for (const key of Object.keys(value)) {
                    if (key === 'length' || __wdioIsIndexKey(key)) {
                        continue;
                    }
                    hasExtras = true;
                    const next = await __wdioSerializeValue(value[key], seen);
                    extras[key] = next === __wdioCycle ? null : next;
                }
                if (!changed && !hasExtras) {
                    return value;
                }
                const result = changed ? copy : listed.slice();
                Object.assign(result, extras);
                return result;
            }
            if (typeof Map !== 'undefined' && value instanceof Map) {
                let changed = false;
                const entries = [];
                for (const [key, entry] of value) {
                    const nextKey = await __wdioSerializeValue(key, seen);
                    const nextValue = await __wdioSerializeValue(entry, seen);
                    if ((nextKey !== __wdioCycle && nextKey !== key) || (nextValue !== __wdioCycle && nextValue !== entry)) {
                        changed = true;
                    }
                    entries.push([
                        nextKey === __wdioCycle ? null : nextKey,
                        nextValue === __wdioCycle ? null : nextValue
                    ]);
                }
                return changed ? new Map(entries) : value;
            }
            if (typeof Set !== 'undefined' && value instanceof Set) {
                const { changed, copy } = await __wdioSerializeEntries(value, seen);
                return changed ? new Set(copy) : value;
            }
            if (Array.isArray(value)) {
                const { changed, copy } = await __wdioSerializeEntries(value, seen);
                return changed ? copy : value;
            }

            let changed = false;
            const copy = {};
            for (const key of Object.keys(value)) {
                const next = await __wdioSerializeValue(value[key], seen);
                if (next === __wdioCycle) {
                    copy[key] = null;
                    continue;
                }
                if (next !== value[key]) {
                    changed = true;
                }
                copy[key] = next;
            }
            return changed ? copy : value;
        } finally {
            seen.delete(value);
        }
    }
`;
  }
});

// src/utils/bidi/value.ts
import { ELEMENT_KEY as ELEMENT_KEY4, SHADOW_ELEMENT_KEY } from "webdriver";
var TYPE_CONSTANT, VALUE_CONSTANT, LocalValue, ReferenceValue;
var init_value = __esm({
  "src/utils/bidi/value.ts"() {
    "use strict";
    init_constants2();
    TYPE_CONSTANT = "type";
    VALUE_CONSTANT = "value";
    LocalValue = class _LocalValue {
      type;
      value;
      constructor(type, value) {
        if (type === "undefined" /* Undefined */ || type === "null" /* Null */) {
          this.type = type;
        } else {
          this.type = type;
          this.value = value;
        }
      }
      /**
       * Creates a new LocalValue object with a string value.
       *
       * @param {string} value - The string value to be stored in the LocalValue object.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createStringValue(value) {
        return new _LocalValue("string" /* String */, value);
      }
      /**
       * Creates a new LocalValue object with a number value.
       *
       * @param {number} value - The number value.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createNumberValue(value) {
        return new _LocalValue("number" /* Number */, value);
      }
      /**
       * Creates a new LocalValue object with a special number value.
       *
       * @param {number} value - The value of the special number.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createSpecialNumberValue(value) {
        if (Number.isNaN(value)) {
          return new _LocalValue("number" /* SpecialNumber */, "NaN");
        }
        if (Object.is(value, -0)) {
          return new _LocalValue("number" /* SpecialNumber */, "-0");
        }
        if (value === Infinity) {
          return new _LocalValue("number" /* SpecialNumber */, "Infinity");
        }
        if (value === -Infinity) {
          return new _LocalValue("number" /* SpecialNumber */, "-Infinity");
        }
        return new _LocalValue("number" /* SpecialNumber */, value);
      }
      /**
       * Creates a new LocalValue object with an undefined value.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createUndefinedValue() {
        return new _LocalValue("undefined" /* Undefined */);
      }
      /**
       * Creates a new LocalValue object with a null value.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createNullValue() {
        return new _LocalValue("null" /* Null */);
      }
      /**
       * Creates a new LocalValue object with a boolean value.
       *
       * @param {boolean} value - The boolean value.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createBooleanValue(value) {
        return new _LocalValue("boolean" /* Boolean */, value);
      }
      /**
       * Creates a new LocalValue object with a BigInt value.
       *
       * @param {BigInt} value - The BigInt value.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createBigIntValue(value) {
        return new _LocalValue("bigint" /* BigInt */, value);
      }
      /**
       * Creates a new LocalValue object with an array.
       *
       * @param {Array} value - The array.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createArrayValue(value) {
        return new _LocalValue("array" /* Array */, value);
      }
      /**
       * Creates a new LocalValue object with date value.
       *
       * @param {string} value - The date.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createDateValue(value) {
        return new _LocalValue("date" /* Date */, value);
      }
      /**
       * Creates a new LocalValue object of map value.
       * @param {Map} map - The map.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createMapValue(map) {
        const value = [];
        Object.entries(map).forEach((entry) => {
          value.push(entry);
        });
        return new _LocalValue("map" /* Map */, value);
      }
      /**
       * Creates a new LocalValue object from the passed object.
       *
       * @param {Object} map - The object.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createObjectValue(object) {
        const value = [];
        Object.entries(object).forEach(([key, val]) => {
          value.push([key, _LocalValue.getArgument(val)]);
        });
        return new _LocalValue("object" /* Object */, value);
      }
      /**
       * Creates a new LocalValue object of regular expression value.
       *
       * @param {string} value - The value of the regular expression.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createRegularExpressionValue(value) {
        return new _LocalValue("regexp" /* RegularExpression */, value);
      }
      /**
       * Creates a new LocalValue object with the specified value.
       * @param {Set} value - The value to be set.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createSetValue(value) {
        return new _LocalValue("set" /* Set */, value);
      }
      /**
       * Creates a new LocalValue object with the given channel value
       *
       * @param {ChannelValue} value - The channel value.
       * @returns {LocalValue} - The created LocalValue object.
       */
      static createChannelValue(value) {
        return new _LocalValue("channel" /* Channel */, value);
      }
      static createReferenceValue(handle, sharedId) {
        return new ReferenceValue(handle, sharedId);
      }
      static getArgument(argument) {
        const type = typeof argument;
        switch (type) {
          case "string" /* String */:
            return _LocalValue.createStringValue(argument);
          case "number" /* Number */:
            if (Number.isNaN(argument) || Object.is(argument, -0) || !Number.isFinite(argument)) {
              return _LocalValue.createSpecialNumberValue(argument);
            }
            return _LocalValue.createNumberValue(argument);
          case "boolean" /* Boolean */:
            return _LocalValue.createBooleanValue(argument);
          case "bigint" /* BigInt */:
            return _LocalValue.createBigIntValue(argument);
          case "undefined" /* Undefined */:
            return _LocalValue.createUndefinedValue();
          case "object" /* Object */:
            if (argument === null) {
              return _LocalValue.createNullValue();
            }
            if (argument instanceof Date) {
              return _LocalValue.createDateValue(argument);
            }
            if (argument instanceof Map) {
              const map = [];
              argument.forEach((value, key) => {
                const objectKey = typeof key === "string" ? key : _LocalValue.getArgument(key);
                const objectValue = _LocalValue.getArgument(value);
                map.push([objectKey, objectValue]);
              });
              return new _LocalValue("map" /* Map */, map);
            }
            if (argument instanceof Set) {
              const set = [];
              argument.forEach((value) => {
                set.push(_LocalValue.getArgument(value));
              });
              return _LocalValue.createSetValue(set);
            }
            if (argument instanceof Array) {
              const arr = [];
              Array.prototype.forEach.call(argument, (value) => {
                arr.push(_LocalValue.getArgument(value));
              });
              return _LocalValue.createArrayValue(arr);
            }
            if (argument instanceof RegExp) {
              return _LocalValue.createRegularExpressionValue({
                pattern: argument.source,
                flags: argument.flags
              });
            }
            if (argument && ELEMENT_KEY4 in argument) {
              return _LocalValue.createReferenceValue(
                "sharedId" /* SharedId */,
                argument[ELEMENT_KEY4]
              );
            }
            if (argument && SHADOW_ELEMENT_KEY in argument) {
              return _LocalValue.createReferenceValue(
                "sharedId" /* SharedId */,
                argument[SHADOW_ELEMENT_KEY]
              );
            }
            return _LocalValue.createObjectValue(argument);
        }
        throw new Error(`Unsupported type: ${type}`);
      }
      asMap() {
        return {
          [TYPE_CONSTANT]: this.type,
          ...!(this.type === "null" /* Null */ || this.type === "undefined" /* Undefined */) ? { [VALUE_CONSTANT]: this.value } : {}
        };
      }
    };
    ReferenceValue = class {
      handle;
      sharedId;
      /**
       * Constructs a new ReferenceValue object.
       * @param {string} handle - The handle value.
       * @param {string} sharedId - The shared ID value.
       */
      constructor(handle, sharedId) {
        if (handle === "handle" /* Handle */) {
          this.handle = sharedId;
        } else if (handle === "sharedId" /* SharedId */) {
          this.sharedId = sharedId;
        } else {
          this.handle = handle;
          this.sharedId = sharedId;
        }
      }
      asMap() {
        const toReturn = {};
        if (typeof this.handle !== "undefined") {
          toReturn["handle" /* Handle */] = this.handle;
        }
        if (typeof this.sharedId !== "undefined") {
          toReturn["sharedId" /* SharedId */] = this.sharedId;
        }
        return toReturn;
      }
    };
  }
});

// src/utils/bidi/index.ts
import { ELEMENT_KEY as ELEMENT_KEY5, SHADOW_ELEMENT_KEY as SHADOW_ELEMENT_KEY2 } from "webdriver";
async function executeInContext(browser, context, script, ...args) {
  const params = {
    functionDeclaration: createBidiFunctionDeclaration(script),
    awaitPromise: true,
    arguments: args.map((arg) => LocalValue.getArgument(arg)),
    target: { context }
  };
  const result = await browser.scriptCallFunction(params);
  return parseScriptResult(params, result);
}
function parseScriptResult(params, result) {
  const type = result.type;
  if (type === "success" /* Success */) {
    return deserialize(result.result);
  }
  if (type === "exception" /* Exception */) {
    throw new WebdriverBidiExeception(params, result);
  }
  throw new Error(`Unknown evaluate result type: ${type}`);
}
function deserialize(result) {
  const deserializedValue = deserializeValue(result);
  references.clear();
  return deserializedValue;
}
function deserializeValue(result) {
  if (result && "internalId" in result && typeof result.internalId === "string") {
    if ("value" in result) {
      references.set(result.internalId, result.value);
    } else {
      result.value = references.get(result.internalId);
    }
  }
  const { type, value } = result;
  if (type === "regexp" /* RegularExpression */) {
    return new RegExp(value.pattern, value.flags);
  }
  if (type === "array" /* Array */ || type === "nodelist" /* NodeList */ || type === "htmlcollection" /* HTMLCollection */) {
    return value.map((element) => deserializeValue(element));
  }
  if (type === "date" /* Date */) {
    return new Date(value);
  }
  if (type === "map" /* Map */) {
    return new Map(value.map(([key, value2]) => [typeof key === "string" ? key : deserializeValue(key), deserializeValue(value2)]));
  }
  if (type === "set" /* Set */) {
    return new Set(value.map((element) => deserializeValue(element)));
  }
  if (type === "number" /* Number */ && value === "NaN") {
    return NaN;
  }
  if (type === "number" /* Number */ && value === "Infinity") {
    return Infinity;
  }
  if (type === "number" /* Number */ && value === "-Infinity") {
    return -Infinity;
  }
  if (type === "number" /* Number */ && value === "-0") {
    return -0;
  }
  if (type === "bigint" /* BigInt */) {
    return BigInt(value);
  }
  if (type === "null" /* Null */) {
    return null;
  }
  if (type === "object" /* Object */) {
    const obj = Object.fromEntries((value || []).map(([key, value2]) => {
      return [typeof key === "string" ? key : deserializeValue(key), deserializeValue(value2)];
    }));
    if (isSerializedBlobValue(obj)) {
      return createBlobFromSerializedValue(obj);
    }
    return obj;
  }
  if (type === "node" /* Node */) {
    return deserializeNode(result);
  }
  if (type === "error" /* Error */) {
    return new Error("<unserializable error>");
  }
  return value;
}
function deserializeNode(node) {
  const props = node.value;
  if (!props || props.nodeType === ELEMENT_NODE || props.nodeType === DOCUMENT_NODE) {
    return { [ELEMENT_KEY5]: node.sharedId };
  }
  if (props.nodeType === DOCUMENT_FRAGMENT_NODE && props.mode) {
    return { [SHADOW_ELEMENT_KEY2]: node.sharedId };
  }
  return { ...props };
}
var references, ELEMENT_NODE, DOCUMENT_NODE, DOCUMENT_FRAGMENT_NODE;
var init_bidi = __esm({
  "src/utils/bidi/index.ts"() {
    "use strict";
    init_constants2();
    init_error();
    init_serialize();
    init_value();
    references = /* @__PURE__ */ new Map();
    ELEMENT_NODE = 1;
    DOCUMENT_NODE = 9;
    DOCUMENT_FRAGMENT_NODE = 11;
  }
});

// src/utils/elementChecks.ts
import { ELEMENT_KEY as ELEMENT_KEY6 } from "webdriver";
import logger4 from "@wdio/logger";
import elementContains from "./scripts/elementContains.js";
import elementsContainedIn from "./scripts/elementsContainedIn.js";
import elementsConnected from "./scripts/elementsConnected.js";
function run(browser, contextId) {
  return (script, ...args) => contextId && browser.isBidi ? executeInContext(browser, contextId, script, ...args) : browser.execute(script, ...args);
}
async function runBatchedElementCheck(elementIds, checkName, contextId, onElementCheckError, batchCheck, perElementCheck) {
  if (elementIds.length === 0) {
    return [];
  }
  const inContext = contextId ? ` in context ${contextId}` : "";
  try {
    const result = await batchCheck();
    if (!Array.isArray(result) || result.length !== elementIds.length) {
      throw new Error(`expected ${elementIds.length} result(s) but got ${Array.isArray(result) ? result.length : typeof result}`);
    }
    return result;
  } catch (err) {
    log4.warn(`Failed to batch-check element ${checkName}${inContext}: ${err.message}. Falling back to per-element checks.`);
  }
  return Promise.all(elementIds.map(async (elementId) => {
    try {
      return await perElementCheck(elementId);
    } catch (err) {
      log4.warn(`Failed to check element ${checkName} for element ${elementId}${inContext}: ${err.message}`);
      onElementCheckError?.(elementId);
      return false;
    }
  }));
}
async function checkElementsContainedIn(browser, scope, elementIds, contextId, onElementCheckError) {
  return runBatchedElementCheck(
    elementIds,
    `containment for scope ${scope}`,
    contextId,
    onElementCheckError,
    () => run(browser, contextId)(
      elementsContainedIn,
      { [ELEMENT_KEY6]: scope },
      elementIds.map((elementId) => ({ [ELEMENT_KEY6]: elementId }))
    ),
    (elementId) => run(browser, contextId)(
      elementContains,
      { [ELEMENT_KEY6]: scope },
      { [ELEMENT_KEY6]: elementId }
    )
  );
}
async function checkElementsConnected(browser, elementIds, contextId, onElementCheckError) {
  return runBatchedElementCheck(
    elementIds,
    "connectivity",
    contextId,
    onElementCheckError,
    () => run(browser, contextId)(
      elementsConnected,
      elementIds.map((elementId) => ({ [ELEMENT_KEY6]: elementId }))
    ),
    (elementId) => run(browser, contextId)(
      (el) => el.isConnected,
      { [ELEMENT_KEY6]: elementId }
    )
  );
}
var log4;
var init_elementChecks = __esm({
  "src/utils/elementChecks.ts"() {
    "use strict";
    init_bidi();
    log4 = logger4("webdriverio");
  }
});

// src/session/shadowRoot.ts
import logger5 from "@wdio/logger";
import customElementWrapper from "./scripts/customElement.js";
function getShadowRootManager(browser) {
  return SessionManager.getSessionManager(browser, ShadowRootManager);
}
var log5, ShadowRootManager, ShadowRootTree;
var init_shadowRoot = __esm({
  "src/session/shadowRoot.ts"() {
    "use strict";
    init_session();
    init_elementChecks();
    log5 = logger5("webdriverio:ShadowRootManager");
    ShadowRootManager = class _ShadowRootManager extends SessionManager {
      #browser;
      #initialize;
      #shadowRoots = /* @__PURE__ */ new Map();
      #currentDocumentIds = /* @__PURE__ */ new Map();
      #documentElements = /* @__PURE__ */ new Map();
      #frameDepth = 0;
      #handleLogEntryListener = this.handleLogEntry.bind(this);
      #commandResultHandlerListener = this.#commandResultHandler.bind(this);
      #handleNavigationCommittedListener = this.#handleNavigationCommitted.bind(this);
      constructor(browser) {
        super(browser, _ShadowRootManager.name);
        this.#browser = browser;
        if (!this.isEnabled()) {
          this.#initialize = Promise.resolve(true);
          return;
        }
        this.#initialize = this.#browser.sessionSubscribe({
          events: ["log.entryAdded", "browsingContext.navigationCommitted"]
        }).then(() => true, () => false);
        this.#browser.on("log.entryAdded", this.#handleLogEntryListener);
        this.#browser.on("result", this.#commandResultHandlerListener);
        this.#browser.on("browsingContext.navigationCommitted", this.#handleNavigationCommittedListener);
        this.#browser.scriptAddPreloadScript({
          functionDeclaration: customElementWrapper.toString()
        }).catch((err) => {
          log5.warn(`Could not register shadow root preload script, shadow DOM will not be pierced in this session: ${err.message}`);
        });
      }
      removeListeners() {
        super.removeListeners();
        this.#browser.off("log.entryAdded", this.#handleLogEntryListener);
        this.#browser.off("result", this.#commandResultHandlerListener);
        this.#browser.off("browsingContext.navigationCommitted", this.#handleNavigationCommittedListener);
      }
      async initialize() {
        return this.#initialize;
      }
      #handleNavigationCommitted({ context }) {
        this.#clearContext(context);
      }
      /**
       * Forget a tracked node that turned out to be gone. The root of the tree
       * or the document element stands for the whole document, which happens
       * when a page is shown again without a `navigationCommitted` event (e.g.
       * restored from Firefox's back-forward cache). Any other node only takes
       * its own subtree along, so roots registered for the current document stay.
       */
      forgetNode(context, node) {
        const tree = this.#shadowRoots.get(context);
        if (!tree || tree.element === node || tree.shadowRoot === node || this.#documentElements.get(context)?.sharedId === node) {
          this.#clearContext(context);
          return;
        }
        const owner = tree.flat().find((entry) => entry.element === node || entry.shadowRoot === node);
        if (owner) {
          tree.remove(owner.element);
        }
      }
      #clearContext(context) {
        this.#shadowRoots.delete(context);
        this.#currentDocumentIds.delete(context);
        this.#documentElements.delete(context);
      }
      /**
       * keep track of frame depth
       */
      #commandResultHandler(result) {
        const noResultError = typeof result.result === "object" && result.result && "error" in result.result && !result.result.error;
        if (result.command === "switchToFrame" && noResultError) {
          this.#frameDepth++;
        }
        if (result.command === "switchToParentFrame" && noResultError) {
          this.#frameDepth = Math.max(0, this.#frameDepth - 1);
        }
      }
      /**
       * check if we are within a frame
       * @returns {boolean} true if we are within a frame
       */
      isWithinFrame() {
        return this.#frameDepth > 0;
      }
      /**
       * capture shadow root elements propagated through console.debug
       */
      handleLogEntry(logEntry) {
        const args = "args" in logEntry && logEntry.level === "debug" ? logEntry.args : void 0;
        if (!args || args[0].type !== "string" || args[0].value !== "[WDIO]" || args[1].type !== "string") {
          return;
        }
        if (!logEntry.source.context) {
          return;
        }
        const eventType = args[1].value;
        if (eventType === "newShadowRoot" && args[2].type === "node" && args[3].type === "node") {
          const [
            /* [WDIO] */
            ,
            /* newShadowRoot */
            ,
            shadowElem,
            rootElem,
            isDocument,
            documentElement
          ] = args;
          const ctxId = logEntry.source.context;
          if (shadowElem.sharedId) {
            const docMatch = shadowElem.sharedId.match(/\.d\.([A-F0-9]+)\./);
            if (docMatch) {
              const newDocId = docMatch[1];
              const currentDocId = this.#currentDocumentIds.get(ctxId);
              if (currentDocId && currentDocId !== newDocId) {
                log5.info(`Document changed in context ${ctxId}: ${currentDocId} -> ${newDocId}, purging ${this.#shadowRoots.get(ctxId)?.flat().length ?? 0} stale shadow roots`);
                this.#shadowRoots.delete(ctxId);
                this.#documentElements.delete(ctxId);
              }
              this.#currentDocumentIds.set(ctxId, newDocId);
            }
          }
          if (!this.#shadowRoots.has(logEntry.source.context)) {
            if (!rootElem.sharedId) {
              throw new Error(`Expected "sharedId" parameter from object ${rootElem}`);
            }
            this.#shadowRoots.set(logEntry.source.context, new ShadowRootTree(rootElem.sharedId));
          } else if (isDocument.type === "boolean" && isDocument.value) {
            if (!rootElem.sharedId) {
              throw new Error(`Expected "sharedId" parameter from object ${rootElem}`);
            }
            const tree2 = this.#shadowRoots.get(logEntry.source.context);
            if (tree2?.element !== rootElem.sharedId) {
              const documentTree = new ShadowRootTree(rootElem.sharedId);
              if (tree2 && documentElement?.type === "node" && documentElement.sharedId && this.#documentElements.get(logEntry.source.context)?.sharedId === documentElement.sharedId) {
                for (const host of tree2.shadowRoot ? [tree2] : tree2.children) {
                  documentTree.addShadowElement(host);
                }
              }
              this.#shadowRoots.set(logEntry.source.context, documentTree);
            }
          }
          this.#documentElements.set(logEntry.source.context, documentElement);
          const tree = this.#shadowRoots.get(logEntry.source.context);
          if (!tree) {
            throw new Error(`Couldn't find tree for context id ${logEntry.source.context}`);
          }
          if (
            // we expect an element id
            !shadowElem.sharedId || // we expect the element to have a shadow root
            !shadowElem.value?.shadowRoot?.sharedId || // we expect the shadow root to have a proper type
            shadowElem.value.shadowRoot.value?.nodeType !== 11
          ) {
            return log5.warn(`Expected element with shadow root but found <${shadowElem.value?.localName} />`);
          }
          log5.info(`Registered new shadow root for element <${shadowElem.value.localName} /> with id ${shadowElem.value.shadowRoot.sharedId}`);
          const newTree = new ShadowRootTree(
            shadowElem.sharedId,
            shadowElem.value.shadowRoot.sharedId,
            shadowElem.value.shadowRoot.value.mode
          );
          if (tree.element === newTree.element) {
            tree.shadowRoot = newTree.shadowRoot;
            tree.mode = newTree.mode;
            return;
          }
          if (rootElem.sharedId) {
            tree.addShadowElement(rootElem.sharedId, newTree);
          } else {
            tree.addShadowElement(newTree);
          }
          return;
        }
        if (eventType === "removeShadowRoot" && args[2].type === "node") {
          if (!args[2].sharedId) {
            return log5.warn("Received removeShadowRoot event without sharedId, element may have been garbage collected");
          }
          const tree = this.#shadowRoots.get(logEntry.source.context);
          if (!tree) {
            return;
          }
          return tree.remove(args[2].sharedId);
        }
        throw new Error(`Invalid parameters for "${eventType}" event: ${args.join(", ")}`);
      }
      async getShadowElementsByContextId(contextId, scope) {
        let tree = this.#shadowRoots.get(contextId);
        if (!tree) {
          return [];
        }
        let documentElement;
        if (scope) {
          const subTree = tree.find(scope);
          if (!subTree) {
            const containedHosts = await this.#findContainedShadowHosts(contextId, scope);
            const elements2 = containedHosts.flatMap((host) => host.getAllLookupScopes());
            return [...new Set(elements2).values()];
          }
          tree = subTree;
        } else {
          documentElement = this.#documentElements.get(contextId)?.sharedId;
        }
        const elements = tree.getAllLookupScopes();
        return [
          ...documentElement ? [documentElement] : [],
          ...new Set(elements).values()
        ];
      }
      async getShadowElementPairsByContextId(contextId, scope) {
        let tree = this.#shadowRoots.get(contextId);
        if (!tree) {
          return [];
        }
        if (scope) {
          const subTree = tree.find(scope);
          if (!subTree) {
            const containedHosts = await this.#findContainedShadowHosts(contextId, scope);
            return containedHosts.flatMap((host) => host.flat().map((t) => [t.element, t.shadowRoot]));
          }
          tree = subTree;
        }
        return tree.flat().map((tree2) => [tree2.element, tree2.shadowRoot]);
      }
      /**
       * Find all tracked shadow hosts that are real DOM descendants of `scope`, even though
       * `scope` itself isn't tracked in the shadow tree (e.g. a plain wrapper element around
       * a web component). Hosts nested inside another contained host are excluded since
       * they're already covered by that host's own (recursive) lookup scopes.
       */
      async #findContainedShadowHosts(contextId, scope) {
        const tree = this.#shadowRoots.get(contextId);
        if (!tree) {
          return [];
        }
        const hosts = tree.flat().filter((t) => t.shadowRoot);
        if (hosts.length === 0) {
          return [];
        }
        const staleHosts = [];
        const containmentResults = await checkElementsContainedIn(
          this.#browser,
          scope,
          hosts.map((host) => host.element),
          contextId,
          (elementId) => staleHosts.push(elementId)
        );
        const containedHosts = hosts.filter((_, i) => containmentResults[i]);
        if (staleHosts.length > 0 && staleHosts.length < hosts.length) {
          const containedSet = new Set(containedHosts);
          for (const elementId of staleHosts) {
            const staleHost = hosts.find((host) => host.element === elementId);
            if (staleHost && staleHost.flat().some((descendant) => containedSet.has(descendant))) {
              continue;
            }
            log5.info(`Pruning stale shadow host ${elementId} from shadow tree of context ${contextId}`);
            tree.remove(elementId);
          }
        }
        const covered = /* @__PURE__ */ new Set();
        const topLevelContained = [];
        for (const host of containedHosts) {
          if (covered.has(host)) {
            continue;
          }
          topLevelContained.push(host);
          for (const descendant of host.flat()) {
            covered.add(descendant);
          }
        }
        return topLevelContained;
      }
      getShadowRootModeById(contextId, element) {
        const tree = this.#shadowRoots.get(contextId);
        if (!tree) {
          return;
        }
        const shadowTree = tree.find(element);
        if (!shadowTree) {
          return;
        }
        return shadowTree.mode;
      }
      deleteShadowRoot(element, contextId) {
        const tree = this.#shadowRoots.get(contextId);
        if (!tree) {
          return;
        }
        return tree.remove(element);
      }
    };
    ShadowRootTree = class _ShadowRootTree {
      element;
      shadowRoot;
      mode;
      children = /* @__PURE__ */ new Set();
      constructor(element, shadowRoot, mode) {
        this.element = element;
        this.shadowRoot = shadowRoot;
        this.mode = mode;
      }
      addShadowElement(...args) {
        const [scope, treeArg] = args;
        if (!scope && !treeArg) {
          throw new Error('Method "addShadowElement" expects at least 2 arguments');
        }
        if (scope instanceof _ShadowRootTree) {
          for (const child of this.children) {
            if (child.element === scope.element) {
              return;
            }
          }
          this.children.add(scope);
          return;
        }
        if (typeof scope === "string" && treeArg instanceof _ShadowRootTree) {
          const tree = this.find(scope) || this.findByShadowId(scope);
          if (!tree) {
            return;
          }
          tree.addShadowElement(treeArg);
          return;
        }
        throw new Error('Invalid arguments for "addShadowElement" method');
      }
      find(element) {
        if (this.element === element) {
          return this;
        }
        for (const child of this.children) {
          const elem = child.find(element);
          if (elem) {
            return elem;
          }
        }
        return void 0;
      }
      findByShadowId(shadowRoot) {
        if (this.shadowRoot === shadowRoot) {
          return this;
        }
        for (const child of this.children) {
          const elem = child.findByShadowId(shadowRoot);
          if (elem) {
            return elem;
          }
        }
        return void 0;
      }
      getAllLookupScopes() {
        return [
          this.shadowRoot ?? this.element,
          ...Array.from(this.children).map((tree) => tree.getAllLookupScopes())
        ].flat();
      }
      flat() {
        return [this, ...Array.from(this.children).map((tree) => tree.flat())].flat();
      }
      remove(element) {
        const childArray = Array.from(this.children);
        for (let i = childArray.length - 1; i >= 0; i--) {
          if (childArray[i].element === element) {
            return this.children.delete(childArray[i]);
          }
          const wasFound = childArray[i].remove(element);
          if (wasFound) {
            return true;
          }
        }
        return false;
      }
    };
  }
});

// src/utils/strictMode.ts
import { getBrowserObject as getBrowserObject9 } from "@wdio/utils";
import isPlainObject3 from "is-plain-obj";
import { ELEMENT_KEY as ELEMENT_KEY7 } from "webdriver";
function isStrictQuery(scope, options) {
  if (options && typeof options.strict === "boolean") {
    return options.strict;
  }
  const { strictSelectors } = getBrowserObject9(scope).options || {};
  return strictSelectors !== false;
}
function isCountableSelector(selector) {
  if (typeof selector === "string" || typeof selector === "function") {
    return true;
  }
  if (isElement(selector)) {
    return false;
  }
  if (!isPlainObject3(selector)) {
    return false;
  }
  if (typeof selector[ELEMENT_KEY7] === "string") {
    return false;
  }
  return true;
}
async function findStrictElement(selector) {
  const browserObject = getBrowserObject9(this);
  const shadowRootManager = getShadowRootManager(browserObject);
  const elems = this.isBidi && typeof selector === "string" && !selector.startsWith(DEEP_SELECTOR) && !shadowRootManager.isWithinFrame() ? await findDeepElements.call(this, selector) : await findElements.call(this, selector);
  if (elems.length > 1) {
    throw new StrictSelectorError(selector, elems.length);
  }
  return elems[0] || buildNotFoundError(selector);
}
var init_strictMode = __esm({
  "src/utils/strictMode.ts"() {
    "use strict";
    init_constants();
    init_utils2();
    init_shadowRoot();
    init_strictSelectorError();
  }
});

// src/commands/browser/$.ts
import { ELEMENT_KEY as ELEMENT_KEY8 } from "webdriver";
async function $(selector, options) {
  const strict = isCountableSelector(selector) && isStrictQuery(this, options);
  if (globalThis.wdio && typeof selector === "string" && !selector.startsWith(DEEP_SELECTOR)) {
    if (strict) {
      const matches = "elementId" in this ? await globalThis.wdio.executeWithScope("$$", this.elementId, selector) : await globalThis.wdio.execute("$$", selector);
      if (matches.length > 1) {
        throw new StrictSelectorError(selector, matches.length);
      }
      return getElement.call(
        this,
        selector,
        matches[0] || buildNotFoundError(selector),
        { strict }
      );
    }
    const res2 = "elementId" in this ? await globalThis.wdio.executeWithScope("$", this.elementId, selector, options) : await globalThis.wdio.execute("$", selector, options);
    return getElement.call(this, selector, res2, { strict });
  }
  if (typeof selector === "object") {
    const elementRef = selector;
    if (typeof elementRef[ELEMENT_KEY8] === "string") {
      return getElement.call(this, void 0, elementRef);
    }
  }
  const res = strict ? await findStrictElement.call(this, selector) : await findElement.call(this, selector);
  return getElement.call(this, selector, res, { strict });
}
var init__2 = __esm({
  "src/commands/browser/$.ts"() {
    "use strict";
    init_constants();
    init_utils2();
    init_strictMode();
    init_getElementObject();
  }
});

// src/utils/actions/base.ts
import { ELEMENT_KEY as ELEMENT_KEY9 } from "webdriver";
import { getBrowserObject as getBrowserObject10 } from "@wdio/utils";
function toBidiActions(sequence) {
  return sequence.map((source) => ({
    ...source,
    actions: source.actions.map((rawAction) => {
      const action2 = rawAction;
      const instant = action2.type === "pointerMove" && DEFAULT_DURATION_MOVES.has(rawAction) ? { ...action2, duration: 0 } : action2;
      const origin = instant.origin;
      if (!origin || typeof origin !== "object" || !(ELEMENT_KEY9 in origin)) {
        return instant;
      }
      return {
        ...instant,
        origin: {
          type: "element",
          element: { sharedId: origin[ELEMENT_KEY9] }
        }
      };
    })
  }));
}
var DEFAULT_DURATION_MOVES, keyActionIds, pointerActionIds, wheelActionIds, BaseAction;
var init_base = __esm({
  "src/utils/actions/base.ts"() {
    "use strict";
    init_browsingContext();
    init_context();
    DEFAULT_DURATION_MOVES = /* @__PURE__ */ new WeakSet();
    keyActionIds = 0;
    pointerActionIds = 0;
    wheelActionIds = 0;
    BaseAction = class {
      constructor(instance, type, params) {
        this.instance = instance;
        this.#instance = instance;
        if (params?.id) {
          this.#id = params.id;
        } else {
          switch (type) {
            case "key":
              this.#id = `key${++keyActionIds}`;
              break;
            case "pointer":
              this.#id = `pointer${++pointerActionIds}`;
              break;
            case "wheel":
              this.#id = `wheel${++wheelActionIds}`;
              break;
            default:
              this.#id = `action${type}`;
          }
        }
        this.#type = type;
        this.#parameters = params?.parameters || {};
      }
      instance;
      #id;
      #type;
      #parameters;
      #instance;
      sequence = [];
      toJSON() {
        return {
          id: this.#id,
          type: this.#type,
          parameters: this.#parameters,
          actions: this.sequence
        };
      }
      /**
       * Inserts a pause action for the specified device, ensuring it idles for a tick.
       * @param duration idle time of tick
       */
      pause(duration) {
        this.sequence.push({ type: "pause", duration });
        return this;
      }
      /**
       * Perform action sequence
       * @param skipRelease set to true if `releaseActions` command should not be invoked
       */
      async perform(skipRelease = false) {
        let originContext;
        for (const seq of this.sequence) {
          if (!seq.origin || typeof seq.origin === "string") {
            continue;
          }
          const origin = seq.origin;
          if (typeof seq.origin.then === "function" || typeof origin.waitForExist === "function" && !origin.elementId) {
            await origin.waitForExist();
            seq.origin = await seq.origin;
          }
          const foreign = await foreignContextId(seq.origin);
          if (foreign) {
            originContext = foreign;
          }
          if (!seq.origin[ELEMENT_KEY9]) {
            throw new Error(`Couldn't find element for "${seq.type}" action sequence`);
          }
          seq.origin = { [ELEMENT_KEY9]: seq.origin[ELEMENT_KEY9] };
        }
        const browser = getBrowserObject10(this.#instance);
        const sequence = [this.toJSON()];
        const contextId = isBrowsingContext(this.#instance) ? this.#instance.contextId : originContext ?? getParallelContextStore().getStore();
        if (contextId) {
          const actions2 = toBidiActions(sequence);
          await browser.inputPerformActions({
            context: contextId,
            actions: actions2
          });
          if (!skipRelease) {
            await browser.inputReleaseActions({ context: contextId });
          }
          return;
        }
        await browser.performActions(sequence);
        if (!skipRelease) {
          await browser.releaseActions();
        }
      }
    };
  }
});

// src/utils/actions/key.ts
var KeyAction;
var init_key = __esm({
  "src/utils/actions/key.ts"() {
    "use strict";
    init_base();
    init_environment();
    init_constants();
    KeyAction = class extends BaseAction {
      constructor(instance, params) {
        super(instance, "key", params);
      }
      #sanitizeKey(value) {
        if (typeof value !== "string") {
          throw new Error(`Invalid type for key input: "${typeof value}", expected a string!`);
        }
        const platformName = this.instance.capabilities.platformName;
        const isMac = (
          // check capabilities first
          platformName && platformName.match(/mac(\s)*os/i) || // if not set, expect we run locally
          this.instance.options.hostname?.match(/0\.0\.0\.0|127\.0\.0\.1|local/i) && environment.value.osType().match(/darwin/i)
        );
        if (value === Key.Ctrl) {
          return isMac ? Key.Command : Key.Control;
        }
        if (value.length > 1) {
          throw new Error(`Your key input contains more than one character: "${value}", only one is allowed though!`);
        }
        return value;
      }
      /**
       * Generates a key up action.
       * @param value key value
       */
      up(value) {
        this.sequence.push({ type: "keyUp", value: this.#sanitizeKey(value) });
        return this;
      }
      /**
       * Generates a key down action.
       * @param value key value
       */
      down(value) {
        this.sequence.push({ type: "keyDown", value: this.#sanitizeKey(value) });
        return this;
      }
    };
  }
});

// src/utils/actions/pointer.ts
function removeDefaultParams(seq) {
  for (const [key, value] of Object.entries(seq)) {
    if (value === 0 && !["x", "y", "button", "duration"].includes(key)) {
      delete seq[key];
    }
  }
}
function mapButton(params) {
  const buttons = {
    left: 0,
    middle: 1,
    right: 2
  };
  if (typeof params === "number") {
    return { button: params };
  }
  if (typeof params === "string") {
    return { button: buttons[params] };
  }
  if (typeof params === "object" && typeof params.button === "string") {
    return { ...params, button: buttons[params.button] };
  }
  return params;
}
var buttonNumbers, buttonNames, buttonValue, ORIGIN_DEFAULT, BUTTON_DEFAULT, POINTER_TYPE_DEFAULT, UP_PARAM_DEFAULTS, PARAM_DEFAULTS, MOVE_PARAM_DEFAULTS, PointerAction;
var init_pointer = __esm({
  "src/utils/actions/pointer.ts"() {
    "use strict";
    init_base();
    buttonNumbers = [0, 1, 2];
    buttonNames = ["left", "middle", "right"];
    buttonValue = [...buttonNumbers, ...buttonNames];
    ORIGIN_DEFAULT = "viewport";
    BUTTON_DEFAULT = 0;
    POINTER_TYPE_DEFAULT = "mouse";
    UP_PARAM_DEFAULTS = {
      button: BUTTON_DEFAULT
    };
    PARAM_DEFAULTS = {
      ...UP_PARAM_DEFAULTS,
      width: 0,
      height: 0,
      pressure: 0,
      tangentialPressure: 0,
      tiltX: 0,
      tiltY: 0,
      twist: 0,
      altitudeAngle: 0,
      azimuthAngle: 0
    };
    MOVE_PARAM_DEFAULTS = {
      x: 0,
      y: 0,
      duration: 100,
      origin: ORIGIN_DEFAULT
    };
    PointerAction = class extends BaseAction {
      constructor(instance, params = {}) {
        if (!params.parameters) {
          params.parameters = { pointerType: POINTER_TYPE_DEFAULT };
        }
        super(instance, "pointer", params);
      }
      move(params = {}, y) {
        const seq = {
          type: "pointerMove",
          // default params
          ...PARAM_DEFAULTS,
          ...UP_PARAM_DEFAULTS,
          ...MOVE_PARAM_DEFAULTS
        };
        if (typeof params === "number") {
          Object.assign(seq, { x: params, y });
        } else if (params) {
          Object.assign(seq, params);
        }
        removeDefaultParams(seq);
        if (typeof params === "number" || !params || params.duration === void 0) {
          DEFAULT_DURATION_MOVES.add(seq);
        }
        this.sequence.push(seq);
        return this;
      }
      up(params = UP_PARAM_DEFAULTS) {
        this.sequence.push({
          type: "pointerUp",
          ...mapButton(params)
        });
        return this;
      }
      down(params = {}) {
        const seq = {
          type: "pointerDown",
          ...PARAM_DEFAULTS,
          ...mapButton(params)
        };
        removeDefaultParams(seq);
        this.sequence.push(seq);
        return this;
      }
      /**
       * An action that cancels this pointer's current input.
       */
      cancel() {
        this.sequence.push({ type: "pointerCancel" });
        return this;
      }
    };
  }
});

// src/utils/actions/wheel.ts
var DEFAULT_SCROLL_PARAMS, WheelAction;
var init_wheel = __esm({
  "src/utils/actions/wheel.ts"() {
    "use strict";
    init_base();
    DEFAULT_SCROLL_PARAMS = {
      x: 0,
      y: 0,
      deltaX: 0,
      deltaY: 0,
      duration: 0
    };
    WheelAction = class extends BaseAction {
      constructor(instance, params) {
        super(instance, "wheel", params);
      }
      /**
       * Scrolls a page to given coordinates or origin.
       */
      scroll(params) {
        this.sequence.push({ type: "scroll", ...DEFAULT_SCROLL_PARAMS, ...params });
        return this;
      }
    };
  }
});

// src/utils/actions/index.ts
var init_actions = __esm({
  "src/utils/actions/index.ts"() {
    "use strict";
    init_key();
    init_pointer();
    init_wheel();
    init_base();
    init_pointer();
  }
});

// src/commands/browser/action.ts
function action(type, opts) {
  if (type === "key") {
    return new KeyAction(this, opts);
  }
  if (type === "pointer") {
    return new PointerAction(this, opts);
  }
  if (type === "wheel") {
    return new WheelAction(this, opts);
  }
  throw new Error(`Unsupported action type "${type}", supported are "key", "pointer", "wheel"`);
}
var init_action = __esm({
  "src/commands/browser/action.ts"() {
    "use strict";
    init_actions();
  }
});

// src/commands/browser/actions.ts
async function actions(actions2) {
  const payload = actions2.map((action2) => action2.toJSON());
  if (isBrowsingContext(this)) {
    await this.browser.inputPerformActions({
      context: this.contextId,
      actions: toBidiActions(payload)
    });
    await this.browser.inputReleaseActions({ context: this.contextId });
    return;
  }
  const parallelContext = getParallelContextStore().getStore();
  if (parallelContext) {
    await this.inputPerformActions({
      context: parallelContext,
      actions: toBidiActions(payload)
    });
    await this.inputReleaseActions({ context: parallelContext });
    return;
  }
  await this.performActions(payload);
  await this.releaseActions();
}
var init_actions2 = __esm({
  "src/commands/browser/actions.ts"() {
    "use strict";
    init_base();
    init_browsingContext();
    init_context();
  }
});

// src/commands/browser/addInitScript.ts
import { getBrowserObject as getBrowserObject11 } from "@wdio/utils";
async function addInitScript(script, ...args) {
  if (typeof script !== "function") {
    throw new Error("The `addInitScript` command requires a function as first parameter, but got: " + typeof script);
  }
  if (isBrowsingContext(this)) {
    assertTopLevel(this, "addInitScript");
  }
  const browser = getBrowserObject11(this);
  if (!browser.isBidi) {
    throw new Error("This command is only supported when automating browser using WebDriver Bidi protocol");
  }
  const serializedParameters = (args || []).map((arg) => JSON.stringify(arg));
  const context = isBrowsingContext(this) ? this.contextId : getParallelContextStore().getStore() ?? await browser.getWindowHandle();
  const src = "return " + script.toString();
  const fn = `(emit) => {
        const closure = new Function(${JSON.stringify(src)})
        return closure()(${serializedParameters.length ? `${serializedParameters.join(", ")}, emit` : "emit"})
    }`;
  const channel = btoa(fn.toString());
  const result = await browser.scriptAddPreloadScript({
    functionDeclaration: fn,
    arguments: [{
      type: "channel",
      value: { channel }
    }],
    contexts: [context]
  });
  await browser.sessionSubscribe({
    events: ["script.message"]
  });
  const eventHandler = /* @__PURE__ */ new Map();
  const messageHandler = (msg) => {
    if (msg.channel === channel) {
      const handler = eventHandler.get("data") || [];
      return handler.forEach((fn2) => fn2(deserialize(msg.data)));
    }
  };
  browser.on("script.message", messageHandler);
  const resetFn = (() => {
    eventHandler.clear();
    browser.off("script.message", messageHandler);
    return browser.scriptRemovePreloadScript({ script: result.script });
  });
  const returnVal = {
    remove: resetFn,
    on: (event, listener) => {
      if (!eventHandler.has(event)) {
        eventHandler.set(event, []);
      }
      eventHandler.get(event)?.push(listener);
    }
  };
  return returnVal;
}
var init_addInitScript = __esm({
  "src/commands/browser/addInitScript.ts"() {
    "use strict";
    init_bidi();
    init_context();
    init_browsingContext();
  }
});

// src/utils/traverseHistory.ts
function historyMarkerId() {
  return `t${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
}
function installHistoryMarker(id) {
  const key = JSON.stringify(id);
  return `(() => {
    const nav = globalThis.navigation
    if (!nav || typeof nav.addEventListener !== 'function') {
        return 'unsupported'
    }
    const events = []
    const onNavigate = (event) => {
        events.push(event.navigationType)
    }
    const root = globalThis.${HISTORY_MARKER} || (globalThis.${HISTORY_MARKER} = { entries: {} })
    root.entries[${key}] = { events, onNavigate }
    nav.addEventListener('navigate', onNavigate)
    return 'installed'
})()`;
}
function readHistoryMarker(id) {
  const key = JSON.stringify(id);
  return `(() => {
    const root = globalThis.${HISTORY_MARKER}
    const entry = root && root.entries && root.entries[${key}]
    if (!entry || !Array.isArray(entry.events) || entry.events.length === 0) {
        return ''
    }
    return String(entry.events[entry.events.length - 1])
})()`;
}
function clearTraversalMarks(id) {
  const key = JSON.stringify(id);
  return `(() => {
    const docRoot = document.documentElement
    const tokens = docRoot && docRoot.${DOCUMENT_TOKENS}
    if (tokens) {
        delete tokens[${key}]
    }
    const root = globalThis.${HISTORY_MARKER}
    const entry = root && root.entries && root.entries[${key}]
    if (!entry) {
        return
    }
    const nav = globalThis.navigation
    if (nav && typeof nav.removeEventListener === 'function') {
        nav.removeEventListener('navigate', entry.onNavigate)
    }
    delete root.entries[${key}]
})()`;
}
function historyReadiness(strategy) {
  if (strategy === "none") {
    return "none";
  }
  if (strategy === "eager") {
    return "interactive";
  }
  return "complete";
}
async function topLevelBrowsingContext2(browser) {
  const parallelContext = getParallelContextStore().getStore();
  if (parallelContext) {
    return parallelContext;
  }
  const handle = getContextManager(browser).getCurrentWindowHandle();
  if (handle) {
    return handle;
  }
  return browser.getWindowHandle();
}
async function pageLoadTimeout(browser) {
  const fromSession = await browser.getTimeouts().then(
    (timeouts) => timeouts?.pageLoad,
    () => void 0
  );
  if (typeof fromSession === "number" && fromSession >= 0) {
    return fromSession;
  }
  const fromCapabilities = browser.capabilities.timeouts?.pageLoad;
  if (typeof fromCapabilities === "number" && fromCapabilities >= 0) {
    return fromCapabilities;
  }
  return DEFAULT_PAGE_LOAD_TIMEOUT;
}
function matchesContext(params, context) {
  return params?.context === context;
}
async function evaluateString(browser, context, expression) {
  try {
    const result = await browser.scriptEvaluate({
      expression,
      awaitPromise: false,
      target: { context }
    });
    if (result.type !== "success") {
      return void 0;
    }
    const value = result.result;
    if (value && typeof value === "object" && "type" in value && value.type === "string" && "value" in value && typeof value.value === "string") {
      return value.value;
    }
    return void 0;
  } catch {
    return void 0;
  }
}
function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}
function readyStateSatisfies(readiness, state) {
  if (readiness === "interactive") {
    return state === "interactive" || state === "complete";
  }
  return state === "complete";
}
function documentSnapshot(token, stamp) {
  const key = JSON.stringify(token);
  return `(() => {
    const root = document.documentElement
    ${stamp ? `if (root) (root.${DOCUMENT_TOKENS} || (root.${DOCUMENT_TOKENS} = {}))[${key}] = true` : ""}
    const tokens = root && root.${DOCUMENT_TOKENS}
    const marked = Boolean(tokens && tokens[${key}] === true)
    return JSON.stringify({ href: location.href, readyState: document.readyState, marked })
})()`;
}
function parseDocumentSnapshot(value) {
  if (!value) {
    return void 0;
  }
  try {
    const parsed = JSON.parse(value);
    if (typeof parsed.href !== "string" || typeof parsed.readyState !== "string" || typeof parsed.marked !== "boolean") {
      return void 0;
    }
    return { href: parsed.href, readyState: parsed.readyState, marked: parsed.marked };
  } catch {
    return void 0;
  }
}
async function traverseTopLevelHistory(browser, delta, targetContext) {
  const context = targetContext ?? await topLevelBrowsingContext2(browser);
  const readiness = historyReadiness(browser.capabilities.pageLoadStrategy);
  if (readiness === "none") {
    await browser.browsingContextTraverseHistory({ context, delta });
    return;
  }
  const timeout = await pageLoadTimeout(browser);
  const expectedEvent = readiness === "interactive" ? "browsingContext.domContentLoaded" : "browsingContext.load";
  let subscription;
  let historyMarker = "unavailable";
  const markerId = historyMarkerId();
  let outgoing;
  let armed = false;
  let settled = false;
  let crossDocument = false;
  let waitError;
  let resolveReady = () => {
  };
  let rejectReady = () => {
  };
  const ready = new Promise((resolve, reject) => {
    resolveReady = () => {
      if (settled) {
        return;
      }
      settled = true;
      resolve();
    };
    rejectReady = (error) => {
      if (settled) {
        return;
      }
      settled = true;
      waitError = error;
      reject(error);
    };
  });
  const readySettled = ready.then(() => void 0, () => void 0);
  const succeed = (params) => {
    if (!armed || !matchesContext(params, context)) {
      return;
    }
    resolveReady();
  };
  const onNavigationStarted = (params) => {
    if (!armed || !matchesContext(params, context)) {
      return;
    }
    crossDocument = true;
    void watchTraversalReadyState(true);
  };
  const watchTraversalReadyState = async (requireNewDocument) => {
    try {
      while (armed && !settled) {
        const sample = parseDocumentSnapshot(await evaluateString(browser, context, documentSnapshot(markerId, false)));
        if (!armed || settled) {
          return;
        }
        if (!sample) {
          await delay(READY_STATE_RETRY_MS);
          continue;
        }
        if (requireNewDocument && (!outgoing || sample.marked)) {
          await delay(READY_STATE_RETRY_MS);
          continue;
        }
        if (readyStateSatisfies(readiness, sample.readyState)) {
          resolveReady();
        }
        return;
      }
    } catch {
    }
  };
  const onNavigationCommitted = (params) => {
    if (!armed || !matchesContext(params, context)) {
      return;
    }
    void watchTraversalReadyState(false);
  };
  const onReadyEvent = (params) => {
    if (!armed || !matchesContext(params, context)) {
      return;
    }
    if (!outgoing) {
      succeed(params);
      return;
    }
    void evaluateString(browser, context, documentSnapshot(markerId, false)).then((snapshot) => parseDocumentSnapshot(snapshot)).catch(() => void 0).then((sample) => {
      if (!sample) {
        void watchTraversalReadyState(true);
        return;
      }
      if (!sample.marked) {
        succeed(params);
      }
    });
  };
  const onDomContentLoaded = (params) => {
    if (readiness === "interactive") {
      onReadyEvent(params);
    }
  };
  const onLoad = (params) => {
    onReadyEvent(params);
  };
  const onFragmentNavigated = (params) => {
    succeed(params);
  };
  const onHistoryUpdated = (params) => {
    if (crossDocument || !armed || !matchesContext(params, context)) {
      return;
    }
    if (historyMarker !== "installed") {
      succeed(params);
      return;
    }
    void evaluateString(browser, context, readHistoryMarker(markerId)).then((kind) => {
      if (!armed || settled || crossDocument || kind !== "traverse") {
        return;
      }
      resolveReady();
    });
  };
  browser.on("browsingContext.navigationStarted", onNavigationStarted);
  browser.on("browsingContext.navigationCommitted", onNavigationCommitted);
  browser.on("browsingContext.domContentLoaded", onDomContentLoaded);
  browser.on("browsingContext.load", onLoad);
  browser.on("browsingContext.fragmentNavigated", onFragmentNavigated);
  browser.on("browsingContext.historyUpdated", onHistoryUpdated);
  const timer = setTimeout(() => {
    rejectReady(new Error(
      `History traversal timed out after ${timeout}ms waiting for ${expectedEvent}`
    ));
  }, timeout);
  let commandError;
  try {
    const subscribed = await browser.sessionSubscribe({
      events: [...HISTORY_NAVIGATION_EVENTS],
      contexts: [context]
    });
    subscription = subscribed.subscription;
    if (await evaluateString(browser, context, installHistoryMarker(markerId)) === "installed") {
      historyMarker = "installed";
    }
    for (let attempt = 0; attempt < 5 && !outgoing && !settled; attempt++) {
      const stamped = parseDocumentSnapshot(await evaluateString(browser, context, documentSnapshot(markerId, true)));
      if (stamped?.marked) {
        outgoing = stamped;
        break;
      }
      if (attempt < 4 && !settled) {
        await delay(READY_STATE_RETRY_MS);
      }
    }
    armed = true;
    try {
      await browser.browsingContextTraverseHistory({ context, delta });
    } catch (err) {
      commandError = err;
    }
    if (commandError) {
      throw commandError;
    }
    if (waitError) {
      throw waitError;
    }
    if (!settled) {
      await readySettled;
    }
    if (waitError) {
      throw waitError;
    }
  } finally {
    armed = false;
    clearTimeout(timer);
    browser.off("browsingContext.navigationStarted", onNavigationStarted);
    browser.off("browsingContext.navigationCommitted", onNavigationCommitted);
    browser.off("browsingContext.domContentLoaded", onDomContentLoaded);
    browser.off("browsingContext.load", onLoad);
    browser.off("browsingContext.fragmentNavigated", onFragmentNavigated);
    browser.off("browsingContext.historyUpdated", onHistoryUpdated);
    if (!settled) {
      resolveReady();
    }
    void evaluateString(browser, context, clearTraversalMarks(markerId));
    if (subscription) {
      void browser.sessionUnsubscribe({ subscriptions: [subscription] }).catch(() => void 0);
    }
  }
}
var DEFAULT_PAGE_LOAD_TIMEOUT, READY_STATE_RETRY_MS, HISTORY_MARKER, DOCUMENT_TOKENS, HISTORY_NAVIGATION_EVENTS;
var init_traverseHistory = __esm({
  "src/utils/traverseHistory.ts"() {
    "use strict";
    init_context();
    DEFAULT_PAGE_LOAD_TIMEOUT = 3e5;
    READY_STATE_RETRY_MS = 50;
    HISTORY_MARKER = "__wdioHistoryTraverse";
    DOCUMENT_TOKENS = "__wdioHistoryTokens";
    HISTORY_NAVIGATION_EVENTS = [
      "browsingContext.navigationStarted",
      "browsingContext.navigationCommitted",
      "browsingContext.domContentLoaded",
      "browsingContext.load",
      "browsingContext.fragmentNavigated",
      "browsingContext.historyUpdated"
    ];
  }
});

// src/commands/browser/back.ts
import { runClassicProtocolCommand } from "webdriver";
async function back() {
  if (!this.isBidi) {
    await runClassicProtocolCommand.call(this, "back");
    return;
  }
  await traverseTopLevelHistory(this, -1);
}
var init_back = __esm({
  "src/commands/browser/back.ts"() {
    "use strict";
    init_traverseHistory();
  }
});

// src/commands/browser/call.ts
function call(fn) {
  if (typeof fn === "function") {
    return fn();
  }
  throw new Error('Command argument for "call" needs to be a function');
}
var init_call = __esm({
  "src/commands/browser/call.ts"() {
    "use strict";
  }
});

// src/commands/browser/custom$$.ts
import { ELEMENT_KEY as ELEMENT_KEY10 } from "webdriver";
function custom$$(strategyName, ...strategyArguments) {
  return ElementArray.fromAsyncCallback(async () => {
    const strategy = this.strategies.get(strategyName);
    if (!strategy) {
      throw new Error("No strategy found for " + strategyName);
    }
    const strategyRef = { strategy, strategyName, strategyArguments };
    let res = await this.execute(strategy, ...strategyArguments);
    if (!Array.isArray(res)) {
      res = [res];
    }
    res = res.filter((el) => !!el && typeof el[ELEMENT_KEY10] === "string");
    return res.length ? await getElements.call(this, strategyRef, res) : [];
  }, {
    selector: strategyName,
    foundWith: "custom$$",
    parent: this,
    props: strategyArguments
  });
}
var init_custom = __esm({
  "src/commands/browser/custom$$.ts"() {
    "use strict";
    init_getElementObject();
    init_array();
  }
});

// src/commands/browser/custom$.ts
import { ELEMENT_KEY as ELEMENT_KEY11 } from "webdriver";
async function custom$(strategyName, ...strategyArguments) {
  const strategy = this.strategies.get(strategyName);
  if (!strategy) {
    throw Error("No strategy found for " + strategyName);
  }
  const strategyRef = { strategy, strategyName, strategyArguments };
  let res = await this.execute(strategy, ...strategyArguments);
  if (Array.isArray(res)) {
    res = res[0];
  }
  if (res && typeof res[ELEMENT_KEY11] === "string") {
    return await getElement.call(this, strategyRef, res, { strict: false });
  }
  return await getElement.call(this, strategyRef, new Error("no such element"), { strict: false });
}
var init_custom2 = __esm({
  "src/commands/browser/custom$.ts"() {
    "use strict";
    init_getElementObject();
  }
});

// src/commands/browser/debug.ts
import { serializeError } from "serialize-error";
import WDIORepl from "@wdio/repl";
function debug(commandTimeout = 5e3) {
  const repl = new WDIORepl();
  const { introMessage } = WDIORepl;
  const process3 = globalThis.process;
  if (!environment.value.variables.WDIO_WORKER_ID || typeof process3.send !== "function") {
    console.log(WDIORepl.introMessage);
    const context = {
      browser: this,
      driver: this,
      $: this.$.bind(this),
      $$: this.$$.bind(this)
    };
    return repl.start(context);
  }
  process3._debugProcess(process3.pid);
  process3.send({
    origin: "debugger",
    name: "start",
    params: { commandTimeout, introMessage }
  });
  let commandResolve = (
    /* istanbul ignore next */
    () => {
    }
  );
  process3.on("message", (m) => {
    if (m.origin !== "debugger") {
      return;
    }
    if (m.name === "stop") {
      process3._debugEnd(process3.pid);
      return commandResolve();
    }
    if (m.name === "eval") {
      repl.eval(m.content.cmd, global, void 0, (err, result) => {
        if (typeof process3.send !== "function") {
          return;
        }
        if (err) {
          process3.send({
            origin: "debugger",
            name: "result",
            params: {
              error: true,
              ...serializeError(err)
            }
          });
        }
        if (typeof result === "function") {
          result = `[Function: ${result.name}]`;
        }
        process3.send({
          origin: "debugger",
          name: "result",
          params: { result }
        });
      });
    }
  });
  return new Promise((resolve) => commandResolve = resolve);
}
var init_debug = __esm({
  "src/commands/browser/debug.ts"() {
    "use strict";
    init_environment();
  }
});

// src/utils/cookiePartition.ts
async function parallelCookiePartition(browser, explicitOrigin) {
  const context = getParallelContextStore().getStore();
  if (!context) {
    return void 0;
  }
  const { contexts } = await browser.browsingContextGetTree({ root: context, maxDepth: 0 });
  const info = contexts[0];
  const userContext = info?.userContext ? { userContext: info.userContext } : {};
  if (explicitOrigin !== void 0) {
    return {
      type: "storageKey",
      ...explicitOrigin === null ? {} : { sourceOrigin: explicitOrigin },
      ...userContext
    };
  }
  let sourceOrigin;
  try {
    const { origin } = new URL(info?.url);
    sourceOrigin = origin === "null" ? void 0 : origin;
  } catch {
    sourceOrigin = void 0;
  }
  if (!sourceOrigin) {
    return { type: "context", context };
  }
  return {
    type: "storageKey",
    sourceOrigin,
    ...userContext
  };
}
function getCookiePartition(sourceOrigin) {
  return { type: "storageKey", sourceOrigin };
}
var init_cookiePartition = __esm({
  "src/utils/cookiePartition.ts"() {
    "use strict";
    init_context();
  }
});

// src/commands/browser/deleteCookies.ts
import logger6 from "@wdio/logger";
async function deleteCookies(filter) {
  const filterArray = typeof filter === "undefined" ? void 0 : Array.isArray(filter) ? filter : [filter];
  if (!this.isBidi) {
    await deleteCookiesClassic.call(this, getNamesForClassic(filterArray));
    return;
  }
  if (isBrowsingContext(this)) {
    const partition2 = {
      type: "context",
      context: this.contextId
    };
    if (!filterArray) {
      await this.browser.storageDeleteCookies({ partition: partition2 });
      return;
    }
    const bidiFilter = filterArray.map((entry) => {
      if (typeof entry === "string") {
        return { name: entry };
      }
      if (typeof entry === "object") {
        return entry;
      }
      throw new Error(`Invalid value for cookie filter, expected 'string' or 'remote.StorageCookieFilter' but found "${typeof entry}"`);
    });
    await Promise.all(bidiFilter.map((entry) => this.browser.storageDeleteCookies({ filter: entry, partition: partition2 })));
    return;
  }
  const parallelPartition = await parallelCookiePartition(this);
  if (parallelPartition) {
    await deleteBidiCookies(this, parallelPartition, filterArray);
    return;
  }
  let url2;
  try {
    url2 = new URL(await this.getUrl());
    if (url2.origin === "null") {
      await deleteCookiesClassic.call(this, getNamesForClassic(filterArray));
      return;
    }
  } catch {
    await deleteCookiesClassic.call(this, getNamesForClassic(filterArray));
    return;
  }
  const partition = getCookiePartition(url2.origin);
  try {
    const { cookies } = await this.storageGetCookies({ partition });
    if (cookies.length === 0 && !this.isMobile) {
      await deleteCookiesClassic.call(this, getNamesForClassic(filterArray));
      return;
    }
  } catch (err) {
    log6.warn(`BiDi deleteCookies check failed, falling back to classic: ${err.message}`);
    await deleteCookiesClassic.call(this, getNamesForClassic(filterArray));
    return;
  }
  try {
    await deleteBidiCookies(this, partition, filterArray);
  } catch (err) {
    log6.warn(`BiDi deleteCookies failed, falling back to classic: ${err.message}`);
    await deleteCookiesClassic.call(this, getNamesForClassic(filterArray));
  }
  return;
}
async function deleteBidiCookies(browser, partition, filterArray) {
  if (!filterArray) {
    await browser.storageDeleteCookies({ partition });
    return;
  }
  const bidiFilter = filterArray.map((f) => {
    if (typeof f === "string") {
      return { name: f };
    }
    if (typeof f === "object") {
      return f;
    }
    throw new Error(`Invalid value for cookie filter, expected 'string' or 'remote.StorageCookieFilter' but found "${typeof f}"`);
  });
  await Promise.all(bidiFilter.map((filter) => browser.storageDeleteCookies({ filter, partition })));
}
function getNamesForClassic(filterArray) {
  return filterArray?.map((f) => {
    if (typeof f === "object") {
      const name = f.name;
      if (!name) {
        throw new Error("In WebDriver Classic you can only filter for cookie names");
      }
      return name;
    }
    if (typeof f === "string") {
      return f;
    }
    throw new Error(`Invalid value for cookie filter, expected 'string' or 'remote.StorageCookieFilter' but found "${typeof f}"`);
  });
}
function deleteCookiesClassic(names) {
  if (names === void 0) {
    return this.deleteAllCookies();
  }
  const namesList = Array.isArray(names) ? names : [names];
  if (namesList.every((obj) => typeof obj !== "string")) {
    return Promise.reject(new Error("Invalid input (see https://webdriver.io/docs/api/browser/deleteCookies for documentation)"));
  }
  return Promise.all(namesList.map((name) => this.deleteCookie(name)));
}
var log6;
var init_deleteCookies = __esm({
  "src/commands/browser/deleteCookies.ts"() {
    "use strict";
    init_browsingContext();
    init_cookiePartition();
    log6 = logger6("webdriverio");
  }
});

// src/commands/browser/downloadFile.ts
async function downloadFile2(fileName, targetDirectory) {
  return environment.value.downloadFile.call(this, fileName, targetDirectory);
}
var init_downloadFile = __esm({
  "src/commands/browser/downloadFile.ts"() {
    "use strict";
    init_environment();
  }
});

// src/clock.ts
import logger7 from "@wdio/logger";
function installFakeTimers(options) {
  window.__clock = window.__wdio_sinon.install(options);
}
function uninstallFakeTimers() {
  window.__clock.uninstall();
}
var log7, fakerScript, ClockManager;
var init_clock = __esm({
  "src/clock.ts"() {
    "use strict";
    init_browsingContext();
    log7 = logger7("webdriverio:ClockManager");
    fakerScript = 'function FakeTimers () {\n/*\n * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no. All rights reserved.\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @typedef {object} IdleDeadline\n * @property {boolean} didTimeout - whether or not the callback was called before reaching the optional timeout\n * @property {function():number} timeRemaining - a floating-point value providing an estimate of the number of milliseconds remaining in the current idle period\n */\n\n/**\n * Queues a function to be called during a browser\'s idle periods\n *\n * @callback RequestIdleCallback\n * @param {function(IdleDeadline)} callback\n * @param {{timeout: number}} options - an options object\n * @returns {number} the id\n */\n\n/**\n * @callback NextTick\n * @param {VoidVarArgsFunc} callback - the callback to run\n * @param {...*} args - optional arguments to call the callback with\n * @returns {void}\n */\n\n/**\n * @callback SetImmediate\n * @param {VoidVarArgsFunc} callback - the callback to run\n * @param {...*} args - optional arguments to call the callback with\n * @returns {NodeImmediate}\n */\n\n/**\n * @callback VoidVarArgsFunc\n * @param {...*} callback - the callback to run\n * @returns {void}\n */\n\n/**\n * @typedef RequestAnimationFrame\n * @property {function(number):void} requestAnimationFrame\n * @returns {number} - the id\n */\n\n/**\n * @typedef Performance\n * @property {function(): number} now\n */\n\n/* eslint-disable jsdoc/require-property-description */\n/**\n * @typedef {object} Clock\n * @property {number} now - the current time\n * @property {Date} Date - the Date constructor\n * @property {number} loopLimit - the maximum number of timers before assuming an infinite loop\n * @property {RequestIdleCallback} requestIdleCallback\n * @property {function(number):void} cancelIdleCallback\n * @property {setTimeout} setTimeout\n * @property {clearTimeout} clearTimeout\n * @property {NextTick} nextTick\n * @property {queueMicrotask} queueMicrotask\n * @property {setInterval} setInterval\n * @property {clearInterval} clearInterval\n * @property {SetImmediate} setImmediate\n * @property {function(NodeImmediate):void} clearImmediate\n * @property {function():number} countTimers\n * @property {RequestAnimationFrame} requestAnimationFrame\n * @property {function(number):void} cancelAnimationFrame\n * @property {function():void} runMicrotasks\n * @property {function(string | number): number} tick\n * @property {function(string | number): Promise<number>} tickAsync\n * @property {function(): number} next\n * @property {function(): Promise<number>} nextAsync\n * @property {function(): number} runAll\n * @property {function(): number} runToFrame\n * @property {function(): Promise<number>} runAllAsync\n * @property {function(): number} runToLast\n * @property {function(): Promise<number>} runToLastAsync\n * @property {function(): void} reset\n * @property {function(number | Date): void} setSystemTime\n * @property {function(number): void} jump\n * @property {Performance} performance\n * @property {function(number[]): number[]} hrtime - process.hrtime (legacy)\n * @property {function(): void} uninstall Uninstall the clock.\n * @property {Function[]} methods - the methods that are faked\n * @property {boolean} [shouldClearNativeTimers] inherited from config\n * @property {{methodName:string, original:any}[] | undefined} timersModuleMethods\n */\n/* eslint-enable jsdoc/require-property-description */\n\n/**\n * Configuration object for the `install` method.\n *\n * @typedef {object} Config\n * @property {number|Date} [now] a number (in milliseconds) or a Date object (default epoch)\n * @property {string[]} [toFake] names of the methods that should be faked.\n * @property {number} [loopLimit] the maximum number of timers that will be run when calling runAll()\n * @property {boolean} [shouldAdvanceTime] tells FakeTimers to increment mocked time automatically (default false)\n * @property {number} [advanceTimeDelta] increment mocked time every <<advanceTimeDelta>> ms (default: 20ms)\n * @property {boolean} [shouldClearNativeTimers] forwards clear timer calls to native functions if they are not fakes (default: false)\n */\n\n/* eslint-disable jsdoc/require-property-description */\n/**\n * The internal structure to describe a scheduled fake timer\n *\n * @typedef {object} Timer\n * @property {Function} func\n * @property {*[]} args\n * @property {number} delay\n * @property {number} callAt\n * @property {number} createdAt\n * @property {boolean} immediate\n * @property {number} id\n * @property {Error} [error]\n */\n\n/**\n * A Node timer\n *\n * @typedef {object} NodeImmediate\n * @property {function(): boolean} hasRef\n * @property {function(): NodeImmediate} ref\n * @property {function(): NodeImmediate} unref\n */\n/* eslint-enable jsdoc/require-property-description */\n\n/**\n * Mocks available features in the specified global namespace.\n *\n * @param {*} _global Namespace to mock (e.g. `window`)\n * @returns {FakeTimers}\n */\nfunction withGlobal(_global) {\n    const maxTimeout = Math.pow(2, 31) - 1; //see https://heycam.github.io/webidl/#abstract-opdef-converttoint\n    const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs\n    const NOOP = function () {\n        return undefined;\n    };\n    const NOOP_ARRAY = function () {\n        return [];\n    };\n    const timeoutResult = _global.setTimeout(NOOP, 0);\n    const addTimerReturnsObject = typeof timeoutResult === "object";\n    const hrtimePresent =\n        _global.process && typeof _global.process.hrtime === "function";\n    const hrtimeBigintPresent =\n        hrtimePresent && typeof _global.process.hrtime.bigint === "function";\n    const nextTickPresent =\n        _global.process && typeof _global.process.nextTick === "function";\n    const utilPromisify = _global.process && require("util").promisify;\n    const performancePresent =\n        _global.performance && typeof _global.performance.now === "function";\n    const hasPerformancePrototype =\n        _global.Performance &&\n        (typeof _global.Performance).match(/^(function|object)$/);\n    const hasPerformanceConstructorPrototype =\n        _global.performance &&\n        _global.performance.constructor &&\n        _global.performance.constructor.prototype;\n    const queueMicrotaskPresent = _global.hasOwnProperty("queueMicrotask");\n    const requestAnimationFramePresent =\n        _global.requestAnimationFrame &&\n        typeof _global.requestAnimationFrame === "function";\n    const cancelAnimationFramePresent =\n        _global.cancelAnimationFrame &&\n        typeof _global.cancelAnimationFrame === "function";\n    const requestIdleCallbackPresent =\n        _global.requestIdleCallback &&\n        typeof _global.requestIdleCallback === "function";\n    const cancelIdleCallbackPresent =\n        _global.cancelIdleCallback &&\n        typeof _global.cancelIdleCallback === "function";\n    const setImmediatePresent =\n        _global.setImmediate && typeof _global.setImmediate === "function";\n    const intlPresent = _global.Intl && typeof _global.Intl === "object";\n\n    _global.clearTimeout(timeoutResult);\n\n    const NativeDate = _global.Date;\n    const NativeIntl = _global.Intl;\n    let uniqueTimerId = idCounterStart;\n\n    /**\n     * @param {number} num\n     * @returns {boolean}\n     */\n    function isNumberFinite(num) {\n        if (Number.isFinite) {\n            return Number.isFinite(num);\n        }\n\n        return isFinite(num);\n    }\n\n    let isNearInfiniteLimit = false;\n\n    /**\n     * @param {Clock} clock\n     * @param {number} i\n     */\n    function checkIsNearInfiniteLimit(clock, i) {\n        if (clock.loopLimit && i === clock.loopLimit - 1) {\n            isNearInfiniteLimit = true;\n        }\n    }\n\n    /**\n     *\n     */\n    function resetIsNearInfiniteLimit() {\n        isNearInfiniteLimit = false;\n    }\n\n    /**\n     * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into\n     * number of milliseconds. This is used to support human-readable strings passed\n     * to clock.tick()\n     *\n     * @param {string} str\n     * @returns {number}\n     */\n    function parseTime(str) {\n        if (!str) {\n            return 0;\n        }\n\n        const strings = str.split(":");\n        const l = strings.length;\n        let i = l;\n        let ms = 0;\n        let parsed;\n\n        if (l > 3 || !/^(\\d\\d:){0,2}\\d\\d?$/.test(str)) {\n            throw new Error(\n                "tick only understands numbers, \'m:s\' and \'h:m:s\'. Each part must be two digits",\n            );\n        }\n\n        while (i--) {\n            parsed = parseInt(strings[i], 10);\n\n            if (parsed >= 60) {\n                throw new Error(`Invalid time ${str}`);\n            }\n\n            ms += parsed * Math.pow(60, l - i - 1);\n        }\n\n        return ms * 1000;\n    }\n\n    /**\n     * Get the decimal part of the millisecond value as nanoseconds\n     *\n     * @param {number} msFloat the number of milliseconds\n     * @returns {number} an integer number of nanoseconds in the range [0,1e6)\n     *\n     * Example: nanoRemainer(123.456789) -> 456789\n     */\n    function nanoRemainder(msFloat) {\n        const modulo = 1e6;\n        const remainder = (msFloat * 1e6) % modulo;\n        const positiveRemainder =\n            remainder < 0 ? remainder + modulo : remainder;\n\n        return Math.floor(positiveRemainder);\n    }\n\n    /**\n     * Used to grok the `now` parameter to createClock.\n     *\n     * @param {Date|number} epoch the system time\n     * @returns {number}\n     */\n    function getEpoch(epoch) {\n        if (!epoch) {\n            return 0;\n        }\n        if (typeof epoch.getTime === "function") {\n            return epoch.getTime();\n        }\n        if (typeof epoch === "number") {\n            return epoch;\n        }\n        throw new TypeError("now should be milliseconds since UNIX epoch");\n    }\n\n    /**\n     * @param {number} from\n     * @param {number} to\n     * @param {Timer} timer\n     * @returns {boolean}\n     */\n    function inRange(from, to, timer) {\n        return timer && timer.callAt >= from && timer.callAt <= to;\n    }\n\n    /**\n     * @param {Clock} clock\n     * @param {Timer} job\n     */\n    function getInfiniteLoopError(clock, job) {\n        const infiniteLoopError = new Error(\n            `Aborting after running ${clock.loopLimit} timers, assuming an infinite loop!`,\n        );\n\n        if (!job.error) {\n            return infiniteLoopError;\n        }\n\n        // pattern never matched in Node\n        const computedTargetPattern = /target\\.*[<|(|[].*?[>|\\]|)]\\s*/;\n        let clockMethodPattern = new RegExp(\n            String(Object.keys(clock).join("|")),\n        );\n\n        if (addTimerReturnsObject) {\n            // node.js environment\n            clockMethodPattern = new RegExp(\n                `\\\\s+at (Object\\\\.)?(?:${Object.keys(clock).join("|")})\\\\s+`,\n            );\n        }\n\n        let matchedLineIndex = -1;\n        job.error.stack.split("\\n").some(function (line, i) {\n            // If we\'ve matched a computed target line (e.g. setTimeout) then we\n            // don\'t need to look any further. Return true to stop iterating.\n            const matchedComputedTarget = line.match(computedTargetPattern);\n            /* istanbul ignore if */\n            if (matchedComputedTarget) {\n                matchedLineIndex = i;\n                return true;\n            }\n\n            // If we\'ve matched a clock method line, then there may still be\n            // others further down the trace. Return false to keep iterating.\n            const matchedClockMethod = line.match(clockMethodPattern);\n            if (matchedClockMethod) {\n                matchedLineIndex = i;\n                return false;\n            }\n\n            // If we haven\'t matched anything on this line, but we matched\n            // previously and set the matched line index, then we can stop.\n            // If we haven\'t matched previously, then we should keep iterating.\n            return matchedLineIndex >= 0;\n        });\n\n        const stack = `${infiniteLoopError}\\n${job.type || "Microtask"} - ${\n            job.func.name || "anonymous"\n        }\\n${job.error.stack\n            .split("\\n")\n            .slice(matchedLineIndex + 1)\n            .join("\\n")}`;\n\n        try {\n            Object.defineProperty(infiniteLoopError, "stack", {\n                value: stack,\n            });\n        } catch (e) {\n            // noop\n        }\n\n        return infiniteLoopError;\n    }\n\n    /**\n     * @param {Date} target\n     * @param {Date} source\n     * @returns {Date} the target after modifications\n     */\n    function mirrorDateProperties(target, source) {\n        let prop;\n        for (prop in source) {\n            if (source.hasOwnProperty(prop)) {\n                target[prop] = source[prop];\n            }\n        }\n\n        // set special now implementation\n        if (source.now) {\n            target.now = function now() {\n                return target.clock.now;\n            };\n        } else {\n            delete target.now;\n        }\n\n        // set special toSource implementation\n        if (source.toSource) {\n            target.toSource = function toSource() {\n                return source.toSource();\n            };\n        } else {\n            delete target.toSource;\n        }\n\n        // set special toString implementation\n        target.toString = function toString() {\n            return source.toString();\n        };\n\n        target.prototype = source.prototype;\n        target.parse = source.parse;\n        target.UTC = source.UTC;\n        target.prototype.toUTCString = source.prototype.toUTCString;\n        target.isFake = true;\n\n        return target;\n    }\n\n    //eslint-disable-next-line jsdoc/require-jsdoc\n    function createDate() {\n        /**\n         * @param {number} year\n         * @param {number} month\n         * @param {number} date\n         * @param {number} hour\n         * @param {number} minute\n         * @param {number} second\n         * @param {number} ms\n         * @returns {Date}\n         */\n        function ClockDate(year, month, date, hour, minute, second, ms) {\n            // the Date constructor called as a function, ref Ecma-262 Edition 5.1, section 15.9.2.\n            // This remains so in the 10th edition of 2019 as well.\n            if (!(this instanceof ClockDate)) {\n                return new NativeDate(ClockDate.clock.now).toString();\n            }\n\n            // if Date is called as a constructor with \'new\' keyword\n            // Defensive and verbose to avoid potential harm in passing\n            // explicit undefined when user does not pass argument\n            switch (arguments.length) {\n                case 0:\n                    return new NativeDate(ClockDate.clock.now);\n                case 1:\n                    return new NativeDate(year);\n                case 2:\n                    return new NativeDate(year, month);\n                case 3:\n                    return new NativeDate(year, month, date);\n                case 4:\n                    return new NativeDate(year, month, date, hour);\n                case 5:\n                    return new NativeDate(year, month, date, hour, minute);\n                case 6:\n                    return new NativeDate(\n                        year,\n                        month,\n                        date,\n                        hour,\n                        minute,\n                        second,\n                    );\n                default:\n                    return new NativeDate(\n                        year,\n                        month,\n                        date,\n                        hour,\n                        minute,\n                        second,\n                        ms,\n                    );\n            }\n        }\n\n        return mirrorDateProperties(ClockDate, NativeDate);\n    }\n\n    /**\n     * Mirror Intl by default on our fake implementation\n     *\n     * Most of the properties are the original native ones,\n     * but we need to take control of those that have a\n     * dependency on the current clock.\n     *\n     * @returns {object} the partly fake Intl implementation\n     */\n    function createIntl() {\n        const ClockIntl = {};\n        /*\n         * All properties of Intl are non-enumerable, so we need\n         * to do a bit of work to get them out.\n         */\n        Object.getOwnPropertyNames(NativeIntl).forEach(\n            (property) => (ClockIntl[property] = NativeIntl[property]),\n        );\n\n        ClockIntl.DateTimeFormat = function (...args) {\n            const realFormatter = new NativeIntl.DateTimeFormat(...args);\n            const formatter = {};\n\n            ["formatRange", "formatRangeToParts", "resolvedOptions"].forEach(\n                (method) => {\n                    formatter[method] =\n                        realFormatter[method].bind(realFormatter);\n                },\n            );\n\n            ["format", "formatToParts"].forEach((method) => {\n                formatter[method] = function (date) {\n                    return realFormatter[method](date || ClockIntl.clock.now);\n                };\n            });\n\n            return formatter;\n        };\n\n        ClockIntl.DateTimeFormat.prototype = Object.create(\n            NativeIntl.DateTimeFormat.prototype,\n        );\n\n        ClockIntl.DateTimeFormat.supportedLocalesOf =\n            NativeIntl.DateTimeFormat.supportedLocalesOf;\n\n        return ClockIntl;\n    }\n\n    //eslint-disable-next-line jsdoc/require-jsdoc\n    function enqueueJob(clock, job) {\n        // enqueues a microtick-deferred task - ecma262/#sec-enqueuejob\n        if (!clock.jobs) {\n            clock.jobs = [];\n        }\n        clock.jobs.push(job);\n    }\n\n    //eslint-disable-next-line jsdoc/require-jsdoc\n    function runJobs(clock) {\n        // runs all microtick-deferred tasks - ecma262/#sec-runjobs\n        if (!clock.jobs) {\n            return;\n        }\n        for (let i = 0; i < clock.jobs.length; i++) {\n            const job = clock.jobs[i];\n            job.func.apply(null, job.args);\n\n            checkIsNearInfiniteLimit(clock, i);\n            if (clock.loopLimit && i > clock.loopLimit) {\n                throw getInfiniteLoopError(clock, job);\n            }\n        }\n        resetIsNearInfiniteLimit();\n        clock.jobs = [];\n    }\n\n    /**\n     * @param {Clock} clock\n     * @param {Timer} timer\n     * @returns {number} id of the created timer\n     */\n    function addTimer(clock, timer) {\n        if (timer.func === undefined) {\n            throw new Error("Callback must be provided to timer calls");\n        }\n\n        if (addTimerReturnsObject) {\n            // Node.js environment\n            if (typeof timer.func !== "function") {\n                throw new TypeError(\n                    `[ERR_INVALID_CALLBACK]: Callback must be a function. Received ${\n                        timer.func\n                    } of type ${typeof timer.func}`,\n                );\n            }\n        }\n\n        if (isNearInfiniteLimit) {\n            timer.error = new Error();\n        }\n\n        timer.type = timer.immediate ? "Immediate" : "Timeout";\n\n        if (timer.hasOwnProperty("delay")) {\n            if (typeof timer.delay !== "number") {\n                timer.delay = parseInt(timer.delay, 10);\n            }\n\n            if (!isNumberFinite(timer.delay)) {\n                timer.delay = 0;\n            }\n            timer.delay = timer.delay > maxTimeout ? 1 : timer.delay;\n            timer.delay = Math.max(0, timer.delay);\n        }\n\n        if (timer.hasOwnProperty("interval")) {\n            timer.type = "Interval";\n            timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;\n        }\n\n        if (timer.hasOwnProperty("animation")) {\n            timer.type = "AnimationFrame";\n            timer.animation = true;\n        }\n\n        if (timer.hasOwnProperty("idleCallback")) {\n            timer.type = "IdleCallback";\n            timer.idleCallback = true;\n        }\n\n        if (!clock.timers) {\n            clock.timers = {};\n        }\n\n        timer.id = uniqueTimerId++;\n        timer.createdAt = clock.now;\n        timer.callAt =\n            clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));\n\n        clock.timers[timer.id] = timer;\n\n        if (addTimerReturnsObject) {\n            const res = {\n                refed: true,\n                ref: function () {\n                    this.refed = true;\n                    return res;\n                },\n                unref: function () {\n                    this.refed = false;\n                    return res;\n                },\n                hasRef: function () {\n                    return this.refed;\n                },\n                refresh: function () {\n                    timer.callAt =\n                        clock.now +\n                        (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));\n\n                    // it _might_ have been removed, but if not the assignment is perfectly fine\n                    clock.timers[timer.id] = timer;\n\n                    return res;\n                },\n                [Symbol.toPrimitive]: function () {\n                    return timer.id;\n                },\n            };\n            return res;\n        }\n\n        return timer.id;\n    }\n\n    /* eslint consistent-return: "off" */\n    /**\n     * Timer comparitor\n     *\n     * @param {Timer} a\n     * @param {Timer} b\n     * @returns {number}\n     */\n    function compareTimers(a, b) {\n        // Sort first by absolute timing\n        if (a.callAt < b.callAt) {\n            return -1;\n        }\n        if (a.callAt > b.callAt) {\n            return 1;\n        }\n\n        // Sort next by immediate, immediate timers take precedence\n        if (a.immediate && !b.immediate) {\n            return -1;\n        }\n        if (!a.immediate && b.immediate) {\n            return 1;\n        }\n\n        // Sort next by creation time, earlier-created timers take precedence\n        if (a.createdAt < b.createdAt) {\n            return -1;\n        }\n        if (a.createdAt > b.createdAt) {\n            return 1;\n        }\n\n        // Sort next by id, lower-id timers take precedence\n        if (a.id < b.id) {\n            return -1;\n        }\n        if (a.id > b.id) {\n            return 1;\n        }\n\n        // As timer ids are unique, no fallback `0` is necessary\n    }\n\n    /**\n     * @param {Clock} clock\n     * @param {number} from\n     * @param {number} to\n     * @returns {Timer}\n     */\n    function firstTimerInRange(clock, from, to) {\n        const timers = clock.timers;\n        let timer = null;\n        let id, isInRange;\n\n        for (id in timers) {\n            if (timers.hasOwnProperty(id)) {\n                isInRange = inRange(from, to, timers[id]);\n\n                if (\n                    isInRange &&\n                    (!timer || compareTimers(timer, timers[id]) === 1)\n                ) {\n                    timer = timers[id];\n                }\n            }\n        }\n\n        return timer;\n    }\n\n    /**\n     * @param {Clock} clock\n     * @returns {Timer}\n     */\n    function firstTimer(clock) {\n        const timers = clock.timers;\n        let timer = null;\n        let id;\n\n        for (id in timers) {\n            if (timers.hasOwnProperty(id)) {\n                if (!timer || compareTimers(timer, timers[id]) === 1) {\n                    timer = timers[id];\n                }\n            }\n        }\n\n        return timer;\n    }\n\n    /**\n     * @param {Clock} clock\n     * @returns {Timer}\n     */\n    function lastTimer(clock) {\n        const timers = clock.timers;\n        let timer = null;\n        let id;\n\n        for (id in timers) {\n            if (timers.hasOwnProperty(id)) {\n                if (!timer || compareTimers(timer, timers[id]) === -1) {\n                    timer = timers[id];\n                }\n            }\n        }\n\n        return timer;\n    }\n\n    /**\n     * @param {Clock} clock\n     * @param {Timer} timer\n     */\n    function callTimer(clock, timer) {\n        if (typeof timer.interval === "number") {\n            clock.timers[timer.id].callAt += timer.interval;\n        } else {\n            delete clock.timers[timer.id];\n        }\n\n        if (typeof timer.func === "function") {\n            timer.func.apply(null, timer.args);\n        } else {\n            /* eslint no-eval: "off" */\n            const eval2 = eval;\n            (function () {\n                eval2(timer.func);\n            })();\n        }\n    }\n\n    /**\n     * Gets clear handler name for a given timer type\n     *\n     * @param {string} ttype\n     */\n    function getClearHandler(ttype) {\n        if (ttype === "IdleCallback" || ttype === "AnimationFrame") {\n            return `cancel${ttype}`;\n        }\n        return `clear${ttype}`;\n    }\n\n    /**\n     * Gets schedule handler name for a given timer type\n     *\n     * @param {string} ttype\n     */\n    function getScheduleHandler(ttype) {\n        if (ttype === "IdleCallback" || ttype === "AnimationFrame") {\n            return `request${ttype}`;\n        }\n        return `set${ttype}`;\n    }\n\n    /**\n     * Creates an anonymous function to warn only once\n     */\n    function createWarnOnce() {\n        let calls = 0;\n        return function (msg) {\n            // eslint-disable-next-line\n            !calls++ && console.warn(msg);\n        };\n    }\n    const warnOnce = createWarnOnce();\n\n    /**\n     * @param {Clock} clock\n     * @param {number} timerId\n     * @param {string} ttype\n     */\n    function clearTimer(clock, timerId, ttype) {\n        if (!timerId) {\n            // null appears to be allowed in most browsers, and appears to be\n            // relied upon by some libraries, like Bootstrap carousel\n            return;\n        }\n\n        if (!clock.timers) {\n            clock.timers = {};\n        }\n\n        // in Node, the ID is stored as the primitive value for `Timeout` objects\n        // for `Immediate` objects, no ID exists, so it gets coerced to NaN\n        const id = Number(timerId);\n\n        if (Number.isNaN(id) || id < idCounterStart) {\n            const handlerName = getClearHandler(ttype);\n\n            if (clock.shouldClearNativeTimers === true) {\n                const nativeHandler = clock[`_${handlerName}`];\n                return typeof nativeHandler === "function"\n                    ? nativeHandler(timerId)\n                    : undefined;\n            }\n            warnOnce(\n                `FakeTimers: ${handlerName} was invoked to clear a native timer instead of one created by this library.` +\n                    "\\nTo automatically clean-up native timers, use `shouldClearNativeTimers`.",\n            );\n        }\n\n        if (clock.timers.hasOwnProperty(id)) {\n            // check that the ID matches a timer of the correct type\n            const timer = clock.timers[id];\n            if (\n                timer.type === ttype ||\n                (timer.type === "Timeout" && ttype === "Interval") ||\n                (timer.type === "Interval" && ttype === "Timeout")\n            ) {\n                delete clock.timers[id];\n            } else {\n                const clear = getClearHandler(ttype);\n                const schedule = getScheduleHandler(timer.type);\n                throw new Error(\n                    `Cannot clear timer: timer created with ${schedule}() but cleared with ${clear}()`,\n                );\n            }\n        }\n    }\n\n    /**\n     * @param {Clock} clock\n     * @param {Config} config\n     * @returns {Timer[]}\n     */\n    function uninstall(clock, config) {\n        let method, i, l;\n        const installedHrTime = "_hrtime";\n        const installedNextTick = "_nextTick";\n\n        for (i = 0, l = clock.methods.length; i < l; i++) {\n            method = clock.methods[i];\n            if (method === "hrtime" && _global.process) {\n                _global.process.hrtime = clock[installedHrTime];\n            } else if (method === "nextTick" && _global.process) {\n                _global.process.nextTick = clock[installedNextTick];\n            } else if (method === "performance") {\n                const originalPerfDescriptor = Object.getOwnPropertyDescriptor(\n                    clock,\n                    `_${method}`,\n                );\n                if (\n                    originalPerfDescriptor &&\n                    originalPerfDescriptor.get &&\n                    !originalPerfDescriptor.set\n                ) {\n                    Object.defineProperty(\n                        _global,\n                        method,\n                        originalPerfDescriptor,\n                    );\n                } else if (originalPerfDescriptor.configurable) {\n                    _global[method] = clock[`_${method}`];\n                }\n            } else {\n                if (_global[method] && _global[method].hadOwnProperty) {\n                    _global[method] = clock[`_${method}`];\n                } else {\n                    try {\n                        delete _global[method];\n                    } catch (ignore) {\n                        /* eslint no-empty: "off" */\n                    }\n                }\n            }\n        }\n\n        if (config.shouldAdvanceTime === true) {\n            _global.clearInterval(clock.attachedInterval);\n        }\n\n        // Prevent multiple executions which will completely remove these props\n        clock.methods = [];\n\n        // return pending timers, to enable checking what timers remained on uninstall\n        if (!clock.timers) {\n            return [];\n        }\n        return Object.keys(clock.timers).map(function mapper(key) {\n            return clock.timers[key];\n        });\n    }\n\n    /**\n     * @param {object} target the target containing the method to replace\n     * @param {string} method the keyname of the method on the target\n     * @param {Clock} clock\n     */\n    function hijackMethod(target, method, clock) {\n        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(\n            target,\n            method,\n        );\n        clock[`_${method}`] = target[method];\n\n        if (method === "Date") {\n            const date = mirrorDateProperties(clock[method], target[method]);\n            target[method] = date;\n        } else if (method === "Intl") {\n            target[method] = clock[method];\n        } else if (method === "performance") {\n            const originalPerfDescriptor = Object.getOwnPropertyDescriptor(\n                target,\n                method,\n            );\n            // JSDOM has a read only performance field so we have to save/copy it differently\n            if (\n                originalPerfDescriptor &&\n                originalPerfDescriptor.get &&\n                !originalPerfDescriptor.set\n            ) {\n                Object.defineProperty(\n                    clock,\n                    `_${method}`,\n                    originalPerfDescriptor,\n                );\n\n                const perfDescriptor = Object.getOwnPropertyDescriptor(\n                    clock,\n                    method,\n                );\n                Object.defineProperty(target, method, perfDescriptor);\n            } else {\n                target[method] = clock[method];\n            }\n        } else {\n            target[method] = function () {\n                return clock[method].apply(clock, arguments);\n            };\n\n            Object.defineProperties(\n                target[method],\n                Object.getOwnPropertyDescriptors(clock[method]),\n            );\n        }\n\n        target[method].clock = clock;\n    }\n\n    /**\n     * @param {Clock} clock\n     * @param {number} advanceTimeDelta\n     */\n    function doIntervalTick(clock, advanceTimeDelta) {\n        clock.tick(advanceTimeDelta);\n    }\n\n    /**\n     * @typedef {object} Timers\n     * @property {setTimeout} setTimeout\n     * @property {clearTimeout} clearTimeout\n     * @property {setInterval} setInterval\n     * @property {clearInterval} clearInterval\n     * @property {Date} Date\n     * @property {Intl} Intl\n     * @property {SetImmediate=} setImmediate\n     * @property {function(NodeImmediate): void=} clearImmediate\n     * @property {function(number[]):number[]=} hrtime\n     * @property {NextTick=} nextTick\n     * @property {Performance=} performance\n     * @property {RequestAnimationFrame=} requestAnimationFrame\n     * @property {boolean=} queueMicrotask\n     * @property {function(number): void=} cancelAnimationFrame\n     * @property {RequestIdleCallback=} requestIdleCallback\n     * @property {function(number): void=} cancelIdleCallback\n     */\n\n    /** @type {Timers} */\n    const timers = {\n        setTimeout: _global.setTimeout,\n        clearTimeout: _global.clearTimeout,\n        setInterval: _global.setInterval,\n        clearInterval: _global.clearInterval,\n        Date: _global.Date,\n    };\n\n    if (setImmediatePresent) {\n        timers.setImmediate = _global.setImmediate;\n        timers.clearImmediate = _global.clearImmediate;\n    }\n\n    if (hrtimePresent) {\n        timers.hrtime = _global.process.hrtime;\n    }\n\n    if (nextTickPresent) {\n        timers.nextTick = _global.process.nextTick;\n    }\n\n    if (performancePresent) {\n        timers.performance = _global.performance;\n    }\n\n    if (requestAnimationFramePresent) {\n        timers.requestAnimationFrame = _global.requestAnimationFrame;\n    }\n\n    if (queueMicrotaskPresent) {\n        timers.queueMicrotask = true;\n    }\n\n    if (cancelAnimationFramePresent) {\n        timers.cancelAnimationFrame = _global.cancelAnimationFrame;\n    }\n\n    if (requestIdleCallbackPresent) {\n        timers.requestIdleCallback = _global.requestIdleCallback;\n    }\n\n    if (cancelIdleCallbackPresent) {\n        timers.cancelIdleCallback = _global.cancelIdleCallback;\n    }\n\n    if (intlPresent) {\n        timers.Intl = _global.Intl;\n    }\n\n    const originalSetTimeout = _global.setImmediate || _global.setTimeout;\n\n    /**\n     * @param {Date|number} [start] the system time - non-integer values are floored\n     * @param {number} [loopLimit] maximum number of timers that will be run when calling runAll()\n     * @returns {Clock}\n     */\n    function createClock(start, loopLimit) {\n        // eslint-disable-next-line no-param-reassign\n        start = Math.floor(getEpoch(start));\n        // eslint-disable-next-line no-param-reassign\n        loopLimit = loopLimit || 1000;\n        let nanos = 0;\n        const adjustedSystemTime = [0, 0]; // [millis, nanoremainder]\n\n        if (NativeDate === undefined) {\n            throw new Error(\n                "The global scope doesn\'t have a `Date` object" +\n                    " (see https://github.com/sinonjs/sinon/issues/1852#issuecomment-419622780)",\n            );\n        }\n\n        const clock = {\n            now: start,\n            Date: createDate(),\n            loopLimit: loopLimit,\n        };\n\n        clock.Date.clock = clock;\n\n        //eslint-disable-next-line jsdoc/require-jsdoc\n        function getTimeToNextFrame() {\n            return 16 - ((clock.now - start) % 16);\n        }\n\n        //eslint-disable-next-line jsdoc/require-jsdoc\n        function hrtime(prev) {\n            const millisSinceStart = clock.now - adjustedSystemTime[0] - start;\n            const secsSinceStart = Math.floor(millisSinceStart / 1000);\n            const remainderInNanos =\n                (millisSinceStart - secsSinceStart * 1e3) * 1e6 +\n                nanos -\n                adjustedSystemTime[1];\n\n            if (Array.isArray(prev)) {\n                if (prev[1] > 1e9) {\n                    throw new TypeError(\n                        "Number of nanoseconds can\'t exceed a billion",\n                    );\n                }\n\n                const oldSecs = prev[0];\n                let nanoDiff = remainderInNanos - prev[1];\n                let secDiff = secsSinceStart - oldSecs;\n\n                if (nanoDiff < 0) {\n                    nanoDiff += 1e9;\n                    secDiff -= 1;\n                }\n\n                return [secDiff, nanoDiff];\n            }\n            return [secsSinceStart, remainderInNanos];\n        }\n\n        /**\n         * A high resolution timestamp in milliseconds.\n         *\n         * @typedef {number} DOMHighResTimeStamp\n         */\n\n        /**\n         * performance.now()\n         *\n         * @returns {DOMHighResTimeStamp}\n         */\n        function fakePerformanceNow() {\n            const hrt = hrtime();\n            const millis = hrt[0] * 1000 + hrt[1] / 1e6;\n            return millis;\n        }\n\n        if (hrtimeBigintPresent) {\n            hrtime.bigint = function () {\n                const parts = hrtime();\n                return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line\n            };\n        }\n\n        if (intlPresent) {\n            clock.Intl = createIntl();\n            clock.Intl.clock = clock;\n        }\n\n        clock.requestIdleCallback = function requestIdleCallback(\n            func,\n            timeout,\n        ) {\n            let timeToNextIdlePeriod = 0;\n\n            if (clock.countTimers() > 0) {\n                timeToNextIdlePeriod = 50; // const for now\n            }\n\n            const result = addTimer(clock, {\n                func: func,\n                args: Array.prototype.slice.call(arguments, 2),\n                delay:\n                    typeof timeout === "undefined"\n                        ? timeToNextIdlePeriod\n                        : Math.min(timeout, timeToNextIdlePeriod),\n                idleCallback: true,\n            });\n\n            return Number(result);\n        };\n\n        clock.cancelIdleCallback = function cancelIdleCallback(timerId) {\n            return clearTimer(clock, timerId, "IdleCallback");\n        };\n\n        clock.setTimeout = function setTimeout(func, timeout) {\n            return addTimer(clock, {\n                func: func,\n                args: Array.prototype.slice.call(arguments, 2),\n                delay: timeout,\n            });\n        };\n        if (typeof _global.Promise !== "undefined" && utilPromisify) {\n            clock.setTimeout[utilPromisify.custom] =\n                function promisifiedSetTimeout(timeout, arg) {\n                    return new _global.Promise(function setTimeoutExecutor(\n                        resolve,\n                    ) {\n                        addTimer(clock, {\n                            func: resolve,\n                            args: [arg],\n                            delay: timeout,\n                        });\n                    });\n                };\n        }\n\n        clock.clearTimeout = function clearTimeout(timerId) {\n            return clearTimer(clock, timerId, "Timeout");\n        };\n\n        clock.nextTick = function nextTick(func) {\n            return enqueueJob(clock, {\n                func: func,\n                args: Array.prototype.slice.call(arguments, 1),\n                error: isNearInfiniteLimit ? new Error() : null,\n            });\n        };\n\n        clock.queueMicrotask = function queueMicrotask(func) {\n            return clock.nextTick(func); // explicitly drop additional arguments\n        };\n\n        clock.setInterval = function setInterval(func, timeout) {\n            // eslint-disable-next-line no-param-reassign\n            timeout = parseInt(timeout, 10);\n            return addTimer(clock, {\n                func: func,\n                args: Array.prototype.slice.call(arguments, 2),\n                delay: timeout,\n                interval: timeout,\n            });\n        };\n\n        clock.clearInterval = function clearInterval(timerId) {\n            return clearTimer(clock, timerId, "Interval");\n        };\n\n        if (setImmediatePresent) {\n            clock.setImmediate = function setImmediate(func) {\n                return addTimer(clock, {\n                    func: func,\n                    args: Array.prototype.slice.call(arguments, 1),\n                    immediate: true,\n                });\n            };\n\n            if (typeof _global.Promise !== "undefined" && utilPromisify) {\n                clock.setImmediate[utilPromisify.custom] =\n                    function promisifiedSetImmediate(arg) {\n                        return new _global.Promise(\n                            function setImmediateExecutor(resolve) {\n                                addTimer(clock, {\n                                    func: resolve,\n                                    args: [arg],\n                                    immediate: true,\n                                });\n                            },\n                        );\n                    };\n            }\n\n            clock.clearImmediate = function clearImmediate(timerId) {\n                return clearTimer(clock, timerId, "Immediate");\n            };\n        }\n\n        clock.countTimers = function countTimers() {\n            return (\n                Object.keys(clock.timers || {}).length +\n                (clock.jobs || []).length\n            );\n        };\n\n        clock.requestAnimationFrame = function requestAnimationFrame(func) {\n            const result = addTimer(clock, {\n                func: func,\n                delay: getTimeToNextFrame(),\n                get args() {\n                    return [fakePerformanceNow()];\n                },\n                animation: true,\n            });\n\n            return Number(result);\n        };\n\n        clock.cancelAnimationFrame = function cancelAnimationFrame(timerId) {\n            return clearTimer(clock, timerId, "AnimationFrame");\n        };\n\n        clock.runMicrotasks = function runMicrotasks() {\n            runJobs(clock);\n        };\n\n        /**\n         * @param {number|string} tickValue milliseconds or a string parseable by parseTime\n         * @param {boolean} isAsync\n         * @param {Function} resolve\n         * @param {Function} reject\n         * @returns {number|undefined} will return the new `now` value or nothing for async\n         */\n        function doTick(tickValue, isAsync, resolve, reject) {\n            const msFloat =\n                typeof tickValue === "number"\n                    ? tickValue\n                    : parseTime(tickValue);\n            const ms = Math.floor(msFloat);\n            const remainder = nanoRemainder(msFloat);\n            let nanosTotal = nanos + remainder;\n            let tickTo = clock.now + ms;\n\n            if (msFloat < 0) {\n                throw new TypeError("Negative ticks are not supported");\n            }\n\n            // adjust for positive overflow\n            if (nanosTotal >= 1e6) {\n                tickTo += 1;\n                nanosTotal -= 1e6;\n            }\n\n            nanos = nanosTotal;\n            let tickFrom = clock.now;\n            let previous = clock.now;\n            // ESLint fails to detect this correctly\n            /* eslint-disable prefer-const */\n            let timer,\n                firstException,\n                oldNow,\n                nextPromiseTick,\n                compensationCheck,\n                postTimerCall;\n            /* eslint-enable prefer-const */\n\n            clock.duringTick = true;\n\n            // perform microtasks\n            oldNow = clock.now;\n            runJobs(clock);\n            if (oldNow !== clock.now) {\n                // compensate for any setSystemTime() call during microtask callback\n                tickFrom += clock.now - oldNow;\n                tickTo += clock.now - oldNow;\n            }\n\n            //eslint-disable-next-line jsdoc/require-jsdoc\n            function doTickInner() {\n                // perform each timer in the requested range\n                timer = firstTimerInRange(clock, tickFrom, tickTo);\n                // eslint-disable-next-line no-unmodified-loop-condition\n                while (timer && tickFrom <= tickTo) {\n                    if (clock.timers[timer.id]) {\n                        tickFrom = timer.callAt;\n                        clock.now = timer.callAt;\n                        oldNow = clock.now;\n                        try {\n                            runJobs(clock);\n                            callTimer(clock, timer);\n                        } catch (e) {\n                            firstException = firstException || e;\n                        }\n\n                        if (isAsync) {\n                            // finish up after native setImmediate callback to allow\n                            // all native es6 promises to process their callbacks after\n                            // each timer fires.\n                            originalSetTimeout(nextPromiseTick);\n                            return;\n                        }\n\n                        compensationCheck();\n                    }\n\n                    postTimerCall();\n                }\n\n                // perform process.nextTick()s again\n                oldNow = clock.now;\n                runJobs(clock);\n                if (oldNow !== clock.now) {\n                    // compensate for any setSystemTime() call during process.nextTick() callback\n                    tickFrom += clock.now - oldNow;\n                    tickTo += clock.now - oldNow;\n                }\n                clock.duringTick = false;\n\n                // corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]\n                timer = firstTimerInRange(clock, tickFrom, tickTo);\n                if (timer) {\n                    try {\n                        clock.tick(tickTo - clock.now); // do it all again - for the remainder of the requested range\n                    } catch (e) {\n                        firstException = firstException || e;\n                    }\n                } else {\n                    // no timers remaining in the requested range: move the clock all the way to the end\n                    clock.now = tickTo;\n\n                    // update nanos\n                    nanos = nanosTotal;\n                }\n                if (firstException) {\n                    throw firstException;\n                }\n\n                if (isAsync) {\n                    resolve(clock.now);\n                } else {\n                    return clock.now;\n                }\n            }\n\n            nextPromiseTick =\n                isAsync &&\n                function () {\n                    try {\n                        compensationCheck();\n                        postTimerCall();\n                        doTickInner();\n                    } catch (e) {\n                        reject(e);\n                    }\n                };\n\n            compensationCheck = function () {\n                // compensate for any setSystemTime() call during timer callback\n                if (oldNow !== clock.now) {\n                    tickFrom += clock.now - oldNow;\n                    tickTo += clock.now - oldNow;\n                    previous += clock.now - oldNow;\n                }\n            };\n\n            postTimerCall = function () {\n                timer = firstTimerInRange(clock, previous, tickTo);\n                previous = tickFrom;\n            };\n\n            return doTickInner();\n        }\n\n        /**\n         * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"\n         * @returns {number} will return the new `now` value\n         */\n        clock.tick = function tick(tickValue) {\n            return doTick(tickValue, false);\n        };\n\n        if (typeof _global.Promise !== "undefined") {\n            /**\n             * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"\n             * @returns {Promise}\n             */\n            clock.tickAsync = function tickAsync(tickValue) {\n                return new _global.Promise(function (resolve, reject) {\n                    originalSetTimeout(function () {\n                        try {\n                            doTick(tickValue, true, resolve, reject);\n                        } catch (e) {\n                            reject(e);\n                        }\n                    });\n                });\n            };\n        }\n\n        clock.next = function next() {\n            runJobs(clock);\n            const timer = firstTimer(clock);\n            if (!timer) {\n                return clock.now;\n            }\n\n            clock.duringTick = true;\n            try {\n                clock.now = timer.callAt;\n                callTimer(clock, timer);\n                runJobs(clock);\n                return clock.now;\n            } finally {\n                clock.duringTick = false;\n            }\n        };\n\n        if (typeof _global.Promise !== "undefined") {\n            clock.nextAsync = function nextAsync() {\n                return new _global.Promise(function (resolve, reject) {\n                    originalSetTimeout(function () {\n                        try {\n                            const timer = firstTimer(clock);\n                            if (!timer) {\n                                resolve(clock.now);\n                                return;\n                            }\n\n                            let err;\n                            clock.duringTick = true;\n                            clock.now = timer.callAt;\n                            try {\n                                callTimer(clock, timer);\n                            } catch (e) {\n                                err = e;\n                            }\n                            clock.duringTick = false;\n\n                            originalSetTimeout(function () {\n                                if (err) {\n                                    reject(err);\n                                } else {\n                                    resolve(clock.now);\n                                }\n                            });\n                        } catch (e) {\n                            reject(e);\n                        }\n                    });\n                });\n            };\n        }\n\n        clock.runAll = function runAll() {\n            let numTimers, i;\n            runJobs(clock);\n            for (i = 0; i < clock.loopLimit; i++) {\n                if (!clock.timers) {\n                    resetIsNearInfiniteLimit();\n                    return clock.now;\n                }\n\n                numTimers = Object.keys(clock.timers).length;\n                if (numTimers === 0) {\n                    resetIsNearInfiniteLimit();\n                    return clock.now;\n                }\n\n                clock.next();\n                checkIsNearInfiniteLimit(clock, i);\n            }\n\n            const excessJob = firstTimer(clock);\n            throw getInfiniteLoopError(clock, excessJob);\n        };\n\n        clock.runToFrame = function runToFrame() {\n            return clock.tick(getTimeToNextFrame());\n        };\n\n        if (typeof _global.Promise !== "undefined") {\n            clock.runAllAsync = function runAllAsync() {\n                return new _global.Promise(function (resolve, reject) {\n                    let i = 0;\n                    /**\n                     *\n                     */\n                    function doRun() {\n                        originalSetTimeout(function () {\n                            try {\n                                runJobs(clock);\n\n                                let numTimers;\n                                if (i < clock.loopLimit) {\n                                    if (!clock.timers) {\n                                        resetIsNearInfiniteLimit();\n                                        resolve(clock.now);\n                                        return;\n                                    }\n\n                                    numTimers = Object.keys(\n                                        clock.timers,\n                                    ).length;\n                                    if (numTimers === 0) {\n                                        resetIsNearInfiniteLimit();\n                                        resolve(clock.now);\n                                        return;\n                                    }\n\n                                    clock.next();\n\n                                    i++;\n\n                                    doRun();\n                                    checkIsNearInfiniteLimit(clock, i);\n                                    return;\n                                }\n\n                                const excessJob = firstTimer(clock);\n                                reject(getInfiniteLoopError(clock, excessJob));\n                            } catch (e) {\n                                reject(e);\n                            }\n                        });\n                    }\n                    doRun();\n                });\n            };\n        }\n\n        clock.runToLast = function runToLast() {\n            const timer = lastTimer(clock);\n            if (!timer) {\n                runJobs(clock);\n                return clock.now;\n            }\n\n            return clock.tick(timer.callAt - clock.now);\n        };\n\n        if (typeof _global.Promise !== "undefined") {\n            clock.runToLastAsync = function runToLastAsync() {\n                return new _global.Promise(function (resolve, reject) {\n                    originalSetTimeout(function () {\n                        try {\n                            const timer = lastTimer(clock);\n                            if (!timer) {\n                                runJobs(clock);\n                                resolve(clock.now);\n                            }\n\n                            resolve(clock.tickAsync(timer.callAt - clock.now));\n                        } catch (e) {\n                            reject(e);\n                        }\n                    });\n                });\n            };\n        }\n\n        clock.reset = function reset() {\n            nanos = 0;\n            clock.timers = {};\n            clock.jobs = [];\n            clock.now = start;\n        };\n\n        clock.setSystemTime = function setSystemTime(systemTime) {\n            // determine time difference\n            const newNow = getEpoch(systemTime);\n            const difference = newNow - clock.now;\n            let id, timer;\n\n            adjustedSystemTime[0] = adjustedSystemTime[0] + difference;\n            adjustedSystemTime[1] = adjustedSystemTime[1] + nanos;\n            // update \'system clock\'\n            clock.now = newNow;\n            nanos = 0;\n\n            // update timers and intervals to keep them stable\n            for (id in clock.timers) {\n                if (clock.timers.hasOwnProperty(id)) {\n                    timer = clock.timers[id];\n                    timer.createdAt += difference;\n                    timer.callAt += difference;\n                }\n            }\n        };\n\n        /**\n         * @param {string|number} tickValue number of milliseconds or a human-readable value like "01:11:15"\n         * @returns {number} will return the new `now` value\n         */\n        clock.jump = function jump(tickValue) {\n            const msFloat =\n                typeof tickValue === "number"\n                    ? tickValue\n                    : parseTime(tickValue);\n            const ms = Math.floor(msFloat);\n\n            for (const timer of Object.values(clock.timers)) {\n                if (clock.now + ms > timer.callAt) {\n                    timer.callAt = clock.now + ms;\n                }\n            }\n            clock.tick(ms);\n        };\n\n        if (performancePresent) {\n            clock.performance = Object.create(null);\n            clock.performance.now = fakePerformanceNow;\n        }\n\n        if (hrtimePresent) {\n            clock.hrtime = hrtime;\n        }\n\n        return clock;\n    }\n\n    /* eslint-disable complexity */\n\n    /**\n     * @param {Config=} [config] Optional config\n     * @returns {Clock}\n     */\n    function install(config) {\n        if (\n            arguments.length > 1 ||\n            config instanceof Date ||\n            Array.isArray(config) ||\n            typeof config === "number"\n        ) {\n            throw new TypeError(\n                `FakeTimers.install called with ${String(\n                    config,\n                )} install requires an object parameter`,\n            );\n        }\n\n        if (_global.Date.isFake === true) {\n            // Timers are already faked; this is a problem.\n            // Make the user reset timers before continuing.\n            throw new TypeError(\n                "Can\'t install fake timers twice on the same global object.",\n            );\n        }\n\n        // eslint-disable-next-line no-param-reassign\n        config = typeof config !== "undefined" ? config : {};\n        config.shouldAdvanceTime = config.shouldAdvanceTime || false;\n        config.advanceTimeDelta = config.advanceTimeDelta || 20;\n        config.shouldClearNativeTimers =\n            config.shouldClearNativeTimers || false;\n\n        if (config.target) {\n            throw new TypeError(\n                "config.target is no longer supported. Use `withGlobal(target)` instead.",\n            );\n        }\n\n        let i, l;\n        const clock = createClock(config.now, config.loopLimit);\n        clock.shouldClearNativeTimers = config.shouldClearNativeTimers;\n\n        clock.uninstall = function () {\n            return uninstall(clock, config);\n        };\n\n        clock.methods = config.toFake || [];\n\n        if (clock.methods.length === 0) {\n            // do not fake nextTick by default - GitHub#126\n            clock.methods = Object.keys(timers).filter(function (key) {\n                return key !== "nextTick" && key !== "queueMicrotask";\n            });\n        }\n\n        if (config.shouldAdvanceTime === true) {\n            const intervalTick = doIntervalTick.bind(\n                null,\n                clock,\n                config.advanceTimeDelta,\n            );\n            const intervalId = _global.setInterval(\n                intervalTick,\n                config.advanceTimeDelta,\n            );\n            clock.attachedInterval = intervalId;\n        }\n\n        if (clock.methods.includes("performance")) {\n            const proto = (() => {\n                if (hasPerformanceConstructorPrototype) {\n                    return _global.performance.constructor.prototype;\n                }\n                if (hasPerformancePrototype) {\n                    return _global.Performance.prototype;\n                }\n            })();\n            if (proto) {\n                Object.getOwnPropertyNames(proto).forEach(function (name) {\n                    if (name !== "now") {\n                        clock.performance[name] =\n                            name.indexOf("getEntries") === 0\n                                ? NOOP_ARRAY\n                                : NOOP;\n                    }\n                });\n            } else if ((config.toFake || []).includes("performance")) {\n                // user explicitly tried to fake performance when not present\n                throw new ReferenceError(\n                    "non-existent performance object cannot be faked",\n                );\n            }\n        }\n        for (i = 0, l = clock.methods.length; i < l; i++) {\n            const nameOfMethodToReplace = clock.methods[i];\n            if (nameOfMethodToReplace === "hrtime") {\n                if (\n                    _global.process &&\n                    typeof _global.process.hrtime === "function"\n                ) {\n                    hijackMethod(_global.process, nameOfMethodToReplace, clock);\n                }\n            } else if (nameOfMethodToReplace === "nextTick") {\n                if (\n                    _global.process &&\n                    typeof _global.process.nextTick === "function"\n                ) {\n                    hijackMethod(_global.process, nameOfMethodToReplace, clock);\n                }\n            } else {\n                hijackMethod(_global, nameOfMethodToReplace, clock);\n            }\n        }\n\n        return clock;\n    }\n\n    /* eslint-enable complexity */\n\n    return {\n        timers: timers,\n        createClock: createClock,\n        install: install,\n        withGlobal: withGlobal,\n    };\n}\n\n/**\n * @typedef {object} FakeTimers\n * @property {Timers} timers\n * @property {createClock} createClock\n * @property {Function} install\n * @property {withGlobal} withGlobal\n */\n\n// /** @type {FakeTimers} */\nwindow.__wdio_sinon = withGlobal(globalThis);\n\n// // exports.timers = defaultImplementation.timers;\n// // exports.createClock = defaultImplementation.createClock;\n// // exports.install = defaultImplementation.install;\n// // exports.withGlobal = withGlobal;\n}\n';
    ClockManager = class {
      #browser;
      /**
       * Where the clock runs: the session's current context, or a held tab
       * when `emulate('clock')` was called on one.
       */
      #scope;
      #resetFn = () => Promise.resolve();
      #isInstalled = false;
      constructor(scope) {
        this.#scope = scope;
        this.#browser = isBrowsingContext(scope) ? scope.browser : scope;
      }
      #execute(script, ...args) {
        return this.#scope.execute(script, ...args);
      }
      /**
       * Install fake timers on the browser. If you call the `emulate` command, WebdriverIO will automatically install
       * the fake timers for you. You can use this method to re-install the fake timers if you have called `restore`.
       *
       * @param options {FakeTimerInstallOpts} Options to pass to the fake clock
       * @returns {Promise<void>}
       */
      async install(options) {
        if (this.#isInstalled) {
          return log7.warn("Fake timers are already installed");
        }
        if (globalThis.window) {
          return;
        }
        const emulateOptions = options || {};
        const functionDeclaration = fakerScript;
        const installOptions = {
          ...emulateOptions,
          now: emulateOptions.now && emulateOptions.now instanceof Date ? emulateOptions.now.getTime() : emulateOptions.now
        };
        const [, libScript, restoreInstallScript] = await Promise.all([
          /**
           * install fake timers for current ex
           */
          (isBrowsingContext(this.#scope) ? this.#scope.execute(`return (${functionDeclaration}).apply(null, arguments)`) : this.#browser.executeScript(`return (${functionDeclaration}).apply(null, arguments)`, [])).then(() => this.#execute(installFakeTimers, installOptions)),
          /**
           * add preload script to to emulate clock for upcoming page loads
           */
          this.#browser.scriptAddPreloadScript({
            functionDeclaration,
            ...isBrowsingContext(this.#scope) ? { contexts: [this.#scope.contextId] } : {}
          }),
          this.#scope.addInitScript(installFakeTimers, installOptions)
        ]);
        this.#resetFn = async () => Promise.all([
          this.#browser.scriptRemovePreloadScript({ script: libScript.script }),
          this.#execute(uninstallFakeTimers),
          restoreInstallScript
        ]);
        this.#isInstalled = true;
      }
      /**
       * Restore all overridden native functions. This is automatically called between tests, so should not
       * generally be needed.
       *
       * ```ts
       * it('should restore the clock', async () => {
       *   console.log(new Date()) // returns e.g. 1722560447102
       *
       *   const clock = await browser.emulate('clock', { now: new Date(2021, 3, 14) })
       *   console.log(await browser.execute(() => new Date().getTime())) // returns 1618383600000
       *
       *   await clock.restore()
       *   console.log(await browser.execute(() => new Date().getTime())) // returns 1722560447102
       * })
       * ```
       *
       * @returns {Promise<void>}
       */
      async restore() {
        await this.#resetFn();
        this.#isInstalled = false;
      }
      /**
       * Move the clock the specified number of `milliseconds`. Any timers within the affected range of time will be called.
       * @param ms {number} The number of milliseconds to move the clock.
       *
       * ```ts
       * it('should move the clock', async () => {
       *   console.log(new Date()) // returns e.g. 1722560447102
       *
       *   const clock = await browser.emulate('clock', { now: new Date(2021, 3, 14) })
       *   console.log(await browser.execute(() => new Date().getTime())) // returns 1618383600000
       *
       *   await clock.tick(1000)
       *   console.log(await browser.execute(() => new Date().getTime())) // returns 1618383601000
       * })
       * ```
       *
       * @param    {number}  ms  The number of milliseconds to move the clock.
       * @returns  {Promise<void>}
       */
      async tick(ms) {
        await this.#execute((ms2) => window.__clock.tick(ms2), ms);
      }
      /**
       * Change the system time to the new now. Now can be a timestamp, date object, or not passed in which defaults
       * to 0. No timers will be called, nor will the time left before they trigger change.
       *
       * ```ts
       * it('should set the system time', async () => {
       *   const clock = await browser.emulate('clock', { now: new Date(2021, 3, 14) })
       *   console.log(await browser.execute(() => new Date().getTime())) // returns 1618383600000
       *
       *   await clock.setSystemTime(new Date(2011, 3, 15))
       *   console.log(await browser.execute(() => new Date().getTime())) // returns 1302850800000
       * })
       * ```
       *
       * @param date {Date|number} The new date to set the system time to.
       * @returns    {Promise<void>}
       */
      async setSystemTime(date) {
        const serializableSystemTime = date instanceof Date ? date.getTime() : date;
        await this.#execute((date2) => window.__clock.setSystemTime(date2), serializableSystemTime);
      }
    };
  }
});

// src/deviceDescriptorsSource.ts
var deviceDescriptorsSource;
var init_deviceDescriptorsSource = __esm({
  "src/deviceDescriptorsSource.ts"() {
    "use strict";
    deviceDescriptorsSource = {
      "Blackberry PlayBook": {
        userAgent: "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/18.0 Safari/536.2+",
        viewport: {
          width: 600,
          height: 1024
        },
        deviceScaleFactor: 1,
        isMobile: true,
        hasTouch: true
      },
      "Blackberry PlayBook landscape": {
        userAgent: "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/18.0 Safari/536.2+",
        viewport: {
          width: 1024,
          height: 600
        },
        deviceScaleFactor: 1,
        isMobile: true,
        hasTouch: true
      },
      "BlackBerry Z30": {
        userAgent: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/18.0 Mobile Safari/537.10+",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "BlackBerry Z30 landscape": {
        userAgent: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/18.0 Mobile Safari/537.10+",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy Note 3": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/18.0 Mobile Safari/534.30",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy Note 3 landscape": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/18.0 Mobile Safari/534.30",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy Note II": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/18.0 Mobile Safari/534.30",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy Note II landscape": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/18.0 Mobile Safari/534.30",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S III": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/18.0 Mobile Safari/534.30",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S III landscape": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/18.0 Mobile Safari/534.30",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S5": {
        userAgent: "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S5 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S8": {
        userAgent: "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 360,
          height: 740
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S8 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 740,
          height: 360
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S9 +": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 320,
          height: 658
        },
        deviceScaleFactor: 4.5,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy S9 + landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 658,
          height: 320
        },
        deviceScaleFactor: 4.5,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy Tab S4": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 712,
          height: 1138
        },
        deviceScaleFactor: 2.25,
        isMobile: true,
        hasTouch: true
      },
      "Galaxy Tab S4 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 1138,
          height: 712
        },
        deviceScaleFactor: 2.25,
        isMobile: true,
        hasTouch: true
      },
      "iPad(gen 5)": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 768,
          height: 1024
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad(gen 5) landscape": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 1024,
          height: 768
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad(gen 6)": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 768,
          height: 1024
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad(gen 6) landscape": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 1024,
          height: 768
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad(gen 7)": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 810,
          height: 1080
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad(gen 7) landscape": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 1080,
          height: 810
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad Mini": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 768,
          height: 1024
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad Mini landscape": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 1024,
          height: 768
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad Pro 11": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 834,
          height: 1194
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPad Pro 11 landscape": {
        userAgent: "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 1194,
          height: 834
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 6": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 375,
          height: 667
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 6 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 667,
          height: 375
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 6 Plus": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 414,
          height: 736
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 6 Plus landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 736,
          height: 414
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 7": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 375,
          height: 667
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 7 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 667,
          height: 375
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 7 Plus": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 414,
          height: 736
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 7 Plus landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 736,
          height: 414
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 8": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 375,
          height: 667
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 8 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 667,
          height: 375
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 8 Plus": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 414,
          height: 736
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 8 Plus landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 736,
          height: 414
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone SE": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/18.0 Mobile/14E304 Safari/602.1",
        viewport: {
          width: 320,
          height: 568
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone SE landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/18.0 Mobile/14E304 Safari/602.1",
        viewport: {
          width: 568,
          height: 320
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone X": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 375,
          height: 812
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone X landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/18.0 Mobile/15A372 Safari/604.1",
        viewport: {
          width: 812,
          height: 375
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone XR": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 414,
          height: 896
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone XR landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 896,
          height: 414
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 11": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 414,
          height: 715
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 11 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 800,
          height: 364
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 11 Pro": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 375,
          height: 635
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 11 Pro landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 724,
          height: 325
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 11 Pro Max": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 414,
          height: 715
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 11 Pro Max landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 808,
          height: 364
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 390,
          height: 664
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 750,
          height: 340
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 Pro": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 390,
          height: 664
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 Pro landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 750,
          height: 340
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 Pro Max": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 428,
          height: 746
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 Pro Max landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 832,
          height: 378
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 Mini": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 375,
          height: 629
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 12 Mini landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 712,
          height: 325
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 390,
          height: 664
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 750,
          height: 342
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 Pro": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 390,
          height: 664
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 Pro landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 750,
          height: 342
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 Pro Max": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 428,
          height: 746
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 Pro Max landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 832,
          height: 380
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 Mini": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 375,
          height: 629
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 13 Mini landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 712,
          height: 327
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 390,
          height: 664
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 750,
          height: 340
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 Plus": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 428,
          height: 746
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 Plus landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 832,
          height: 378
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 Pro": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 393,
          height: 660
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 Pro landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 734,
          height: 343
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 Pro Max": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 430,
          height: 740
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 14 Pro Max landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 814,
          height: 380
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 393,
          height: 659
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 734,
          height: 343
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 Plus": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 430,
          height: 739
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 Plus landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 814,
          height: 380
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 Pro": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 393,
          height: 659
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 Pro landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 734,
          height: 343
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 Pro Max": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 430,
          height: 739
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "iPhone 15 Pro Max landscape": {
        userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1",
        viewport: {
          width: 814,
          height: 380
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Kindle Fire HDX": {
        userAgent: "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
        viewport: {
          width: 800,
          height: 1280
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Kindle Fire HDX landscape": {
        userAgent: "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
        viewport: {
          width: 1280,
          height: 800
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "LG Optimus L70": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 384,
          height: 640
        },
        deviceScaleFactor: 1.25,
        isMobile: true,
        hasTouch: true
      },
      "LG Optimus L70 landscape": {
        userAgent: "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 640,
          height: 384
        },
        deviceScaleFactor: 1.25,
        isMobile: true,
        hasTouch: true
      },
      "Microsoft Lumia 550": {
        userAgent: "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36 Edge/14.14263",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Microsoft Lumia 550 landscape": {
        userAgent: "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36 Edge/14.14263",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Microsoft Lumia 950": {
        userAgent: "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36 Edge/14.14263",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 4,
        isMobile: true,
        hasTouch: true
      },
      "Microsoft Lumia 950 landscape": {
        userAgent: "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36 Edge/14.14263",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 4,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 10": {
        userAgent: "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 800,
          height: 1280
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 10 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 1280,
          height: 800
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 4": {
        userAgent: "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 384,
          height: 640
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 4 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 640,
          height: 384
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 5": {
        userAgent: "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 5 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 5X": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 412,
          height: 732
        },
        deviceScaleFactor: 2.625,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 5X landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 732,
          height: 412
        },
        deviceScaleFactor: 2.625,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 6": {
        userAgent: "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 412,
          height: 732
        },
        deviceScaleFactor: 3.5,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 6 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 732,
          height: 412
        },
        deviceScaleFactor: 3.5,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 6P": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 412,
          height: 732
        },
        deviceScaleFactor: 3.5,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 6P landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 732,
          height: 412
        },
        deviceScaleFactor: 3.5,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 7": {
        userAgent: "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 600,
          height: 960
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Nexus 7 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 960,
          height: 600
        },
        deviceScaleFactor: 2,
        isMobile: true,
        hasTouch: true
      },
      "Nokia Lumia 520": {
        userAgent: "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)",
        viewport: {
          width: 320,
          height: 533
        },
        deviceScaleFactor: 1.5,
        isMobile: true,
        hasTouch: true
      },
      "Nokia Lumia 520 landscape": {
        userAgent: "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)",
        viewport: {
          width: 533,
          height: 320
        },
        deviceScaleFactor: 1.5,
        isMobile: true,
        hasTouch: true
      },
      "Nokia N9": {
        userAgent: "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13",
        viewport: {
          width: 480,
          height: 854
        },
        deviceScaleFactor: 1,
        isMobile: true,
        hasTouch: true
      },
      "Nokia N9 landscape": {
        userAgent: "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13",
        viewport: {
          width: 854,
          height: 480
        },
        deviceScaleFactor: 1,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 2": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 411,
          height: 731
        },
        deviceScaleFactor: 2.625,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 2 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 731,
          height: 411
        },
        deviceScaleFactor: 2.625,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 2 XL": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 411,
          height: 823
        },
        deviceScaleFactor: 3.5,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 2 XL landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 823,
          height: 411
        },
        deviceScaleFactor: 3.5,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 3": {
        userAgent: "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 393,
          height: 786
        },
        deviceScaleFactor: 2.75,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 3 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 786,
          height: 393
        },
        deviceScaleFactor: 2.75,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 4": {
        userAgent: "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 353,
          height: 745
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 4 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 745,
          height: 353
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 4a(5G)": {
        userAgent: "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 412,
          height: 765
        },
        deviceScaleFactor: 2.63,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 4a(5G) landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 840,
          height: 312
        },
        deviceScaleFactor: 2.63,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 5": {
        userAgent: "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 393,
          height: 727
        },
        deviceScaleFactor: 2.75,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 5 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 802,
          height: 293
        },
        deviceScaleFactor: 2.75,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 7": {
        userAgent: "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 412,
          height: 839
        },
        deviceScaleFactor: 2.625,
        isMobile: true,
        hasTouch: true
      },
      "Pixel 7 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 863,
          height: 360
        },
        deviceScaleFactor: 2.625,
        isMobile: true,
        hasTouch: true
      },
      "Moto G4": {
        userAgent: "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 360,
          height: 640
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Moto G4 landscape": {
        userAgent: "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Mobile Safari/537.36",
        viewport: {
          width: 640,
          height: 360
        },
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true
      },
      "Desktop Chrome HiDPI": {
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 2,
        isMobile: false,
        hasTouch: false
      },
      "Desktop Edge HiDPI": {
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36 Edg/128.0.6613.18",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 2,
        isMobile: false,
        hasTouch: false
      },
      "Desktop Firefox HiDPI": {
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 2,
        isMobile: false,
        hasTouch: false
      },
      "Desktop Safari": {
        userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 2,
        isMobile: false,
        hasTouch: false
      },
      "Desktop Chrome": {
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 1,
        isMobile: false,
        hasTouch: false
      },
      "Desktop Edge": {
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.18 Safari/537.36 Edg/128.0.6613.18",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 1,
        isMobile: false,
        hasTouch: false
      },
      "Desktop Firefox": {
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0",
        viewport: {
          width: 1280,
          height: 720
        },
        deviceScaleFactor: 1,
        isMobile: false,
        hasTouch: false
      }
    };
  }
});

// src/session/emulationState.ts
function overrideMap(browser) {
  let map = overrides.get(browser);
  if (!map) {
    map = /* @__PURE__ */ new Map();
    overrides.set(browser, map);
  }
  return map;
}
function rememberOverride(browser, context, patch) {
  const map = overrideMap(browser);
  map.set(context, { ...map.get(context), ...patch });
}
function rememberedOverride(browser, context) {
  return overrideMap(browser).get(context) ?? {};
}
function claimRestore(browser, scope, contexts) {
  const key = `${scope}:${contexts.join(",")}`;
  let map = latestRestore.get(browser);
  if (!map) {
    map = /* @__PURE__ */ new Map();
    latestRestore.set(browser, map);
  }
  const token = /* @__PURE__ */ Symbol();
  map.set(key, token);
  return () => map.get(key) === token;
}
var overrides, latestRestore;
var init_emulationState = __esm({
  "src/session/emulationState.ts"() {
    "use strict";
    overrides = /* @__PURE__ */ new WeakMap();
    latestRestore = /* @__PURE__ */ new WeakMap();
  }
});

// src/commands/browser/emulate.ts
function storeRestoreFunction(browser, scope, fn) {
  if (!restoreFunctions.has(browser)) {
    restoreFunctions.set(browser, /* @__PURE__ */ new Map());
  }
  const restoreFunctionsList = restoreFunctions.get(browser)?.get(scope);
  const updatedList = restoreFunctionsList ? [...restoreFunctionsList, fn] : [fn];
  restoreFunctions.get(browser)?.set(scope, updatedList);
}
function browserOf(target) {
  return isBrowsingContext(target) ? target.browser : target;
}
async function topLevelContexts(target) {
  if (isBrowsingContext(target)) {
    return [target.contextId];
  }
  return [await getContextManager(target).getCurrentTopLevelContext()];
}
async function install(target, scope, apply, clear, memory) {
  const browser = browserOf(target);
  const contexts = await topLevelContexts(target);
  await apply(contexts);
  memory?.apply(contexts[0]);
  const current = claimRestore(browser, scope, contexts);
  const restore2 = async () => {
    if (!current()) {
      return;
    }
    await clear(contexts);
    memory?.clear(contexts[0]);
  };
  storeRestoreFunction(browser, scope, restore2);
  return restore2;
}
function isUnsupportedCommand(err) {
  const message = err instanceof Error ? err.message : String(err);
  return message.includes("unknown command") || message.includes("unsupported operation") || /**
   * Chrome 155: `unknown error - Method emulation.setViewportMetaOverride is not implemented.`
   */
  /\bMethod \S+ is not implemented\b/.test(message);
}
function setCapturedViewport(browser, context, viewport, devicePixelRatio) {
  return browser.browsingContextSetViewport({
    context,
    viewport,
    devicePixelRatio
  });
}
function toMediaFeatureWire(features) {
  const wire = {};
  for (const [key, value] of Object.entries(features)) {
    if (value === void 0) {
      continue;
    }
    wire[key.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)] = value;
  }
  return wire;
}
function geolocationCoordinates(options) {
  if (typeof options.latitude !== "number" || typeof options.longitude !== "number") {
    throw new Error('Expected geolocation emulation options to include numeric "latitude" and "longitude"');
  }
  const coordinates = {
    latitude: options.latitude,
    longitude: options.longitude
  };
  if (typeof options.accuracy === "number") {
    coordinates.accuracy = options.accuracy;
  }
  if (options.altitude !== void 0) {
    coordinates.altitude = options.altitude;
  }
  if (options.altitudeAccuracy !== void 0) {
    coordinates.altitudeAccuracy = options.altitudeAccuracy;
  }
  if (options.heading !== void 0) {
    coordinates.heading = options.heading;
  }
  if (options.speed !== void 0) {
    coordinates.speed = options.speed;
  }
  return coordinates;
}
function assertNonEmptyString(scope, options) {
  if (typeof options !== "string" || options.length === 0) {
    throw new Error(`Expected "${scope}" emulation options to be a non-empty string, received ${typeof options === "string" ? '""' : typeof options}`);
  }
  return options;
}
function assertOrientation2(options) {
  const value = options;
  const natural = value && typeof value === "object" ? value.natural : void 0;
  const type = value && typeof value === "object" ? value.type : void 0;
  if (!ORIENTATION_NATURAL.includes(natural) || !ORIENTATION_TYPES.includes(type)) {
    throw new Error('Expected "orientation" emulation options to be { natural: "portrait" | "landscape", type: "portrait-primary" | "portrait-secondary" | "landscape-primary" | "landscape-secondary" }');
  }
  return {
    natural,
    type
  };
}
function assertScreen(options) {
  const value = options;
  if (!value || typeof value !== "object" || !Number.isInteger(value.width) || !Number.isInteger(value.height) || value.width < 0 || value.height < 0) {
    throw new Error('Expected "screen" emulation options to be { width, height } with non-negative integers');
  }
  return { width: value.width, height: value.height };
}
function assertMedia(options) {
  if (!options || typeof options !== "object" || Array.isArray(options)) {
    throw new Error('Expected "media" emulation options to be an object of media features');
  }
  const entries = Object.entries(options).filter(([, value]) => value !== void 0);
  if (entries.length === 0) {
    throw new Error('Expected "media" emulation options to include at least one media feature');
  }
  return Object.fromEntries(entries);
}
async function emulateDevice(target, name) {
  const browser = browserOf(target);
  if (typeof name !== "string") {
    throw new Error(`Expected "device" emulation options to be a string, received "${typeof name}"`);
  }
  const device = deviceDescriptorsSource[name];
  if (!device) {
    throw new Error(`Unknown device name "${name}", please use one of the following: ${Object.keys(deviceDescriptorsSource).join(", ")}`);
  }
  const contexts = await topLevelContexts(target);
  const context = contexts[0];
  const previous = rememberedOverride(browser, context);
  const desktop = deviceDescriptorsSource["Desktop Chrome"];
  const deviceViewport = {
    width: device.viewport.width,
    height: device.viewport.height,
    devicePixelRatio: device.deviceScaleFactor
  };
  const deviceTouch = device.hasTouch ? 1 : null;
  const deviceTextLayout = device.isMobile ? "mobile" : null;
  const deviceViewportMeta = device.isMobile ? true : null;
  const steps = [
    {
      apply: () => browser.emulationSetUserAgentOverride({ userAgent: device.userAgent, contexts }),
      undo: () => browser.emulationSetUserAgentOverride({
        userAgent: previous.userAgent === void 0 ? null : previous.userAgent,
        contexts
      }),
      clear: () => browser.emulationSetUserAgentOverride({ userAgent: null, contexts }),
      remember: { userAgent: device.userAgent },
      forget: { userAgent: null }
    },
    {
      apply: () => setCapturedViewport(browser, context, {
        width: deviceViewport.width,
        height: deviceViewport.height
      }, deviceViewport.devicePixelRatio),
      undo: () => previous.viewport ? setCapturedViewport(browser, context, {
        width: previous.viewport.width,
        height: previous.viewport.height
      }, previous.viewport.devicePixelRatio) : setCapturedViewport(browser, context, null, null),
      clear: () => setCapturedViewport(browser, context, {
        width: desktop.viewport.width,
        height: desktop.viewport.height
      }, desktop.deviceScaleFactor),
      remember: { viewport: deviceViewport },
      forget: {
        viewport: {
          width: desktop.viewport.width,
          height: desktop.viewport.height,
          devicePixelRatio: desktop.deviceScaleFactor
        }
      }
    },
    {
      apply: () => browser.emulationSetTouchOverride({ maxTouchPoints: deviceTouch, contexts }),
      undo: () => browser.emulationSetTouchOverride({
        maxTouchPoints: previous.touch === void 0 ? null : previous.touch,
        contexts
      }),
      clear: () => browser.emulationSetTouchOverride({ maxTouchPoints: null, contexts }),
      remember: { touch: deviceTouch },
      forget: { touch: null },
      skip: deviceTouch === null && (previous.touch ?? null) === null
    },
    {
      apply: () => browser.emulationSetTextLayoutModeOverride({ textLayoutMode: deviceTextLayout, contexts }),
      undo: () => browser.emulationSetTextLayoutModeOverride({
        textLayoutMode: previous.textLayout === void 0 ? null : previous.textLayout,
        contexts
      }),
      clear: () => browser.emulationSetTextLayoutModeOverride({ textLayoutMode: null, contexts }),
      remember: { textLayout: deviceTextLayout },
      forget: { textLayout: null },
      skip: deviceTextLayout === null && (previous.textLayout ?? null) === null,
      optional: true
    },
    {
      apply: () => browser.emulationSetViewportMetaOverride({ viewportMeta: deviceViewportMeta, contexts }),
      undo: () => browser.emulationSetViewportMetaOverride({
        viewportMeta: previous.viewportMeta === void 0 ? null : previous.viewportMeta,
        contexts
      }),
      clear: () => browser.emulationSetViewportMetaOverride({ viewportMeta: null, contexts }),
      remember: { viewportMeta: deviceViewportMeta },
      forget: { viewportMeta: null },
      skip: deviceViewportMeta === null && (previous.viewportMeta ?? null) === null,
      optional: true
    }
  ];
  const applied = [];
  try {
    for (const step of steps) {
      if (step.skip) {
        continue;
      }
      try {
        await step.apply();
      } catch (err) {
        if (step.optional && isUnsupportedCommand(err)) {
          continue;
        }
        throw err;
      }
      applied.push(step);
    }
  } catch (err) {
    for (const step of [...applied].reverse()) {
      await Promise.resolve(step.undo()).catch(() => {
      });
    }
    throw err;
  }
  const current = claimRestore(browser, "device", contexts);
  rememberOverride(browser, context, Object.assign({}, ...applied.map((step) => step.remember)));
  const restore2 = async () => {
    if (!current()) {
      return;
    }
    for (const step of [...applied].reverse()) {
      await step.clear();
    }
    rememberOverride(browser, context, Object.assign({}, ...applied.map((step) => step.forget)));
  };
  storeRestoreFunction(browser, "device", restore2);
  return restore2;
}
async function emulate(scope, options) {
  const target = this;
  const browser = browserOf(target);
  if (!browser.isBidi) {
    throw new Error("emulate command is only supported for Bidi");
  }
  if (scope === "geolocation") {
    if (!options || typeof options !== "object") {
      throw new Error("Missing geolocation emulation options");
    }
    if ("error" in options) {
      if (options.error !== "positionUnavailable") {
        throw new Error('Expected geolocation error to be "positionUnavailable"');
      }
      return install(
        target,
        "geolocation",
        (contexts) => browser.emulationSetGeolocationOverride({
          error: { type: "positionUnavailable" },
          contexts
        }),
        (contexts) => browser.emulationSetGeolocationOverride({ coordinates: null, contexts })
      );
    }
    const coordinates = geolocationCoordinates(options);
    return install(
      target,
      "geolocation",
      (contexts) => browser.emulationSetGeolocationOverride({ coordinates, contexts }),
      (contexts) => browser.emulationSetGeolocationOverride({ coordinates: null, contexts })
    );
  }
  if (scope === "userAgent") {
    if (typeof options !== "string") {
      throw new Error(`Expected userAgent emulation options to be a string, received ${typeof options}`);
    }
    return install(
      target,
      "userAgent",
      (contexts) => browser.emulationSetUserAgentOverride({ userAgent: options, contexts }),
      (contexts) => browser.emulationSetUserAgentOverride({ userAgent: null, contexts }),
      {
        apply: (context) => rememberOverride(browser, context, { userAgent: options }),
        clear: (context) => rememberOverride(browser, context, { userAgent: null })
      }
    );
  }
  if (scope === "clock") {
    const clock = new ClockManager(target);
    await clock.install(options);
    storeRestoreFunction(browser, "clock", clock.restore.bind(clock));
    return clock;
  }
  if (scope === "colorScheme") {
    if (options !== "light" && options !== "dark") {
      throw new Error(`Expected "colorScheme" emulation options to be either "light" or "dark", received "${options}"`);
    }
    const features = toMediaFeatureWire({ prefersColorScheme: options });
    return install(
      target,
      "colorScheme",
      (contexts) => browser.emulationSetMediaFeaturesOverride({ features, contexts }),
      (contexts) => browser.emulationSetMediaFeaturesOverride({ features: null, contexts })
    );
  }
  if (scope === "media") {
    const features = toMediaFeatureWire(assertMedia(options));
    return install(
      target,
      "media",
      (contexts) => browser.emulationSetMediaFeaturesOverride({ features, contexts }),
      (contexts) => browser.emulationSetMediaFeaturesOverride({ features: null, contexts })
    );
  }
  if (scope === "onLine") {
    if (typeof options !== "boolean") {
      throw new Error(`Expected "onLine" emulation options to be a boolean, received "${typeof options}"`);
    }
    return install(
      target,
      "onLine",
      (contexts) => browser.emulationSetNetworkConditions({
        networkConditions: options ? null : { type: "offline" },
        contexts
      }),
      (contexts) => browser.emulationSetNetworkConditions({ networkConditions: null, contexts })
    );
  }
  if (scope === "locale") {
    const locale = assertNonEmptyString("locale", options);
    return install(
      target,
      "locale",
      (contexts) => browser.emulationSetLocaleOverride({ locale, contexts }),
      (contexts) => browser.emulationSetLocaleOverride({ locale: null, contexts })
    );
  }
  if (scope === "timezone") {
    const timezone = assertNonEmptyString("timezone", options);
    return install(
      target,
      "timezone",
      (contexts) => browser.emulationSetTimezoneOverride({ timezone, contexts }),
      (contexts) => browser.emulationSetTimezoneOverride({ timezone: null, contexts })
    );
  }
  if (scope === "touch") {
    if (typeof options !== "number" || !Number.isInteger(options) || options < 1) {
      throw new Error(`Expected "touch" emulation options to be an integer >= 1, received "${options}"`);
    }
    return install(
      target,
      "touch",
      (contexts) => browser.emulationSetTouchOverride({ maxTouchPoints: options, contexts }),
      (contexts) => browser.emulationSetTouchOverride({ maxTouchPoints: null, contexts }),
      {
        apply: (context) => rememberOverride(browser, context, { touch: options }),
        clear: (context) => rememberOverride(browser, context, { touch: null })
      }
    );
  }
  if (scope === "orientation") {
    const screenOrientation = assertOrientation2(options);
    return install(
      target,
      "orientation",
      (contexts) => browser.emulationSetScreenOrientationOverride({ screenOrientation, contexts }),
      (contexts) => browser.emulationSetScreenOrientationOverride({ screenOrientation: null, contexts })
    );
  }
  if (scope === "screen") {
    const screenArea = assertScreen(options);
    return install(
      target,
      "screen",
      (contexts) => browser.emulationSetScreenSettingsOverride({ screenArea, contexts }),
      (contexts) => browser.emulationSetScreenSettingsOverride({ screenArea: null, contexts })
    );
  }
  if (scope === "viewportMeta") {
    if (options !== true) {
      throw new Error('Expected "viewportMeta" emulation options to be true');
    }
    return install(
      target,
      "viewportMeta",
      (contexts) => browser.emulationSetViewportMetaOverride({ viewportMeta: true, contexts }),
      (contexts) => browser.emulationSetViewportMetaOverride({ viewportMeta: null, contexts }),
      {
        apply: (context) => rememberOverride(browser, context, { viewportMeta: true }),
        clear: (context) => rememberOverride(browser, context, { viewportMeta: null })
      }
    );
  }
  if (scope === "textLayout") {
    if (options !== "mobile") {
      throw new Error('Expected "textLayout" emulation options to be "mobile"');
    }
    return install(
      target,
      "textLayout",
      (contexts) => browser.emulationSetTextLayoutModeOverride({ textLayoutMode: "mobile", contexts }),
      (contexts) => browser.emulationSetTextLayoutModeOverride({ textLayoutMode: null, contexts }),
      {
        apply: (context) => rememberOverride(browser, context, { textLayout: "mobile" }),
        clear: (context) => rememberOverride(browser, context, { textLayout: null })
      }
    );
  }
  if (scope === "scripting") {
    if (options !== false) {
      throw new Error('Expected "scripting" emulation options to be false');
    }
    return install(
      target,
      "scripting",
      (contexts) => browser.emulationSetScriptingEnabled({ enabled: false, contexts }),
      (contexts) => browser.emulationSetScriptingEnabled({ enabled: null, contexts })
    );
  }
  if (scope === "scrollbar") {
    if (options !== "classic" && options !== "overlay") {
      throw new Error(`Expected "scrollbar" emulation options to be "classic" or "overlay", received "${options}"`);
    }
    return install(
      target,
      "scrollbar",
      (contexts) => browser.emulationSetScrollbarTypeOverride({ scrollbarType: options, contexts }),
      (contexts) => browser.emulationSetScrollbarTypeOverride({ scrollbarType: null, contexts })
    );
  }
  if (scope === "forcedColors") {
    if (options !== "light" && options !== "dark") {
      throw new Error(`Expected "forcedColors" emulation options to be "light" or "dark", received "${options}"`);
    }
    return install(
      target,
      "forcedColors",
      (contexts) => browser.emulationSetForcedColorsModeThemeOverride({ theme: options, contexts }),
      (contexts) => browser.emulationSetForcedColorsModeThemeOverride({ theme: null, contexts })
    );
  }
  if (scope === "device") {
    return emulateDevice(target, options);
  }
  throw new Error(`Invalid scope "${scope}", expected one of ${SCOPES.map((name) => `"${name}"`).join(", ")}`);
}
var SCOPES, ORIENTATION_NATURAL, ORIENTATION_TYPES;
var init_emulate = __esm({
  "src/commands/browser/emulate.ts"() {
    "use strict";
    init_clock();
    init_deviceDescriptorsSource();
    init_constants();
    init_context();
    init_browsingContext();
    init_emulationState();
    SCOPES = [
      "geolocation",
      "userAgent",
      "colorScheme",
      "media",
      "onLine",
      "locale",
      "timezone",
      "touch",
      "orientation",
      "screen",
      "viewportMeta",
      "textLayout",
      "scripting",
      "scrollbar",
      "forcedColors",
      "device",
      "clock"
    ];
    ORIENTATION_NATURAL = ["portrait", "landscape"];
    ORIENTATION_TYPES = ["portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"];
  }
});

// src/utils/scriptTimeout.ts
function markAttachedSession(browser) {
  attachedBrowsers.add(browser);
}
function trackScriptTimeout(browser) {
  if (trackedBrowsers.has(browser)) {
    return;
  }
  trackedBrowsers.add(browser);
  browser.on("result", ({ command, body, result }) => {
    if (command !== "setTimeouts" || !body || typeof body !== "object" || !("script" in body) || body.script === void 0) {
      return;
    }
    if (result && typeof result === "object" && "error" in result && result.error) {
      return;
    }
    scriptTimeouts.set(browser, {
      sessionId: browser.sessionId,
      script: typeof body.script === "number" ? body.script : null
    });
  });
}
async function scriptTimeoutOf(browser) {
  const set = scriptTimeouts.get(browser);
  if (set && set.sessionId === browser.sessionId) {
    return set.script;
  }
  const fromCapabilities = attachedBrowsers.has(browser) ? void 0 : browser.capabilities?.timeouts?.script;
  if (fromCapabilities === null || typeof fromCapabilities === "number") {
    return fromCapabilities;
  }
  const sessionId = browser.sessionId;
  const fromSession = typeof browser.getTimeouts === "function" ? await browser.getTimeouts().then(({ script: script2 }) => script2, () => void 0) : void 0;
  const script = fromSession === null || typeof fromSession === "number" ? fromSession : DEFAULT_SCRIPT_TIMEOUT;
  const current = scriptTimeouts.get(browser);
  if (current && current.sessionId === sessionId) {
    return current.script;
  }
  scriptTimeouts.set(browser, { sessionId, script });
  return script;
}
var DEFAULT_SCRIPT_TIMEOUT, scriptTimeouts, trackedBrowsers, attachedBrowsers;
var init_scriptTimeout = __esm({
  "src/utils/scriptTimeout.ts"() {
    "use strict";
    DEFAULT_SCRIPT_TIMEOUT = 3e4;
    scriptTimeouts = /* @__PURE__ */ new WeakMap();
    trackedBrowsers = /* @__PURE__ */ new WeakSet();
    attachedBrowsers = /* @__PURE__ */ new WeakSet();
  }
});

// src/commands/browser/execute.ts
import { getBrowserObject as getBrowserObject12 } from "@wdio/utils";
import { BIDI_SCRIPT_TIMEOUT } from "webdriver";
import { polyfillFn } from "./scripts/polyfill.js";
async function execute(script, ...args) {
  if (typeof script !== "string" && typeof script !== "function") {
    throw new Error("number or type of arguments don't agree with execute protocol command");
  }
  const browser = getBrowserObject12(this);
  const multiRemote2 = "isMultiRemote" in this && this.isMultiRemote;
  if (this.isBidi && !multiRemote2) {
    const held = heldBrowsingContext(this) ?? args.reduce(
      (found, arg) => found ?? heldBrowsingContext(arg),
      void 0
    );
    if (held?.isFrame) {
      await assertFrameAttached(held);
    }
    const context = held ? held.contextId : await contextIdOf(this);
    const functionDeclaration = createBidiFunctionDeclaration(script);
    const params = {
      functionDeclaration,
      awaitPromise: true,
      /**
       * like in Classic, an element becomes its reference, and an element that was
       * not found throws a clear error: the serializer would read it as a plain
       * object and fail on its first command ("Unsupported type: function")
       */
      arguments: verifyArgsAndStripIfElement(args).map((arg) => LocalValue.getArgument(arg)),
      target: {
        context
      }
    };
    const scriptTimeout = await scriptTimeoutOf(browser);
    if (scriptTimeout !== null) {
      Object.assign(params, { [BIDI_SCRIPT_TIMEOUT]: scriptTimeout });
    }
    const result = await browser.scriptCallFunction(params);
    return parseScriptResult(params, result);
  }
  const isAsyncFn = typeof script === "function" && script.constructor.name === "AsyncFunction";
  if (typeof script === "function") {
    script = isAsyncFn ? `
            ${polyfillFn}
            webdriverioPolyfill();
            var done = arguments[arguments.length - 1];
            var args = Array.prototype.slice.call(arguments, 0, -1);
            Promise.resolve((${script}).apply(null, args)).then(function (result) {
                done(result)
            }, function (error) {
                done({
                    __wdioError: true,
                    message: error && error.message ? error.message : String(error),
                    stack: error && error.stack,
                    name: error && error.name
                })
            })
        ` : `
            ${polyfillFn}
            webdriverioPolyfill();
            return (${script}).apply(null, arguments)
        `;
  }
  const scriptArgs = verifyArgsAndStripIfElement(args);
  if (isAsyncFn) {
    const result = await browser.executeAsyncScript(script, scriptArgs);
    if (isScriptError(result)) {
      const error = new Error(result.message);
      if (result.name) {
        error.name = result.name;
      }
      if (result.stack) {
        error.stack = result.stack;
      }
      throw error;
    }
    return result;
  }
  return browser.executeScript(script, scriptArgs);
}
function isScriptError(result) {
  return Boolean(
    result && typeof result === "object" && result.__wdioError === true
  );
}
var init_execute = __esm({
  "src/commands/browser/execute.ts"() {
    "use strict";
    init_utils2();
    init_value();
    init_bidi();
    init_serialize();
    init_scriptTimeout();
    init_browsingContext();
  }
});

// src/commands/browser/forward.ts
import { runClassicProtocolCommand as runClassicProtocolCommand2 } from "webdriver";
async function forward() {
  if (!this.isBidi) {
    await runClassicProtocolCommand2.call(this, "forward");
    return;
  }
  await traverseTopLevelHistory(this, 1);
}
var init_forward = __esm({
  "src/commands/browser/forward.ts"() {
    "use strict";
    init_traverseHistory();
  }
});

// src/commands/browser/getCookies.ts
import logger8 from "@wdio/logger";
async function getCookies(filter, sourceOrigin) {
  assertObjectCookieFilter(filter);
  if (!this.isBidi) {
    return getCookiesClassic.call(this, filter);
  }
  if (isBrowsingContext(this)) {
    return readBidiCookies(this.browser, {
      ...sourceOrigin === null ? {} : {
        partition: { type: "context", context: this.contextId }
      },
      ...typeof filter !== "undefined" ? { filter } : {}
    }, filter);
  }
  const parallelPartition = await parallelCookiePartition(this, sourceOrigin);
  if (parallelPartition) {
    return readBidiCookies(this, {
      partition: parallelPartition,
      ...typeof filter !== "undefined" ? { filter } : {}
    }, filter, true);
  }
  let url2;
  try {
    url2 = new URL(await this.getUrl());
    if (url2.origin === "null") {
      return getCookiesClassic.call(this, filter);
    }
  } catch {
    return getCookiesClassic.call(this, filter);
  }
  const params = sourceOrigin === null ? {} : { partition: getCookiePartition(sourceOrigin || url2.origin) };
  if (typeof filter !== "undefined") {
    params.filter = filter;
  }
  return readBidiCookies(this, params, filter);
}
async function readBidiCookies(browser, params, filter, isolated = params.partition?.type === "context") {
  try {
    const { cookies } = await browser.storageGetCookies(params);
    if (cookies.length === 0 && !isolated) {
      log8.debug("BiDi getCookies returned empty, falling back to classic");
      return getCookiesClassic.call(browser, filter);
    }
    return cookies.map((cookie) => ({
      ...cookie,
      value: cookie.value.type === "base64" ? Buffer.from(cookie.value.value, "base64").toString("utf-8") : cookie.value.value
    }));
  } catch (err) {
    if (isolated) {
      throw err;
    }
    log8.warn(`BiDi getCookies failed, falling back to classic: ${err.message}`);
    return getCookiesClassic.call(browser, filter);
  }
}
function assertObjectCookieFilter(filter) {
  if (typeof filter === "undefined") {
    return;
  }
  if (typeof filter === "string" || Array.isArray(filter)) {
    throw new Error(REMOVED_COOKIE_FILTER);
  }
  if (typeof filter !== "object" || filter === null) {
    throw new Error("`getCookies` only accepts a cookie filter object.");
  }
}
async function getCookiesClassic(filter) {
  if (!filter) {
    return this.getAllCookies();
  }
  const allCookies = await this.getAllCookies();
  const filterValue = getCookieValue(filter.value);
  return allCookies.filter((cookie) => (filter.name === void 0 || filter.name === cookie.name) && (filter.value === void 0 || filterValue === cookie.value) && (filter.path === void 0 || filter.path === cookie.path) && (filter.domain === void 0 || filter.domain === cookie.domain) && (filter.sameSite === void 0 || filter.sameSite === cookie.sameSite) && (filter.expiry === void 0 || filter.expiry === cookie.expiry) && (filter.httpOnly === void 0 || filter.httpOnly === cookie.httpOnly) && (filter.secure === void 0 || filter.secure === cookie.secure));
}
function getCookieValue(value) {
  if (!value) {
    return;
  }
  return value.type === "base64" ? Buffer.from(value.value, "base64").toString("utf-8") : value.value;
}
var log8, REMOVED_COOKIE_FILTER;
var init_getCookies = __esm({
  "src/commands/browser/getCookies.ts"() {
    "use strict";
    init_browsingContext();
    init_cookiePartition();
    log8 = logger8("webdriverio");
    REMOVED_COOKIE_FILTER = "Passing a string or string array to `getCookies` was removed in WebdriverIO v10. Use an object filter, for example `await browser.getCookies({ name: 'session' })`.";
  }
});

// src/commands/browser/getPuppeteer.ts
import logger9 from "@wdio/logger";
import { userImport } from "@wdio/utils";
async function getPuppeteer() {
  if (globalThis.wdio) {
    throw new Error("Puppeteer is not supported in browser runner");
  }
  const puppeteer = await userImport("puppeteer-core");
  if (!puppeteer) {
    throw new Error(
      'You need to install "puppeteer-core" package as a dependency in order to use the "getPuppeteer" method'
    );
  }
  if (this.puppeteer?.connected) {
    log9.debug("Reusing existing puppeteer session");
    return this.puppeteer;
  }
  const { headers } = this.options;
  const cdpEndpoint = this.capabilities["se:cdp"];
  if (cdpEndpoint) {
    this.puppeteer = await puppeteer.connect({
      browserWSEndpoint: cdpEndpoint,
      defaultViewport: null,
      headers
    });
    return this.puppeteer;
  }
  const requestedCapabilities = this.requestedCapabilities?.alwaysMatch || this.requestedCapabilities;
  const isAerokubeSession = requestedCapabilities["selenoid:options"] || requestedCapabilities["moon:options"];
  if (isAerokubeSession) {
    const { hostname, port } = this.options;
    this.puppeteer = await puppeteer.connect({
      browserWSEndpoint: `ws://${hostname}:${port}/devtools/${this.sessionId}`,
      defaultViewport: null,
      headers
    });
    return this.puppeteer;
  }
  const chromiumOptions = this.capabilities["goog:chromeOptions"] || this.capabilities["ms:edgeOptions"];
  if (chromiumOptions && chromiumOptions.debuggerAddress) {
    this.puppeteer = await puppeteer.connect({
      browserURL: `http://${chromiumOptions.debuggerAddress.replace("localhost", "0.0.0.0")}`,
      defaultViewport: null
    });
    return this.puppeteer;
  } else if (
    /**
     * if --remote-debugging-pipe is set as Chrome flag, we can't attach to the session
     * as there won't be a `debuggerAddress` available in the capabilities. Provide this
     * better error message to the user.
     */
    chromiumOptions && (chromiumOptions.args?.includes(DEBUG_PIPE_FLAG) || chromiumOptions.args?.includes(`--${DEBUG_PIPE_FLAG}`))
  ) {
    throw new Error(`Cannot attach to Chrome Devtools session if --${DEBUG_PIPE_FLAG} is set as Chrome flag.`);
  }
  if (this.capabilities.browserName?.toLowerCase() === "firefox") {
    if (!this.capabilities.browserVersion) {
      throw new Error(`Can't find "browserVersion" in capabilities`);
    }
    const majorVersion = parseInt(this.capabilities.browserVersion.split(".").shift() || "", 10);
    if (majorVersion >= 79) {
      const reqCaps = this.requestedCapabilities.alwaysMatch || this.requestedCapabilities;
      let browserURL;
      if (this.capabilities["moz:debuggerAddress"]) {
        browserURL = this.capabilities["moz:debuggerAddress"];
      } else {
        const ffOptions = this.capabilities["moz:firefoxOptions"];
        const ffArgs = reqCaps["moz:firefoxOptions"]?.args || [];
        const rdPort = ffOptions && ffOptions.debuggerAddress ? ffOptions.debuggerAddress : ffArgs[ffArgs.findIndex((arg) => arg === FF_REMOTE_DEBUG_ARG) + 1];
        if (rdPort) {
          browserURL = `http://localhost:${rdPort}`;
        }
      }
      if (!browserURL) {
        throw new Error(
          'Could\'t find a websocket url within returned capabilities to connect to! Make sure you have "moz:debuggerAddress" set to `true` in your Firefox capabilities'
        );
      }
      this.puppeteer = await puppeteer.connect({
        browserURL,
        defaultViewport: null
      });
      return this.puppeteer;
    }
  }
  throw new Error(
    "Using DevTools capabilities is not supported for this session. This feature is only supported for local testing on Chrome, Firefox and Chromium Edge."
  );
}
var log9, DEBUG_PIPE_FLAG;
var init_getPuppeteer = __esm({
  "src/commands/browser/getPuppeteer.ts"() {
    "use strict";
    init_constants();
    log9 = logger9("webdriverio");
    DEBUG_PIPE_FLAG = "remote-debugging-pipe";
  }
});

// src/utils/parallelGuard.ts
function assertNotInParallelScope(command, reason) {
  if (getParallelContextStore().getStore()) {
    throw new Error(`"${command}" is not supported inside parallel mode tests because ${reason}`);
  }
}
var init_parallelGuard = __esm({
  "src/utils/parallelGuard.ts"() {
    "use strict";
    init_context();
  }
});

// src/commands/browser/getWindowSize.ts
import { getBrowserObject as getBrowserObject13 } from "@wdio/utils";
async function getWindowSize() {
  assertNotInParallelScope("getWindowSize", WINDOW_REASON);
  const browser = getBrowserObject13(this);
  const { width, height } = await browser.getWindowRect();
  return { width, height };
}
var WINDOW_REASON;
var init_getWindowSize = __esm({
  "src/commands/browser/getWindowSize.ts"() {
    "use strict";
    init_parallelGuard();
    WINDOW_REASON = "parallel tests share one OS window, use setViewport to size a test's page";
  }
});

// src/utils/webExtension.ts
function annotateWebExtensionError(err, command) {
  const message = err instanceof Error ? err.message : String(err);
  if (!/method not available/i.test(message)) {
    return err instanceof Error ? err : new Error(message);
  }
  const error = new Error(
    `${message} Start Chrome or Edge with --enable-unsafe-extension-debugging and --remote-debugging-pipe so ${command} is available. Chrome 136 and newer also require --user-data-dir together with --remote-debugging-pipe.`
  );
  if (err instanceof Error) {
    Object.defineProperty(error, "cause", {
      configurable: true,
      value: err
    });
  }
  return error;
}
var init_webExtension = __esm({
  "src/utils/webExtension.ts"() {
    "use strict";
  }
});

// src/commands/browser/installExtension.ts
async function installExtension(extension) {
  if (!this.isBidi) {
    throw new Error("installExtension requires a WebDriver BiDi session (webExtension.install)");
  }
  const extensionData = await extensionDataFor.call(this, extension);
  let result;
  try {
    result = await this.webExtensionInstall({ extensionData });
  } catch (err) {
    throw annotateWebExtensionError(err, "webExtension.install");
  }
  const id = result?.extension;
  if (typeof id !== "string" || id.length === 0) {
    throw new Error("webExtension.install did not return an extension id");
  }
  return id;
}
async function extensionDataFor(extension) {
  if (isBase64Payload(extension)) {
    return { type: "base64", value: extension.base64 };
  }
  if (typeof extension !== "string") {
    throw new Error("installExtension expects a path string or { base64: string }");
  }
  return environment.value.extensionDataFromPath(extension, isRemoteSession(this));
}
function isBase64Payload(value) {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    return false;
  }
  const record = value;
  return Object.keys(record).length === 1 && typeof record.base64 === "string";
}
function isRemoteSession(browser) {
  const { hostname, user, key } = browser.options;
  if (typeof user === "string" && user.length > 0 && typeof key === "string" && key.length > 0) {
    return true;
  }
  return typeof hostname === "string" && hostname.length > 0 && !LOCAL_HOSTS.has(hostname.toLowerCase());
}
var LOCAL_HOSTS;
var init_installExtension = __esm({
  "src/commands/browser/installExtension.ts"() {
    "use strict";
    init_environment();
    init_webExtension();
    LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
  }
});

// src/commands/browser/keys.ts
async function keys(value) {
  let keySequence = [];
  if (typeof value === "string") {
    keySequence = checkUnicode(value);
  } else if (Array.isArray(value)) {
    const charArray = value;
    for (const charSet of charArray) {
      keySequence = keySequence.concat(checkUnicode(charSet));
    }
  } else {
    throw new Error('"keys" command requires a string or array of strings as parameter');
  }
  const keyAction = this.action("key");
  keySequence.forEach((value2) => keyAction.down(value2));
  if (!this.isIOS) {
    keyAction.pause(10);
  }
  keySequence.forEach((value2) => keyAction.up(value2));
  return keyAction.perform(true);
}
var init_keys = __esm({
  "src/commands/browser/keys.ts"() {
    "use strict";
    init_utils2();
  }
});

// src/utils/Timer.ts
function timeoutError() {
  return Object.assign(new Error(TIMEOUT_ERROR), { code: TIMER_TIMEOUT });
}
var TIMEOUT_ERROR, NOOP, Timer, Timer_default;
var init_Timer = __esm({
  "src/utils/Timer.ts"() {
    "use strict";
    init_errorCodes();
    TIMEOUT_ERROR = "timeout";
    NOOP = () => {
    };
    Timer = class {
      constructor(_delay, _timeout, _fn, _leading = false, _signal) {
        this._delay = _delay;
        this._timeout = _timeout;
        this._fn = _fn;
        this._leading = _leading;
        this._signal = _signal;
        this.#retPromise = new Promise((resolve, reject) => {
          this._resolve = resolve;
          this._reject = reject;
        });
        this._start();
      }
      _delay;
      _timeout;
      _fn;
      _leading;
      _signal;
      #retPromise;
      _conditionExecutedCnt = 0;
      _resolve = NOOP;
      _reject = NOOP;
      _startTime;
      _ticks = 0;
      _timeoutId;
      _mainTimeoutId;
      _lastError;
      then(thennable, catchable) {
        return this.#retPromise.then(thennable, catchable);
      }
      catch(catchable) {
        return this.#retPromise.catch(catchable);
      }
      _start() {
        this._startTime = Date.now();
        if (this._leading) {
          this._tick();
        } else {
          this._timeoutId = setTimeout(this._tick.bind(this), this._delay);
        }
        if (this._wasConditionExecuted()) {
          return;
        }
        this._mainTimeoutId = setTimeout(() => {
          if (!this._wasConditionExecuted()) {
            return;
          }
          const reason = this._lastError || timeoutError();
          this._reject(reason);
          this._stop();
        }, this._timeout);
      }
      _stop() {
        if (this._timeoutId) {
          clearTimeout(this._timeoutId);
        }
        delete this._timeoutId;
      }
      _stopMain() {
        if (this._mainTimeoutId) {
          clearTimeout(this._mainTimeoutId);
        }
      }
      _tick() {
        try {
          const result = this._fn();
          if (!result || typeof result.then !== "function") {
            return this._checkCondition(void 0, result);
          }
          result.then(
            (res) => this._checkCondition(void 0, res),
            (err) => this._checkCondition(err)
          );
        } catch (err) {
          return this._checkCondition(err);
        }
      }
      _checkCondition(err, res) {
        this._lastError = err;
        if (this._signal?.aborted) {
          this._reject(this._lastError || new Error("Aborted"));
          this._stop();
          this._stopMain();
          return;
        }
        ++this._conditionExecutedCnt;
        if (res) {
          this._resolve(res);
          this._stop();
          this._stopMain();
          return;
        }
        const diff = Date.now() - (this._startTime || 0) - this._ticks++ * this._delay;
        const delay2 = Math.max(0, this._delay - diff);
        this._stop();
        if (this._hasTime(delay2)) {
          this._timeoutId = setTimeout(this._tick.bind(this), delay2);
        } else {
          this._stopMain();
          const reason = this._lastError || timeoutError();
          this._reject(reason);
        }
      }
      _hasTime(delay2) {
        return Date.now() - (this._startTime || 0) + delay2 <= this._timeout;
      }
      _wasConditionExecuted() {
        return this._conditionExecutedCnt > 0;
      }
    };
    Timer_default = Timer;
  }
});

// src/utils/interception/utils.ts
function parseOverwrite(overwrite, request) {
  const result = {};
  if ("body" in overwrite && overwrite.body) {
    const bodyOverwrite = typeof overwrite.body === "function" ? overwrite.body(request) : overwrite.body;
    result.body = bodyOverwrite?.type === "string" || bodyOverwrite?.type === "base64" ? bodyOverwrite : typeof bodyOverwrite === "string" ? { type: "string", value: bodyOverwrite } : { type: "base64", value: btoa(JSON.stringify(bodyOverwrite || "")) };
  }
  if ("headers" in overwrite) {
    const headersOverwrite = typeof overwrite.headers === "function" ? overwrite.headers(request) : overwrite.headers;
    result.headers = Object.entries(headersOverwrite || {}).map(([name, value]) => ({
      name,
      value: { type: "string", value }
    }));
  }
  if ("cookies" in overwrite && overwrite.cookies) {
    const cookieOverwrite = typeof overwrite.cookies === "function" ? overwrite.cookies(request) || [] : overwrite.cookies;
    result.cookies = cookieOverwrite.map((cookie) => ({
      name: cookie.name,
      value: {
        type: "string",
        value: cookie.value
      },
      domain: cookie.domain,
      path: cookie.path,
      expires: cookie.expiry,
      httpOnly: cookie.httpOnly,
      secure: cookie.secure,
      sameSite: cookie.sameSite?.toLowerCase()
    }));
  }
  if ("statusCode" in overwrite && overwrite.statusCode) {
    const statusCodeOverwrite = typeof overwrite.statusCode === "function" ? overwrite.statusCode(request) : overwrite.statusCode;
    result.statusCode = statusCodeOverwrite;
  }
  if ("method" in overwrite) {
    result.method = typeof overwrite.method === "function" ? overwrite.method(request) : overwrite.method;
  }
  if ("url" in overwrite) {
    result.url = typeof overwrite.url === "function" ? overwrite.url(request) : overwrite.url;
  }
  return result;
}
function getPatternParam(pattern, key) {
  const value = pattern[key];
  if (URL_PATTERN_SYNTAX.test(value)) {
    return;
  }
  if (key === "port" && pattern.port === "") {
    return pattern.protocol === "https" ? "443" : "80";
  }
  return value;
}
var URL_PATTERN_SYNTAX;
var init_utils = __esm({
  "src/utils/interception/utils.ts"() {
    "use strict";
    URL_PATTERN_SYNTAX = /[*:(){}?+\\]/;
  }
});

// src/utils/interception/index.ts
import logger10 from "@wdio/logger";
import { setWdioKind } from "@wdio/utils";
import { URLPattern } from "urlpattern-polyfill";
function isContested(event) {
  return Boolean(event.intercepts && event.intercepts.length > 1);
}
function isClaimed(event) {
  return Boolean(event[RELEASED]);
}
function claim(event) {
  const claimable = event;
  if (claimable[RELEASED]) {
    return false;
  }
  claimable[RELEASED] = true;
  return true;
}
function trackPending(event, decision) {
  const marked = event;
  const pending = marked[PENDING] ?? (marked[PENDING] = []);
  const settled = decision.then(() => void 0, () => void 0);
  pending.push(settled);
  void settled.finally(() => {
    const index = pending.indexOf(settled);
    if (index !== -1) {
      pending.splice(index, 1);
    }
  });
}
function pendingDecisions(event) {
  const pending = event[PENDING];
  return pending ? pending.slice() : [];
}
function toStringBody(payload) {
  if (typeof payload === "string") {
    return payload;
  }
  const serialized = JSON.stringify(payload);
  if (typeof serialized !== "string") {
    throw new Error(
      `Failed to serialize mock.respond() payload of type "${typeof payload}". The response body must be a string, ArrayBufferView, ArrayBuffer, or JSON-serializable value.`
    );
  }
  return serialized;
}
function decodeHeader(value) {
  return value.type === "string" ? value.value : UTF8_DECODER.decode(decodeBase64(value.value));
}
function isArrayBuffer(value) {
  try {
    getArrayBufferByteLength.call(value);
    return true;
  } catch {
    return false;
  }
}
function toNetworkBody(payload) {
  if (ArrayBuffer.isView(payload)) {
    const bytes = new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength);
    return { type: "base64", value: encodeBase64(bytes) };
  }
  if (isArrayBuffer(payload)) {
    return { type: "base64", value: encodeBase64(new Uint8Array(payload)) };
  }
  return { type: "string", value: toStringBody(payload) };
}
function parseUrlPattern(url2) {
  if (typeof url2 === "object") {
    return url2;
  }
  url2 = url2.replace(/(?<!\\)\*{2,}/g, "*");
  if (url2.startsWith("http")) {
    return new URLPattern(url2);
  }
  return new URLPattern({
    pathname: url2
  });
}
function getPatternId(pattern) {
  return `${pattern.protocol}|${pattern.username}|${pattern.password}|${pattern.hostname}|${pattern.port}|${pattern.pathname}|${pattern.search}|${pattern.hash}`;
}
function areFilterOptionsEqual(a = {}, b = {}) {
  const keys2 = ["method", "requestHeaders", "responseHeaders", "statusCode", "postData"];
  return keys2.every((key) => isFilterOptionValueEqual(a[key], b[key]));
}
function isFilterOptionValueEqual(a, b) {
  if (a === b) {
    return true;
  }
  if (typeof a === "function" || typeof b === "function") {
    return false;
  }
  if (a && b && typeof a === "object" && typeof b === "object") {
    const aKeys = Object.keys(a).sort();
    const bKeys = Object.keys(b).sort();
    if (aKeys.length !== bKeys.length) {
      return false;
    }
    return aKeys.every((k, i) => k === bKeys[i] && a[k] === b[k]);
  }
  return false;
}
var log10, DEFAULT_SPY_COLLECTED_BODY_SIZE, subscribedSessions, RELEASED, PENDING, getArrayBufferByteLength, UTF8_DECODER, WebDriverInterception;
var init_interception = __esm({
  "src/utils/interception/index.ts"() {
    "use strict";
    init_Timer();
    init_base64();
    init_utils();
    init_mock();
    init_sessionEnded();
    log10 = logger10("WebDriverInterception");
    DEFAULT_SPY_COLLECTED_BODY_SIZE = 10 * 1024 * 1024;
    subscribedSessions = /* @__PURE__ */ new WeakMap();
    RELEASED = /* @__PURE__ */ Symbol("wdio.interception.released");
    PENDING = /* @__PURE__ */ Symbol("wdio.interception.pending");
    getArrayBufferByteLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get;
    UTF8_DECODER = new TextDecoder("utf-8", { ignoreBOM: true });
    WebDriverInterception = class _WebDriverInterception {
      #pattern;
      #patternId;
      #mockId;
      /**
       * The `SESSION_MOCKS` key `mock()` stored this interception under
       */
      #sessionKey;
      /**
       * Restores a mock of a held context when that context closes
       */
      #onContextDestroyed;
      #warnedAboutEarlyAnswer = false;
      #filterOptions;
      #browser;
      #contexts;
      /**
       * Iframes below an owned context. Their non-blocked events carry the iframe's
       * id, so ownership can't be read off `#contexts` alone.
       */
      #descendantContexts = /* @__PURE__ */ new Set();
      #onContextCreated;
      #eventHandler = /* @__PURE__ */ new Map();
      #restored = false;
      #requestOverwrites = [];
      #respondOverwrites = [];
      #calls = [];
      #overwrittenResponseBodies = /* @__PURE__ */ new Map();
      #requestPostData = /* @__PURE__ */ new Map();
      #isCollectingNetworkData;
      #hasOneResponseCollected = false;
      #hasOneBodyReadStarted = false;
      #blockedRequests = /* @__PURE__ */ new Set();
      #requestsRespondedWithoutFetch = /* @__PURE__ */ new Set();
      constructor(pattern, mockId, filterOptions, browser, isCollectingNetworkData = false, sessionKey, contexts) {
        this.#sessionKey = sessionKey;
        this.#pattern = pattern;
        this.#patternId = getPatternId(pattern);
        this.#mockId = mockId;
        this.#filterOptions = filterOptions;
        this.#browser = browser;
        this.#contexts = contexts;
        this.#isCollectingNetworkData = isCollectingNetworkData;
        browser.on("network.beforeRequestSent", this.#handleBeforeRequestSent.bind(this));
        browser.on("network.responseStarted", this.#handleResponseStarted.bind(this));
        browser.on("network.responseCompleted", this.#handleResponseCompleted.bind(this));
        if (contexts?.length) {
          this.#onContextDestroyed = ({ context }) => {
            this.#descendantContexts.delete(context);
            if (contexts.includes(context)) {
              this.restore().catch(() => {
              });
            }
          };
          browser.on("browsingContext.contextDestroyed", this.#onContextDestroyed);
          this.#onContextCreated = ({ context, parent }) => {
            if (parent && this.#isOwnedContext(parent)) {
              this.#descendantContexts.add(context);
            }
          };
          browser.on("browsingContext.contextCreated", this.#onContextCreated);
        }
      }
      static async initiate(url2, filterOptions, browser, scope = {}) {
        const pattern = parseUrlPattern(url2);
        const isCollectingNetworkData = browser.options.maxSpyCollectedBodySize !== 0;
        if (!subscribedSessions.has(browser) || subscribedSessions.get(browser) !== browser.sessionId) {
          await browser.sessionSubscribe({
            events: [
              "network.beforeRequestSent",
              "network.responseStarted",
              "network.responseCompleted",
              "browsingContext.contextCreated"
            ]
          });
          try {
            if (isCollectingNetworkData) {
              await browser.networkAddDataCollector({
                dataTypes: ["request", "response"],
                maxEncodedDataSize: typeof browser.options.maxSpyCollectedBodySize === "number" ? browser.options.maxSpyCollectedBodySize : DEFAULT_SPY_COLLECTED_BODY_SIZE
              });
            }
          } catch (error) {
            log10.warn(`[BiDi] network.addDataCollector not supported: ${error?.message}`);
          }
          log10.info("subscribed to network events");
          subscribedSessions.set(browser, browser.sessionId);
        }
        const interception = await browser.networkAddIntercept({
          ...scope.contexts ? { contexts: scope.contexts } : {},
          phases: ["beforeRequestSent", "responseStarted"],
          urlPatterns: [{
            type: "pattern",
            protocol: getPatternParam(pattern, "protocol"),
            hostname: getPatternParam(pattern, "hostname"),
            pathname: getPatternParam(pattern, "pathname"),
            port: getPatternParam(pattern, "port"),
            search: getPatternParam(pattern, "search")
          }]
        });
        const mock2 = new _WebDriverInterception(pattern, interception.intercept, filterOptions, browser, isCollectingNetworkData, scope.sessionKey, scope.contexts);
        await mock2.#seedDescendantContexts();
        return mock2;
      }
      /**
       * `contextCreated` only reports iframes created after the mock, so iframes
       * already below a held context are read from the tree.
       */
      async #seedDescendantContexts() {
        for (const root of this.#contexts ?? []) {
          try {
            const { contexts } = await this.#browser.browsingContextGetTree({ root });
            const pending = contexts.flatMap(({ children }) => children ?? []);
            for (let info = pending.pop(); info; info = pending.pop()) {
              this.#descendantContexts.add(info.context);
              pending.push(...info.children ?? []);
            }
          } catch (err) {
            log10.warn(`Mock may miss requests of iframes that already exist: failed to read the context tree of ${root}: ${err.message}`);
          }
        }
      }
      #emit(event, args) {
        if (!this.#eventHandler.has(event)) {
          return;
        }
        const handlers = this.#eventHandler.get(event) || [];
        for (const handler of handlers) {
          handler(args);
        }
      }
      #addEventHandler(event, handler) {
        if (!this.#eventHandler.has(event)) {
          this.#eventHandler.set(event, []);
        }
        const handlers = this.#eventHandler.get(event);
        handlers?.push(handler);
      }
      /**
       * Release a paused request, unless another mock listening to the same event
       * has already released it.
       *
       * `handling` says whether this mock is the one the request belongs to. A mock
       * that only releases because the request does *not* match it must not take the
       * release away from a mock that does. Listeners of one event run synchronously,
       * so it waits until that dispatch finishes. A `postData` match also has to
       * read the body first, and that decision is recorded on the event before the
       * listener yields. The declining mock waits for those decisions too, then
       * releases only if nobody claimed the request.
       */
      #release(event, handling, call2) {
        if (!isContested(event)) {
          return call2();
        }
        if (handling) {
          return claim(event) ? call2() : void 0;
        }
        if (!isClaimed(event)) {
          queueMicrotask(() => {
            const release = () => {
              if (claim(event)) {
                call2();
              }
            };
            const pending = pendingDecisions(event);
            if (pending.length === 0) {
              release();
              return;
            }
            void Promise.all(pending).then(release);
          });
        }
        return void 0;
      }
      #handleBeforeRequestSent(request) {
        if (!this.#isOwnEvent(request)) {
          return;
        }
        if (this.#restored) {
          if (request.intercepts?.includes(this.#mockId)) {
            return this.#release(request, false, () => this.#browser.networkContinueRequest({
              request: request.request.request
            }).catch(() => {
            }));
          }
          return;
        }
        if (!this.#isRequestMatching(request)) {
          if (request.intercepts?.includes(this.#mockId)) {
            return this.#release(request, false, () => this.#browser.networkContinueRequest({
              request: request.request.request
            }).catch(this.#handleNetworkProvideResponseError));
          }
          return;
        }
        if (this.#filterOptions.postData) {
          if (!this.#matchesFilterOptions(request, { includePostData: false })) {
            return this.#release(request, false, () => this.#browser.networkContinueRequest({
              request: request.request.request
            }).catch(this.#handleNetworkProvideResponseError));
          }
          const decision = this.#handleBeforeRequestSentWithPostData(request);
          if (isContested(request)) {
            trackPending(request, decision);
          }
          return decision;
        }
        return this.#continueBeforeRequestSent(request);
      }
      /**
       * `fetchResponse: false` answers before a response exists. Callbacks are
       * typed to receive one, so give them the status this mock sends by default.
       * A callback can still replace that status.
       */
      #eventForEarlyResponse(request) {
        return {
          ...request,
          response: {
            status: 200,
            headers: []
          }
        };
      }
      async #handleBeforeRequestSentWithPostData(request) {
        await this.#populateRequestPostData(request);
        return this.#continueBeforeRequestSent(request, { requestFiltersMatch: true });
      }
      #continueBeforeRequestSent(request, { requestFiltersMatch = false } = {}) {
        const matches = requestFiltersMatch ? this.#matchesPostDataFilter(request) : this.#matchesFilterOptions(request);
        if (!matches) {
          return this.#release(request, false, () => this.#browser.networkContinueRequest({
            request: request.request.request
          }).catch(this.#handleNetworkProvideResponseError));
        }
        const requestId = request.request.request;
        this.#emit("request", request);
        if (this.#requestOverwrites[0]?.abort) {
          const { abort } = this.#requestOverwrites[0].once ? this.#requestOverwrites.shift() || {} : this.#requestOverwrites[0];
          if (abort) {
            this.#emit("fail", requestId);
            return this.#release(request, true, () => this.#withBlockedRequestTracking(
              requestId,
              this.#browser.networkFailRequest({ request: requestId }).catch(this.#handleNetworkProvideResponseError)
            ));
          }
        }
        const responseOverwrite = this.#respondOverwrites[0];
        if (responseOverwrite?.overwrite && ("fetchResponse" in responseOverwrite.overwrite && responseOverwrite.overwrite.fetchResponse === false || this.#mustAnswerBeforeRequestSent())) {
          const { overwrite } = responseOverwrite.once ? this.#respondOverwrites.shift() || {} : responseOverwrite;
          if (!overwrite) {
            return;
          }
          this.#emit("overwrite", request);
          try {
            const responseData = parseOverwrite(
              overwrite,
              this.#eventForEarlyResponse(request)
            );
            if (responseData.body) {
              this.#overwrittenResponseBodies.set(requestId, responseData.body);
            }
            this.#requestsRespondedWithoutFetch.add(requestId);
            return this.#withBlockedRequestTracking(
              requestId,
              this.#browser.networkProvideResponse({
                request: requestId,
                statusCode: 200,
                ...responseData
              }).catch((err) => {
                this.#requestsRespondedWithoutFetch.delete(requestId);
                return this.#handleNetworkProvideResponseError(err);
              })
            );
          } catch (err) {
            this.#requestsRespondedWithoutFetch.delete(requestId);
            log10.error(`Failed to apply mock.respond() overwrite: ${err.message}`);
            return this.#withBlockedRequestTracking(
              requestId,
              this.#browser.networkFailRequest({
                request: requestId
              }).catch(this.#handleNetworkProvideResponseError)
            );
          }
        }
        const hasRequestOverwrites = this.#requestOverwrites.length > 0;
        if (hasRequestOverwrites) {
          const { overwrite } = this.#requestOverwrites[0].once ? this.#requestOverwrites.shift() || {} : this.#requestOverwrites[0];
          this.#emit("overwrite", request);
          return this.#release(request, true, () => this.#withBlockedRequestTracking(
            requestId,
            this.#browser.networkContinueRequest({
              request: requestId,
              ...overwrite ? parseOverwrite(overwrite, request) : {}
            }).catch(this.#handleNetworkProvideResponseError)
          ));
        }
        this.#emit("continue", requestId);
        return this.#release(request, true, () => this.#withBlockedRequestTracking(
          requestId,
          this.#browser.networkContinueRequest({
            request: requestId
          }).catch(this.#handleNetworkProvideResponseError)
        ));
      }
      #handleResponseStarted(request) {
        if (!this.#isOwnEvent(request)) {
          return;
        }
        if (this.#restored) {
          if (request.intercepts?.includes(this.#mockId)) {
            return this.#release(request, false, () => this.#browser.networkProvideResponse({
              request: request.request.request
            }).catch(() => {
            }));
          }
          return;
        }
        const isHandledByThisMock = request.intercepts?.includes(this.#mockId);
        const urlMatches = this.#pattern && this.#pattern.test(request.request.url);
        if (!urlMatches) {
          if (isHandledByThisMock && request.isBlocked) {
            return this.#release(request, false, () => this.#browser.networkProvideResponse({
              request: request.request.request
            }).catch(this.#handleNetworkProvideResponseError));
          }
          return;
        }
        this.#attachPostData(request);
        const filterMatches = this.#matchesFilterOptions(request);
        if (filterMatches) {
          this.#calls.push(request);
        }
        if (this.#requestsRespondedWithoutFetch.delete(request.request.request)) {
          return;
        }
        if (!request.isBlocked) {
          return;
        }
        if (!filterMatches) {
          this.#emit("continue", request.request.request);
          return this.#release(request, false, () => this.#browser.networkProvideResponse({
            request: request.request.request
          }).catch(this.#handleNetworkProvideResponseError));
        }
        const requestId = request.request.request;
        if (this.#respondOverwrites.length === 0 || !this.#respondOverwrites[0].overwrite) {
          this.#emit("continue", requestId);
          return this.#release(request, true, () => this.#withBlockedRequestTracking(
            requestId,
            this.#browser.networkProvideResponse({
              request: requestId
            }).catch(this.#handleNetworkProvideResponseError)
          ));
        }
        const { overwrite } = this.#respondOverwrites[0].once ? this.#respondOverwrites.shift() || {} : this.#respondOverwrites[0];
        if (overwrite) {
          this.#emit("overwrite", request);
          try {
            const responseData = parseOverwrite(overwrite, request);
            if (responseData.body) {
              this.#overwrittenResponseBodies.set(requestId, responseData.body);
            }
            return this.#release(request, true, () => this.#withBlockedRequestTracking(
              requestId,
              this.#browser.networkProvideResponse({
                request: requestId,
                ...responseData
              }).catch((err) => this.#handleUnsupportedOverwrite(err, requestId))
            ));
          } catch (err) {
            log10.error(`Failed to apply mock.respond() overwrite: ${err.message}`);
            return this.#release(request, true, () => this.#withBlockedRequestTracking(
              requestId,
              this.#browser.networkFailRequest({
                request: requestId
              }).catch(this.#handleNetworkProvideResponseError)
            ));
          }
        }
        this.#emit("continue", requestId);
        return this.#release(request, true, () => this.#withBlockedRequestTracking(
          requestId,
          this.#browser.networkProvideResponse({
            request: requestId
          }).catch(this.#handleNetworkProvideResponseError)
        ));
      }
      async #handleResponseCompleted(response) {
        if (!this.#isOwnEvent(response)) {
          return;
        }
        if (this.#restored) {
          return;
        }
        if (this.#browser.options.maxSpyCollectedBodySize === 0 || !this.#pattern.test(response.request.url) || !this.#matchesFilterOptions(response, { includePostData: false })) {
          return;
        }
        const requestWithPostData = await this.#populateRequestPostData(response);
        if (!this.#matchesPostDataFilter(requestWithPostData)) {
          this.#requestPostData.delete(response.request.request);
          return;
        }
        const call2 = this.#getCall(response.request.request);
        if (!call2) {
          return;
        }
        this.#attachPostData(call2);
        this.#hasOneBodyReadStarted = true;
        try {
          const { bytes } = await this.#browser.networkGetData({
            request: response.request.request,
            dataType: "response"
          });
          if (bytes) {
            call2.body = bytes.value;
          }
        } catch (err) {
          log10.debug(`Failed to get response body for ${response.request.request}: ${err.message}`);
        } finally {
          if (this.#calls.includes(call2)) {
            this.#hasOneResponseCollected = true;
          }
          this.#requestPostData.delete(response.request.request);
        }
      }
      /**
       * It appears that the networkProvideResponse method may throw an "no such request" error even though the request
       * is marked as "blocked", in these cases we can safely ignore the error.
       * @param err Bidi message error
       */
      /**
       * Firefox only takes a response body in `network.provideResponse` while
       * the request is blocked in `beforeRequestSent`, not once the response
       * started (https://wpt.fyi/results/webdriver/tests/bidi/network/provide_response).
       * Answer there, like `fetchResponse: false`, unless the mock filters on the
       * response, which needs the backend.
       */
      #mustAnswerBeforeRequestSent() {
        if (!this.#browser.isFirefox) {
          return false;
        }
        if (this.#filterOptions.statusCode !== void 0 || this.#filterOptions.responseHeaders !== void 0) {
          return false;
        }
        if (!this.#warnedAboutEarlyAnswer) {
          this.#warnedAboutEarlyAnswer = true;
          log10.warn(
            "Firefox can not replace a response body after the request was sent. mock.respond() answers before the request is sent instead, as with `fetchResponse: false`."
          );
        }
        return true;
      }
      /**
       * A browser that can't replace the body once the response started rejects
       * `network.provideResponse`, which would leave the request blocked. Let the
       * real response through and say so, instead of hanging the test.
       */
      #handleUnsupportedOverwrite(err, requestId) {
        if (!err.message.includes("unsupported operation")) {
          return this.#handleNetworkProvideResponseError(err);
        }
        log10.warn(
          `mock.respond() could not replace the response of request ${requestId}: ${err.message}. The page received the real response. Use \`fetchResponse: false\` to answer before the request is sent.`
        );
        return this.#browser.networkProvideResponse({ request: requestId }).catch(this.#handleNetworkProvideResponseError);
      }
      /**
       * The error of a network command that answers a paused request. It runs in a network
       * event listener: no caller waits for it, so it is logged, not thrown (a thrown error
       * would be an unhandled rejection). A request that is gone needs no answer.
       */
      #handleNetworkProvideResponseError = (err) => {
        if (err.message.endsWith("no such request")) {
          return;
        }
        logBackgroundError(log10, "Failed to answer a paused request", err, this.#browser);
      };
      /**
       * Read a cached binary overwrite as a Buffer in Node.js or Uint8Array in browsers.
       */
      getBinaryResponse(requestId) {
        const body = this.#overwrittenResponseBodies.get(requestId);
        if (body?.type !== "base64") {
          return null;
        }
        if (/[^A-Za-z0-9+/=\s]/.test(body.value)) {
          log10.warn(`Invalid base64 data for request ${requestId}`);
          return null;
        }
        return decodeBase64(body.value);
      }
      #attachPostData(request) {
        const requestWithPostData = request;
        const postData = this.#requestPostData.get(request.request.request);
        if (postData !== void 0) {
          requestWithPostData.postData = postData;
        }
        return requestWithPostData;
      }
      async #populateRequestPostData(request) {
        const requestWithPostData = this.#attachPostData(request);
        if (requestWithPostData.postData !== void 0 || this.#browser.options.maxSpyCollectedBodySize === 0) {
          return requestWithPostData;
        }
        try {
          const { bytes } = await this.#browser.networkGetData({
            request: request.request.request,
            dataType: "request"
          });
          if (bytes) {
            requestWithPostData.postData = bytes.value;
            this.#requestPostData.set(request.request.request, bytes.value);
          }
        } catch (err) {
          log10.debug(`Failed to get request body for ${request.request.request}: ${err.message}`);
        }
        return requestWithPostData;
      }
      /**
       * Simulate a responseStarted event for testing purposes
       * @param request NetworkResponseCompletedParameters to simulate
       */
      simulateResponseStarted(request) {
        try {
          this.#handleResponseStarted(request);
        } catch (e) {
          console.log("DEBUG: Error in simulateResponseStarted:", e);
          throw e;
        }
      }
      debugResponseBodies() {
        return this.#overwrittenResponseBodies;
      }
      #getCall(requestId) {
        for (let index = this.#calls.length - 1; index >= 0; index--) {
          const call2 = this.#calls[index];
          if (call2.request.request === requestId) {
            return call2;
          }
        }
      }
      #isOwnedContext(context) {
        return !!this.#contexts?.includes(context) || this.#descendantContexts.has(context);
      }
      /**
       * A blocked request belongs to the mock whose intercept paused it, whatever
       * context (e.g. an iframe) it came from; the intercept is already scoped to
       * the held contexts. Observed requests are matched on the context tree, or
       * on a call this mock already recorded, as the tree can lag behind events.
       */
      #isOwnEvent(event) {
        if (!this.#contexts?.length) {
          return true;
        }
        if (event.isBlocked) {
          return !!event.intercepts?.includes(this.#mockId);
        }
        return event.context !== null && this.#isOwnedContext(event.context) || !!this.#getCall(event.request.request);
      }
      #isRequestMatching(request) {
        const matches = this.#pattern && this.#pattern.test(request.request.url);
        return request.isBlocked && matches;
      }
      #matchesPostDataFilter(request) {
        if (!this.#filterOptions.postData) {
          return true;
        }
        return typeof this.#filterOptions.postData === "function" ? this.#filterOptions.postData(request.postData) : request.postData === this.#filterOptions.postData;
      }
      #matchesFilterOptions(request, { includePostData = true } = {}) {
        let isRequestMatching = true;
        if (isRequestMatching && this.#filterOptions.method) {
          isRequestMatching = typeof this.#filterOptions.method === "function" ? this.#filterOptions.method(request.request.method) : this.#filterOptions.method.toLowerCase() === request.request.method.toLowerCase();
        }
        if (isRequestMatching && this.#filterOptions.requestHeaders) {
          isRequestMatching = typeof this.#filterOptions.requestHeaders === "function" ? this.#filterOptions.requestHeaders(request.request.headers.reduce((acc, { name, value }) => {
            acc[name] = decodeHeader(value);
            return acc;
          }, {})) : Object.entries(this.#filterOptions.requestHeaders).every(([key, value]) => {
            const header = request.request.headers.find(({ name }) => name === key);
            if (!header) {
              return false;
            }
            return decodeHeader(header.value) === value;
          });
        }
        if (isRequestMatching && includePostData) {
          isRequestMatching = this.#matchesPostDataFilter(request);
        }
        if (isRequestMatching && this.#filterOptions.responseHeaders && "response" in request) {
          isRequestMatching = typeof this.#filterOptions.responseHeaders === "function" ? this.#filterOptions.responseHeaders(request.response.headers.reduce((acc, { name, value }) => {
            acc[name] = decodeHeader(value);
            return acc;
          }, {})) : Object.entries(this.#filterOptions.responseHeaders).every(([key, value]) => {
            const header = request.response.headers.find(({ name }) => name === key);
            if (!header) {
              return false;
            }
            return decodeHeader(header.value) === value;
          });
        }
        if (isRequestMatching && this.#filterOptions.statusCode && "response" in request) {
          isRequestMatching = typeof this.#filterOptions.statusCode === "function" ? this.#filterOptions.statusCode(request.response.status) : this.#filterOptions.statusCode === request.response.status;
        }
        return isRequestMatching;
      }
      #setOverwrite = (overwriteProp, { overwrite, abort, once }) => {
        return once ? [
          ...overwriteProp.filter(({ once: once2 }) => once2),
          { overwrite, abort, once }
        ] : [{ overwrite, abort }];
      };
      /**
       * allows access to all requests made with given pattern
       */
      get calls() {
        return this.#calls;
      }
      get hasAtLeastOneResponseReceived() {
        const isResponseReceived = this.calls && this.calls.length > 0;
        return isResponseReceived && (!this.#isCollectingNetworkData || this.#hasOneResponseCollected);
      }
      /**
       * Resets all information stored in the `mock.calls` set.
       */
      clear() {
        this.#calls = [];
        this.#overwrittenResponseBodies.clear();
        this.#requestPostData.clear();
        this.#hasOneResponseCollected = false;
        this.#hasOneBodyReadStarted = false;
        this.#blockedRequests.clear();
        this.#requestsRespondedWithoutFetch.clear();
        return this;
      }
      /**
       * Does what `mock.clear()` does and makes removes custom request overrides
       * and response overwrites
       */
      reset() {
        this.clear();
        this.#respondOverwrites = [];
        this.#requestOverwrites = [];
        return this;
      }
      /**
       * Does everything that `mock.reset()` does, and also
       * removes any mocked return values or implementations.
       * Restored mock does not emit events and could not mock responses
       */
      async restore() {
        const blockedRequestIds = Array.from(this.#blockedRequests);
        if (this.#onContextDestroyed) {
          this.#browser.off("browsingContext.contextDestroyed", this.#onContextDestroyed);
          this.#onContextDestroyed = void 0;
        }
        if (this.#onContextCreated) {
          this.#browser.off("browsingContext.contextCreated", this.#onContextCreated);
          this.#onContextCreated = void 0;
        }
        this.reset();
        this.#respondOverwrites = [];
        const handle = this.#sessionKey ?? await this.#browser.getWindowHandle();
        log10.trace(`Restoring mock for ${handle}`);
        SESSION_MOCKS[handle]?.delete(this);
        for (const requestId of blockedRequestIds) {
          try {
            await this.#browser.networkContinueRequest({ request: requestId });
          } catch (err) {
            log10.trace(`Failed to continue in-flight request ${requestId} during restore:`, err);
          }
        }
        this.#blockedRequests.clear();
        if (this.#mockId) {
          await this.#browser.networkRemoveIntercept({ intercept: this.#mockId });
        }
        this.#restored = true;
        return this;
      }
      /**
       * Always use request modification for the next request done by the browser.
       * @param payload  payload to overwrite the request
       * @param once     apply overwrite only once for the next request
       * @returns        this instance to chain commands
       */
      request(overwrite, once) {
        this.#ensureNotRestored();
        this.#requestOverwrites = this.#setOverwrite(this.#requestOverwrites, { overwrite, once });
        return this;
      }
      /**
       * alias for `mock.request(…, true)`
       */
      requestOnce(payload) {
        return this.request(payload, true);
      }
      /**
       * Always respond with same overwrite
       * @param {*}       payload  payload to overwrite the response
       * @param {*}       params   additional respond parameters to overwrite
       * @param {boolean} once     apply overwrite only once for the next request
       * @returns                  this instance to chain commands
       */
      respond(payload, params = {}, once) {
        this.#ensureNotRestored();
        this.#assertCanSkipFetch(params);
        const body = typeof payload === "function" ? (request) => toNetworkBody(payload(request)) : toNetworkBody(payload);
        const overwrite = { body, ...params };
        this.#respondOverwrites = this.#setOverwrite(this.#respondOverwrites, { overwrite, once });
        return this;
      }
      /**
       * alias for `mock.respond(…, true)`
       */
      respondOnce(payload, params = {}) {
        return this.respond(payload, params, true);
      }
      /**
       * Abort the request with an error code
       * @param {string} errorReason  error code of the response
       * @param {boolean} once        if request should be aborted only once for the next request
       */
      abort(once) {
        this.#ensureNotRestored();
        this.#requestOverwrites = this.#setOverwrite(this.#requestOverwrites, { abort: true, once });
        return this;
      }
      /**
       * alias for `mock.abort(true)`
       */
      abortOnce() {
        return this.abort(true);
      }
      /**
       * Redirect request to another URL
       * @param {string} redirectUrl  URL to redirect to
       * @param {boolean} sticky      if request should be redirected for all following requests
       */
      redirect(redirectUrl, once) {
        this.#ensureNotRestored();
        const requestWith = { url: redirectUrl };
        this.request(requestWith, once);
        return this;
      }
      /**
       * alias for `mock.redirect(…, true)`
       */
      redirectOnce(redirectUrl) {
        return this.redirect(redirectUrl, true);
      }
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      on(event, callback) {
        this.#addEventHandler(event, callback);
        return this;
      }
      #ensureNotRestored() {
        if (this.#restored) {
          throw new Error("This can't be done on restored mock");
        }
      }
      /**
       * A status or response-header filter matches the backend response.
       * `fetchResponse: false` never calls the backend, so the filter cannot
       * be decided and must not be silently ignored or bypassed by fetching.
       */
      #assertCanSkipFetch(params) {
        if (params.fetchResponse !== false) {
          return;
        }
        const filtersOnResponse = this.#filterOptions.statusCode !== void 0 || this.#filterOptions.responseHeaders !== void 0;
        if (!filtersOnResponse) {
          return;
        }
        throw new Error(
          "fetchResponse: false cannot be used when the mock filters on statusCode or responseHeaders. Those filters need the backend response, and this option does not call the backend."
        );
      }
      /**
       * Keep the request id tracked until the BiDi call settles so restore()
       * can still continue it if cleanup races an in-flight interception.
       */
      #withBlockedRequestTracking(requestId, networkCall) {
        this.#blockedRequests.add(requestId);
        return Promise.resolve(networkCall).finally(() => {
          this.#blockedRequests.delete(requestId);
        });
      }
      isSameDefinition(url2, filterOptions = {}) {
        const pattern = parseUrlPattern(url2);
        return this.#patternId === getPatternId(pattern) && areFilterOptionsEqual(this.#filterOptions, filterOptions);
      }
      waitForResponse({
        timeout = this.#browser.options.waitforTimeout,
        interval = this.#browser.options.waitforInterval,
        timeoutMsg
      } = {}) {
        if (typeof timeout !== "number") {
          timeout = this.#browser.options.waitforTimeout;
        }
        if (typeof interval !== "number") {
          interval = this.#browser.options.waitforInterval;
        }
        const isResponseReceived = () => this.hasAtLeastOneResponseReceived;
        const timer = new Timer_default(interval, timeout, isResponseReceived, true);
        return this.#browser.call(() => timer.catch((e) => {
          if (e.message === "timeout") {
            if (this.#hasOneBodyReadStarted) {
              log10.warn(`waitForResponse: a response was received, but its body was not collected within ${timeout}ms, continuing without it`);
              return true;
            }
            if (typeof timeoutMsg === "string") {
              throw new Error(timeoutMsg);
            }
            throw new Error(`waitForResponse timed out after ${timeout}ms`);
          }
          throw new Error(`waitForResponse failed with the following reason: ${e && e.message || e}`);
        }));
      }
    };
    setWdioKind(WebDriverInterception.prototype, "mock");
  }
});

// src/commands/browser/mock.ts
import { getBrowserObject as getBrowserObject14 } from "@wdio/utils";
async function mock(url2, filterOptions) {
  if (!this.isBidi) {
    throw new Error("Mocking is only supported when running tests using WebDriver Bidi");
  }
  if (isBrowsingContext(this)) {
    assertTopLevel(this, "mock");
  }
  const browser = getBrowserObject14(this);
  const context = await contextIdOf(this);
  if (!SESSION_MOCKS[context]) {
    SESSION_MOCKS[context] = /* @__PURE__ */ new Set();
  }
  const normalizedFilterOptions = filterOptions || {};
  for (const existingMock of Array.from(SESSION_MOCKS[context])) {
    if (!existingMock.isSameDefinition(url2, normalizedFilterOptions)) {
      continue;
    }
    await existingMock.restore();
    SESSION_MOCKS[context].delete(existingMock);
  }
  const networkInterception = await WebDriverInterception.initiate(url2, normalizedFilterOptions, browser, {
    contexts: isBrowsingContext(this) || getParallelContextStore().getStore() ? [context] : void 0,
    sessionKey: context
  });
  SESSION_MOCKS[context].add(networkInterception);
  return networkInterception;
}
var SESSION_MOCKS;
var init_mock = __esm({
  "src/commands/browser/mock.ts"() {
    "use strict";
    init_interception();
    init_context();
    init_browsingContext();
    SESSION_MOCKS = {};
  }
});

// src/commands/browser/mockClearAll.ts
import logger11 from "@wdio/logger";
async function mockClearAll() {
  for (const [handle, mocks] of Object.entries(SESSION_MOCKS)) {
    log11.trace(`Clearing mocks for ${handle}`);
    for (const mock2 of mocks) {
      mock2.clear();
    }
  }
}
var log11;
var init_mockClearAll = __esm({
  "src/commands/browser/mockClearAll.ts"() {
    "use strict";
    init_mock();
    log11 = logger11("webdriverio:mockClearAll");
  }
});

// src/commands/browser/mockRestoreAll.ts
import logger12 from "@wdio/logger";
async function mockRestoreAll() {
  for (const [handle, mocks] of Object.entries(SESSION_MOCKS)) {
    log12.trace(`Clearing mocks for ${handle}`);
    for (const mock2 of mocks) {
      await mock2.restore();
    }
  }
}
var log12;
var init_mockRestoreAll = __esm({
  "src/commands/browser/mockRestoreAll.ts"() {
    "use strict";
    init_mock();
    log12 = logger12("webdriverio:mockRestoreAll");
  }
});

// src/commands/browser/react$.ts
import { waitToLoadReact, react$ as react$Script } from "./scripts/react.js";
async function react$(selector, { props = {}, state = {} } = {}) {
  await this.execute(reactScript);
  await this.execute(waitToLoadReact);
  const res = await this.execute(
    react$Script,
    selector,
    props,
    state
  );
  return getElement.call(this, selector, res, { isReactElement: true, strict: false, reactOptions: { props, state } });
}
var init_react = __esm({
  "src/commands/browser/react$.ts"() {
    "use strict";
    init_constant();
    init_getElementObject();
  }
});

// src/commands/browser/react$$.ts
import { waitToLoadReact as waitToLoadReact2, react$$ as react$$Script } from "./scripts/react.js";
function react$$(selector, { props = {}, state = {} } = {}) {
  return ElementArray.fromAsyncCallback(async () => {
    await this.execute(reactScript);
    await this.execute(waitToLoadReact2);
    const res = await this.execute(
      react$$Script,
      selector,
      props,
      state
    );
    return getElements.call(this, selector, res, { isReactElement: true, reactOptions: { props, state } });
  }, {
    selector,
    foundWith: "react$$",
    parent: this,
    /**
     * the arguments after the selector, so that
     * `parent[foundWith](selector, ...props)` runs the same query again
     */
    props: [{ props, state }]
  });
}
var init_react2 = __esm({
  "src/commands/browser/react$$.ts"() {
    "use strict";
    init_constant();
    init_getElementObject();
    init_array();
  }
});

// src/commands/browser/scroll.ts
import logger13 from "@wdio/logger";
function scroll(x = 0, y = 0) {
  if (!x && !y) {
    log13.warn('"scroll" command was called with no parameters, skipping execution');
    return Promise.resolve();
  }
  if (this.isMobile) {
    return this.execute((x2, y2) => window.scrollBy(x2, y2), x, y);
  }
  return this.action("wheel").scroll({
    deltaX: x,
    deltaY: y,
    duration: 0
  }).perform();
}
var log13;
var init_scroll = __esm({
  "src/commands/browser/scroll.ts"() {
    "use strict";
    log13 = logger13("webdriverio");
  }
});

// src/commands/browser/saveScreenshot.ts
async function saveScreenshot2(filepath, options) {
  return environment.value.saveScreenshot.call(this, filepath, options);
}
var init_saveScreenshot = __esm({
  "src/commands/browser/saveScreenshot.ts"() {
    "use strict";
    init_environment();
  }
});

// src/commands/browser/savePDF.ts
async function savePDF2(filepath, options) {
  return environment.value.savePDF.call(this, filepath, options);
}
var init_savePDF = __esm({
  "src/commands/browser/savePDF.ts"() {
    "use strict";
    init_environment();
  }
});

// src/commands/browser/setCookies.ts
import logger14 from "@wdio/logger";
async function setCookies(cookieObjs) {
  const cookieObjsList = !Array.isArray(cookieObjs) ? [cookieObjs] : cookieObjs;
  if (cookieObjsList.some((obj) => typeof obj !== "object")) {
    throw new Error("Invalid input (see https://webdriver.io/docs/api/browser/setCookies for documentation)");
  }
  if (!this.isBidi) {
    const classic = isBrowsingContext(this) ? this.browser : this;
    await Promise.all(cookieObjsList.map((cookieObj) => classic.addCookie(cookieObj)));
    return;
  }
  const browser = isBrowsingContext(this) ? this.browser : this;
  if (isBrowsingContext(this)) {
    const origin = this.url.startsWith("http") ? this.url : await this.getUrl();
    const url3 = new URL(origin);
    await Promise.all(cookieObjsList.map((cookie) => browser.storageSetCookie({
      cookie: {
        ...cookie,
        domain: cookie.domain || url3.hostname,
        value: {
          type: "string",
          value: cookie.value
        }
      },
      partition: {
        type: "context",
        context: this.contextId
      }
    })));
    return;
  }
  const parallelPartition = await parallelCookiePartition(this);
  if (parallelPartition) {
    const defaultDomain = cookieObjsList.every((cookie) => cookie.domain) ? void 0 : new URL(await this.getUrl()).hostname;
    await Promise.all(cookieObjsList.map((cookie) => this.storageSetCookie({
      cookie: {
        ...cookie,
        domain: cookie.domain || defaultDomain,
        value: {
          type: "string",
          value: cookie.value
        }
      },
      partition: parallelPartition
    })));
    return;
  }
  let url2;
  try {
    url2 = new URL(await this.getUrl());
    if (url2.origin === "null") {
      await Promise.all(cookieObjsList.map((cookieObj) => this.addCookie(cookieObj)));
      return;
    }
  } catch {
    await Promise.all(cookieObjsList.map((cookieObj) => this.addCookie(cookieObj)));
    return;
  }
  try {
    await Promise.all(cookieObjsList.map((cookie) => this.storageSetCookie({
      cookie: {
        ...cookie,
        domain: cookie.domain || url2.hostname,
        value: {
          type: "string",
          value: cookie.value
        }
      },
      partition: getCookiePartition(url2.origin)
    })));
  } catch (err) {
    log14.warn(`BiDi setCookies failed, falling back to classic: ${err.message}`);
    await Promise.all(cookieObjsList.map((cookieObj) => this.addCookie(cookieObj)));
  }
  return;
}
var log14;
var init_setCookies = __esm({
  "src/commands/browser/setCookies.ts"() {
    "use strict";
    init_browsingContext();
    init_cookiePartition();
    log14 = logger14("webdriverio");
  }
});

// src/commands/browser/setViewport.ts
import { getBrowserObject as getBrowserObject15 } from "@wdio/utils";
async function setViewport(options) {
  if (typeof options.width !== "number" || typeof options.height !== "number") {
    throw new Error("setViewport expects width and height of type number");
  }
  if (options.width < minWindowSize || options.width > maxWindowSize || options.height < minWindowSize || options.height > maxWindowSize) {
    throw new Error("setViewport expects width and height to be a number in the 0 to 2^31 \u2212 1 range");
  }
  if (options.devicePixelRatio && (typeof options.devicePixelRatio !== "number" || options.devicePixelRatio < 0)) {
    throw new Error("setViewport expects devicePixelRatio to be a number in the 0 to 2^31 \u2212 1 range");
  }
  if (isBrowsingContext(this)) {
    assertTopLevel(this, "setViewport");
  }
  const browser = getBrowserObject15(this);
  const context = await contextIdOf(this);
  const devicePixelRatio = options.devicePixelRatio || 1;
  await browser.browsingContextSetViewport({
    context,
    devicePixelRatio,
    viewport: {
      width: options.width,
      height: options.height
    }
  });
  rememberOverride(browser, context, {
    viewport: {
      width: options.width,
      height: options.height,
      devicePixelRatio
    }
  });
}
var minWindowSize, maxWindowSize;
var init_setViewport = __esm({
  "src/commands/browser/setViewport.ts"() {
    "use strict";
    init_browsingContext();
    init_emulationState();
    minWindowSize = 0;
    maxWindowSize = Number.MAX_SAFE_INTEGER;
  }
});

// src/commands/browser/restore.ts
async function restore(scopes2) {
  const scopeArray = !scopes2 || Array.isArray(scopes2) ? scopes2 : [scopes2];
  const instanceRestoreFunctions = restoreFunctions.get(this);
  if (!instanceRestoreFunctions) {
    return;
  }
  await Promise.all(Array.from(instanceRestoreFunctions.entries()).map(async ([scope, restoreFunctionsList]) => {
    if (!scopeArray || scopeArray.includes(scope)) {
      await Promise.all(restoreFunctionsList.map((fn) => fn()));
      instanceRestoreFunctions.set(scope, []);
    }
  }));
}
var init_restore = __esm({
  "src/commands/browser/restore.ts"() {
    "use strict";
    init_constants();
  }
});

// src/commands/browser/waitUntil.ts
import { getBrowserObject as getBrowserObject16 } from "@wdio/utils";
function waitUntil(condition, {
  timeout = this.options.waitforTimeout,
  interval = this.options.waitforInterval,
  timeoutMsg
} = {}) {
  if (typeof condition !== "function") {
    throw new Error("Condition is not a function");
  }
  if (typeof timeout !== "number") {
    timeout = this.options.waitforTimeout;
  }
  if (typeof interval !== "number") {
    interval = this.options.waitforInterval;
  }
  const browser = getBrowserObject16(this);
  const abort = new AbortController();
  const abortOnSessionEnd = (result) => {
    if (result.command === "deleteSession") {
      abort.abort();
    }
  };
  browser.on("result", abortOnSessionEnd);
  const fn = condition.bind(this);
  const timer = new Timer_default(interval, timeout, fn, true, abort.signal);
  return timer.catch((e) => {
    if (hasCode(e, TIMER_TIMEOUT)) {
      const message = typeof timeoutMsg === "function" ? timeoutMsg() : typeof timeoutMsg === "string" ? timeoutMsg : `waitUntil condition timed out after ${timeout}ms`;
      throw Object.assign(new Error(message), { code: WAIT_UNTIL_TIMEOUT });
    }
    const err = new Error(`waitUntil condition failed with the following reason: ${e && e.message || e}`);
    err.cause = e;
    const origStack = e.stack;
    if (!origStack || !err.stack) {
      throw err;
    }
    const [errMsg, ...waitUntilErrorStackLines] = err.stack.split("\n");
    err.stack = [
      errMsg,
      ...origStack.split("\n").slice(1),
      "    ---",
      ...waitUntilErrorStackLines
    ].filter((errorLine) => !errorLine.includes("/node_modules/webdriverio/") && !errorLine.includes("/node_modules/@wdio/")).join("\n");
    throw err;
  }).finally(() => {
    browser.off("result", abortOnSessionEnd);
  });
}
var init_waitUntil = __esm({
  "src/commands/browser/waitUntil.ts"() {
    "use strict";
    init_Timer();
    init_errorCodes();
  }
});

// src/commands/browser/pause.ts
function pause(milliseconds = 1e3) {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
var init_pause = __esm({
  "src/commands/browser/pause.ts"() {
    "use strict";
  }
});

// src/commands/browsingContext/frame.ts
async function frame(target) {
  if (typeof target === "function") {
    return frameByPredicate(this, target);
  }
  if (isFrameQuery(target)) {
    return frameByQuery(this, target);
  }
  if (target && typeof target === "object") {
    const candidate = target;
    const element = typeof candidate.getElement === "function" ? await candidate.getElement() : candidate;
    return frameFromElement(this, element);
  }
  if (typeof target === "string") {
    if (target.includes("://") || target.startsWith("/") || /^[A-Fa-f0-9-]{16,}$/.test(target)) {
      const mayBeXPath = target.startsWith("/");
      const waited = await this.waitUntil(
        async () => await frameFromTree(this, target) || mayBeXPath && await selectorExists(this, target) || false,
        {
          timeout: this.options.waitforTimeout,
          interval: this.options.waitforInterval,
          timeoutMsg: `Could not find a frame for "${target}"`
        }
      ).catch(() => void 0);
      if (waited && waited !== true) {
        return waited;
      }
    } else {
      const element2 = await existingElement(this, target);
      if (element2 && ["iframe", "frame"].includes(await element2.getTagName())) {
        return frameFromElement(this, element2);
      }
    }
    const fromTree = await frameFromTree(this, target);
    if (fromTree) {
      return fromTree;
    }
    const element = await this.$(target);
    return frameFromElement(this, element);
  }
  throw new Error("`frame` expects a selector, an element, a url, a context id, or a function");
}
function isFrameQuery(target) {
  if (!target || typeof target !== "object" || Object.getPrototypeOf(target) !== Object.prototype) {
    return false;
  }
  const keys2 = Object.keys(target);
  return keys2.length === 1 && ["selector", "url", "id"].includes(keys2[0]);
}
async function frameByQuery(caller, query) {
  if ("selector" in query) {
    if (typeof query.selector !== "string") {
      throw new Error("`frame({ selector })` expects a string selector");
    }
    return frameFromElement(caller, await caller.$(query.selector));
  }
  let matches;
  let description;
  if ("id" in query) {
    if (typeof query.id !== "string") {
      throw new Error("`frame({ id })` expects a browsing context id string");
    }
    matches = (node) => node.context === query.id;
    description = `id "${query.id}"`;
  } else {
    const { url: url2 } = query;
    if (typeof url2 !== "string" && !(url2 instanceof RegExp)) {
      throw new Error("`frame({ url })` expects a string or a RegExp");
    }
    matches = typeof url2 === "string" ? (node) => node.url === url2 : (node) => {
      url2.lastIndex = 0;
      return url2.test(node.url);
    };
    description = `url ${typeof url2 === "string" ? `"${url2}"` : String(url2)}`;
  }
  const found = await caller.waitUntil(
    async () => await findInTree(caller, await childNodes(caller), matches) || false,
    {
      timeout: caller.options.waitforTimeout,
      interval: caller.options.waitforInterval,
      timeoutMsg: `Could not find a frame with ${description}`
    }
  ).catch(() => void 0);
  if (!found) {
    throw new Error(`Could not find a frame with ${description}`);
  }
  return found;
}
async function frameFromElement(parent, element) {
  await element.waitForExist({
    timeoutMsg: `Can't find a frame with selector ${describeSelector(element)} because it doesn't exist`
  });
  const result = await parent.execute(
    (iframe) => iframe.contentWindow,
    element
  );
  const contextId = result && typeof result === "object" ? result.context : void 0;
  if (!contextId) {
    throw new Error("The element is not a frame with a browsing context");
  }
  return getBrowsingContext(parent.browser, contextId, {
    isFrame: true,
    parent,
    url: ""
  });
}
async function existingElement(caller, selector) {
  try {
    const element = await caller.$(selector);
    return await element.isExisting() ? element : void 0;
  } catch (err) {
    if (err instanceof StrictSelectorError) {
      throw err;
    }
    return void 0;
  }
}
async function selectorExists(caller, selector) {
  try {
    const element = await caller.$(selector);
    return await element.isExisting();
  } catch {
    return false;
  }
}
async function frameFromTree(caller, target) {
  const children = await childNodes(caller);
  return findInTree(caller, children, (node) => node.context === target || node.url === target || node.url.includes(target), (node) => node.context === target ? 0 : node.url === target ? 1 : 2);
}
async function frameByPredicate(caller, predicate) {
  const browser = caller.browser;
  const functionDeclaration = createBidiFunctionDeclaration(predicate);
  const match = await caller.waitUntil(async () => {
    const children = await childNodes(caller);
    return await findInTree(caller, children, async (node) => {
      const result = await browser.scriptCallFunction({
        functionDeclaration,
        awaitPromise: true,
        arguments: [
          LocalValue.getArgument({ context: node.context, url: node.url })
        ],
        target: { context: node.context }
      }).catch(() => void 0);
      return Boolean(result && result.type === "success" && result.result.type === "boolean" && result.result.value);
    }) || false;
  }, {
    timeout: caller.options.waitforTimeout,
    interval: caller.options.waitforInterval,
    timeoutMsg: "No frame matched the given function"
  }).catch(() => void 0);
  if (!match) {
    throw new Error("No frame matched the given function");
  }
  return match;
}
async function findInTree(parent, nodes, matches, rank) {
  let best;
  await walk(parent, nodes);
  return best?.context;
  async function walk(owner, level) {
    for (const node of level) {
      const context = getBrowsingContext(owner.browser, node.context, {
        isFrame: true,
        parent: owner,
        url: node.url
      });
      if (await matches(node)) {
        const score = rank ? rank(node) : 0;
        if (!best || score < best.rank) {
          best = { context, rank: score };
        }
        if (!rank) {
          return true;
        }
      }
      if (node.children?.length && await walk(context, node.children)) {
        return true;
      }
    }
    return false;
  }
}
async function childNodes(parent) {
  const { contexts } = await parent.browser.browsingContextGetTree({
    root: parent.contextId
  });
  return contexts[0]?.children ?? [];
}
var init_frame = __esm({
  "src/commands/browsingContext/frame.ts"() {
    "use strict";
    init_serialize();
    init_value();
    init_browsingContext2();
    init_strictSelectorError();
    init_describeSelector();
  }
});

// src/session/networkManager.ts
function getNetworkManager(browser) {
  return SessionManager.getSessionManager(browser, NetworkManager);
}
function isTrackedNavigationUrl(url2) {
  return SUPPORTED_NAVIGATION_PROTOCOLS.some((protocol) => url2.startsWith(protocol));
}
function headerListToObject(headers) {
  return headers.reduce((acc, { name, value }) => {
    acc[name] = value.value;
    return acc;
  }, {});
}
var UNKNOWN_NAVIGATION_ID, SUPPORTED_NAVIGATION_PROTOCOLS, NetworkManager;
var init_networkManager = __esm({
  "src/session/networkManager.ts"() {
    "use strict";
    init_session();
    UNKNOWN_NAVIGATION_ID = "UNKNOWN_NAVIGATION_ID";
    SUPPORTED_NAVIGATION_PROTOCOLS = ["http", "https", "data", "file"];
    NetworkManager = class _NetworkManager extends SessionManager {
      #browser;
      #initialize;
      #requests = /* @__PURE__ */ new Map();
      #lastNetworkId;
      #lastNavigationByContext = /* @__PURE__ */ new Map();
      #navigationStartedListener = this.#navigationStarted.bind(this);
      #responseCompletedListener = this.#responseCompleted.bind(this);
      #beforeRequestSentListener = this.#beforeRequestSent.bind(this);
      #fetchErrorListener = this.#fetchError.bind(this);
      constructor(browser) {
        super(browser, _NetworkManager.name);
        this.#browser = browser;
        if (!this.isEnabled()) {
          this.#initialize = Promise.resolve(true);
          return;
        }
        this.#initialize = this.#browser.sessionSubscribe({
          events: [
            "browsingContext.navigationStarted",
            "browsingContext.fragmentNavigated",
            "network.responseCompleted",
            "network.beforeRequestSent",
            "network.fetchError"
          ]
        }).then(() => true, () => false);
        this.#browser.on("browsingContext.navigationStarted", this.#navigationStartedListener);
        this.#browser.on("browsingContext.fragmentNavigated", this.#navigationStartedListener);
        this.#browser.on("network.responseCompleted", this.#responseCompletedListener);
        this.#browser.on("network.beforeRequestSent", this.#beforeRequestSentListener);
        this.#browser.on("network.fetchError", this.#fetchErrorListener);
      }
      removeListeners() {
        super.removeListeners();
        this.#browser.off("browsingContext.navigationStarted", this.#navigationStartedListener);
        this.#browser.off("browsingContext.fragmentNavigated", this.#navigationStartedListener);
        this.#browser.off("network.responseCompleted", this.#responseCompletedListener);
        this.#browser.off("network.beforeRequestSent", this.#beforeRequestSentListener);
        this.#browser.off("network.fetchError", this.#fetchErrorListener);
      }
      async initialize() {
        return this.#initialize;
      }
      #beforeRequestSent(log29) {
        if (log29.navigation) {
          return;
        }
        const request = this.#findRootRequest(log29.navigation, log29.context);
        if (!request) {
          return;
        }
        const { request: id, headers, cookies, url: url2 } = log29.request;
        request.children?.push({
          id,
          url: url2,
          headers: headerListToObject(headers),
          cookies: cookies.map((cookie) => ({
            name: cookie.name,
            value: cookie.value.type === "string" ? cookie.value.value : atob(cookie.value.value),
            domain: cookie.domain,
            path: cookie.path,
            size: cookie.size,
            httpOnly: cookie.httpOnly,
            secure: cookie.secure,
            sameSite: cookie.sameSite,
            expiry: cookie.expiry
          })),
          timestamp: log29.timestamp
        });
      }
      #navigationStarted(log29) {
        if (
          /**
           * we need a navigation id to identify the request
           */
          !log29.navigation || /**
           * ignore urls that users wouldn't navigate to
           */
          !isTrackedNavigationUrl(log29.url)
        ) {
          if (log29.navigation === null && log29.url === "") {
            this.#lastNetworkId = UNKNOWN_NAVIGATION_ID;
            return this.#requests.set(UNKNOWN_NAVIGATION_ID, {
              url: "",
              headers: {},
              timestamp: log29.timestamp,
              redirectChain: [],
              children: []
            });
          }
          return;
        }
        this.#lastNetworkId = log29.navigation;
        this.#lastNavigationByContext.set(log29.context, log29.navigation);
        this.#requests.set(log29.navigation, {
          url: log29.url,
          headers: {},
          timestamp: log29.timestamp,
          navigation: log29.navigation,
          redirectChain: [],
          children: []
        });
      }
      #fetchError(log29) {
        const response = this.#findRootRequest(log29.navigation, log29.context);
        if (!response) {
          return;
        }
        const request = response.children?.find((child) => child.id === log29.request.request);
        if (!request) {
          return;
        }
        request.error = log29.errorText;
      }
      #findRootRequest(navigationId, context) {
        const response = this.#requests.get(navigationId || UNKNOWN_NAVIGATION_ID);
        if (response) {
          return response;
        }
        const contextNavigation = context ? this.#lastNavigationByContext.get(context) : void 0;
        const contextRequest = contextNavigation ? this.#requests.get(contextNavigation) : void 0;
        if (contextRequest) {
          return contextRequest;
        }
        const firstRequest = this.#requests.values().next().value;
        return this.#lastNetworkId ? this.#requests.get(this.#lastNetworkId) || firstRequest : firstRequest;
      }
      #responseCompleted(log29) {
        const response = this.#findRootRequest(log29.navigation, log29.context);
        if (!response) {
          return;
        }
        if (!response.navigation && response.url === "") {
          response.url = log29.request.url;
          response.navigation = log29.navigation;
        }
        if (log29.navigation === response.navigation) {
          if (response.url !== log29.response.url) {
            response.redirectChain?.push(response.url);
          }
          response.url = log29.response.url;
          const { headers: requestHeaders } = log29.request;
          const { fromCache, headers: responseHeaders, mimeType, status } = log29.response;
          response.headers = headerListToObject(requestHeaders), response.response = {
            fromCache,
            headers: headerListToObject(responseHeaders),
            mimeType,
            status
          };
          return;
        }
        const request = response.children?.find((child) => child.id === log29.request.request);
        if (!request) {
          return;
        }
        request.response = {
          fromCache: log29.response.fromCache,
          headers: headerListToObject(log29.response.headers),
          mimeType: log29.response.mimeType,
          status: log29.response.status
        };
        response.children?.push(request);
      }
      getRequestResponseData(navigationId) {
        return this.#requests.get(navigationId);
      }
      /**
       * Returns the number of requests that are currently pending.
       * @param context browsing context id
       * @returns the number of requests that are currently pending
       */
      getPendingRequests(navigationId) {
        const request = this.#requests.get(navigationId);
        if (!request) {
          throw new Error(`Couldn't find request for navigation with id ${navigationId}`);
        }
        const subRequests = request.children || [];
        return subRequests.filter((child) => (
          /**
           * either the request has no response yet
           */
          !child.response && /**
           * and there was no request error
           */
          !child.error
        ));
      }
    };
  }
});

// src/commands/browser/navigateInContext.ts
import { setWdioKind as setWdioKind2 } from "@wdio/utils";
async function navigateInContext(browser, context, path9, options = {}) {
  let resetPreloadScript;
  if (options.onBeforeLoad) {
    if (typeof options.onBeforeLoad !== "function") {
      throw new Error(`Option "onBeforeLoad" must be a function, but received: ${typeof options.onBeforeLoad}`);
    }
    const target = contextIdValue(context);
    const current = contextIdValue(await getContextManager(browser).getCurrentContext());
    const fn = options.onBeforeLoad;
    if (target === current) {
      resetPreloadScript = await browser.addInitScript(fn);
    } else {
      const register = addInitScript;
      resetPreloadScript = await register.call(setWdioKind2({
        contextId: target,
        browser,
        isFrame: false
      }, "browsing-context"), fn);
    }
  }
  if (options.auth) {
    options.headers = {
      ...options.headers || {},
      Authorization: `Basic ${btoa(`${options.auth.user}:${options.auth.pass}`)}`
    };
  }
  let navigationError;
  let request = void 0;
  try {
    let mock2;
    if (options.headers) {
      mock2 = await browser.mock(path9);
      mock2.requestOnce({ headers: options.headers });
    }
    const classicPageLoadStrategy = browser.capabilities.pageLoadStrategy === "none" ? "none" : browser.capabilities.pageLoadStrategy === "normal" ? "complete" : browser.capabilities.pageLoadStrategy === "eager" ? "interactive" : void 0;
    const wait = options.wait === "networkIdle" ? "complete" : options.wait || classicPageLoadStrategy || DEFAULT_WAIT_STATE;
    const navigation = await browser.browsingContextNavigate({
      context,
      url: path9,
      wait
    }).catch(async (err) => {
      const isNavigationRace = err.message.includes("navigation canceled by concurrent navigation") || err.message.includes("failed with error: unknown error") || err.message.includes("no such frame");
      if (!isNavigationRace) {
        throw err;
      }
      if (getParallelContextStore().getStore()) {
        if (CONTEXT_GONE_MARKERS.some((marker) => err.message.includes(marker))) {
          throw err;
        }
        return browser.browsingContextNavigate({ context, url: path9, wait });
      }
      const current = contextIdValue(await getContextManager(browser).getCurrentContext());
      if (contextIdValue(context) === current) {
        return browser.navigateTo(validateUrl(path9));
      }
      throw err;
    });
    if (mock2) {
      await mock2.restore();
    }
    const navigationId = navigation?.navigation;
    if (!navigationId) {
      return void 0;
    }
    const network = getNetworkManager(browser);
    if (options.wait === "networkIdle" && isTrackedNavigationUrl(path9)) {
      const timeout = options.timeout || DEFAULT_NETWORK_IDLE_TIMEOUT;
      await browser.waitUntil(async () => {
        return network.getPendingRequests(navigationId).length === 0;
      }, {
        timeout,
        timeoutMsg: () => {
          const pendingRequests = network.getPendingRequests(navigationId);
          return `Navigation to '${path9}' timed out after ${timeout}ms with ${pendingRequests.length} (${pendingRequests.map((r) => r.url).join(", ")}) pending requests`;
        }
      });
    }
    if (path9.startsWith("http")) {
      request = await browser.waitUntil(
        () => network.getRequestResponseData(navigationId),
        {
          interval: 1,
          timeoutMsg: `Navigation to '${path9}' timed out as no request payload was received`
        }
      );
    }
  } catch (err) {
    navigationError = err;
  } finally {
    if (resetPreloadScript) {
      try {
        await resetPreloadScript.remove();
      } catch (cleanupError) {
        if (!navigationError) {
          navigationError = cleanupError;
        }
      }
    }
  }
  if (navigationError) {
    throw navigationError;
  }
  return request;
}
var DEFAULT_NETWORK_IDLE_TIMEOUT, DEFAULT_WAIT_STATE, CONTEXT_GONE_MARKERS;
var init_navigateInContext = __esm({
  "src/commands/browser/navigateInContext.ts"() {
    "use strict";
    init_utils2();
    init_networkManager();
    init_context();
    init_browsingContext();
    init_addInitScript();
    DEFAULT_NETWORK_IDLE_TIMEOUT = 5e3;
    DEFAULT_WAIT_STATE = "complete";
    CONTEXT_GONE_MARKERS = ["context disposal", "no such frame"];
  }
});

// src/commands/browsingContext/navigate.ts
async function navigate(path9, options = {}) {
  if (typeof path9 !== "string") {
    throw new Error('Parameter for "navigate" command needs to be type of string');
  }
  const browser = this.browser;
  if (typeof browser.options.baseUrl === "string" && browser.options.baseUrl) {
    path9 = new URL(path9, browser.options.baseUrl).href;
  }
  const request = await navigateInContext(browser, this.contextId, path9, options);
  this.url = path9;
  if (request) {
    this.request = request;
  }
  return this;
}
var init_navigate = __esm({
  "src/commands/browsingContext/navigate.ts"() {
    "use strict";
    init_navigateInContext();
  }
});

// src/commands/browsingContext/refresh.ts
async function refresh() {
  if (this.isFrame) {
    return reloadFrame(this);
  }
  await this.browser.browsingContextReload({
    context: this.contextId,
    wait: "complete"
  });
}
async function reloadFrame(frame2) {
  const token = await frame2.execute(() => {
    const marker = Math.random().toString(36).slice(2);
    window.__wdioReload = marker;
    const channel = new MessageChannel();
    channel.port1.onmessage = () => location.reload();
    channel.port2.postMessage(null);
    return marker;
  });
  const capabilities = frame2.browser.capabilities;
  await frame2.waitUntil(async () => {
    const state = await frame2.execute(() => ({
      marker: window.__wdioReload,
      ready: document.readyState
    })).catch(() => void 0);
    return Boolean(state && state.marker !== token && state.ready === "complete");
  }, {
    timeout: capabilities.timeouts?.pageLoad ?? 3e5,
    interval: 50,
    timeoutMsg: "The frame did not finish reloading"
  });
}
var init_refresh = __esm({
  "src/commands/browsingContext/refresh.ts"() {
    "use strict";
  }
});

// src/commands/browsingContext/closeWindow.ts
async function closeWindow() {
  assertTopLevel(this, "closeWindow");
  await this.browser.browsingContextClose({ context: this.contextId });
}
var init_closeWindow = __esm({
  "src/commands/browsingContext/closeWindow.ts"() {
    "use strict";
    init_browsingContext();
  }
});

// src/commands/browsingContext/activate.ts
async function activate() {
  assertTopLevel(this, "activate");
  await this.browser.browsingContextActivate({ context: this.contextId });
}
var init_activate = __esm({
  "src/commands/browsingContext/activate.ts"() {
    "use strict";
    init_browsingContext();
  }
});

// src/commands/browsingContext/back.ts
async function back2() {
  assertTopLevel(this, "back");
  await traverseTopLevelHistory(this.browser, -1, this.contextId);
}
var init_back2 = __esm({
  "src/commands/browsingContext/back.ts"() {
    "use strict";
    init_browsingContext();
    init_traverseHistory();
  }
});

// src/commands/browsingContext/forward.ts
async function forward2() {
  assertTopLevel(this, "forward");
  await traverseTopLevelHistory(this.browser, 1, this.contextId);
}
var init_forward2 = __esm({
  "src/commands/browsingContext/forward.ts"() {
    "use strict";
    init_browsingContext();
    init_traverseHistory();
  }
});

// src/commands/browsingContext/getTitle.ts
async function getTitle() {
  return this.execute(() => document.title);
}
var init_getTitle = __esm({
  "src/commands/browsingContext/getTitle.ts"() {
    "use strict";
  }
});

// src/commands/browsingContext/getUrl.ts
async function getUrl() {
  const url2 = await this.execute(() => document.URL);
  if (typeof url2 === "string") {
    this.url = url2;
  }
  return url2;
}
var init_getUrl = __esm({
  "src/commands/browsingContext/getUrl.ts"() {
    "use strict";
  }
});

// src/session/dialog.ts
function getDialogManager(browser) {
  return SessionManager.getSessionManager(browser, DialogManager);
}
var DialogManager, Dialog;
var init_dialog = __esm({
  "src/session/dialog.ts"() {
    "use strict";
    init_session();
    DialogManager = class _DialogManager extends SessionManager {
      #browser;
      #initialize;
      #autoHandleDialog = true;
      #prompts = /* @__PURE__ */ new Map();
      #handleUserPromptListener = this.#handleUserPrompt.bind(this);
      constructor(browser) {
        super(browser, _DialogManager.name);
        this.#browser = browser;
        if (!this.isEnabled()) {
          this.#initialize = Promise.resolve(true);
          return;
        }
        this.#initialize = this.#browser.sessionSubscribe({
          events: ["browsingContext.userPromptOpened"]
        }).then(() => true, () => false);
        this.#browser.on("_dialogListenerRegistered", () => this.#switchListenerFlag(false));
        this.#browser.on("_dialogListenerRemoved", () => this.#switchListenerFlag(true));
        this.#browser.on("browsingContext.userPromptOpened", this.#handleUserPromptListener);
      }
      removeListeners() {
        super.removeListeners();
        this.#browser.off("browsingContext.userPromptOpened", this.#handleUserPromptListener);
        this.#browser.removeAllListeners("_dialogListenerRegistered");
        this.#browser.removeAllListeners("_dialogListenerRemoved");
      }
      async initialize() {
        return this.#initialize;
      }
      promptMessage(context) {
        return this.#prompts.get(context);
      }
      clearPrompt(context) {
        this.#prompts.delete(context);
      }
      /**
       * capture shadow root elements propagated through console.debug
       */
      async #handleUserPrompt(log29) {
        this.#prompts.set(log29.context, log29.message);
        if (this.#autoHandleDialog) {
          this.#prompts.delete(log29.context);
          try {
            return await this.#browser.browsingContextHandleUserPrompt({
              accept: false,
              context: log29.context
            });
          } catch (err) {
            if (err instanceof Error && (err.message.includes("no such alert") || err.message.includes("no such frame"))) {
              return;
            }
            throw err;
          }
        }
        const dialog = new Dialog(log29, this.#browser);
        this.#browser.emit("dialog", dialog);
      }
      /**
       * Is called when a new dialog listener is registered with the `dialog` name.
       * In these cases we set a flag to the `#listener` map to indicate that we
       * are listening to dialog events for this page in this context.
       */
      #switchListenerFlag(value) {
        this.#autoHandleDialog = value;
      }
    };
    Dialog = class {
      #browser;
      #context;
      #message;
      #defaultValue;
      #type;
      constructor(event, browser) {
        this.#message = event.message;
        this.#defaultValue = event.defaultValue;
        this.#type = event.type;
        this.#context = event.context;
        this.#browser = browser;
      }
      message() {
        return this.#message;
      }
      defaultValue() {
        return this.#defaultValue;
      }
      type() {
        return this.#type;
      }
      /**
       * Returns when the dialog has been accepted.
       *
       * @alias dialog.accept
       * @param {string=} promptText  A text to enter into prompt. Does not cause any effects if the dialog's type is not prompt.
       * @returns {Promise<void>}
       */
      async accept(userText) {
        await this.#handle({ accept: true, userText });
      }
      async dismiss() {
        await this.#handle({ accept: false });
      }
      /**
       * Answer the dialog in the context that opened it, which is not always
       * the session's current context (a held tab, for example). A dialog whose
       * context closed, or that another handler answered first, is done.
       */
      async #handle(params) {
        const browser = this.#browser;
        try {
          await browser.browsingContextHandleUserPrompt({
            context: this.#context,
            ...params
          });
        } catch (err) {
          if (err instanceof Error && (err.message.includes("no such alert") || err.message.includes("no such frame"))) {
            return;
          }
          throw err;
        } finally {
          getDialogManager(browser).clearPrompt(this.#context);
        }
      }
    };
  }
});

// src/commands/browsingContext/acceptAlert.ts
async function acceptAlert(userText) {
  await this.browser.browsingContextHandleUserPrompt({
    context: this.contextId,
    accept: true,
    ...userText !== void 0 ? { userText } : {}
  });
  getDialogManager(this.browser).clearPrompt(this.contextId);
}
var init_acceptAlert = __esm({
  "src/commands/browsingContext/acceptAlert.ts"() {
    "use strict";
    init_dialog();
  }
});

// src/commands/browsingContext/dismissAlert.ts
async function dismissAlert() {
  await this.browser.browsingContextHandleUserPrompt({
    context: this.contextId,
    accept: false
  });
  getDialogManager(this.browser).clearPrompt(this.contextId);
}
var init_dismissAlert = __esm({
  "src/commands/browsingContext/dismissAlert.ts"() {
    "use strict";
    init_dialog();
  }
});

// src/commands/browsingContext/getAlertText.ts
async function getAlertText() {
  const stored = getDialogManager(this.browser).promptMessage(this.contextId);
  if (stored !== void 0) {
    return stored;
  }
  return this.browser.getAlertText();
}
var init_getAlertText = __esm({
  "src/commands/browsingContext/getAlertText.ts"() {
    "use strict";
    init_dialog();
  }
});

// src/browsingContext.ts
import { resolveCustomCommandOptions, setWdioKind as setWdioKind3, webdriverMonad, wrapCommand } from "@wdio/utils";
function onBrowser(command, fn) {
  return async function(...args) {
    assertTopLevel(this, command);
    return fn.apply(this.browser, args);
  };
}
function topLevel(command, fn) {
  return async function(...args) {
    assertTopLevel(this, command);
    return fn.apply(this, args);
  };
}
function rejectCommand(name) {
  return function() {
    return Promise.reject(new Error(
      `\`${name}\` is only available on the browser, not on a browsing context. Use \`browser.${name}(name, fn, { attachToBrowsingContext: true })\` to change the commands of every browsing context.`
    ));
  };
}
function assertCommandName(command, name) {
  const reason = FORBIDDEN_COMMAND_NAMES.get(name);
  if (reason) {
    throw new Error(`${command}: a browsing context command cannot be named "${name}": ${reason}.`);
  }
}
function getRegistry(browser) {
  let registry = registries.get(browser);
  if (!registry) {
    const contexts = /* @__PURE__ */ new Set();
    registry = {
      commands: /* @__PURE__ */ new Map(),
      overrides: /* @__PURE__ */ new Map(),
      contexts,
      finalizer: new FinalizationRegistry((ref2) => contexts.delete(ref2))
    };
    registries.set(browser, registry);
  }
  return registry;
}
function composeOverrides(base, overrides2 = []) {
  return overrides2.reduce((previous, override) => {
    return function(...args) {
      const context = this;
      function originalCommand(...originalArgs) {
        return previous.apply(this || context, originalArgs);
      }
      return override.call(context, originalCommand, ...args);
    };
  }, base);
}
function resolveCommand(registry, name) {
  const base = registry.commands.get(name) || commandProperties()[name]?.value;
  if (typeof base !== "function") {
    return void 0;
  }
  return composeOverrides(base, registry.overrides.get(name));
}
function liveContexts(registry) {
  const contexts = [];
  for (const ref2 of registry.contexts) {
    const context = ref2.deref();
    if (context) {
      contexts.push(context);
    } else {
      registry.contexts.delete(ref2);
    }
  }
  return contexts;
}
function applyToLiveContexts(registry, name) {
  const command = resolveCommand(registry, name);
  if (!command) {
    return;
  }
  for (const context of liveContexts(registry)) {
    Object.defineProperty(context, name, {
      value: wrapCommand(name, command),
      configurable: true,
      writable: true
    });
  }
}
function addBrowsingContextCommand(browser, name, fn) {
  if (typeof fn !== "function") {
    throw new Error(`addCommand: the browsing context command "${name}" must be a function`);
  }
  assertCommandName("addCommand", name);
  if (RESERVED_PROPERTIES.has(name) || name in commandProperties()) {
    throw new Error(
      `addCommand: "${name}" is already a property of every browsing context. Use \`overwriteCommand(name, fn, { attachToBrowsingContext: true })\` to change a built-in command.`
    );
  }
  const registry = getRegistry(browser);
  registry.commands.set(name, fn);
  applyToLiveContexts(registry, name);
}
function overwriteBrowsingContextCommand(browser, name, fn) {
  if (typeof fn !== "function") {
    throw new Error(`overwriteCommand: the browsing context command "${name}" must be overwritten with a function`);
  }
  assertCommandName("overwriteCommand", name);
  const registry = getRegistry(browser);
  if (!registry.commands.has(name) && typeof commandProperties()[name]?.value !== "function") {
    throw new Error(`overwriteCommand: no browsing context command to be overwritten: ${name}`);
  }
  registry.overrides.set(name, [...registry.overrides.get(name) || [], fn]);
  applyToLiveContexts(registry, name);
}
function enableBrowsingContextCommands(browser) {
  const addCommand = browser.addCommand;
  const overwriteCommand = browser.overwriteCommand;
  browser.addCommand = function(name, fn, options) {
    const resolved = resolveCustomCommandOptions("addCommand", options);
    if (resolved.attachToBrowsingContext) {
      return addBrowsingContextCommand(browser, name, fn);
    }
    return addCommand.call(this || browser, name, fn, resolved);
  };
  browser.overwriteCommand = function(name, fn, options) {
    const resolved = resolveCustomCommandOptions("overwriteCommand", options);
    if (resolved.attachToBrowsingContext) {
      return overwriteBrowsingContextCommand(browser, name, fn);
    }
    return overwriteCommand.call(this || browser, name, fn, resolved);
  };
}
function commandProperties() {
  const commands = {
    $,
    $$,
    custom$,
    custom$$,
    react$,
    react$$,
    execute,
    action,
    actions,
    keys,
    scroll,
    saveScreenshot: saveScreenshot2,
    savePDF: savePDF2,
    getCookies,
    setCookies,
    deleteCookies,
    setViewport,
    addInitScript,
    mock,
    mockClearAll: topLevel("mockClearAll", mockClearAll),
    mockRestoreAll: topLevel("mockRestoreAll", mockRestoreAll),
    waitUntil,
    pause,
    frame,
    navigate,
    refresh,
    closeWindow,
    activate,
    back: back2,
    forward: forward2,
    getTitle,
    getUrl,
    acceptAlert,
    dismissAlert,
    getAlertText,
    emulate: topLevel("emulate", emulate),
    restore: onBrowser("restore", restore)
  };
  const properties = {
    strategies: { value: null, writable: true }
  };
  for (const [name, value] of Object.entries(commands)) {
    properties[name] = { value, configurable: true };
  }
  return properties;
}
function getBrowsingContext(browser, contextId, init) {
  const registry = getRegistry(browser);
  const monad = webdriverMonad({
    ...browser.options,
    capabilities: browser.capabilities
  }, (client) => {
    client.contextId = contextId;
    client.browser = browser;
    client.isFrame = init.isFrame;
    client.url = init.url;
    if (init.parent) {
      client.parent = init.parent;
    }
    if (init.request) {
      client.request = init.request;
    }
    client.capabilities = browser.capabilities;
    client.strategies = browser.strategies;
    const target = client;
    const source = browser;
    for (const flag of SESSION_FLAGS) {
      if (flag in browser) {
        target[flag] = source[flag];
      }
    }
    client.on = browser.on.bind(browser);
    client.off = browser.off.bind(browser);
    client.once = browser.once.bind(browser);
    client.emit = browser.emit.bind(browser);
    client.removeListener = browser.removeListener.bind(browser);
    client.removeAllListeners = browser.removeAllListeners.bind(browser);
    return setWdioKind3(client, "browsing-context");
  }, contextProperties(registry));
  const context = monad(browser.sessionId, wrapCommand);
  context.addCommand = rejectCommand("addCommand");
  context.overwriteCommand = rejectCommand("overwriteCommand");
  const ref2 = new WeakRef(context);
  registry.contexts.add(ref2);
  registry.finalizer.register(context, ref2);
  return context;
}
function contextProperties(registry) {
  const properties = commandProperties();
  for (const [name, fn] of registry.commands) {
    properties[name] = { value: fn, configurable: true };
  }
  for (const [name, overrides2] of registry.overrides) {
    const base = properties[name]?.value;
    if (typeof base === "function") {
      properties[name] = { value: composeOverrides(base, overrides2), configurable: true };
    }
  }
  return properties;
}
var SESSION_FLAGS, RESERVED_PROPERTIES, FORBIDDEN_COMMAND_NAMES, registries;
var init_browsingContext2 = __esm({
  "src/browsingContext.ts"() {
    "use strict";
    init__2();
    init__();
    init_custom2();
    init_custom();
    init_react();
    init_react2();
    init_execute();
    init_action();
    init_actions2();
    init_keys();
    init_scroll();
    init_saveScreenshot();
    init_savePDF();
    init_getCookies();
    init_setCookies();
    init_deleteCookies();
    init_setViewport();
    init_addInitScript();
    init_mock();
    init_mockClearAll();
    init_mockRestoreAll();
    init_emulate();
    init_restore();
    init_waitUntil();
    init_pause();
    init_frame();
    init_navigate();
    init_refresh();
    init_closeWindow();
    init_activate();
    init_back2();
    init_forward2();
    init_getTitle();
    init_getUrl();
    init_acceptAlert();
    init_dismissAlert();
    init_getAlertText();
    init_browsingContext();
    SESSION_FLAGS = [
      "isBidi",
      "isMobile",
      "isIOS",
      "isAndroid",
      "isFirefox",
      "isChrome",
      "isSafari"
    ];
    RESERVED_PROPERTIES = /* @__PURE__ */ new Set([
      "contextId",
      "browser",
      "isFrame",
      "url",
      "parent",
      "request",
      "capabilities",
      "strategies",
      "sessionId",
      "options",
      "commandList",
      "addCommand",
      "overwriteCommand",
      "on",
      "off",
      "once",
      "emit",
      "removeListener",
      "removeAllListeners",
      ...SESSION_FLAGS
    ]);
    FORBIDDEN_COMMAND_NAMES = /* @__PURE__ */ new Map([
      ["then", "it would make every browsing context a thenable, and awaiting a command that returns a context would call it"],
      ["catch", "it would make every browsing context look like a promise"],
      ["finally", "it would make every browsing context look like a promise"],
      ["__propertiesObject__", "WebdriverIO uses it internally"],
      ["__elementOverrides__", "WebdriverIO uses it internally"],
      ["constructor", "it is an object internal"],
      ["__proto__", "it is an object internal"]
    ]);
    registries = /* @__PURE__ */ new WeakMap();
  }
});

// src/commands/browser/newWindow.ts
import { sleep } from "@wdio/utils";
import newWindowHelper from "./scripts/newWindow.js";
async function newWindow(url2, options = {}) {
  if (typeof url2 !== "string") {
    throw new Error("number or type of arguments don't agree with newWindow command");
  }
  const legacyOptions = options;
  if (legacyOptions.windowName || legacyOptions.windowFeatures || legacyOptions.windowFeature) {
    throw new Error(
      "The `windowName` and `windowFeatures` options were removed from `newWindow` in WebdriverIO v10. Only `{ type: 'tab' | 'window' }` is supported."
    );
  }
  const { type = "window" } = options;
  if (!["tab", "window"].includes(type)) {
    throw new Error(`Invalid type '${type}' provided to newWindow command. Use either 'tab' or 'window'`);
  }
  if (this.isMobile) {
    throw new Error("newWindow command is not supported on mobile platforms");
  }
  const tabsBefore = await this.getWindowHandles();
  if (this.isBidi) {
    const reference = options.referenceContext;
    if (reference && typeof reference !== "string" && reference.isFrame) {
      throw new Error("`referenceContext` must be a top-level browsing context");
    }
    const referenceContext = typeof reference === "string" ? reference : reference?.contextId;
    const { context } = await this.browsingContextCreate({
      type,
      ...referenceContext ? { referenceContext } : {}
    });
    await this.browsingContextNavigate({ context, url: url2, wait: historyReadiness(this.capabilities.pageLoadStrategy) });
    return getBrowsingContext(this, context, { isFrame: false, url: url2 });
  }
  await this.execute(newWindowHelper, url2);
  let tabsAfter = await this.getWindowHandles();
  const now = Date.now();
  while (Date.now() - now < WAIT_FOR_NEW_HANDLE_TIMEOUT) {
    tabsAfter = await this.getWindowHandles();
    if (tabsAfter.length > tabsBefore.length) {
      break;
    }
    await sleep(100);
  }
  const newTab = tabsAfter.pop();
  if (!newTab) {
    throw new Error("No window handle was found to switch to");
  }
  await this.switchToWindow(newTab);
  return { handle: newTab, type };
}
var WAIT_FOR_NEW_HANDLE_TIMEOUT;
var init_newWindow = __esm({
  "src/commands/browser/newWindow.ts"() {
    "use strict";
    init_browsingContext2();
    init_traverseHistory();
    WAIT_FOR_NEW_HANDLE_TIMEOUT = 3e3;
  }
});

// src/commands/browser/browsingContexts.ts
async function browsingContexts() {
  if (!this.isBidi) {
    throw new Error("`browsingContexts` is only available in a WebDriver BiDi session");
  }
  const { contexts } = await this.browsingContextGetTree({});
  return contexts.map((info) => getBrowsingContext(this, contextIdValue(info.context), {
    isFrame: false,
    url: info.url
  }));
}
var init_browsingContexts = __esm({
  "src/commands/browser/browsingContexts.ts"() {
    "use strict";
    init_browsingContext();
    init_browsingContext2();
  }
});

// src/session/polyfill.ts
import logger15 from "@wdio/logger";
import { polyfillFn as polyfillFn2 } from "./scripts/polyfill.js";
function getPolyfillManager(browser) {
  return SessionManager.getSessionManager(browser, PolyfillManager);
}
var log15, PolyfillManager;
var init_polyfill = __esm({
  "src/session/polyfill.ts"() {
    "use strict";
    init_session();
    init_utils2();
    log15 = logger15("webdriverio:PolyfillManager");
    PolyfillManager = class _PolyfillManager extends SessionManager {
      #initialize;
      #browser;
      #scriptsRegisteredInContexts = /* @__PURE__ */ new Set();
      #registerScriptsListener = this.#registerScripts.bind(this);
      constructor(browser) {
        super(browser, _PolyfillManager.name);
        this.#browser = browser;
        if (!this.isEnabled()) {
          this.#initialize = Promise.resolve(true);
          return;
        }
        this.#browser.on("browsingContext.contextCreated", this.#registerScriptsListener);
        this.#initialize = Promise.all([
          this.#browser.browsingContextGetTree({}).then(({ contexts }) => {
            return Promise.all(contexts.map((context) => this.#registerScripts(context)));
          }),
          this.#browser.sessionSubscribe({
            events: ["browsingContext.contextCreated"]
          })
        ]).then(() => true, () => false);
      }
      removeListeners() {
        super.removeListeners();
        this.#browser.off("browsingContext.contextCreated", this.#registerScriptsListener);
      }
      #registerScripts(context) {
        if (this.#scriptsRegisteredInContexts.has(context.context)) {
          return;
        }
        const functionDeclaration = createFunctionDeclarationFromString(polyfillFn2);
        log15.info(`Adding polyfill script to context with id ${context.context}`);
        this.#scriptsRegisteredInContexts.add(context.context);
        return Promise.all([
          !context.parent ? this.#browser.scriptAddPreloadScript({
            functionDeclaration,
            contexts: [context.context]
          }).catch(() => {
          }) : Promise.resolve(),
          this.#browser.scriptCallFunction({
            functionDeclaration,
            target: context,
            awaitPromise: false
          }).catch(() => {
          })
        ]);
      }
      async initialize() {
        return this.#initialize;
      }
    };
  }
});

// src/session/index.ts
function registerSessionManager(instance) {
  const initializationPromises = [
    getContextManager(instance).initialize()
  ];
  if (typeof instance.capabilities.webSocketUrl === "string") {
    trackScriptTimeout(instance);
    initializationPromises.push(
      getPolyfillManager(instance).initialize(),
      getShadowRootManager(instance).initialize(),
      getNetworkManager(instance).initialize(),
      getDialogManager(instance).initialize()
    );
  }
  return Promise.all(initializationPromises);
}
var init_session2 = __esm({
  "src/session/index.ts"() {
    "use strict";
    init_polyfill();
    init_shadowRoot();
    init_networkManager();
    init_dialog();
    init_context();
    init_scriptTimeout();
  }
});

// src/utils/bidi/browserOverwrites.ts
function applyBidiBrowserOverwrites(browser) {
  if (environment.value.variables.WDIO_UNIT_TESTS) {
    return;
  }
  if (isStub(browser.options?.automationProtocol)) {
    return;
  }
  if (!isBidiCommandsEnabled(browser) || overwrittenBrowsers.has(browser)) {
    return;
  }
  overwrittenBrowsers.add(browser);
  const overwrite = browser.overwriteCommand.bind(browser);
  overwrite("getTitle", async function(origCommand) {
    if (isBidiCommandsEnabled(this)) {
      const context = await getContextManager(this).getCurrentContext();
      const result = await this.scriptEvaluate({
        expression: "document.title",
        target: { context },
        awaitPromise: false
      });
      return result.result?.value || "";
    }
    return origCommand();
  });
  overwrite("getUrl", async function(origCommand) {
    if (isBidiCommandsEnabled(this)) {
      const context = await getContextManager(this).getCurrentContext();
      const tree = await this.browsingContextGetTree({ root: context });
      return tree.contexts[0]?.url || "";
    }
    return origCommand();
  });
  overwrite("getPageSource", async function(origCommand) {
    if (isBidiCommandsEnabled(this)) {
      const context = await getContextManager(this).getCurrentContext();
      const result = await this.scriptEvaluate({
        expression: "document.documentElement.outerHTML",
        target: { context },
        awaitPromise: false
      });
      return result.result?.value || "";
    }
    return origCommand();
  });
  overwrite("takeScreenshot", async function(origCommand) {
    if (isBidiCommandsEnabled(this)) {
      const context = await getContextManager(this).getCurrentTopLevelContext();
      const { data } = await this.browsingContextCaptureScreenshot({
        context,
        origin: "viewport",
        format: { type: "image/png" }
      });
      return data;
    }
    return origCommand();
  });
  overwrite("refresh", async function(origCommand) {
    if (isBidiCommandsEnabled(this)) {
      const context = await getContextManager(this).getCurrentTopLevelContext();
      await this.browsingContextReload({ context, wait: "complete" });
      return null;
    }
    return origCommand();
  });
  overwrite("takeElementScreenshot", async function(origCommand, elementId) {
    if (isBidiCommandsEnabled(this)) {
      const context = await getContextManager(this).getCurrentContext();
      const clip = { type: "element", element: { sharedId: elementId } };
      const { data } = await this.browsingContextCaptureScreenshot({ context, clip });
      return data;
    }
    return origCommand(elementId);
  });
}
var overwrittenBrowsers;
var init_browserOverwrites = __esm({
  "src/utils/bidi/browserOverwrites.ts"() {
    "use strict";
    init_utils2();
    init_context();
    init_environment();
    init_elementCommands();
    overwrittenBrowsers = /* @__PURE__ */ new WeakSet();
  }
});

// src/commands/browser/reloadSession.ts
import logger16 from "@wdio/logger";
async function reloadSession(newCapabilities) {
  const oldSessionId = this.sessionId;
  const shutdownDriver = Boolean(newCapabilities?.browserName);
  try {
    await this.deleteSession({ shutdownDriver });
  } catch (err) {
    log16.warn(`Suppressing error closing the session: ${err.stack}`);
  }
  if (this.puppeteer?.connected) {
    this.puppeteer.disconnect();
    log16.debug("Disconnected puppeteer session");
  }
  const ProtocolDriver = (await import(
    /* @vite-ignore */
    this.options.automationProtocol
  )).default;
  await ProtocolDriver.reloadSession(this, newCapabilities);
  await registerSessionManager(this);
  applyBidiBrowserOverwrites(this);
  const options = this.options;
  if (Array.isArray(options.onReload) && options.onReload.length) {
    await Promise.all(options.onReload.map((hook) => hook(oldSessionId, this.sessionId)));
  }
  return this.sessionId;
}
var log16;
var init_reloadSession = __esm({
  "src/commands/browser/reloadSession.ts"() {
    "use strict";
    init_session2();
    init_browserOverwrites();
    log16 = logger16("webdriverio");
  }
});

// src/commands/browser/saveRecordingScreen.ts
async function saveRecordingScreen2(filepath) {
  return environment.value.saveRecordingScreen.call(this, filepath);
}
var init_saveRecordingScreen = __esm({
  "src/commands/browser/saveRecordingScreen.ts"() {
    "use strict";
    init_environment();
  }
});

// src/commands/browser/setTimeout.ts
async function setTimeout2(timeouts) {
  if (typeof timeouts !== "object") {
    throw new Error('Parameter for "setTimeout" command needs to be an object');
  }
  if ("page load" in timeouts) {
    throw new Error("The `page load` timeout key was removed in WebdriverIO v10. Use `{ pageLoad: ... }`.");
  }
  const timeoutKeys = ["implicit", "pageLoad", "script"];
  const knownTimeoutValues = Object.entries(timeouts).filter(([key]) => timeoutKeys.includes(key)).map(([, timeout]) => timeout);
  const timeoutValues = knownTimeoutValues.length > 0 ? knownTimeoutValues : Object.values(timeouts);
  const definedTimeoutValues = timeoutValues.filter((timeout) => timeout !== void 0);
  if (definedTimeoutValues.some((timeout) => typeof timeout !== "number" || timeout < 0 || timeout > Number.MAX_SAFE_INTEGER) || timeoutValues.length > 0 && definedTimeoutValues.length === 0) {
    throw new Error("Specified timeout values are not valid integer (see https://webdriver.io/docs/api/browser/setTimeout for documentation).");
  }
  const implicit = timeouts.implicit;
  const pageLoad = timeouts.pageLoad;
  const script = timeouts.script;
  const setTimeouts = this.setTimeouts.bind(this);
  return setTimeouts(implicit, pageLoad, script);
}
var init_setTimeout = __esm({
  "src/commands/browser/setTimeout.ts"() {
    "use strict";
  }
});

// src/commands/browser/setWindowSize.ts
import { getBrowserObject as getBrowserObject17 } from "@wdio/utils";
async function setWindowSize(width, height) {
  if (typeof width !== "number" || typeof height !== "number") {
    throw new Error("setWindowSize expects width and height of type number");
  }
  if (width < minWindowSize2 || width > maxWindowSize2 || height < minWindowSize2 || height > maxWindowSize2) {
    throw new Error("setWindowSize expects width and height to be a number in the 0 to 2^31 \u2212 1 range");
  }
  assertNotInParallelScope("setWindowSize", WINDOW_REASON2);
  const browser = getBrowserObject17(this);
  await browser.setWindowRect(null, null, width, height);
}
var WINDOW_REASON2, minWindowSize2, maxWindowSize2;
var init_setWindowSize = __esm({
  "src/commands/browser/setWindowSize.ts"() {
    "use strict";
    init_parallelGuard();
    WINDOW_REASON2 = "parallel tests share one OS window, use setViewport to size a test's page";
    minWindowSize2 = 0;
    maxWindowSize2 = Number.MAX_SAFE_INTEGER;
  }
});

// src/commands/browser/switchWindow.ts
async function switchWindow(matcher) {
  if (this.isBidi) {
    throw new Error(
      "`switchWindow` was removed for WebDriver BiDi sessions in WebdriverIO v10. Hold the browsing context returned by `browser.url()` or `browser.newWindow()`, or find one with `browser.browsingContexts()`."
    );
  }
  if (typeof matcher !== "string" && !(matcher instanceof RegExp)) {
    throw new Error('Unsupported parameter for switchWindow, required is "string" or a RegExp');
  }
  const contextManager = getContextManager(this);
  const tabs = await this.getWindowHandles();
  if (typeof matcher === "string" && tabs.includes(matcher)) {
    if (matcher === contextManager.getCurrentWindowHandle()) {
      return matcher;
    }
    await this.switchToWindow(matcher);
    contextManager.setCurrentContext(matcher);
    return matcher;
  }
  const matchesTarget = (target) => {
    if (typeof matcher === "string") {
      return target.includes(matcher);
    }
    return matcher.test(target);
  };
  for (const tab of tabs) {
    await this.switchToWindow(tab);
    contextManager.setCurrentContext(tab);
    const url2 = await this.getUrl();
    if (matchesTarget(url2)) {
      return tab;
    }
    const title = await this.getTitle();
    if (matchesTarget(title)) {
      return tab;
    }
    const windowName = await this.execute(
      /* istanbul ignore next */
      () => window.name
    );
    if (windowName && matchesTarget(windowName)) {
      return tab;
    }
  }
  throw new Error(`No window found with title, url, name or window handle matching "${matcher}"`);
}
var init_switchWindow = __esm({
  "src/commands/browser/switchWindow.ts"() {
    "use strict";
    init_context();
  }
});

// src/commands/browser/switchFrame.ts
import { getWdioKind as getWdioKind3 } from "@wdio/utils";
async function switchFrame(context) {
  if (this.isBidi) {
    throw new Error(
      "`switchFrame` was removed for WebDriver BiDi sessions in WebdriverIO v10. Call `frame()` on the browsing context returned by `browser.url()` or `browser.newWindow()`."
    );
  }
  function isPossiblyUnresolvedElement(input) {
    return getWdioKind3(input) === "element";
  }
  if (typeof context === "function") {
    throw new Error("Cannot use a function to fetch a context in WebDriver Classic");
  }
  if (typeof context === "string") {
    throw new Error("Cannot use a string to fetch a context in WebDriver Classic");
  }
  if (isPossiblyUnresolvedElement(context)) {
    const element = await context.getElement();
    await element.waitForExist({
      timeoutMsg: `Can't switch to frame with selector ${describeSelector(element)} because it doesn't exist`
    });
    return switchToFrame(this, element);
  }
  return switchToFrame(this, context);
}
function switchToFrame(browser, frame2) {
  const classicBrowser = browser;
  toggleDisableDeprecationWarning();
  return classicBrowser.switchToFrame(frame2).finally(toggleDisableDeprecationWarning);
}
function toggleDisableDeprecationWarning() {
  if (typeof process !== "undefined" && process.env) {
    process.env.DISABLE_WEBDRIVERIO_DEPRECATION_WARNINGS = process.env.DISABLE_WEBDRIVERIO_DEPRECATION_WARNINGS ? void 0 : "true";
  }
}
var init_switchFrame = __esm({
  "src/commands/browser/switchFrame.ts"() {
    "use strict";
    init_describeSelector();
  }
});

// src/commands/browser/throttleCPU.ts
async function throttleCPU(factor) {
  if (typeof factor !== "number") {
    throw new Error('Invalid factor for "throttleCPU". Expected it to be a number (int)');
  }
  assertNotInParallelScope("throttleCPU", "it targets the whole browser");
  const failedConnectionMessage = "No Puppeteer connection could be established which is required to use this command";
  await this.getPuppeteer();
  if (!this.puppeteer) {
    throw new Error(failedConnectionMessage);
  }
  const pages = await this.puppeteer.pages();
  if (!pages.length) {
    throw new Error(failedConnectionMessage);
  }
  const client = await pages[0].target().createCDPSession();
  await client.send("Emulation.setCPUThrottlingRate", { rate: factor });
}
var init_throttleCPU = __esm({
  "src/commands/browser/throttleCPU.ts"() {
    "use strict";
    init_parallelGuard();
  }
});

// src/commands/browser/throttleNetwork.ts
import { getBrowserObject as getBrowserObject18 } from "@wdio/utils";
import logger17 from "@wdio/logger";
async function throttleNetwork(params) {
  if (
    /**
     * check string parameter
     */
    (typeof params !== "string" || !NETWORK_PRESET_TYPES.includes(params)) && /**
     * check object parameter
     */
    typeof params !== "object"
  ) {
    throw new Error(`Invalid parameter for "throttleNetwork". Expected it to be typeof object or one of the following values: ${NETWORK_PRESET_TYPES.join(", ")} but found "${params}"`);
  }
  assertNotInParallelScope("throttleNetwork", "it targets the whole browser");
  if (this.isSauce) {
    const browser = getBrowserObject18(this);
    await browser.sauceThrottleNetwork(params);
    return;
  }
  const failedConnectionMessage = "No Puppeteer connection could be established which is required to use this command";
  await this.getPuppeteer();
  if (!this.puppeteer) {
    throw new Error(failedConnectionMessage);
  }
  const pages = await this.puppeteer.pages();
  if (!pages.length) {
    throw new Error(failedConnectionMessage);
  }
  const conditions = typeof params === "string" ? NETWORK_PRESETS[params] : params;
  const client = await pages[0].target().createCDPSession();
  await client.send("Network.emulateNetworkConditions", conditions);
  const serviceWorkers = this.puppeteer.targets().filter((target) => target.type() === "service_worker");
  for (const serviceWorker of serviceWorkers) {
    try {
      const serviceWorkerClient = await serviceWorker.createCDPSession();
      await serviceWorkerClient.send("Network.enable");
      await serviceWorkerClient.send("Network.emulateNetworkConditions", conditions);
    } catch {
      log17.debug("Skipped network throttling for a service worker that terminated during attach");
    }
  }
  return;
}
var log17, NETWORK_PRESETS, NETWORK_PRESET_TYPES;
var init_throttleNetwork = __esm({
  "src/commands/browser/throttleNetwork.ts"() {
    "use strict";
    init_parallelGuard();
    log17 = logger17("webdriverio:throttleNetwork");
    NETWORK_PRESETS = {
      "offline": {
        offline: true,
        downloadThroughput: 0,
        uploadThroughput: 0,
        latency: 1
      },
      "GPRS": {
        offline: false,
        downloadThroughput: 50 * 1024 / 8,
        uploadThroughput: 20 * 1024 / 8,
        latency: 500
      },
      "Regular2G": {
        offline: false,
        downloadThroughput: 250 * 1024 / 8,
        uploadThroughput: 50 * 1024 / 8,
        latency: 300
      },
      "Good2G": {
        offline: false,
        downloadThroughput: 450 * 1024 / 8,
        uploadThroughput: 150 * 1024 / 8,
        latency: 150
      },
      "Regular3G": {
        offline: false,
        downloadThroughput: 750 * 1024 / 8,
        uploadThroughput: 250 * 1024 / 8,
        latency: 100
      },
      "Good3G": {
        offline: false,
        downloadThroughput: 1.5 * 1024 * 1024 / 8,
        uploadThroughput: 750 * 1024 / 8,
        latency: 40
      },
      "Regular4G": {
        offline: false,
        downloadThroughput: 4 * 1024 * 1024 / 8,
        uploadThroughput: 3 * 1024 * 1024 / 8,
        latency: 20
      },
      "DSL": {
        offline: false,
        downloadThroughput: 2 * 1024 * 1024 / 8,
        uploadThroughput: 1 * 1024 * 1024 / 8,
        latency: 5
      },
      "WiFi": {
        offline: false,
        downloadThroughput: 30 * 1024 * 1024 / 8,
        uploadThroughput: 15 * 1024 * 1024 / 8,
        latency: 2
      },
      "online": {
        offline: false,
        latency: 0,
        downloadThroughput: -1,
        uploadThroughput: -1
      }
    };
    NETWORK_PRESET_TYPES = Object.keys(NETWORK_PRESETS);
  }
});

// src/commands/browser/uninstallExtension.ts
async function uninstallExtension(extensionId) {
  if (!this.isBidi) {
    throw new Error("uninstallExtension requires a WebDriver BiDi session (webExtension.uninstall)");
  }
  if (typeof extensionId !== "string" || extensionId.length === 0) {
    throw new Error("uninstallExtension expects the extension id returned by installExtension");
  }
  try {
    await this.webExtensionUninstall({ extension: extensionId });
  } catch (err) {
    throw annotateWebExtensionError(err, "webExtension.uninstall");
  }
}
var init_uninstallExtension = __esm({
  "src/commands/browser/uninstallExtension.ts"() {
    "use strict";
    init_webExtension();
  }
});

// src/utils/classicContext.ts
function classicContext(browser, url2) {
  let currentUrl = url2;
  return new Proxy(browser, {
    get(target, prop) {
      if (prop === "url") {
        return currentUrl;
      }
      if (prop === "getUrl") {
        return async () => {
          currentUrl = await target.getUrl();
          return currentUrl;
        };
      }
      if (prop === "isFrame") {
        return false;
      }
      if (prop === "parent" || prop === "request" || prop === "contextId") {
        return void 0;
      }
      if (prop === "browser") {
        return target;
      }
      if (typeof prop === "string" && prop in BIDI_ONLY_COMMANDS) {
        return () => Promise.reject(new Error(
          `\`${prop}()\` needs a WebDriver BiDi session, but this session uses WebDriver Classic (for example Appium or Safari), where \`browser.url()\` returns the browser itself. ${BIDI_ONLY_COMMANDS[prop]}`
        ));
      }
      const value = Reflect.get(target, prop);
      return typeof value === "function" ? value.bind(target) : value;
    }
  });
}
var BIDI_ONLY_COMMANDS;
var init_classicContext = __esm({
  "src/utils/classicContext.ts"() {
    "use strict";
    BIDI_ONLY_COMMANDS = {
      frame: "Use `browser.switchFrame()` to run commands in a frame.",
      navigate: "Use `browser.url()` to navigate.",
      activate: "Use `browser.switchWindow()` to bring a window to the front."
    };
  }
});

// src/commands/browser/url.ts
async function url(path9, options = {}) {
  if (typeof path9 !== "string") {
    throw new Error('Parameter for "url" command needs to be type of string');
  }
  if (typeof this.options.baseUrl === "string" && this.options.baseUrl) {
    path9 = new URL(path9, this.options.baseUrl).href;
  }
  const isHttp = path9.startsWith("http");
  if (this.isBidi && (isHttp || getParallelContextStore().getStore())) {
    const context = await getContextManager(this).getCurrentContext();
    const request = await navigateInContext(this, context, isHttp ? path9 : validateUrl(path9), options);
    return getBrowsingContext(this, contextIdValue(context), {
      isFrame: false,
      url: path9,
      ...request ? { request } : {}
    });
  }
  if (Object.keys(options).length > 0) {
    throw new Error("Setting url options is only supported when automating browser using WebDriver Bidi protocol");
  }
  await this.navigateTo(validateUrl(path9));
  if (this.isBidi) {
    const context = await getContextManager(this).getCurrentContext();
    return getBrowsingContext(this, contextIdValue(context), { isFrame: false, url: path9 });
  }
  return classicContext(this, path9);
}
var init_url = __esm({
  "src/commands/browser/url.ts"() {
    "use strict";
    init_utils2();
    init_context();
    init_browsingContext();
    init_browsingContext2();
    init_navigateInContext();
    init_classicContext();
  }
});

// src/utils/interception/types.ts
var init_types = __esm({
  "src/utils/interception/types.ts"() {
    "use strict";
  }
});

// src/types.ts
var MobileScrollDirection;
var init_types2 = __esm({
  "src/types.ts"() {
    "use strict";
    init_types();
    init_actions();
    init_addInitScript();
    MobileScrollDirection = /* @__PURE__ */ ((MobileScrollDirection2) => {
      MobileScrollDirection2["Down"] = "down";
      MobileScrollDirection2["Up"] = "up";
      MobileScrollDirection2["Left"] = "left";
      MobileScrollDirection2["Right"] = "right";
      return MobileScrollDirection2;
    })(MobileScrollDirection || {});
  }
});

// src/commands/mobile/swipe.ts
import logger18 from "@wdio/logger";
async function swipe(options) {
  const browser = this;
  if (!browser.isNativeContext) {
    throw new Error("The swipe command is only available for mobile platforms in the NATIVE context.");
  }
  let { scrollableElement, from, to } = options || {};
  if (scrollableElement && (from || to)) {
    log18.warn("`scrollableElement` is provided, so `from` and `to` will be ignored.");
  }
  if (!from || !to) {
    scrollableElement = scrollableElement || await getScrollableElement(browser);
    ({ from, to } = await calculateFromTo({
      browser,
      direction: options?.direction || SWIPE_DEFAULTS.DIRECTION,
      percentage: options?.percent,
      scrollableElement
    }));
  }
  return w3cSwipe({ browser, duration: options?.duration || SWIPE_DEFAULTS.DURATION, from, to });
}
async function calculateFromTo({
  browser,
  direction,
  percentage,
  scrollableElement
}) {
  let swipePercentage = SWIPE_DEFAULTS.PERCENT;
  if (percentage !== void 0) {
    if (isNaN(percentage)) {
      log18.warn("The percentage to swipe should be a number.");
    } else if (percentage < 0 || percentage > 1) {
      log18.warn("The percentage to swipe should be a number between 0 and 1.");
    } else {
      swipePercentage = percentage;
    }
  }
  const { x, y, width, height } = await browser.getElementRect(await scrollableElement?.elementId);
  const verticalOffset = height - height * swipePercentage;
  const horizontalOffset = width - width * swipePercentage;
  const scrollRectangles = {
    top: { x: Math.round(x + width / 2), y: Math.round(y + verticalOffset / 2) },
    right: { x: Math.round(x + width - horizontalOffset / 2), y: Math.round(y + height / 2) },
    bottom: { x: Math.round(x + width / 2), y: Math.round(y + height - verticalOffset / 2) },
    left: { x: Math.round(x + horizontalOffset / 2), y: Math.round(y + height / 2) }
  };
  let from;
  let to;
  switch (direction) {
    case "down" /* Down */:
      from = scrollRectangles.top;
      to = scrollRectangles.bottom;
      break;
    case "left" /* Left */:
      from = scrollRectangles.right;
      to = scrollRectangles.left;
      break;
    case "right" /* Right */:
      from = scrollRectangles.left;
      to = scrollRectangles.right;
      break;
    case "up" /* Up */:
      from = scrollRectangles.bottom;
      to = scrollRectangles.top;
      break;
    default:
      throw new Error(`Unknown direction: ${direction}`);
  }
  return { from, to };
}
async function getScrollableElement(browser) {
  const defaultAndroidSelector = "//android.widget.ScrollView";
  const defaultIosSelector = '-ios predicate string:type == "XCUIElementTypeApplication"';
  const selector = browser.isIOS ? (
    // For iOS, we need to find the application element, if we can't find it, we should throw an error
    defaultIosSelector
  ) : (
    // There is always a scrollview for Android or, if this fails we should throw an error
    defaultAndroidSelector
  );
  const scrollableElements = await browser.$$(
    selector
  );
  if (scrollableElements.length > 0) {
    return scrollableElements[0];
  }
  throw new Error(
    `Default scrollable element '${browser.isIOS ? defaultIosSelector : defaultAndroidSelector}' was not found. Our advice is to provide a scrollable element like this:

await browser.swipe({ scrollableElement: $('#scrollable') });

        `
  );
}
async function w3cSwipe({ browser, duration, from, to }) {
  await browser.action("pointer", {
    parameters: { pointerType: browser.isMobile ? "touch" : "mouse" }
  }).move(from.x, from.y).down().pause(10).move({ duration, x: to.x, y: to.y }).up().perform();
  return browser.pause(500);
}
var log18, SWIPE_DEFAULTS;
var init_swipe = __esm({
  "src/commands/mobile/swipe.ts"() {
    "use strict";
    init_types2();
    log18 = logger18("webdriverio");
    SWIPE_DEFAULTS = {
      DIRECTION: "up" /* Up */,
      DURATION: 1500,
      PERCENT: 0.95
    };
  }
});

// src/commands/mobile/tap.ts
import logger19 from "@wdio/logger";
import { getBrowserObject as getBrowserObject19 } from "@wdio/utils";
async function tap(options) {
  const isElement2 = this.selector !== void 0;
  const element = isElement2 ? this : null;
  const browser = isElement2 ? getBrowserObject19(this) : this;
  if (!browser.isMobile) {
    throw new Error("The tap command is only available for mobile platforms.");
  }
  validateTapOptions(options);
  if (element) {
    return await elementTap(browser, element, options);
  }
  if (!options || options.x === void 0 || options.y === void 0) {
    throw new Error("The tap command requires x and y coordinates to be set for screen taps.");
  }
  return await screenTap(browser, options);
}
function validateTapOptions(options) {
  if (options) {
    if (typeof options !== "object" || Array.isArray(options)) {
      throw new TypeError("Options must be an object.");
    }
    const { x, y, ...otherArgs } = options;
    if (x === void 0 !== (y === void 0)) {
      throw new TypeError(`If ${x !== void 0 ? "x" : "y"} is set, then ${x !== void 0 ? "y" : "x"} must also be set.`);
    }
    if (x !== void 0 && y !== void 0 && Object.keys(otherArgs).length > 0) {
      throw new TypeError(`If x and y are provided, no other arguments are allowed. Found: ${Object.keys(otherArgs).join(", ")}`);
    }
    const invalidCoordinates = [];
    if (x !== void 0 && x < 0) {
      invalidCoordinates.push("x");
    }
    if (y !== void 0 && y < 0) {
      invalidCoordinates.push("y");
    }
    if (invalidCoordinates.length > 0) {
      throw new TypeError(`The ${invalidCoordinates.join(" and ")} value${invalidCoordinates.length > 1 ? "s" : ""} must be positive.`);
    }
  }
}
async function elementTap(browser, element, options) {
  if (browser.isNativeContext) {
    return await nativeTap(element, browser, options);
  }
  if (options) {
    log19.warn("The options object is not supported in Web environments and will be ignored.");
  }
  return await webTap(element);
}
async function webTap(element) {
  return element.click();
}
async function executeNativeTap(browser, options) {
  return await browser.execute(
    `mobile: ${browser.isIOS ? "tap" : "clickGesture"}`,
    { ...browser.isIOS ? { x: 0, y: 0 } : {}, ...options }
  );
}
async function nativeTap(element, browser, options = {}) {
  try {
    if (!element.elementId) {
      throw new Error("no such element");
    }
    return await executeNativeTap(browser, { elementId: element.elementId });
  } catch (error) {
    let err = error;
    if (typeof error === "string") {
      err = new Error(error);
    }
    if (!err.message.includes("no such element")) {
      throw err;
    }
    const scrollIntoViewOptions = Object.fromEntries(
      Object.entries({
        direction: options?.direction,
        maxScrolls: options?.maxScrolls,
        scrollableElement: options?.scrollableElement
      }).filter(([_, value]) => value !== void 0)
    );
    try {
      await element.scrollIntoView(scrollIntoViewOptions);
      return await executeNativeTap(browser, { elementId: element.elementId });
    } catch (scrollError) {
      let err2 = scrollError;
      if (typeof scrollError === "string") {
        err2 = new Error(scrollError);
      }
      if (err2.message.includes("Element not found within scroll limit of")) {
        throw new Error(`Element not found within the automatic 'tap' scroll limit of ${scrollIntoViewOptions?.maxScrolls || "10"} scrolls by scrolling "${scrollIntoViewOptions?.direction || "down"}". The 'tap' methods will automatically scroll if it can't find the element. It might be that 'direction|maxScrolls|scrollableElement' are not correct. You can change change them like this:

await elem.tap({
    direction: 'left' // possible options are: 'up|down|left|right'
    maxScrolls: 15,
    scrollableElement: $('#scrollable'),
});

                `);
      } else if (err2.message.includes("Default scrollable element")) {
        const match = err2.message.match(/Default scrollable element '(.*?)' was not found/);
        const scrollableElement = match?.[1] || "unknown-scrollable-element";
        throw new Error(`The 'tap' method tried to automatically scroll to the element but couldn't find the default scrollable element. '${scrollableElement}' If needed you can provide a custom scrollable element, together with the 'direction' and the 'maxScrolls' like this:

await elem.tap({
    scrollableElement: $('#scrollable'),
});

                `);
      }
      throw err2;
    }
  }
}
async function screenTap(browser, options) {
  const { x, y } = options;
  if (browser.isNativeContext) {
    return await executeNativeTap(browser, options);
  }
  return await browser.action(
    "pointer",
    {
      parameters: { pointerType: "touch" }
    }
  ).move({ x, y }).down({ button: 0 }).pause(10).up({ button: 0 }).perform();
}
var log19;
var init_tap = __esm({
  "src/commands/mobile/tap.ts"() {
    "use strict";
    log19 = logger19("webdriver");
  }
});

// src/commands/mobile/getContext.ts
import logger20 from "@wdio/logger";
async function getContext(options) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getContext` command is only available for mobile platforms.");
  }
  const currentAppiumContext = await browser.getAppiumContext();
  if (!options || !options?.returnDetailedContext || currentAppiumContext === "NATIVE_APP") {
    return currentAppiumContext;
  }
  delete options.returnDetailedContext;
  return getDetailedContext(browser, currentAppiumContext, options);
}
async function getDetailedContext(browser, currentAppiumContext, options) {
  const detailedContexts = await browser.getContexts({
    ...options,
    // Defaults
    returnDetailedContexts: true,
    // We want to get back the detailed context information
    isAndroidWebviewVisible: true,
    // We only want to get back the visible webviews
    filterByCurrentAndroidApp: true,
    // We only want to get back the webviews that are attached to the current app
    returnAndroidDescriptionData: false
    // We don't want to get back the Android Webview description data
  });
  const parsedContexts = detailedContexts.filter((context) => context.id === currentAppiumContext);
  if (parsedContexts.length > 1) {
    log20.warn(`We found more than 1 detailed context for the current context '${currentAppiumContext}'. We will return the first context.`);
    return parsedContexts[0];
  } else if (parsedContexts.length === 0) {
    log20.warn(`We did not get back any detailed context for the current context '${currentAppiumContext}'. We will return the current context as a string.`);
    return currentAppiumContext;
  }
  return parsedContexts[0];
}
var log20;
var init_getContext = __esm({
  "src/commands/mobile/getContext.ts"() {
    "use strict";
    log20 = logger20("webdriver");
  }
});

// src/commands/mobile/getContexts.ts
import logger21 from "@wdio/logger";
async function getContexts(options) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getContexts` command is only available for mobile platforms.");
  }
  if (!options || !options.returnDetailedContexts) {
    log21.info("The standard Appium `contexts` method is used. If you want to get more detailed data, you can set `returnDetailedContexts` to `true`.");
    return browser.getAppiumContexts();
  }
  const defaultOptions = {
    androidWebviewConnectionRetryTime: 500,
    androidWebviewConnectTimeout: 5e3,
    filterByCurrentAndroidApp: false,
    isAndroidWebviewVisible: true,
    returnAndroidDescriptionData: false
  };
  return getCurrentContexts({ browser, ...{ ...defaultOptions, ...options } });
}
async function parsedAndroidContexts({
  contexts,
  filterByCurrentAndroidApp,
  isAttachedAndVisible,
  packageName
}) {
  const currentWebviewName = `WEBVIEW_${packageName}`;
  let parsedContexts = contexts;
  if (filterByCurrentAndroidApp) {
    parsedContexts = contexts.filter((context) => context.webviewName === currentWebviewName);
  }
  const result = [{ id: "NATIVE_APP" }];
  if (!parsedContexts || parsedContexts.length < 1) {
    return result;
  }
  parsedContexts.forEach(
    (context) => context.pages?.filter((page) => {
      if (packageName === CHROME_PACKAGE_NAME) {
        return true;
      }
      if (page.type === "page" && page.description) {
        let descriptionObj;
        try {
          descriptionObj = JSON.parse(page.description);
        } catch (e) {
          return false;
        }
        return isAttachedAndVisible ? descriptionObj.attached === true && descriptionObj.visible === true : true;
      }
      return !isAttachedAndVisible;
    }).forEach((page) => {
      const {
        attached = false,
        empty = false,
        height = 0,
        never_attached: neverAttached = false,
        screenX = 0,
        screenY = 0,
        visible = false,
        width = 0
      } = JSON.parse(page.description || "{}");
      const pageData = {
        androidWebviewData: {
          attached,
          empty,
          height,
          neverAttached,
          screenX,
          screenY,
          visible,
          width
        },
        id: context.webviewName,
        title: page.title,
        url: page.url,
        packageName: context.info["Android-Package"],
        webviewPageId: page.id
      };
      result.push(pageData);
    })
  );
  return result;
}
async function getCurrentContexts({
  browser,
  androidWebviewConnectionRetryTime,
  androidWebviewConnectTimeout,
  filterByCurrentAndroidApp,
  isAndroidWebviewVisible,
  returnAndroidDescriptionData,
  waitForWebviewMs
}) {
  const contexts = await (waitForWebviewMs !== void 0 ? browser.execute("mobile: getContexts", { waitForWebviewMs }) : browser.execute("mobile: getContexts"));
  if (browser.isIOS) {
    return contexts;
  }
  const packageName = await browser.getCurrentPackage();
  const startTime = Date.now();
  const retryInterval = androidWebviewConnectionRetryTime;
  let isPackageNameMissing = false;
  while (Date.now() - startTime < androidWebviewConnectTimeout) {
    const parsedContexts = await parsedAndroidContexts({
      contexts,
      filterByCurrentAndroidApp,
      isAttachedAndVisible: isAndroidWebviewVisible,
      packageName
    });
    const matchingContexts = parsedContexts.filter((context) => context.packageName === packageName);
    isPackageNameMissing = matchingContexts.length === 0;
    const hasAndroidWebviewData = matchingContexts.some((context) => Boolean(context.androidWebviewData));
    const isAndroidWebviewDataMissing = matchingContexts.length > 0 && !hasAndroidWebviewData;
    const hasNonEmptyAndroidWebviewData = matchingContexts.some((context) => context.androidWebviewData && !context.androidWebviewData.empty);
    const isAndroidWebviewDataEmpty = matchingContexts.length > 0 && hasAndroidWebviewData && !hasNonEmptyAndroidWebviewData;
    if (packageName === CHROME_PACKAGE_NAME) {
      return parsedContexts;
    }
    if (!isPackageNameMissing && !isAndroidWebviewDataMissing && !isAndroidWebviewDataEmpty) {
      if (!returnAndroidDescriptionData) {
        parsedContexts.forEach((context) => {
          if ("androidWebviewData" in context) {
            delete context.androidWebviewData;
          }
        });
      }
      return parsedContexts;
    }
    await new Promise((resolve) => setTimeout(resolve, retryInterval));
  }
  throw new Error(
    `The packageName '${packageName}' ${isPackageNameMissing ? "could not be found!" : "matches, but no webview with pages was loaded in this response: " + JSON.stringify(contexts) + "'"}`
  );
}
var log21, CHROME_PACKAGE_NAME;
var init_getContexts = __esm({
  "src/commands/mobile/getContexts.ts"() {
    "use strict";
    log21 = logger21("webdriver");
    CHROME_PACKAGE_NAME = "com.android.chrome";
  }
});

// src/commands/mobile/switchContext.ts
import logger22 from "@wdio/logger";
async function switchContext(options) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `switchContext` command is only available for mobile platforms.");
  }
  if (!options) {
    throw new Error("You need to provide at least a context name to switch to. See https://webdriver.io/docs/api/mobile/switchContext for more information.");
  }
  if (typeof options === "string") {
    log22.info("The standard Appium `context`-method is used. If you want to switch to a webview with a specific title or url, please provide an object with the `title` or `url` property. See https://webdriver.io/docs/api/mobile/switchContext for more information.");
    return browser.switchAppiumContext(options);
  }
  if (!options.title && !options.url) {
    throw new Error("You need to provide at least a `title` or `url` property to use full potential of the `switchContext` command. See https://webdriver.io/docs/api/mobile/switchContext for more information.");
  }
  return switchToContext({ browser, options });
}
async function switchToContext({ browser, options }) {
  const getContextsOptions = {
    returnDetailedContexts: true,
    filterByCurrentAndroidApp: false,
    isAndroidWebviewVisible: false,
    returnAndroidDescriptionData: true,
    ...options?.androidWebviewConnectionRetryTime && { androidWebviewConnectionRetryTime: options.androidWebviewConnectionRetryTime },
    ...options?.androidWebviewConnectTimeout && { androidWebviewConnectTimeout: options.androidWebviewConnectTimeout }
  };
  const contexts = await browser.getContexts(getContextsOptions);
  let identifier;
  if (options.appIdentifier) {
    identifier = options.appIdentifier;
  } else {
    identifier = browser.isIOS ? (await browser.execute("mobile: activeAppInfo"))?.bundleId : await browser.getCurrentPackage();
  }
  const { matchingContext, reasons } = findMatchingContext({ browser, contexts, identifier, ...options?.title && { title: options.title }, ...options?.url && { url: options.url } });
  if (!matchingContext) {
    throw new Error(reasons.join("\n"));
  }
  log22.info("WebdriverIO found a matching context:", JSON.stringify(matchingContext, null, 2));
  if (!browser.isIOS) {
    const webviewName = `WEBVIEW_${identifier}`;
    await browser.switchAppiumContext(webviewName);
  }
  const switchFunction = browser.isIOS ? browser.switchAppiumContext.bind(browser) : browser.switchToWindow.bind(browser);
  const matchingContextId = browser.isIOS ? matchingContext.id : matchingContext.webviewPageId;
  return switchFunction(matchingContextId);
}
function findMatchingContext({
  browser: { isIOS },
  contexts,
  identifier,
  title,
  url: url2
}) {
  const reasons = [];
  reasons.push(`We parsed a total of ${contexts.length} Webviews but did not find a matching context. The reasons are:`);
  const matchingContext = contexts.find((context, index) => {
    reasons.push(`- Webview ${index + 1}: '${context.id}'`);
    if (context.id === "NATIVE_APP") {
      reasons.push("  - Skipped context because it is NATIVE_APP");
      return false;
    }
    const idMatch = isIOS ? context.bundleId === identifier : context.packageName === identifier;
    const titleMatches = title ? title instanceof RegExp ? title.test(context.title || "") : context.title?.includes(title) : true;
    const urlMatches = url2 ? url2 instanceof RegExp ? url2.test(context.url || "") : context.url?.includes(url2) : true;
    const additionalAndroidChecks = isIOS ? true : context.androidWebviewData?.attached && context.androidWebviewData?.visible;
    if (!idMatch) {
      reasons.push(`  - App ${isIOS ? "bundleId" : "packageName"} '${identifier}' did not match: '${context.id}'`);
    }
    if (!titleMatches) {
      reasons.push(`  - Title '${title}' did not match: '${context.title}'`);
    }
    if (!urlMatches) {
      reasons.push(`  - URL '${url2}' did not match: '${context.url}'`);
    }
    if (!additionalAndroidChecks) {
      reasons.push("  - Additional Android checks failed");
    }
    return idMatch && titleMatches && urlMatches && additionalAndroidChecks;
  });
  return { matchingContext, reasons };
}
var log22;
var init_switchContext = __esm({
  "src/commands/mobile/switchContext.ts"() {
    "use strict";
    log22 = logger22("webdriver");
  }
});

// src/commands/mobile/relaunchActiveApp.ts
async function relaunchActiveApp() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `relaunchActiveApp` command is only available for mobile platforms.");
  }
  if (browser.isIOS) {
    const { bundleId, processArguments: { args, env } } = await browser.execute("mobile: activeAppInfo");
    const iOSLaunchOptions = {
      bundleId,
      ...args.length > 0 && { arguments: args },
      ...Object.keys(env).length > 0 && { environment: env }
    };
    await browser.execute("mobile: terminateApp", { bundleId });
    return browser.execute("mobile:launchApp", iOSLaunchOptions);
  }
  const packageName = await browser.getCurrentPackage();
  await browser.execute("mobile: terminateApp", { appId: packageName });
  return browser.execute("mobile: activateApp", { appId: packageName });
}
var init_relaunchActiveApp = __esm({
  "src/commands/mobile/relaunchActiveApp.ts"() {
    "use strict";
  }
});

// src/commands/mobile/deepLink.ts
async function deepLink(link, appIdentifier, waitForLaunch) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `deepLink` command is only available for mobile platforms.");
  }
  if (!isDeepLinkUrl(link)) {
    throw new Error(`The provided link is not a valid deep link URL.${browser.isIOS ? " If your url is a `universal deep link` then use the `url` command instead." : ""}`);
  }
  if (!appIdentifier) {
    const mobileOS = browser.isIOS ? "iOS" : "Android";
    const identifierValue = browser.isIOS ? "bundleId" : "package";
    throw new Error(`When using a deep link URL for ${mobileOS}, you need to provide the \`${identifierValue}\` of the app that the deep link should open.`);
  }
  const args = {
    url: link,
    [browser.isIOS ? "bundleId" : "package"]: appIdentifier
  };
  if (!browser.isIOS && waitForLaunch !== void 0) {
    args.waitForLaunch = waitForLaunch;
  }
  return browser.execute("mobile:deepLink", args);
}
function isDeepLinkUrl(link) {
  const deepLinkRegex = /^(?!https?:\/\/)[a-zA-Z][\w+\-.]*:\/\//;
  return deepLinkRegex.test(link);
}
var init_deepLink = __esm({
  "src/commands/mobile/deepLink.ts"() {
    "use strict";
  }
});

// src/commands/mobile/lock.ts
async function lock(seconds) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `lock` command is only available for mobile platforms.");
  }
  return executeMobile(browser, "mobile: lock", { seconds });
}
var init_lock = __esm({
  "src/commands/mobile/lock.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/touchId.ts
async function touchId(match, type = "touchId") {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `touchId` command is only available for mobile platforms.");
  }
  if (!browser.isIOS) {
    throw new Error("The `touchId` command is only available for iOS. For Android, use `fingerPrint` instead.");
  }
  return executeMobile(browser, "mobile: sendBiometricMatch", { match, type });
}
var init_touchId = __esm({
  "src/commands/mobile/touchId.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/toggleEnrollTouchId.ts
async function toggleEnrollTouchId(enabled) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `toggleEnrollTouchId` command is only available for mobile platforms.");
  }
  if (!browser.isIOS) {
    throw new Error("The `toggleEnrollTouchId` command is only available for iOS.");
  }
  return executeMobile(browser, "mobile: enrollBiometric", { enabled });
}
var init_toggleEnrollTouchId = __esm({
  "src/commands/mobile/toggleEnrollTouchId.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/launchApp.ts
async function launchApp(options) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `launchApp` command is only available for mobile platforms.");
  }
  let mobileCmd;
  let mobileArgs;
  if (browser.isIOS) {
    mobileCmd = "mobile: launchApp";
    const bundleId = options?.bundleId ?? (await executeMobile(browser, "mobile: activeAppInfo")).bundleId;
    mobileArgs = { bundleId };
    if (options?.arguments !== void 0) {
      mobileArgs.arguments = options.arguments;
    }
    if (options?.environment !== void 0) {
      mobileArgs.environment = options.environment;
    }
  } else {
    mobileCmd = "mobile: activateApp";
    const appId = options?.appId ?? await browser.getCurrentPackage();
    mobileArgs = { appId };
  }
  return executeMobile(browser, mobileCmd, mobileArgs);
}
var init_launchApp = __esm({
  "src/commands/mobile/launchApp.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/background.ts
async function background(seconds) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `background` command is only available for mobile platforms.");
  }
  return executeMobile(browser, "mobile: backgroundApp", { seconds });
}
var init_background = __esm({
  "src/commands/mobile/background.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getStrings.ts
async function getStrings(language, stringFile) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getStrings` command is only available for mobile platforms.");
  }
  return executeMobile(browser, "mobile: getAppStrings", { language, stringFile });
}
var init_getStrings = __esm({
  "src/commands/mobile/getStrings.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/setClipboard.ts
async function setClipboard(content, contentType, label) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `setClipboard` command is only available for mobile platforms.");
  }
  return executeMobile(browser, "mobile: setClipboard", { content, contentType, label });
}
var init_setClipboard = __esm({
  "src/commands/mobile/setClipboard.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getClipboard.ts
async function getClipboard(contentType) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getClipboard` command is only available for mobile platforms.");
  }
  return executeMobile(browser, "mobile: getClipboard", { contentType });
}
var init_getClipboard = __esm({
  "src/commands/mobile/getClipboard.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/toggleAirplaneMode.ts
async function toggleAirplaneMode(enabled) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `toggleAirplaneMode` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `toggleAirplaneMode` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: setConnectivity", { airplaneMode: enabled });
}
var init_toggleAirplaneMode = __esm({
  "src/commands/mobile/toggleAirplaneMode.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/toggleData.ts
async function toggleData(enabled) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `toggleData` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `toggleData` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: setConnectivity", { data: enabled });
}
var init_toggleData = __esm({
  "src/commands/mobile/toggleData.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/toggleWiFi.ts
async function toggleWiFi(enabled) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `toggleWiFi` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `toggleWiFi` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: setConnectivity", { wifi: enabled });
}
var init_toggleWiFi = __esm({
  "src/commands/mobile/toggleWiFi.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/unlock.ts
async function unlock(options) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `unlock` command is only available for mobile platforms.");
  }
  const args = browser.isAndroid && options ? { ...options } : {};
  return executeMobile(browser, "mobile: unlock", args);
}
var init_unlock = __esm({
  "src/commands/mobile/unlock.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/isLocked.ts
async function isLocked() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `isLocked` command is only available for mobile platforms.");
  }
  return executeMobile(browser, "mobile: isLocked", {});
}
var init_isLocked = __esm({
  "src/commands/mobile/isLocked.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/shake.ts
async function shake() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `shake` command is only available for mobile platforms.");
  }
  if (!browser.isIOS) {
    throw new Error("The `shake` command is only available for iOS.");
  }
  return executeMobile(browser, "mobile: shake", {});
}
var init_shake = __esm({
  "src/commands/mobile/shake.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/closeApp.ts
async function closeApp(options) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `closeApp` command is only available for mobile platforms.");
  }
  let terminateArgs;
  if (browser.isIOS) {
    const bundleId = options?.bundleId ?? (await executeMobile(browser, "mobile: activeAppInfo")).bundleId;
    terminateArgs = { bundleId };
  } else {
    const appId = options?.appId ?? await browser.getCurrentPackage();
    terminateArgs = { appId };
  }
  return executeMobile(browser, "mobile: terminateApp", terminateArgs);
}
var init_closeApp = __esm({
  "src/commands/mobile/closeApp.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getCurrentActivity.ts
async function getCurrentActivity() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getCurrentActivity` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `getCurrentActivity` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: getCurrentActivity", {});
}
var init_getCurrentActivity = __esm({
  "src/commands/mobile/getCurrentActivity.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getCurrentPackage.ts
async function getCurrentPackage() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getCurrentPackage` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `getCurrentPackage` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: getCurrentPackage", {});
}
var init_getCurrentPackage = __esm({
  "src/commands/mobile/getCurrentPackage.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getPerformanceData.ts
async function getPerformanceData(packageName, dataType, dataReadTimeout) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getPerformanceData` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `getPerformanceData` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: getPerformanceData", { packageName, dataType, dataReadTimeout });
}
var init_getPerformanceData = __esm({
  "src/commands/mobile/getPerformanceData.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getPerformanceDataTypes.ts
async function getPerformanceDataTypes() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getPerformanceDataTypes` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `getPerformanceDataTypes` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: getPerformanceDataTypes", {});
}
var init_getPerformanceDataTypes = __esm({
  "src/commands/mobile/getPerformanceDataTypes.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getSystemBars.ts
async function getSystemBars() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getSystemBars` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `getSystemBars` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: getSystemBars", {});
}
var init_getSystemBars = __esm({
  "src/commands/mobile/getSystemBars.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/getDisplayDensity.ts
async function getDisplayDensity() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `getDisplayDensity` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `getDisplayDensity` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: getDisplayDensity", {});
}
var init_getDisplayDensity = __esm({
  "src/commands/mobile/getDisplayDensity.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/pressKeyCode.ts
async function pressKeyCode(keycode, metastate, flags) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `pressKeyCode` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `pressKeyCode` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: pressKey", { keycode, metastate, flags });
}
var init_pressKeyCode = __esm({
  "src/commands/mobile/pressKeyCode.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/longPressKeyCode.ts
async function longPressKeyCode(keycode, metastate, flags) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `longPressKeyCode` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `longPressKeyCode` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: pressKey", { keycode, metastate, flags, isLongPress: true });
}
var init_longPressKeyCode = __esm({
  "src/commands/mobile/longPressKeyCode.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/sendKeyEvent.ts
async function sendKeyEvent(keycode, metastate) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `sendKeyEvent` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `sendKeyEvent` command is only available for Android.");
  }
  const args = { keycode: parseInt(keycode, 10) };
  if (metastate !== void 0) {
    args.metastate = parseInt(metastate, 10);
  }
  return executeMobile(browser, "mobile: pressKey", args);
}
var init_sendKeyEvent = __esm({
  "src/commands/mobile/sendKeyEvent.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/startActivity.ts
async function startActivity(options) {
  const browser = this;
  if (typeof options !== "object" || options === null) {
    throw new Error(
      "`startActivity` only accepts an options object in WebdriverIO v10. Use `browser.startActivity({ appPackage, appActivity })`."
    );
  }
  const legacyOptions = options;
  if ("appWaitPackage" in legacyOptions || "appWaitActivity" in legacyOptions || "optionalIntentArguments" in legacyOptions) {
    throw new Error(
      "The `appWaitPackage`, `appWaitActivity`, and `optionalIntentArguments` options were removed from `startActivity` in WebdriverIO v10. They only applied to the removed Appium HTTP endpoint and are not accepted by `mobile: startActivity`."
    );
  }
  if (!browser.isMobile) {
    throw new Error("The `startActivity` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `startActivity` command is only available for Android.");
  }
  const mobileArgs = {
    component: `${options.appPackage}/${options.appActivity}`
  };
  if (options.intentAction !== void 0) {
    mobileArgs.action = options.intentAction;
  }
  if (options.intentCategory !== void 0) {
    mobileArgs.categories = options.intentCategory;
  }
  if (options.intentFlags !== void 0) {
    mobileArgs.flags = options.intentFlags;
  }
  if (options.dontStopAppOnReset !== void 0) {
    mobileArgs.stop = options.dontStopAppOnReset !== "true";
  }
  return executeMobile(browser, "mobile: startActivity", mobileArgs);
}
var init_startActivity = __esm({
  "src/commands/mobile/startActivity.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/openNotifications.ts
async function openNotifications() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `openNotifications` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `openNotifications` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: openNotifications", {});
}
var init_openNotifications = __esm({
  "src/commands/mobile/openNotifications.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/toggleLocationServices.ts
async function toggleLocationServices() {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `toggleLocationServices` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `toggleLocationServices` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: toggleGps", {});
}
var init_toggleLocationServices = __esm({
  "src/commands/mobile/toggleLocationServices.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/toggleNetworkSpeed.ts
async function toggleNetworkSpeed(netspeed) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `toggleNetworkSpeed` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `toggleNetworkSpeed` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: networkSpeed", { netspeed });
}
var init_toggleNetworkSpeed = __esm({
  "src/commands/mobile/toggleNetworkSpeed.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/gsmCall.ts
async function gsmCall(phoneNumber, action2) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `gsmCall` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `gsmCall` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: gsmCall", { phoneNumber, action: action2 });
}
var init_gsmCall = __esm({
  "src/commands/mobile/gsmCall.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/gsmSignal.ts
async function gsmSignal(signalStrength) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `gsmSignal` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `gsmSignal` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: gsmSignal", { signalStrength });
}
var init_gsmSignal = __esm({
  "src/commands/mobile/gsmSignal.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/gsmVoice.ts
async function gsmVoice(state) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `gsmVoice` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `gsmVoice` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: gsmVoice", { state });
}
var init_gsmVoice = __esm({
  "src/commands/mobile/gsmVoice.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/sendSms.ts
async function sendSms(phoneNumber, message) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `sendSms` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `sendSms` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: sendSms", { phoneNumber, message });
}
var init_sendSms = __esm({
  "src/commands/mobile/sendSms.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/fingerPrint.ts
async function fingerPrint(fingerprintId) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `fingerPrint` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `fingerPrint` command is only available for Android. For iOS, use `touchId` instead.");
  }
  return executeMobile(browser, "mobile: fingerprint", { fingerprintId });
}
var init_fingerPrint = __esm({
  "src/commands/mobile/fingerPrint.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/powerCapacity.ts
async function powerCapacity(percent) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `powerCapacity` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `powerCapacity` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: powerCapacity", { percent });
}
var init_powerCapacity = __esm({
  "src/commands/mobile/powerCapacity.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/powerAC.ts
async function powerAC(state) {
  const browser = this;
  if (!browser.isMobile) {
    throw new Error("The `powerAC` command is only available for mobile platforms.");
  }
  if (!browser.isAndroid) {
    throw new Error("The `powerAC` command is only available for Android.");
  }
  return executeMobile(browser, "mobile: powerAC", { state });
}
var init_powerAC = __esm({
  "src/commands/mobile/powerAC.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/utils/mobileDialog.ts
function toXPathStringLiteral(value) {
  if (!value.includes("'")) {
    return `'${value}'`;
  }
  if (!value.includes('"')) {
    return `"${value}"`;
  }
  const concatSeparator = `, "'", `;
  return `concat(${value.split("'").map((part) => `'${part}'`).join(concatSeparator)})`;
}
function androidButtonSelector(buttonText) {
  return `//android.widget.Button[@text=${toXPathStringLiteral(buttonText)}]`;
}
function assertMobileNativeDialogCommand(browser, commandName) {
  if (!browser.isMobile) {
    throw new Error(`The \`${commandName}\` command is only available for mobile platforms.`);
  }
  if (!browser.isIOS && !browser.isAndroid) {
    throw new Error(`The \`${commandName}\` command is only available for iOS and Android.`);
  }
  if (!browser.isNativeContext) {
    throw new Error(`The \`${commandName}\` command is only available for mobile platforms in the NATIVE context.`);
  }
}
function isMissingDialogError(err) {
  if (!(err instanceof Error)) {
    return false;
  }
  const message = err.message.toLowerCase();
  const errorCode = ("error" in err && typeof err.error === "string" ? err.error : err.name).toLowerCase();
  return message.includes("no such element") || message.includes("no such alert") || message.includes("unable to find") && message.includes("element") || message.includes("could not be located on the page") || errorCode === "no such element" || errorCode === "no such alert";
}
async function interactWithDialog(browser, action2, buttonText, isIOS) {
  if (buttonText) {
    const selector = isIOS ? `~${buttonText}` : androidButtonSelector(buttonText);
    await browser.$(selector, { strict: false }).click();
    return;
  }
  if (action2 === "accept") {
    await browser.acceptAlert();
    return;
  }
  await browser.dismissAlert();
}
async function handleMobileDialog(browser, action2, buttonText) {
  if (browser.isIOS) {
    const { bundleId } = await browser.execute("mobile: activeAppInfo");
    try {
      await browser.execute("mobile: activateApp", { bundleId: SPRINGBOARD_BUNDLE_ID });
      await interactWithDialog(browser, action2, buttonText, true);
    } catch (err) {
      if (isMissingDialogError(err)) {
        return;
      }
      throw err;
    } finally {
      if (bundleId) {
        await browser.execute("mobile: activateApp", { bundleId });
      }
    }
    return;
  }
  try {
    await interactWithDialog(browser, action2, buttonText, false);
  } catch (err) {
    if (isMissingDialogError(err)) {
      return;
    }
    throw err;
  }
}
var SPRINGBOARD_BUNDLE_ID;
var init_mobileDialog = __esm({
  "src/utils/mobileDialog.ts"() {
    "use strict";
    SPRINGBOARD_BUNDLE_ID = "com.apple.springboard";
  }
});

// src/commands/mobile/acceptDialog.ts
async function acceptDialog(buttonText) {
  const browser = this;
  assertMobileNativeDialogCommand(browser, "acceptDialog");
  return handleMobileDialog(browser, "accept", buttonText);
}
var init_acceptDialog = __esm({
  "src/commands/mobile/acceptDialog.ts"() {
    "use strict";
    init_mobileDialog();
  }
});

// src/commands/mobile/dismissDialog.ts
async function dismissDialog(buttonText) {
  const browser = this;
  assertMobileNativeDialogCommand(browser, "dismissDialog");
  return handleMobileDialog(browser, "dismiss", buttonText);
}
var init_dismissDialog = __esm({
  "src/commands/mobile/dismissDialog.ts"() {
    "use strict";
    init_mobileDialog();
  }
});

// src/commands/browser.ts
var browser_exports = {};
__export(browser_exports, {
  $: () => $,
  $$: () => $$,
  SESSION_MOCKS: () => SESSION_MOCKS,
  acceptDialog: () => acceptDialog,
  action: () => action,
  actions: () => actions,
  addInitScript: () => addInitScript,
  back: () => back,
  background: () => background,
  browsingContexts: () => browsingContexts,
  call: () => call,
  closeApp: () => closeApp,
  custom$: () => custom$,
  custom$$: () => custom$$,
  debug: () => debug,
  deepLink: () => deepLink,
  deleteCookies: () => deleteCookies,
  dismissDialog: () => dismissDialog,
  downloadFile: () => downloadFile2,
  emulate: () => emulate,
  execute: () => execute,
  fingerPrint: () => fingerPrint,
  forward: () => forward,
  getClipboard: () => getClipboard,
  getContext: () => getContext,
  getContexts: () => getContexts,
  getCookies: () => getCookies,
  getCurrentActivity: () => getCurrentActivity,
  getCurrentPackage: () => getCurrentPackage,
  getDisplayDensity: () => getDisplayDensity,
  getPerformanceData: () => getPerformanceData,
  getPerformanceDataTypes: () => getPerformanceDataTypes,
  getPuppeteer: () => getPuppeteer,
  getStrings: () => getStrings,
  getSystemBars: () => getSystemBars,
  getWindowSize: () => getWindowSize,
  gsmCall: () => gsmCall,
  gsmSignal: () => gsmSignal,
  gsmVoice: () => gsmVoice,
  installExtension: () => installExtension,
  isLocked: () => isLocked,
  keys: () => keys,
  launchApp: () => launchApp,
  lock: () => lock,
  longPressKeyCode: () => longPressKeyCode,
  mock: () => mock,
  mockClearAll: () => mockClearAll,
  mockRestoreAll: () => mockRestoreAll,
  newWindow: () => newWindow,
  openNotifications: () => openNotifications,
  pause: () => pause,
  powerAC: () => powerAC,
  powerCapacity: () => powerCapacity,
  pressKeyCode: () => pressKeyCode,
  react$: () => react$,
  react$$: () => react$$,
  relaunchActiveApp: () => relaunchActiveApp,
  reloadSession: () => reloadSession,
  restore: () => restore,
  savePDF: () => savePDF2,
  saveRecordingScreen: () => saveRecordingScreen2,
  saveScreenshot: () => saveScreenshot2,
  scroll: () => scroll,
  sendKeyEvent: () => sendKeyEvent,
  sendSms: () => sendSms,
  setClipboard: () => setClipboard,
  setCookies: () => setCookies,
  setTimeout: () => setTimeout2,
  setViewport: () => setViewport,
  setWindowSize: () => setWindowSize,
  shake: () => shake,
  startActivity: () => startActivity,
  swipe: () => swipe,
  switchContext: () => switchContext,
  switchFrame: () => switchFrame,
  switchWindow: () => switchWindow,
  tap: () => tap,
  throttleCPU: () => throttleCPU,
  throttleNetwork: () => throttleNetwork,
  toggleAirplaneMode: () => toggleAirplaneMode,
  toggleData: () => toggleData,
  toggleEnrollTouchId: () => toggleEnrollTouchId,
  toggleLocationServices: () => toggleLocationServices,
  toggleNetworkSpeed: () => toggleNetworkSpeed,
  toggleWiFi: () => toggleWiFi,
  touchId: () => touchId,
  uninstallExtension: () => uninstallExtension,
  unlock: () => unlock,
  url: () => url,
  waitUntil: () => waitUntil
});
var init_browser = __esm({
  "src/commands/browser.ts"() {
    "use strict";
    init__();
    init__2();
    init_action();
    init_actions2();
    init_addInitScript();
    init_back();
    init_call();
    init_custom();
    init_custom2();
    init_debug();
    init_deleteCookies();
    init_downloadFile();
    init_emulate();
    init_execute();
    init_forward();
    init_getCookies();
    init_getPuppeteer();
    init_getWindowSize();
    init_installExtension();
    init_keys();
    init_mock();
    init_mockClearAll();
    init_mockRestoreAll();
    init_newWindow();
    init_browsingContexts();
    init_pause();
    init_react2();
    init_react();
    init_reloadSession();
    init_restore();
    init_savePDF();
    init_saveRecordingScreen();
    init_saveScreenshot();
    init_scroll();
    init_setCookies();
    init_setTimeout();
    init_setViewport();
    init_setWindowSize();
    init_switchWindow();
    init_switchFrame();
    init_throttleCPU();
    init_throttleNetwork();
    init_uninstallExtension();
    init_url();
    init_waitUntil();
    init_swipe();
    init_tap();
    init_getContext();
    init_getContexts();
    init_switchContext();
    init_relaunchActiveApp();
    init_deepLink();
    init_lock();
    init_touchId();
    init_toggleEnrollTouchId();
    init_launchApp();
    init_background();
    init_getStrings();
    init_setClipboard();
    init_getClipboard();
    init_toggleAirplaneMode();
    init_toggleData();
    init_toggleWiFi();
    init_unlock();
    init_isLocked();
    init_shake();
    init_closeApp();
    init_getCurrentActivity();
    init_getCurrentPackage();
    init_getPerformanceData();
    init_getPerformanceDataTypes();
    init_getSystemBars();
    init_getDisplayDensity();
    init_pressKeyCode();
    init_longPressKeyCode();
    init_sendKeyEvent();
    init_startActivity();
    init_openNotifications();
    init_toggleLocationServices();
    init_toggleNetworkSpeed();
    init_gsmCall();
    init_gsmSignal();
    init_gsmVoice();
    init_sendSms();
    init_fingerPrint();
    init_powerCapacity();
    init_powerAC();
    init_acceptDialog();
    init_dismissDialog();
  }
});

// src/commands/element/$$.ts
var $$2;
var init__3 = __esm({
  "src/commands/element/$$.ts"() {
    "use strict";
    init__();
    $$2 = $$;
  }
});

// src/commands/element/$.ts
var $2;
var init__4 = __esm({
  "src/commands/element/$.ts"() {
    "use strict";
    init__2();
    $2 = $;
  }
});

// src/commands/element/addValue.ts
import { getBrowserObject as getBrowserObject20 } from "@wdio/utils";
import { CommandRuntimeOptions } from "webdriver";
function addValue(value, options) {
  if (!VALID_TYPES.includes(typeof value)) {
    throw new Error(
      'The setValue/addValue command only take string or number values. If you like to use special characters, use the "keys" command.'
    );
  }
  const browser = getBrowserObject20(this);
  if (isBidiCommandsEnabled(browser)) {
    return options?.mask ? bidiAddMaskedValue(this, value.toString()) : bidiAddValue(this, value.toString());
  }
  if (options) {
    return this.elementSendKeys(this.elementId, value.toString(), new CommandRuntimeOptions(options));
  }
  return this.elementSendKeys(this.elementId, value.toString());
}
var VALID_TYPES;
var init_addValue = __esm({
  "src/commands/element/addValue.ts"() {
    "use strict";
    init_elementCommands();
    VALID_TYPES = ["string", "number"];
  }
});

// src/commands/element/clearValue.ts
import { getBrowserObject as getBrowserObject21 } from "@wdio/utils";
function clearValue() {
  const browser = getBrowserObject21(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiClearValue(this);
  }
  return this.elementClear(this.elementId);
}
var init_clearValue = __esm({
  "src/commands/element/clearValue.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/click.ts
import logger23 from "@wdio/logger";
import { getBrowserObject as getBrowserObject22, sleep as sleep2 } from "@wdio/utils";
function click(options) {
  if (typeof options !== "undefined") {
    if (typeof options !== "object" || Array.isArray(options)) {
      throw new TypeError("Options must be an object");
    }
    return actionClick(this, options);
  }
  const browser = getBrowserObject22(this);
  if (isBidiCommandsEnabled(browser)) {
    return actionClick(this, {}, browser);
  }
  return elementClick(this);
}
async function workaround(element) {
  await element.scrollIntoView({ block: "center", inline: "center" });
}
async function bringIntoView(browser, element, offset) {
  try {
    const result = await browser.execute((elem, offset2, maxFrameWait) => {
      const hitTest = () => {
        const rect = elem.getClientRects()[0];
        if (!rect) {
          return "no-box";
        }
        const left = Math.max(0, Math.min(rect.x, rect.x + rect.width));
        const right = Math.min(window.innerWidth, Math.max(rect.x, rect.x + rect.width));
        const top = Math.max(0, Math.min(rect.y, rect.y + rect.height));
        const bottom = Math.min(window.innerHeight, Math.max(rect.y, rect.y + rect.height));
        let x = Math.floor((left + right) / 2);
        let y = Math.floor((top + bottom) / 2);
        if (x < 0 || x > window.innerWidth || y < 0 || y > window.innerHeight) {
          return "missed";
        }
        if (offset2.x || offset2.y) {
          if (x !== Math.floor(rect.x + rect.width / 2) || y !== Math.floor(rect.y + rect.height / 2)) {
            return "missed";
          }
          if (rect.left <= x + offset2.x && x + offset2.x <= rect.right && rect.top <= y + offset2.y && y + offset2.y <= rect.bottom) {
            x += offset2.x;
            y += offset2.y;
          }
        }
        let hit = document.elementFromPoint(x, y);
        while (hit?.shadowRoot) {
          const inner = hit.shadowRoot.elementFromPoint(x, y);
          if (!inner || inner === hit) {
            break;
          }
          hit = inner;
        }
        for (let node = hit; node; node = node.parentNode || node.host || null) {
          if (node === elem) {
            return "hit";
          }
        }
        return "missed";
      };
      if (hitTest() !== "missed") {
        return;
      }
      for (const scroll2 of [
        { block: "center", inline: "center" },
        { block: "end", inline: "nearest" },
        { block: "start", inline: "nearest" }
      ]) {
        elem.scrollIntoView({ ...scroll2, behavior: "instant" });
        if (hitTest() !== "missed") {
          break;
        }
      }
      if (document.visibilityState === "hidden") {
        return;
      }
      return new Promise((resolve) => {
        requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
        setTimeout(resolve, maxFrameWait);
      });
    }, element, offset, MAX_FRAME_WAIT);
    if (browser.isIOS && result && typeof result === "object") {
      await sleep2(MAX_FRAME_WAIT);
    }
  } catch (err) {
    log23.debug(`Could not scroll the element into view before the click: ${err.message}`);
  }
}
async function elementClick(element) {
  const browser = getBrowserObject22(element);
  if (browser.isFirefox || browser.isMobile && browser.isIOS && !await browser.isNativeContext) {
    await bringIntoView(browser, element, { x: 0, y: 0 });
  }
  try {
    return await element.elementClick(element.elementId);
  } catch (error) {
    let err = error;
    if (typeof error === "string") {
      err = new Error(error);
    }
    if (!`${err.name} ${err.message}`.includes("click intercepted")) {
      throw err;
    }
    const isNativeApp = browser.isMobile && (await browser.isNativeContext || browser.isWindowsApp || browser.isMacApp);
    await (isNativeApp ? workaround(element) : bringIntoView(browser, element, { x: 0, y: 0 }));
    return element.elementClick(element.elementId);
  }
}
async function actionClick(element, options, bidiBrowser) {
  const defaultOptions = {
    button: 0,
    x: 0,
    y: 0,
    skipRelease: false,
    duration: 0
  };
  const { button, x, y, skipRelease, duration } = { ...defaultOptions, ...options };
  if (typeof x !== "number" || typeof y !== "number" || !Number.isInteger(x) || !Number.isInteger(y)) {
    throw new TypeError("Coordinates must be integers");
  }
  if (!buttonValue.includes(button)) {
    throw new Error("Button type not supported.");
  }
  const browser = bidiBrowser ?? getBrowserObject22(element);
  if (x || y) {
    const { width, height } = isBidiCommandsEnabled(browser) ? await bidiGetRect(element) : await browser.getElementRect(element.elementId);
    if (x && x < -Math.floor(width / 2) || x && x > Math.floor(width / 2)) {
      log23.warn("x would cause a out of bounds error as it goes outside of element");
    }
    if (y && y < -Math.floor(height / 2) || y && y > Math.floor(height / 2)) {
      log23.warn("y would cause a out of bounds error as it goes outside of element");
    }
  }
  const isNativeApp = browser.isMobile && (await browser.isNativeContext || browser.isWindowsApp || browser.isMacApp);
  if (!isNativeApp) {
    await bringIntoView(browser, element, { x, y });
  }
  if (bidiBrowser) {
    await bidiAssertClickable(element);
  }
  const moveDuration = bidiBrowser ? { duration: 0 } : {};
  const clickNested = async () => {
    await browser.action("pointer", {
      parameters: { pointerType: browser.isMobile ? "touch" : "mouse" }
    }).move({ origin: element, x, y, ...moveDuration }).down({ button }).pause(duration).up({ button }).perform(skipRelease);
  };
  try {
    return await clickNested();
  } catch {
    await workaround(element);
    return clickNested();
  }
}
var log23, MAX_FRAME_WAIT;
var init_click = __esm({
  "src/commands/element/click.ts"() {
    "use strict";
    init_elementCommands();
    init_actions();
    log23 = logger23("webdriver");
    MAX_FRAME_WAIT = 100;
  }
});

// src/commands/element/custom$$.ts
import { ELEMENT_KEY as ELEMENT_KEY12 } from "webdriver";
import { getBrowserObject as getBrowserObject23 } from "@wdio/utils";
function custom$$2(strategyName, ...strategyArguments) {
  return ElementArray.fromAsyncCallback(async () => {
    const browserObject = getBrowserObject23(this);
    const strategy = browserObject.strategies.get(strategyName);
    if (!strategy) {
      throw new Error("No strategy found for " + strategyName);
    }
    if (!this.elementId) {
      throw new Error(`Can't call custom$ on element with selector "${describeSelector(this)}" because element wasn't found`);
    }
    const strategyRef = { strategy, strategyName, strategyArguments: [...strategyArguments, this] };
    let res = await browserObject.execute(strategy, ...strategyArguments, this);
    if (!Array.isArray(res)) {
      res = [res];
    }
    res = res.filter((el) => !!el && typeof el[ELEMENT_KEY12] === "string");
    return res.length ? await getElements.call(this, strategyRef, res) : [];
  }, {
    selector: strategyName,
    foundWith: "custom$$",
    parent: this,
    props: strategyArguments
  });
}
var init_custom3 = __esm({
  "src/commands/element/custom$$.ts"() {
    "use strict";
    init_getElementObject();
    init_array();
    init_describeSelector();
  }
});

// src/commands/element/custom$.ts
import { ELEMENT_KEY as ELEMENT_KEY13 } from "webdriver";
import { getBrowserObject as getBrowserObject24 } from "@wdio/utils";
async function custom$2(strategyName, ...strategyArguments) {
  const browserObject = getBrowserObject24(this);
  const strategy = browserObject.strategies.get(strategyName);
  if (!strategy) {
    throw Error("No strategy found for " + strategyName);
  }
  if (!this.elementId) {
    throw Error(`Can't call custom$ on element with selector "${describeSelector(this)}" because element wasn't found`);
  }
  const strategyRef = { strategy, strategyName, strategyArguments: [...strategyArguments, this] };
  let res = await browserObject.execute(strategy, ...strategyArguments, this);
  if (Array.isArray(res)) {
    res = res[0];
  }
  if (res && typeof res[ELEMENT_KEY13] === "string") {
    return await getElement.call(this, strategyRef, res, { strict: false });
  }
  return await getElement.call(this, strategyRef, new Error("no such element"), { strict: false });
}
var init_custom4 = __esm({
  "src/commands/element/custom$.ts"() {
    "use strict";
    init_getElementObject();
    init_describeSelector();
  }
});

// src/commands/element/doubleClick.ts
import { getBrowserObject as getBrowserObject25 } from "@wdio/utils";
async function doubleClick() {
  const browser = getBrowserObject25(this);
  return browser.action("pointer", { parameters: { pointerType: "mouse" } }).move({ origin: this }).down().up().pause(10).down().up().perform();
}
var init_doubleClick = __esm({
  "src/commands/element/doubleClick.ts"() {
    "use strict";
  }
});

// src/commands/element/dragAndDrop.ts
import { getBrowserObject as getBrowserObject26, isLoadedElement } from "@wdio/utils";
async function dragAndDrop(target, options = {}) {
  const moveToCoordinates = target;
  const moveToElement = await target;
  const isMovingToElement = isLoadedElement(moveToElement);
  if (
    /**
     * no target was specified
     */
    !moveToElement || /**
     * target is not from type element
     */
    !isMovingToElement && /**
     * and is also not an object with x and y number parameters
     */
    (typeof moveToCoordinates.x !== "number" || typeof moveToCoordinates.y !== "number")
  ) {
    throw new Error('command dragAndDrop requires an WebdriverIO Element or and object with "x" and "y" variables as first parameter');
  }
  const ACTION_BUTTON = 0;
  const browser = getBrowserObject26(this);
  const defaultOptions = { duration: browser.isMobile ? 250 : 10 };
  const { duration } = { ...defaultOptions, ...options };
  const origin = this;
  const targetOrigin = isMovingToElement ? moveToElement : "pointer";
  const targetX = isMovingToElement ? 0 : moveToCoordinates.x;
  const targetY = isMovingToElement ? 0 : moveToCoordinates.y;
  return browser.action("pointer", {
    parameters: { pointerType: browser.isMobile ? "touch" : "mouse" }
  }).move({ duration: 0, origin, x: 0, y: 0 }).down({ button: ACTION_BUTTON }).pause(10).move({ duration, origin: targetOrigin, x: targetX, y: targetY }).up({ button: ACTION_BUTTON }).perform();
}
var init_dragAndDrop = __esm({
  "src/commands/element/dragAndDrop.ts"() {
    "use strict";
  }
});

// src/commands/element/execute.ts
async function execute2(script, ...args) {
  const scope = this;
  await scope.waitForExist();
  return execute.call(scope, script, scope, ...args);
}
var init_execute2 = __esm({
  "src/commands/element/execute.ts"() {
    "use strict";
    init_execute();
  }
});

// src/commands/element/getAttribute.ts
import { getBrowserObject as getBrowserObject27 } from "@wdio/utils";
function getAttribute(attributeName) {
  const browser = getBrowserObject27(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiGetAttribute(this, attributeName);
  }
  return this.getElementAttribute(this.elementId, attributeName);
}
var init_getAttribute = __esm({
  "src/commands/element/getAttribute.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/getCSSProperty.ts
import cssShorthandProps from "css-shorthand-properties";
import { getBrowserObject as getBrowserObject28 } from "@wdio/utils";
async function getCSSProperty(cssProperty, pseudoElement) {
  const getCSSProp = cssShorthandProps.isShorthand(cssProperty) ? getShorthandPropertyCSSValue : getPropertyCSSValue;
  const cssValue2 = await getCSSProp.call(
    this,
    {
      cssProperty,
      pseudoElement
    }
  );
  return parseCSS(cssValue2, cssProperty);
}
async function getShorthandPropertyCSSValue(options) {
  const { pseudoElement, cssProperty } = options;
  const properties = getShorthandProperties(cssProperty);
  if (pseudoElement) {
    const cssValues2 = await Promise.all(
      properties.map((prop) => getPseudoElementCSSValue(
        this,
        {
          pseudoElement,
          cssProperty: prop
        }
      ))
    );
    return mergeEqualSymmetricalValue(cssValues2);
  }
  const cssValues = await Promise.all(
    properties.map((prop) => getElementCSSValue(this, prop))
  );
  return mergeEqualSymmetricalValue(cssValues);
}
async function getPropertyCSSValue(options) {
  const { pseudoElement, cssProperty } = options;
  if (pseudoElement) {
    return await getPseudoElementCSSValue(
      this,
      {
        pseudoElement,
        cssProperty
      }
    );
  }
  return await getElementCSSValue(this, cssProperty);
}
async function getElementCSSValue(elem, cssProperty) {
  const browser = getBrowserObject28(elem);
  if (isBidiCommandsEnabled(browser)) {
    return bidiGetCSSProperty(elem, cssProperty);
  }
  return elem.getElementCSSValue(elem.elementId, cssProperty);
}
function getShorthandProperties(cssProperty) {
  return cssShorthandProps.expand(cssProperty);
}
function mergeEqualSymmetricalValue(cssValues) {
  let newCssValues = [...cssValues];
  while (newCssValues.length % 2 === 0) {
    const mergedValues = [
      newCssValues.slice(0, newCssValues.length / 2).join(" "),
      newCssValues.slice(newCssValues.length / 2).join(" ")
    ];
    const hasEqualProperties = mergedValues.every((v) => v === mergedValues[0]);
    if (!hasEqualProperties) {
      break;
    }
    newCssValues = newCssValues.slice(0, newCssValues.length / 2);
  }
  return newCssValues.join(" ");
}
async function getPseudoElementCSSValue(elem, options) {
  const { cssProperty, pseudoElement } = options;
  const read = (elem2, pseudoElement2, cssProperty2) => {
    if (typeof elem2.isConnected === "boolean" && !elem2.isConnected) {
      throw new Error("stale element reference: element is not attached to the page document");
    }
    return window.getComputedStyle(elem2, pseudoElement2)[cssProperty2];
  };
  const cssValue2 = await foreignContextId(elem) ? await elem.execute(read, pseudoElement, cssProperty) : await getBrowserObject28(elem).execute(read, elem, pseudoElement, cssProperty);
  return cssValue2;
}
var init_getCSSProperty = __esm({
  "src/commands/element/getCSSProperty.ts"() {
    "use strict";
    init_utils2();
    init_browsingContext();
    init_elementCommands();
  }
});

// src/commands/element/getComputedRole.ts
function getComputedRole() {
  return this.getElementComputedRole(this.elementId);
}
var init_getComputedRole = __esm({
  "src/commands/element/getComputedRole.ts"() {
    "use strict";
  }
});

// src/commands/element/getComputedLabel.ts
function getComputedLabel() {
  return this.getElementComputedLabel(this.elementId);
}
var init_getComputedLabel = __esm({
  "src/commands/element/getComputedLabel.ts"() {
    "use strict";
  }
});

// src/commands/element/getElement.ts
async function getElement2() {
  return this;
}
var init_getElement = __esm({
  "src/commands/element/getElement.ts"() {
    "use strict";
  }
});

// src/commands/element/getHTML.ts
import { ELEMENT_KEY as ELEMENT_KEY14 } from "webdriver";
import { prettify as prettifyFn } from "htmlfy";
import { getBrowserObject as getBrowserObject29 } from "@wdio/utils";
import getHTMLScript from "./scripts/getHTML.js";
import getHTMLShadowScript from "./scripts/getHTMLShadow.js";
async function getHTML(options = {}) {
  const browser = getBrowserObject29(this);
  if (typeof options === "boolean") {
    throw new Error(
      `Passing a boolean to \`getHTML\` was removed in WebdriverIO v10. Use \`element.getHTML({ includeSelectorTag: ${options} })\`.`
    );
  }
  if (typeof options !== "object" || options === null) {
    throw new Error("The `getHTML` options parameter must be an object");
  }
  const { includeSelectorTag, pierceShadowRoot, removeCommentNodes, prettify, excludeElements } = Object.assign({
    includeSelectorTag: true,
    pierceShadowRoot: true,
    removeCommentNodes: true,
    prettify: true,
    excludeElements: []
  }, options);
  const basicGetHTML = (elementId, includeSelectorTag2) => {
    return browser.execute(getHTMLScript, {
      [ELEMENT_KEY14]: elementId
    }, includeSelectorTag2, excludeElements);
  };
  if (pierceShadowRoot && this.isBidi) {
    if (globalThis.wdio) {
      return globalThis.wdio.executeWithScope(
        "getHTML",
        this.elementId,
        { includeSelectorTag, pierceShadowRoot, removeCommentNodes, prettify, excludeElements }
      );
    }
    const { load: load2 } = await import("cheerio");
    const shadowRootManager = getShadowRootManager(browser);
    const context = await contextIdOf(this);
    const shadowRootElementPairs = await shadowRootManager.getShadowElementPairsByContextId(context, this.elementId);
    const elementsWithShadowRootAndIdVerified = (await Promise.all(
      shadowRootElementPairs.map(([elemId, elem]) => executeInContext(browser, context, (elem2) => elem2.tagName, { [ELEMENT_KEY14]: elemId }).then(
        () => [elemId, elem],
        () => void 0
      ))
    )).filter(Boolean).map(([elemId, shadowId]) => [
      elemId,
      { [ELEMENT_KEY14]: elemId },
      shadowId ? { [ELEMENT_KEY14]: shadowId } : void 0
    ]);
    const { html, shadowElementHTML } = await this.execute(
      getHTMLShadowScript,
      includeSelectorTag,
      elementsWithShadowRootAndIdVerified
    );
    const $3 = load2(html);
    populateHTML($3, shadowElementHTML.map(({ id, ...props }) => ({
      ...props,
      id,
      mode: shadowRootManager.getShadowRootModeById(context, id) || "open"
    })));
    return sanitizeHTML($3, { removeCommentNodes, prettify, excludeElements });
  }
  const returnHTML = await basicGetHTML(this.elementId, includeSelectorTag);
  return sanitizeHTML(returnHTML, { removeCommentNodes, prettify });
}
function populateHTML($3, shadowElementHTML) {
  const shadowElements = $3(SHADOW_ID_ATTR);
  if (shadowElements.length === 0) {
    return;
  }
  for (const elem of shadowElements) {
    const id = elem.attribs[SHADOW_ID_ATTR_NAME];
    const shadowReference = shadowElementHTML.find(({ id: shadowRootId }) => id === shadowRootId);
    if (!shadowReference) {
      continue;
    }
    $3(`[${SHADOW_ID_ATTR_NAME}="${id}"]`).append([
      `<template shadowrootmode="${shadowReference.mode}">`,
      shadowReference.styles && shadowReference.styles.length > 0 ? `	<style>${shadowReference.styles.join("\n")}</style>` : "",
      `	${shadowReference.html}`,
      "</template>"
    ].join("\n"));
    delete elem.attribs[SHADOW_ID_ATTR_NAME];
  }
  populateHTML($3, shadowElementHTML);
}
function removeCommentNodesDeep($3, node) {
  $3(node).contents().each((_, child) => {
    if (child.type === "comment") {
      $3(child).remove();
      return;
    }
    removeCommentNodesDeep($3, child);
  });
}
function sanitizeHTML($3, options = {}) {
  const isCheerioObject = $3 && typeof $3 !== "string";
  if (isCheerioObject) {
    for (const elemToRemove of options.excludeElements || []) {
      $3(elemToRemove).remove();
    }
    if (options.removeCommentNodes) {
      removeCommentNodesDeep($3, $3.root()[0]);
    }
  }
  let returnHTML = isCheerioObject ? $3("body").html() : $3;
  if (!isCheerioObject && options.removeCommentNodes && returnHTML) {
    returnHTML = returnHTML.replace(/<!--[\s\S]*?-->/g, "");
  }
  return options.prettify ? prettifyFn(returnHTML) : returnHTML;
}
var SHADOW_ID_ATTR_NAME, SHADOW_ID_ATTR;
var init_getHTML = __esm({
  "src/commands/element/getHTML.ts"() {
    "use strict";
    init_shadowRoot();
    init_browsingContext();
    init_bidi();
    SHADOW_ID_ATTR_NAME = "data-wdio-shadow-id";
    SHADOW_ID_ATTR = `[${SHADOW_ID_ATTR_NAME}]`;
  }
});

// src/commands/element/getLocation.ts
async function getLocation(prop) {
  const { x, y } = await getElementRect(this);
  const location2 = { x, y };
  if (prop === "x" || prop === "y") {
    return location2[prop];
  }
  return location2;
}
var init_getLocation = __esm({
  "src/commands/element/getLocation.ts"() {
    "use strict";
    init_utils2();
  }
});

// src/commands/element/getProperty.ts
import { getBrowserObject as getBrowserObject30 } from "@wdio/utils";
function getProperty(property) {
  const browser = getBrowserObject30(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiGetProperty(this, property);
  }
  return this.getElementProperty(this.elementId, property);
}
var init_getProperty = __esm({
  "src/commands/element/getProperty.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/getSize.ts
async function getSize(prop) {
  const rect = await getElementRect(this);
  if (prop && typeof rect[prop] === "number") {
    return rect[prop];
  }
  return {
    width: rect.width,
    height: rect.height
  };
}
var init_getSize = __esm({
  "src/commands/element/getSize.ts"() {
    "use strict";
    init_utils2();
  }
});

// src/commands/element/getTagName.ts
import { getBrowserObject as getBrowserObject31 } from "@wdio/utils";
function getTagName() {
  const browser = getBrowserObject31(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiGetTagName(this);
  }
  return this.getElementTagName(this.elementId);
}
var init_getTagName = __esm({
  "src/commands/element/getTagName.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/getText.ts
import { getBrowserObject as getBrowserObject32 } from "@wdio/utils";
function getText() {
  const browser = getBrowserObject32(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiGetText(this);
  }
  return this.getElementText(this.elementId);
}
var init_getText = __esm({
  "src/commands/element/getText.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/getValue.ts
import { getBrowserObject as getBrowserObject33 } from "@wdio/utils";
function getValue() {
  const browser = getBrowserObject33(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiGetValue(this);
  }
  const value = this.getElementProperty(this.elementId, "value");
  return value.then((res) => typeof res === "string" ? res : "");
}
var init_getValue = __esm({
  "src/commands/element/getValue.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/isClickable.ts
import { ELEMENT_KEY as ELEMENT_KEY15 } from "webdriver";
import { getBrowserObject as getBrowserObject34 } from "@wdio/utils";
import isElementClickableScript from "./scripts/isElementClickable.js";
async function isClickable() {
  if (!await this.isDisplayed()) {
    return false;
  }
  if (this.isMobile && this.isNativeContext) {
    throw new Error("Method not supported in mobile native environment. It is unlikely that you need to use this command.");
  }
  if (await foreignContextId(this)) {
    return this.execute(isElementClickableScript);
  }
  const browser = getBrowserObject34(this);
  return browser.execute(isElementClickableScript, {
    [ELEMENT_KEY15]: this.elementId
  });
}
var init_isClickable = __esm({
  "src/commands/element/isClickable.ts"() {
    "use strict";
    init_browsingContext();
  }
});

// src/commands/element/isDisplayed.ts
import { getBrowserObject as getBrowserObject35 } from "@wdio/utils";
import checkVisibilityScript from "./scripts/checkVisibility.js";
import isElementDisplayedLegacyScript from "./scripts/isElementDisplayed.js";
import isElementInViewportScript from "./scripts/isElementInViewport.js";
async function isDisplayed(commandParams = DEFAULT_PARAMS) {
  const browser = getBrowserObject35(this);
  if (!await hasElementId(this)) {
    return false;
  }
  if (browser.isMobile && (browser.isNativeContext || browser.isWindowsApp || browser.isMacApp)) {
    if (commandParams?.withinViewport) {
      throw new Error(
        "Cannot determine element visibility within viewport for native mobile apps as it is not feasible to determine full vertical and horizontal application bounds. In most cases a basic visibility check should suffice."
      );
    }
    return await this.isElementDisplayed(this.elementId);
  }
  let hadToFallback = false;
  const [isDisplayed2, displayProperty] = await Promise.all([
    browser.execute(checkVisibilityScript, this, {
      ...DEFAULT_PARAMS,
      ...commandParams
    }).then((result) => {
      if (result === null) {
        hadToFallback = true;
        return browser.execute(isElementDisplayedLegacyScript, this);
      }
      return result;
    }),
    browser.execute(function(elem) {
      try {
        const style = window.getComputedStyle(elem);
        return { value: style?.display ?? "" };
      } catch {
        if (typeof elem.isConnected === "boolean" && !elem.isConnected) {
          throw new Error("stale element reference: element is not attached to the page document");
        }
        return { value: "" };
      }
    }, this)
  ]);
  const hasDisplayContentsCSSProperty = displayProperty.value === "contents";
  const shouldRecheckContentVisibility = !hadToFallback && hasDisplayContentsCSSProperty;
  const finalResponse = shouldRecheckContentVisibility ? await browser.execute(isElementDisplayedLegacyScript, this).catch(() => false) : isDisplayed2;
  if (finalResponse && commandParams?.withinViewport) {
    return browser.execute(isElementInViewportScript, this);
  }
  return finalResponse;
}
var DEFAULT_PARAMS;
var init_isDisplayed = __esm({
  "src/commands/element/isDisplayed.ts"() {
    "use strict";
    init_utils2();
    DEFAULT_PARAMS = {
      withinViewport: false,
      contentVisibilityAuto: true,
      opacityProperty: true,
      visibilityProperty: true
    };
  }
});

// src/commands/element/isEnabled.ts
import { getBrowserObject as getBrowserObject36 } from "@wdio/utils";
function isEnabled() {
  const browser = getBrowserObject36(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiIsEnabled(this);
  }
  return this.isElementEnabled(this.elementId);
}
var init_isEnabled = __esm({
  "src/commands/element/isEnabled.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/isEqual.ts
import { getBrowserObject as getBrowserObject37 } from "@wdio/utils";
async function isEqual(el) {
  const browser = getBrowserObject37(this);
  if (browser.isMobile) {
    const context = await browser.getContext().catch(() => void 0);
    const contextId = typeof context === "string" ? context : context?.id;
    if (contextId && contextId.toLowerCase().includes("native")) {
      return this.elementId === el.elementId;
    }
  }
  let result;
  try {
    result = await browser.execute(
      /* istanbul ignore next */
      function(el1, el2) {
        return el1 === el2;
      },
      this,
      el
    );
  } catch {
    result = false;
  }
  return result;
}
var init_isEqual = __esm({
  "src/commands/element/isEqual.ts"() {
    "use strict";
  }
});

// src/commands/element/isExisting.ts
import { getBrowserObject as getBrowserObject38 } from "@wdio/utils";
async function isExisting() {
  if (!this.selector) {
    const browser = getBrowserObject38(this);
    const probe = isBidiCommandsEnabled(browser) ? bidiGetTagName(this) : this.getElementTagName(this.elementId);
    return probe.then(
      () => true,
      () => false
    );
  }
  const elements = await findAllAgain(this);
  return elements.length > (this.index ?? 0);
}
var init_isExisting = __esm({
  "src/commands/element/isExisting.ts"() {
    "use strict";
    init_findElementAgain();
    init_elementCommands();
  }
});

// src/commands/element/isFocused.ts
import { getBrowserObject as getBrowserObject39 } from "@wdio/utils";
import isFocusedScript from "./scripts/isFocused.js";
async function isFocused() {
  const browser = await getBrowserObject39(this);
  return browser.execute(isFocusedScript, this);
}
var init_isFocused = __esm({
  "src/commands/element/isFocused.ts"() {
    "use strict";
  }
});

// src/commands/element/isSelected.ts
import { getBrowserObject as getBrowserObject40 } from "@wdio/utils";
function isSelected() {
  const browser = getBrowserObject40(this);
  if (isBidiCommandsEnabled(browser)) {
    return bidiIsSelected(this);
  }
  return this.isElementSelected(this.elementId);
}
var init_isSelected = __esm({
  "src/commands/element/isSelected.ts"() {
    "use strict";
    init_elementCommands();
  }
});

// src/commands/element/isStable.ts
import { getBrowserObject as getBrowserObject41 } from "@wdio/utils";
import isElementStable from "./scripts/isElementStable.js";
async function isStable() {
  const browser = getBrowserObject41(this);
  if (browser.isMobile && browser.isNativeContext) {
    throw new Error("The `isStable` command is only available for desktop and mobile browsers.");
  }
  return await browser.execute(isElementStable, this);
}
var init_isStable = __esm({
  "src/commands/element/isStable.ts"() {
    "use strict";
  }
});

// src/commands/element/moveTo.ts
import logger24 from "@wdio/logger";
import { getBrowserObject as getBrowserObject42 } from "@wdio/utils";
async function moveTo({ xOffset, yOffset } = {}) {
  const browser = getBrowserObject42(this);
  if (xOffset || yOffset) {
    const { width, height } = isBidiCommandsEnabled(browser) ? await bidiGetRect(this) : await this.getElementRect(this.elementId);
    if (xOffset && xOffset < -Math.floor(width / 2) || xOffset && xOffset > Math.floor(width / 2)) {
      log24.warn("xOffset would cause a out of bounds error as it goes outside of element");
    }
    if (yOffset && yOffset < -Math.floor(height / 2) || yOffset && yOffset > Math.floor(height / 2)) {
      log24.warn("yOffset would cause a out of bounds error as it goes outside of element");
    }
  }
  const held = await foreignContext(this);
  if (held) {
    await held.execute((elem) => {
      elem.scrollIntoView({ block: "nearest", inline: "nearest" });
    }, this);
  }
  const moveToNested = async () => {
    await browser.action("pointer", { parameters: { pointerType: "mouse" } }).move({ origin: this, x: xOffset || 0, y: yOffset || 0 }).perform();
  };
  try {
    await moveToNested();
  } catch {
    await this.scrollIntoView({ block: "center", inline: "center" });
    await moveToNested();
  }
}
var log24;
var init_moveTo = __esm({
  "src/commands/element/moveTo.ts"() {
    "use strict";
    init_foreignContext();
    init_elementCommands();
    log24 = logger24("webdriver");
  }
});

// src/commands/element/nextElement.ts
function nextElement() {
  return this.$(
    /* istanbul ignore next */
    function nextElement2() {
      return this.nextElementSibling;
    }
  );
}
var init_nextElement = __esm({
  "src/commands/element/nextElement.ts"() {
    "use strict";
  }
});

// src/commands/element/parentElement.ts
function parentElement() {
  return this.$(
    /* istanbul ignore next */
    function parentElement2() {
      return this.parentElement;
    }
  );
}
var init_parentElement = __esm({
  "src/commands/element/parentElement.ts"() {
    "use strict";
  }
});

// src/commands/element/previousElement.ts
function previousElement() {
  return this.$(
    /* istanbul ignore next */
    function previousElement2() {
      return this.previousElementSibling;
    }
  );
}
var init_previousElement = __esm({
  "src/commands/element/previousElement.ts"() {
    "use strict";
  }
});

// src/commands/element/react$$.ts
import { getBrowserObject as getBrowserObject43 } from "@wdio/utils";
import { waitToLoadReact as waitToLoadReact3, react$$ as react$$Script2 } from "./scripts/react.js";
function react$$2(selector, { props = {}, state = {} } = {}) {
  return ElementArray.fromAsyncCallback(async () => {
    const browser = await getBrowserObject43(this);
    await this.execute(reactScript);
    await this.execute(waitToLoadReact3);
    const res = await browser.execute(
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      react$$Script2,
      selector,
      props,
      state,
      this
    );
    return getElements.call(this, selector, res, { isReactElement: true, reactOptions: { props, state } });
  }, {
    selector,
    foundWith: "react$$",
    parent: this,
    /**
     * the arguments after the selector, so that
     * `parent[foundWith](selector, ...props)` runs the same query again
     */
    props: [{ props, state }]
  });
}
var init_react3 = __esm({
  "src/commands/element/react$$.ts"() {
    "use strict";
    init_constant();
    init_getElementObject();
    init_array();
  }
});

// src/commands/element/react$.ts
import { getBrowserObject as getBrowserObject44 } from "@wdio/utils";
import { waitToLoadReact as waitToLoadReact4, react$ as react$Script2 } from "./scripts/react.js";
async function react$2(selector, { props = {}, state = {} } = {}) {
  const browser = await getBrowserObject44(this);
  await this.execute(reactScript);
  await this.execute(waitToLoadReact4);
  const res = await browser.execute(
    react$Script2,
    selector,
    props,
    state,
    this
  );
  return getElement.call(this, selector, res, { isReactElement: true, strict: false, reactOptions: { props, state } });
}
var init_react4 = __esm({
  "src/commands/element/react$.ts"() {
    "use strict";
    init_constant();
    init_getElementObject();
  }
});

// src/commands/element/saveScreenshot.ts
async function saveScreenshot3(filepath) {
  return environment.value.saveElementScreenshot.call(this, filepath);
}
var init_saveScreenshot2 = __esm({
  "src/commands/element/saveScreenshot.ts"() {
    "use strict";
    init_environment();
  }
});

// src/commands/element/scrollIntoView.ts
import logger25 from "@wdio/logger";
import { getBrowserObject as getBrowserObject45 } from "@wdio/utils";
async function scrollIntoView(options = { block: "start", inline: "nearest" }) {
  const browser = getBrowserObject45(this);
  if (browser.isMobile) {
    if (await browser.isNativeContext) {
      return nativeMobileScrollIntoView({
        browser,
        element: this,
        options: options || {}
      });
    }
    return scrollIntoViewWeb.call(this, options);
  }
  if (options === true) {
    options = { block: "start", inline: "nearest" };
  }
  if (options === false) {
    options = { block: "end", inline: "nearest" };
  }
  try {
    const measure = async () => browser.execute((elem) => {
      const { left, top, width, height } = elem.getBoundingClientRect();
      let isPainted = false;
      try {
        const cx = left + width / 2;
        const cy = top + height / 2;
        const deepElementsFromPoint = (root) => {
          const hits = root.elementsFromPoint(cx, cy);
          const topHit = hits[0];
          return topHit?.shadowRoot ? deepElementsFromPoint(topHit.shadowRoot) : hits;
        };
        isPainted = deepElementsFromPoint(document).includes(elem);
      } catch {
      }
      return {
        elemRect: {
          x: left + window.scrollX,
          y: top + window.scrollY,
          width,
          height
        },
        viewport: {
          width: window.innerWidth,
          height: window.innerHeight
        },
        scroll: {
          x: window.scrollX,
          y: window.scrollY
        },
        isPainted
      };
    }, this);
    const getVisibility = ({ elemRect, viewport, scroll: { x: windowScrollX, y: windowScrollY } }) => {
      const TOL = VERIFY_TOLERANCE_PX;
      const isVisibleY = elemRect.y >= windowScrollY - TOL && elemRect.y + elemRect.height <= windowScrollY + viewport.height + TOL;
      const isVisibleX = elemRect.x >= windowScrollX - TOL && elemRect.x + elemRect.width <= windowScrollX + viewport.width + TOL;
      const spansViewportY = elemRect.y <= windowScrollY + TOL && elemRect.y + elemRect.height >= windowScrollY + viewport.height - TOL;
      const spansViewportX = elemRect.x <= windowScrollX + TOL && elemRect.x + elemRect.width >= windowScrollX + viewport.width - TOL;
      return {
        y: isVisibleY || spansViewportY,
        x: isVisibleX || spansViewportX
      };
    };
    const computeDelta = (measurement) => {
      const { elemRect, viewport, scroll: { x: windowScrollX, y: windowScrollY } } = measurement;
      const targetByOption = {
        start: { y: elemRect.y, x: elemRect.x },
        center: {
          y: elemRect.y - (viewport.height - elemRect.height) / 2,
          x: elemRect.x - (viewport.width - elemRect.width) / 2
        },
        end: {
          y: elemRect.y - (viewport.height - elemRect.height),
          x: elemRect.x - (viewport.width - elemRect.width)
        }
      };
      let [deltaX, deltaY] = [targetByOption.start.x, targetByOption.start.y];
      if (options && typeof options === "object") {
        const { block, inline } = options;
        const isVisible = getVisibility(measurement);
        if (block === "nearest") {
          if (isVisible.y) {
            deltaY = windowScrollY;
          } else {
            const nearestYDistance = Math.min(...Object.values(targetByOption).map((delta) => Math.abs(delta.y - windowScrollY)));
            deltaY = Object.values(targetByOption).find((delta) => Math.abs(delta.y - windowScrollY) === nearestYDistance).y;
          }
        } else if (block) {
          deltaY = targetByOption[block].y;
        }
        if (inline === "nearest") {
          if (isVisible.x) {
            deltaX = windowScrollX;
          } else {
            const nearestXDistance = Math.min(...Object.values(targetByOption).map((delta) => Math.abs(delta.x - windowScrollX)));
            deltaX = Object.values(targetByOption).find((delta) => Math.abs(delta.x - windowScrollX) === nearestXDistance).x;
          }
        } else if (inline) {
          deltaX = targetByOption[inline].x;
        }
      }
      return {
        deltaX: Math.round(deltaX - windowScrollX),
        deltaY: Math.round(deltaY - windowScrollY)
      };
    };
    const initialMeasurement = await measure();
    const initialDelta = computeDelta(initialMeasurement);
    if (initialMeasurement.isPainted && initialDelta.deltaX === 0 && initialDelta.deltaY === 0) {
      return;
    }
    const wheelScroll = (deltaX, deltaY) => browser.action("wheel").scroll({ duration: 0, x: 0, y: 0, deltaX, deltaY, origin: this }).perform();
    if (initialMeasurement.isPainted) {
      await wheelScroll(initialDelta.deltaX, initialDelta.deltaY);
    } else {
      await wheelScroll(0, 0);
      const remainingDelta = computeDelta(await measure());
      if (remainingDelta.deltaX !== 0 || remainingDelta.deltaY !== 0) {
        await wheelScroll(remainingDelta.deltaX, remainingDelta.deltaY);
      }
    }
    await browser.execute(async (elem) => {
      try {
        let last = elem.getBoundingClientRect();
        let stableFrames = 0;
        let totalFrames = 0;
        const maxFrames = 60;
        await new Promise((resolve) => {
          const check = () => {
            totalFrames++;
            const current = elem.getBoundingClientRect();
            if (current.top === last.top && current.left === last.left) {
              stableFrames++;
            } else {
              stableFrames = 0;
              last = current;
            }
            if (stableFrames >= 2 || totalFrames >= maxFrames) {
              return resolve();
            }
            requestAnimationFrame(check);
          };
          requestAnimationFrame(check);
        });
      } catch {
      }
    }, this);
    const finalMeasurement = await measure();
    if (!finalMeasurement.isPainted) {
      log25.warn(
        "scrollIntoView via the WebDriver Actions API did not bring the element into view! Re-attempting using `Element.scrollIntoView` via Web API."
      );
      await scrollIntoViewWeb.call(this, options);
    }
  } catch (err) {
    log25.warn(
      `Failed to execute "scrollIntoView" using WebDriver Actions API: ${err.message}!
Re-attempting using \`Element.scrollIntoView\` via Web API.`
    );
    await scrollIntoViewWeb.call(this, options);
  }
}
async function mobileScrollUntilVisible({
  browser,
  direction,
  duration,
  element,
  maxScrolls,
  percent,
  scrollableElement
}) {
  let isVisible = false;
  let hasScrolled = false;
  let scrolls = 0;
  while (!isVisible && scrolls < maxScrolls) {
    try {
      isVisible = await element.isDisplayed();
    } catch (err) {
      if (err instanceof StrictSelectorError) {
        throw err;
      }
      isVisible = false;
    }
    if (isVisible) {
      break;
    }
    await browser.swipe({
      direction,
      ...duration ? { duration } : {},
      ...percent ? { percent } : {},
      ...scrollableElement ? { scrollableElement } : {}
    });
    hasScrolled = true;
    scrolls++;
  }
  return { hasScrolled, isVisible };
}
async function nativeMobileScrollIntoView({
  browser,
  element,
  options
}) {
  const defaultOptions = {
    maxScrolls: 10,
    direction: "up" /* Up */
  };
  const mobileOptions = {
    ...defaultOptions,
    ...options || {}
  };
  const { hasScrolled, isVisible } = await mobileScrollUntilVisible({
    browser,
    element,
    maxScrolls: mobileOptions.maxScrolls,
    direction: mobileOptions.direction,
    ...mobileOptions?.duration ? { duration: mobileOptions.duration } : {},
    ...mobileOptions?.percent ? { percent: mobileOptions.percent } : {},
    ...mobileOptions?.scrollableElement ? { scrollableElement: mobileOptions.scrollableElement } : {}
  });
  if (hasScrolled && isVisible) {
    return browser.pause(1e3);
  } else if (isVisible) {
    return;
  }
  throw new Error(`Element not found within scroll limit of ${mobileOptions.maxScrolls} scrolls by scrolling "${mobileOptions.direction}". Are you sure the element is within the scrollable element or the direction is correct? You can change the scrollable element or direction like this:

await elem.scrollIntoView({
    direction: 'left' // possible options are: 'up|down|left|right'
    scrollableElement: $('#scrollable'),
});

        `);
}
function scrollIntoViewWeb(options = { block: "start", inline: "nearest" }) {
  const browser = getBrowserObject45(this);
  return browser.execute(
    (elem, options2) => elem.scrollIntoView(options2),
    this,
    options
  );
}
var log25, VERIFY_TOLERANCE_PX;
var init_scrollIntoView = __esm({
  "src/commands/element/scrollIntoView.ts"() {
    "use strict";
    init_types2();
    init_strictSelectorError();
    log25 = logger25("webdriverio");
    VERIFY_TOLERANCE_PX = 1;
  }
});

// src/commands/element/selectByAttribute.ts
import { ELEMENT_KEY as ELEMENT_KEY16 } from "webdriver";
import { getBrowserObject as getBrowserObject46 } from "@wdio/utils";
async function selectByAttribute(attribute, value) {
  value = typeof value === "number" ? value.toString() : value;
  const browser = getBrowserObject46(this);
  if (isBidiCommandsEnabled(browser)) {
    let disabled;
    await this.waitUntil(async () => {
      const result = await bidiSelectByAttribute(this, attribute, value);
      disabled = result.disabled;
      return result.selected || !!disabled;
    }, {
      timeoutMsg: `Option with attribute "${attribute}=${value}" not found.`
    });
    if (disabled) {
      throw bidiDisabledSelectError("selectByAttribute", `option with attribute "${attribute}=${value}"`, disabled);
    }
    return;
  }
  const normalized = `[normalize-space(@${attribute.trim()}) = "${value.trim()}"]`;
  let optionElement;
  await this.waitUntil(async () => {
    optionElement = await this.findElementFromElement(
      this.elementId,
      "xpath",
      `./option${normalized}|./optgroup/option${normalized}`
    );
    return ELEMENT_KEY16 in optionElement;
  }, {
    timeoutMsg: `Option with attribute "${attribute}=${value}" not found.`
  });
  return this.elementClick(getElementFromResponse(optionElement));
}
var init_selectByAttribute = __esm({
  "src/commands/element/selectByAttribute.ts"() {
    "use strict";
    init_utils2();
    init_elementCommands();
  }
});

// src/commands/element/selectByIndex.ts
import { getBrowserObject as getBrowserObject47 } from "@wdio/utils";
async function selectByIndex(index) {
  if (index < 0) {
    throw new Error("Index needs to be 0 or any other positive number");
  }
  const browser = getBrowserObject47(this);
  if (isBidiCommandsEnabled(browser)) {
    let optionCount = 0;
    let disabled;
    await this.waitUntil(async () => {
      const result = await bidiSelectByIndex(this, index);
      optionCount = result.count;
      disabled = result.disabled;
      return result.selected || !!disabled;
    }, {
      timeoutMsg: () => optionCount === 0 ? "Select element doesn't contain any option element" : `Option with index "${index}" not found. Select element only contains ${optionCount} option elements`
    });
    if (disabled) {
      throw bidiDisabledSelectError("selectByIndex", `option with index "${index}"`, disabled);
    }
    return;
  }
  const fetchOptionElements = async () => {
    return this.findElementsFromElement(this.elementId, "css selector", "option");
  };
  let optionElements = [];
  await this.waitUntil(async () => {
    optionElements = await fetchOptionElements();
    return optionElements.length > 0;
  }, {
    timeoutMsg: "Select element doesn't contain any option element"
  });
  await this.waitUntil(async () => {
    optionElements = await fetchOptionElements();
    return typeof optionElements[index] !== "undefined";
  }, {
    timeoutMsg: `Option with index "${index}" not found. Select element only contains ${optionElements.length} option elements`
  });
  return this.elementClick(getElementFromResponse(optionElements[index]));
}
var init_selectByIndex = __esm({
  "src/commands/element/selectByIndex.ts"() {
    "use strict";
    init_utils2();
    init_elementCommands();
  }
});

// src/commands/element/selectByVisibleText.ts
import { getBrowserObject as getBrowserObject48 } from "@wdio/utils";
async function selectByVisibleText(text) {
  text = typeof text === "number" ? text.toString() : text;
  const normalized = text.trim().replace(/\s+/g, " ");
  const browser = getBrowserObject48(this);
  if (isBidiCommandsEnabled(browser)) {
    let disabled;
    await this.waitUntil(async () => {
      const result = await bidiSelectByVisibleText(this, normalized);
      disabled = result.disabled;
      return result.selected || !!disabled;
    }, {
      timeoutMsg: `Option with text "${text}" not found.`
    });
    if (disabled) {
      throw bidiDisabledSelectError("selectByVisibleText", `option with text "${text}"`, disabled);
    }
    return;
  }
  const formatted = /"/.test(normalized) ? 'concat("' + normalized.split('"').join(`", '"', "`) + '")' : `"${normalized}"`;
  const dotFormat = `[. = ${formatted}]`;
  const spaceFormat = `[normalize-space(text()) = ${formatted}]`;
  const selections = [
    `./option${dotFormat}`,
    `./option${spaceFormat}`,
    `./optgroup/option${dotFormat}`,
    `./optgroup/option${spaceFormat}`
  ];
  const optionElement = await this.$(selections.join("|"), { strict: false });
  if (!await optionElement.isExisting()) {
    const option = await getBrowserObject48(this).execute(function(select, wanted) {
      const normalize = (value) => value.replace(/\s+/g, " ").trim();
      return Array.from(select.options || []).find((o) => normalize(o.text) === wanted || normalize(o.label) === wanted) || null;
    }, this, normalized);
    const optionId = option && typeof option === "object" ? option.elementId ?? getElementFromResponse(option) : void 0;
    if (optionId) {
      return this.elementClick(optionId);
    }
  }
  await optionElement.waitForExist({
    timeoutMsg: `Option with text "${text}" not found.`
  });
  return this.elementClick(getElementFromResponse(optionElement));
}
var init_selectByVisibleText = __esm({
  "src/commands/element/selectByVisibleText.ts"() {
    "use strict";
    init_utils2();
    init_elementCommands();
  }
});

// src/commands/element/setFiles.ts
import path8 from "node:path";
import { getBrowserObject as getBrowserObject49 } from "@wdio/utils";
async function setFiles(files) {
  const browser = getBrowserObject49(this);
  if (!browser.isBidi) {
    throw new Error(
      "setFiles requires a WebDriver BiDi session. On a classic session, use setValue with a path the local browser can already see."
    );
  }
  const list = Array.isArray(files) ? files : [files];
  if (list.length === 0) {
    throw new Error("setFiles requires at least one file path.");
  }
  const resolved = list.map((file, index) => {
    if (typeof file !== "string") {
      const where = Array.isArray(files) ? ` at index ${index}` : "";
      const received = file === null ? "null" : typeof file;
      throw new Error(`setFiles expected a file path string${where}, received ${received}.`);
    }
    return path8.resolve(file);
  });
  const context = await contextIdOf(this);
  await browser.inputSetFiles({
    context,
    element: { sharedId: this.elementId },
    files: resolved
  });
}
var init_setFiles = __esm({
  "src/commands/element/setFiles.ts"() {
    "use strict";
    init_browsingContext();
  }
});

// src/commands/element/setValue.ts
import { getBrowserObject as getBrowserObject50 } from "@wdio/utils";
async function setValue(value, options) {
  if ((typeof value === "string" || typeof value === "number") && await setsDirectly(this)) {
    const browser = getBrowserObject50(this);
    const done = await browser.execute(function setInputValue(elem, newValue) {
      if (elem.disabled || elem.readOnly) {
        return false;
      }
      const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set;
      setter.call(elem, newValue);
      elem.dispatchEvent(new Event("input", { bubbles: true }));
      elem.dispatchEvent(new Event("change", { bubbles: true }));
      return true;
    }, this, value.toString());
    if (done) {
      return;
    }
  }
  await this.clearValue();
  await clearStubbornValue(this);
  return this.addValue(value, options);
}
function noPropertyUnlessElementChanged(err) {
  if (isElementNotFoundAgain(err) || isStaleElementToFindAgain(err)) {
    throw err;
  }
  return void 0;
}
async function clearStubbornValue(elem) {
  const browser = getBrowserObject50(elem);
  if (browser.isMobile && (browser.isNativeContext || browser.isWindowsApp || browser.isMacApp)) {
    return;
  }
  const remaining = await readProperty(elem, "value");
  if (typeof remaining !== "string" || remaining === "") {
    return;
  }
  await browser.execute((el) => el.focus(), elem);
  await browser.keys([Key.Ctrl, "a"]);
  await browser.keys(Key.Backspace);
}
async function setsDirectly(elem) {
  const browser = getBrowserObject50(elem);
  if (browser.isMobile && (browser.isNativeContext || browser.isWindowsApp || browser.isMacApp)) {
    return false;
  }
  const type = await readProperty(elem, "type");
  return typeof type === "string" && SET_DIRECTLY.includes(type);
}
function readProperty(elem, name) {
  const read = isBidiCommandsEnabled(getBrowserObject50(elem)) ? bidiGetProperty(elem, name) : elem.getElementProperty(elem.elementId, name);
  return read.catch(noPropertyUnlessElementChanged);
}
var SET_DIRECTLY;
var init_setValue = __esm({
  "src/commands/element/setValue.ts"() {
    "use strict";
    init_constants();
    init_elementNotFound();
    init_utils2();
    init_elementCommands();
    SET_DIRECTLY = ["range", "date", "datetime-local", "month", "week", "time", "color"];
  }
});

// src/utils/findStrategy.ts
import { roleElements } from "aria-query";
import { knownRoles, ROLE_SYNONYMS } from "@wdio/utils";
function escapeXPathString(value) {
  if (!value.includes('"')) {
    return `"${value}"`;
  }
  if (!value.includes("'")) {
    return `'${value}'`;
  }
  const parts = [];
  for (const segment of value.split('"')) {
    if (segment.length > 0) {
      parts.push(`"${segment}"`);
    }
    parts.push(`'"'`);
  }
  parts.pop();
  return `concat(${parts.join(", ")})`;
}
function getAriaXPathSelector(label) {
  const escaped = escapeXPathString(label);
  const conditions = [
    // aria label is recevied by other element with aria-labelledBy
    // https://www.w3.org/TR/accname-1.1/#step2B
    `.//*[@aria-labelledby][id(@aria-labelledby)[normalize-space(text()) = ${escaped}]]`,
    // aria label is recevied by other element with aria-labelledBy
    // https://www.w3.org/TR/accname-1.1/#step2B
    `.//*[@aria-describedby][id(@aria-describedby)[normalize-space(text()) = ${escaped}]]`,
    // element has direct aria label
    // https://www.w3.org/TR/accname-1.1/#step2C
    `.//*[@aria-label = ${escaped}]`,
    // input and textarea with a label
    // https://www.w3.org/TR/accname-1.1/#step2D
    `.//input[@id][@id = (//label[normalize-space() = ${escaped}]/@for)]`,
    `.//textarea[@id][@id = (//label[normalize-space() = ${escaped}]/@for)]`,
    // input and textarea with a label as parent
    // https://www.w3.org/TR/accname-1.1/#step2D
    `.//input[ancestor::label[normalize-space(text()) = ${escaped}]]`,
    `.//textarea[ancestor::label[normalize-space(text()) = ${escaped}]]`,
    // aria label is received by a placeholder
    // https://www.w3.org/TR/accname-1.1/#step2D
    `.//input[@placeholder=${escaped}]`,
    `.//textarea[@placeholder=${escaped}]`,
    // aria label is received by a aria-placeholder
    // https://www.w3.org/TR/accname-1.1/#step2D
    `.//input[@aria-placeholder=${escaped}]`,
    `.//textarea[@aria-placeholder=${escaped}]`,
    // aria label is received by a title
    // https://www.w3.org/TR/accname-1.1/#step2D
    `.//*[not(self::label)][@title=${escaped}]`,
    // images with an alt tag
    // https://www.w3.org/TR/accname-1.1/#step2D
    `.//img[@alt=${escaped}]`,
    // aria label is received from element text content
    // https://www.w3.org/TR/accname-1.1/#step2G
    `.//*[not(self::label)][normalize-space(text()) = ${escaped}]`
  ];
  return conditions.join(" | ");
}
function editDistance(a, b) {
  const row = Array.from({ length: b.length + 1 }, (_, i) => i);
  for (let i = 1; i <= a.length; i++) {
    let previous = row[0];
    row[0] = i;
    for (let j = 1; j <= b.length; j++) {
      const current = row[j];
      row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
      previous = current;
    }
  }
  return row[b.length];
}
function parseRoleSelector(selector) {
  const match = selector.match(ROLE_SELECTOR_REGEXP);
  if (!match) {
    throw new Error(
      `InvalidSelectorMatch. Strategy 'role' has failed to match '${selector}'. Expected \`role/<role>\` or \`role/<role>[name="<accessible name>"]\`.`
    );
  }
  const role = match[1];
  const roles = knownRoles();
  if (!roles.includes(role)) {
    const closest = roles.reduce((best, candidate) => editDistance(role, candidate) < editDistance(role, best) ? candidate : best);
    throw new Error(
      `InvalidSelectorMatch. Strategy 'role' has failed to match '${selector}': "${role}" is not an ARIA role. Did you mean "${closest}"?`
    );
  }
  const canonicalRole = ROLE_SYNONYMS[role] || role;
  const rawName = match[2] ?? match[3];
  return rawName === void 0 ? { role: canonicalRole } : { role: canonicalRole, name: rawName.replace(/\\(.)/g, "$1") };
}
var DEFAULT_STRATEGY, DIRECT_SELECTOR_REGEXP, XPATH_SELECTORS_START, NAME_MOBILE_SELECTORS_START, XPATH_SELECTOR_REGEXP, IMAGEPATH_MOBILE_SELECTORS_ENDSWITH, defineStrategy, ROLE_SELECTOR_REGEXP, findStrategy, createRoleBaseXpathSelector;
var init_findStrategy = __esm({
  "src/utils/findStrategy.ts"() {
    "use strict";
    init_environment();
    init_constants();
    DEFAULT_STRATEGY = "css selector";
    DIRECT_SELECTOR_REGEXP = /^(id|css selector|xpath|link text|partial link text|name|tag name|class name|-android uiautomator|-android datamatcher|-android viewmatcher|-android viewtag|-ios uiautomation|-ios predicate string|-ios class chain|accessibility id):(.+)/;
    XPATH_SELECTORS_START = [
      "/",
      "(",
      "../",
      "./",
      "*/"
    ];
    NAME_MOBILE_SELECTORS_START = [
      "uia",
      "xcuielementtype",
      "android.widget",
      "cyi",
      "android.view"
    ];
    XPATH_SELECTOR_REGEXP = [
      // HTML tag
      /^([a-z0-9|-]*)/,
      // optional . or # + class or id
      /(?:(\.|#)(-?[_a-zA-Z]+[_a-zA-Z0-9-]*))?/,
      // optional [attribute-name="attribute-selector"]
      /(?:\[(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)(?:=(?:"|')([a-zA-Z0-9\-_. ]+)(?:"|'))?\])?/,
      // optional case insensitive
      /(\.)?/,
      // *=query or =query
      /(\*)?=(.+)$/
    ];
    IMAGEPATH_MOBILE_SELECTORS_ENDSWITH = [
      ".jpg",
      ".jpeg",
      ".gif",
      ".png",
      ".bmp",
      ".svg"
    ];
    defineStrategy = function(selector) {
      if (typeof selector === "object") {
        if (JSON.stringify(selector).indexOf("test.espresso.matcher.ViewMatchers") < 0) {
          return "-android datamatcher";
        }
        return "-android viewmatcher";
      }
      const stringSelector = selector;
      if (DIRECT_SELECTOR_REGEXP.test(stringSelector)) {
        return "directly";
      }
      if (IMAGEPATH_MOBILE_SELECTORS_ENDSWITH.some((path9) => {
        const selector2 = stringSelector.toLowerCase();
        return selector2.endsWith(path9) && selector2 !== path9;
      })) {
        return "-image";
      }
      if (XPATH_SELECTORS_START.some((option) => stringSelector.startsWith(option))) {
        return "xpath";
      }
      if (stringSelector.startsWith("=")) {
        return "link text";
      }
      if (stringSelector.startsWith("*=")) {
        return "partial link text";
      }
      if (stringSelector.startsWith("id=")) {
        return "id";
      }
      if (stringSelector.startsWith(DEEP_SELECTOR)) {
        return "shadow";
      }
      if (stringSelector.startsWith(ARIA_SELECTOR)) {
        return "aria";
      }
      if (stringSelector.startsWith(ROLE_SELECTOR)) {
        return "role selector";
      }
      if (stringSelector.startsWith("android=")) {
        return "-android uiautomator";
      }
      if (stringSelector.startsWith("ios=")) {
        return "-ios uiautomation";
      }
      if (stringSelector.startsWith("~")) {
        return "accessibility id";
      }
      if (NAME_MOBILE_SELECTORS_START.some((option) => stringSelector.toLowerCase().startsWith(option))) {
        return "class name";
      }
      if (stringSelector.search(/<[0-9a-zA-Z-]+( \/)*>/g) >= 0) {
        return "tag name";
      }
      if (stringSelector.search(/^\[name=(?:"(.[^"]*)"|'(.[^']*)')]$/) >= 0) {
        return "name";
      }
      if (selector === ".." || selector === ".") {
        return "xpath";
      }
      if (stringSelector.match(new RegExp(XPATH_SELECTOR_REGEXP.map((rx) => rx.source).join("")))) {
        return "xpath extended";
      }
      if (/^\[role=[A-Za-z]+]$/.test(stringSelector)) {
        return "role";
      }
    };
    ROLE_SELECTOR_REGEXP = /^role\/([a-zA-Z]+)(?:\[name=(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')\])?$/;
    findStrategy = function(selector, isMobile, isBidi2) {
      const stringSelector = selector;
      let using = DEFAULT_STRATEGY;
      let value = selector;
      switch (defineStrategy(selector)) {
        // user has specified locator strategy directly
        case "directly": {
          const match = stringSelector.match(DIRECT_SELECTOR_REGEXP);
          if (!match) {
            throw new Error("InvalidSelectorStrategy");
          }
          using = match[1];
          value = match[2];
          break;
        }
        case "xpath": {
          using = "xpath";
          break;
        }
        case "id": {
          using = "id";
          value = stringSelector.slice(3);
          break;
        }
        case "link text": {
          using = "link text";
          value = stringSelector.slice(1);
          break;
        }
        case "partial link text": {
          using = "partial link text";
          value = stringSelector.slice(2);
          break;
        }
        case "shadow":
          using = "shadow";
          value = stringSelector.slice(DEEP_SELECTOR.length);
          break;
        case "role selector": {
          using = "role";
          value = JSON.stringify(parseRoleSelector(stringSelector));
          break;
        }
        case "aria": {
          const label = stringSelector.slice(ARIA_SELECTOR.length);
          if (isBidi2) {
            using = "aria";
            value = label;
          } else {
            using = "xpath";
            value = getAriaXPathSelector(label);
          }
          break;
        }
        case "-android uiautomator": {
          using = "-android uiautomator";
          value = stringSelector.slice(8);
          break;
        }
        case "-android datamatcher": {
          using = "-android datamatcher";
          value = JSON.stringify(value);
          break;
        }
        case "-android viewmatcher": {
          using = "-android viewmatcher";
          value = JSON.stringify(value);
          break;
        }
        case "-ios uiautomation": {
          using = "-ios uiautomation";
          value = stringSelector.slice(4);
          break;
        }
        case "accessibility id": {
          using = "accessibility id";
          value = stringSelector.slice(1);
          break;
        }
        case "class name": {
          using = "class name";
          break;
        }
        case "tag name": {
          using = "tag name";
          value = stringSelector.replace(/<|>|\/|\s/g, "");
          break;
        }
        case "name": {
          if (isMobile) {
            const match = stringSelector.match(/^\[name=(?:"(.[^"]*)"|'(.[^']*)')]$/);
            if (!match) {
              throw new Error(`InvalidSelectorMatch. Strategy 'name' has failed to match '${stringSelector}'`);
            }
            using = "name";
            value = match[1] || match[2];
          }
          break;
        }
        case "xpath extended": {
          using = "xpath";
          const match = stringSelector.match(new RegExp(XPATH_SELECTOR_REGEXP.map((rx) => rx.source).join("")));
          if (!match) {
            throw new Error(`InvalidSelectorMatch: Strategy 'xpath extended' has failed to match '${stringSelector}'`);
          }
          const PREFIX_NAME = { ".": "class", "#": "id" };
          const conditions = [];
          const [
            tag,
            prefix,
            name,
            attrName,
            attrValue,
            insensitive,
            partial,
            query
          ] = match.slice(1);
          if (prefix) {
            if (prefix === ".") {
              conditions.push(`contains(concat(" ",@${PREFIX_NAME[prefix]}," "), " ${name} ")`);
            } else {
              conditions.push(`contains(@${PREFIX_NAME[prefix]}, "${name}")`);
            }
          }
          if (attrName) {
            conditions.push(
              attrValue ? `contains(@${attrName}, "${attrValue}")` : `@${attrName}`
            );
          }
          const partialNot = ` and not(${`.//${tag || "*"}${conditions.length ? `[${conditions.join(" and ")}]` : ""}`})`;
          if (insensitive) {
            conditions.push(
              partial ? `contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), "${query.toLowerCase()}")${partialNot}` : `normalize-space(translate(text(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")) = "${query.toLowerCase()}"`
            );
          } else {
            conditions.push(partial ? `contains(., "${query}")${partialNot}` : `normalize-space(text()) = "${query}"`);
          }
          const getValue2 = () => `.//${tag || "*"}[${conditions.join(" and ")}]`;
          value = getValue2();
          if (!partial) {
            conditions.pop();
            conditions.push(
              `not(${value})`,
              `normalize-space() = "${insensitive ? query.toLowerCase() : query}"`
            );
            value = value + " | " + getValue2();
          }
          break;
        }
        case "-image": {
          using = "-image";
          value = environment.value.readFileSync(stringSelector, { encoding: "base64" });
          break;
        }
        case "role": {
          const match = stringSelector.match(/^\[role=(.+)\]/);
          if (!match) {
            throw new Error(`InvalidSelectorMatch. Strategy 'role' has failed to match '${stringSelector}'`);
          }
          using = "css selector";
          value = createRoleBaseXpathSelector(match[1]);
          break;
        }
      }
      return { using, value };
    };
    createRoleBaseXpathSelector = (role) => {
      const locatorArr = [];
      roleElements.get(role)?.forEach((value) => {
        let locator;
        let tagAttribute, tagAttributevalue;
        const tagname = value.name;
        if (value.attributes instanceof Array) {
          value.attributes.forEach((val) => {
            tagAttribute = val.name;
            tagAttributevalue = val.value;
          });
        }
        if (!tagAttribute) {
          locator = tagname;
        } else if (!tagAttributevalue) {
          locator = `${tagname}[${tagAttribute}]`;
        } else {
          locator = `${tagname}[${tagAttribute}="${tagAttributevalue}"]`;
        }
        locatorArr.push(locator);
      });
      let xpathLocator = `[role="${role}"]`;
      locatorArr.forEach((loc) => {
        xpathLocator += "," + loc;
      });
      return xpathLocator;
    };
  }
});

// src/utils/bidi/locate.ts
import { ELEMENT_KEY as ELEMENT_KEY17 } from "webdriver";
function isParallelContextActive() {
  return Boolean(getParallelContextStore().getStore());
}
async function locateRelativeXPath(browser, context, elementId, expression) {
  const result = await browser.browsingContextLocateNodes({
    locator: { type: "xpath", value: expression },
    context,
    startNodes: [{ sharedId: elementId }]
  });
  return result.nodes.filter((node) => Boolean(node.sharedId)).map((node) => ({ [ELEMENT_KEY17]: node.sharedId }));
}
var init_locate = __esm({
  "src/utils/bidi/locate.ts"() {
    "use strict";
    init_context();
  }
});

// src/commands/element/shadow$$.ts
import logger26 from "@wdio/logger";
import { getBrowserObject as getBrowserObject51 } from "@wdio/utils";
import { SHADOW_ELEMENT_KEY as SHADOW_ELEMENT_KEY3 } from "webdriver";
import { shadowFnFactory } from "./scripts/shadowFnFactory.js";
function shadow$$(selector) {
  return ElementArray.fromAsyncCallback(async () => {
    const browser = getBrowserObject51(this);
    if (isParallelContextActive() || await foreignContext(this)) {
      return [...await this.$$(shadowFnFactory(selector, true))];
    }
    try {
      const shadowRoot = await browser.getElementShadowRoot(this.elementId);
      const { using, value } = findStrategy(selector, this.isMobile);
      const res = await browser.findElementsFromShadowRoot(shadowRoot[SHADOW_ELEMENT_KEY3], using, value);
      return await getElements.call(this, selector, res, { isShadowElement: true });
    } catch (err) {
      log26.warn(
        `Failed to fetch element within shadow DOM using WebDriver command: ${err.message}!
Falling back to JavaScript shim.`
      );
      const fallback = await this.$$(shadowFnFactory(selector, true));
      return [...fallback];
    }
  }, {
    selector,
    foundWith: "shadow$$",
    parent: this,
    props: []
  });
}
var log26;
var init_shadow = __esm({
  "src/commands/element/shadow$$.ts"() {
    "use strict";
    init_getElementObject();
    init_array();
    init_findStrategy();
    init_foreignContext();
    init_locate();
    log26 = logger26("webdriverio");
  }
});

// src/commands/element/shadow$.ts
import logger27 from "@wdio/logger";
import { SHADOW_ELEMENT_KEY as SHADOW_ELEMENT_KEY4 } from "webdriver";
import { shadowFnFactory as shadowFnFactory2 } from "./scripts/shadowFnFactory.js";
import { getBrowserObject as getBrowserObject52 } from "@wdio/utils";
async function shadow$(selector) {
  const browser = getBrowserObject52(this);
  if (isParallelContextActive() || await foreignContext(this)) {
    return this.$(shadowFnFactory2(selector), { strict: false });
  }
  try {
    const shadowRoot = await browser.getElementShadowRoot(this.elementId);
    const { using, value } = findStrategy(selector, this.isMobile);
    const res = await browser.findElementFromShadowRoot(shadowRoot[SHADOW_ELEMENT_KEY4], using, value);
    return getElement.call(this, selector, res, { isShadowElement: true, strict: false });
  } catch (err) {
    log27.warn(
      `Failed to fetch element within shadow DOM using WebDriver command: ${err.message}!
Falling back to JavaScript shim.`
    );
    return this.$(shadowFnFactory2(selector), { strict: false });
  }
}
var log27;
var init_shadow2 = __esm({
  "src/commands/element/shadow$.ts"() {
    "use strict";
    init_getElementObject();
    init_findStrategy();
    init_foreignContext();
    init_locate();
    log27 = logger27("webdriverio");
  }
});

// src/commands/element/waitForClickable.ts
import { getBrowserObject as getBrowserObject53 } from "@wdio/utils";
async function waitForClickable({
  timeout = this.options.waitforTimeout,
  interval = this.options.waitforInterval,
  reverse = false,
  timeoutMsg = `element ("${describeSelector(this)}") still ${reverse ? "" : "not "}clickable after ${timeout}ms`
} = {}) {
  const browser = getBrowserObject53(this);
  if (browser.isMobile && browser.isNativeContext && !browser.capabilities?.browserName) {
    throw new Error("The `waitForClickable` command is only available for desktop and mobile browsers.");
  }
  return this.waitUntil(
    async () => reverse !== await this.isClickable(),
    { timeout, timeoutMsg, interval }
  );
}
var init_waitForClickable = __esm({
  "src/commands/element/waitForClickable.ts"() {
    "use strict";
    init_describeSelector();
  }
});

// src/commands/element/waitForDisplayed.ts
function waitForDisplayed({
  timeout = this.options.waitforTimeout,
  interval = this.options.waitforInterval,
  reverse = false,
  withinViewport = false,
  contentVisibilityAuto = true,
  opacityProperty = true,
  visibilityProperty = true,
  timeoutMsg = `element ("${describeSelector(this)}") still ${reverse ? "" : "not "}displayed${withinViewport ? " within viewport" : ""} after ${timeout}ms`
} = {}) {
  return this.waitUntil(
    async () => reverse !== await this.isDisplayed({ withinViewport, contentVisibilityAuto, opacityProperty, visibilityProperty }),
    { timeout, interval, timeoutMsg }
  );
}
var init_waitForDisplayed = __esm({
  "src/commands/element/waitForDisplayed.ts"() {
    "use strict";
    init_describeSelector();
  }
});

// src/commands/element/waitForEnabled.ts
async function waitForEnabled({
  timeout = this.options.waitforTimeout,
  interval = this.options.waitforInterval,
  reverse = false,
  timeoutMsg = `element ("${describeSelector(this)}") still ${reverse ? "" : "not "}enabled after ${timeout}ms`
} = {}) {
  if (!this.elementId && !reverse) {
    await this.waitForExist({ timeout, interval, timeoutMsg });
  }
  return this.waitUntil(
    async () => reverse !== await this.isEnabled(),
    { timeout, interval, timeoutMsg }
  );
}
var init_waitForEnabled = __esm({
  "src/commands/element/waitForEnabled.ts"() {
    "use strict";
    init_describeSelector();
  }
});

// src/commands/element/waitForExist.ts
import { ELEMENT_KEY as ELEMENT_KEY18 } from "webdriver";
import { getBrowserObject as getBrowserObject54 } from "@wdio/utils";
async function waitForExist({
  timeout = this.options.waitforTimeout,
  interval = this.options.waitforInterval,
  reverse = false,
  timeoutMsg = `element ("${describeSelector(this)}") still ${reverse ? "" : "not "}existing after ${timeout}ms`
} = {}) {
  const isExisting2 = await this.waitUntil(
    async () => reverse !== await this.isExisting(),
    { timeout, interval, timeoutMsg }
  );
  if (!reverse && isExisting2 && canFindAgain(this)) {
    let isCurrentIdValid = false;
    if (this.elementId) {
      try {
        const browser = getBrowserObject54(this);
        await (isBidiCommandsEnabled(browser) ? bidiGetTagName(this) : this.getElementTagName(this.elementId));
        isCurrentIdValid = true;
      } catch {
      }
    }
    if (!isCurrentIdValid) {
      const element = await findElementAgain(this, { wait: true });
      this.elementId = element?.elementId;
      this[ELEMENT_KEY18] = this.elementId;
    }
    delete this.error;
  }
  return isExisting2;
}
var init_waitForExist = __esm({
  "src/commands/element/waitForExist.ts"() {
    "use strict";
    init_findElementAgain();
    init_elementCommands();
    init_describeSelector();
  }
});

// src/commands/element/waitForStable.ts
import { getBrowserObject as getBrowserObject55 } from "@wdio/utils";
async function waitForStable({
  timeout = this.options.waitforTimeout,
  interval = this.options.waitforInterval,
  reverse = false,
  timeoutMsg = `element ("${describeSelector(this)}") still ${reverse ? "" : "not "}stable after ${timeout}ms`
} = {}) {
  let failure;
  const browser = getBrowserObject55(this);
  if (browser.isMobile && browser.isNativeContext) {
    throw new Error("The `waitForStable` command is only available for desktop and mobile browsers.");
  }
  await this.waitUntil(
    async () => {
      failure = void 0;
      try {
        return reverse !== await this.isStable();
      } catch (error2) {
        failure = { error: error2 };
        return !reverse;
      }
    },
    { timeout, interval, timeoutMsg }
  );
  if (!failure) {
    return;
  }
  const { error } = failure;
  if (isElementNotFoundAgain(error)) {
    throw error;
  }
  const errorMsg = error instanceof Error ? error.message : typeof error === "string" ? error : "";
  throw Error(errorMsg || "The waitForStable command got an unknown error");
}
var init_waitForStable = __esm({
  "src/commands/element/waitForStable.ts"() {
    "use strict";
    init_describeSelector();
    init_elementNotFound();
  }
});

// src/commands/element/waitUntil.ts
var waitUntil2;
var init_waitUntil2 = __esm({
  "src/commands/element/waitUntil.ts"() {
    "use strict";
    init_waitUntil();
    waitUntil2 = waitUntil;
  }
});

// src/commands/mobile/dragAndDrop.ts
var init_dragAndDrop2 = __esm({
  "src/commands/mobile/dragAndDrop.ts"() {
    "use strict";
  }
});

// src/commands/mobile/longPress.ts
import { getBrowserObject as getBrowserObject56 } from "@wdio/utils";
function longPress(options) {
  const browser = getBrowserObject56(this);
  if (!browser.isMobile) {
    throw new Error("The longPress command is only available for mobile platforms.");
  }
  if (typeof options !== "undefined" && (typeof options !== "object" || Array.isArray(options))) {
    throw new TypeError("Options must be an object");
  }
  const defaultOptions = {
    duration: 1500,
    x: 0,
    y: 0
  };
  const { duration, x, y } = { ...defaultOptions, ...options };
  if (!browser.isNativeContext && browser.isIOS) {
    return browser.execute(
      (el, duration2) => {
        const touchStart = new TouchEvent("touchstart", {
          touches: [new Touch({ identifier: 0, target: el, clientX: 0, clientY: 0 })],
          bubbles: true,
          cancelable: true
        });
        el.dispatchEvent(touchStart);
        setTimeout(() => {
          const touchEnd = new TouchEvent("touchend", {
            changedTouches: [new Touch({ identifier: 0, target: el, clientX: 0, clientY: 0 })],
            bubbles: true,
            cancelable: true
          });
          el.dispatchEvent(touchEnd);
        }, duration2);
      },
      this,
      duration
    );
  }
  return this.click({ duration, x, y });
}
var init_longPress = __esm({
  "src/commands/mobile/longPress.ts"() {
    "use strict";
  }
});

// src/commands/mobile/pinch.ts
import { getBrowserObject as getBrowserObject57 } from "@wdio/utils";
async function pinch(options = {}) {
  const browser = getBrowserObject57(this);
  if (!browser.isMobile) {
    throw new Error("The pinch command is only available for mobile platforms.");
  }
  const { duration, scale } = validatePinchAndZoomOptions({ browser, gesture: "pinch", options });
  const gestureConfig = browser.isIOS ? {
    elementId: await this.elementId,
    scale,
    velocity: -Math.abs(duration)
    // Velocity is always negative for iOS pinch
  } : {
    elementId: await this.elementId,
    percent: scale,
    speed: calculateAndroidPinchAndZoomSpeed({ browser, duration, scale })
  };
  return browser.execute(browser.isIOS ? "mobile: pinch" : "mobile: pinchCloseGesture", gestureConfig);
}
var init_pinch = __esm({
  "src/commands/mobile/pinch.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/mobile/zoom.ts
import { getBrowserObject as getBrowserObject58 } from "@wdio/utils";
async function zoom(options = {}) {
  const browser = getBrowserObject58(this);
  if (!browser.isMobile) {
    throw new Error("The zoom command is only available for mobile platforms.");
  }
  const { duration, scale } = validatePinchAndZoomOptions({ browser, gesture: "zoom", options });
  const gestureConfig = browser.isIOS ? {
    elementId: await this.elementId,
    scale,
    velocity: duration
  } : {
    elementId: await this.elementId,
    percent: scale,
    speed: calculateAndroidPinchAndZoomSpeed({ browser, duration, scale })
  };
  return browser.execute(browser.isIOS ? "mobile: pinch" : "mobile: pinchOpenGesture", gestureConfig);
}
var init_zoom = __esm({
  "src/commands/mobile/zoom.ts"() {
    "use strict";
    init_mobile();
  }
});

// src/commands/element.ts
var element_exports = {};
__export(element_exports, {
  $: () => $2,
  $$: () => $$2,
  addValue: () => addValue,
  clearValue: () => clearValue,
  click: () => click,
  custom$: () => custom$2,
  custom$$: () => custom$$2,
  doubleClick: () => doubleClick,
  dragAndDrop: () => dragAndDrop,
  execute: () => execute2,
  getAttribute: () => getAttribute,
  getCSSProperty: () => getCSSProperty,
  getComputedLabel: () => getComputedLabel,
  getComputedRole: () => getComputedRole,
  getElement: () => getElement2,
  getHTML: () => getHTML,
  getLocation: () => getLocation,
  getProperty: () => getProperty,
  getSize: () => getSize,
  getTagName: () => getTagName,
  getText: () => getText,
  getValue: () => getValue,
  isClickable: () => isClickable,
  isDisplayed: () => isDisplayed,
  isEnabled: () => isEnabled,
  isEqual: () => isEqual,
  isExisting: () => isExisting,
  isFocused: () => isFocused,
  isSelected: () => isSelected,
  isStable: () => isStable,
  longPress: () => longPress,
  moveTo: () => moveTo,
  nextElement: () => nextElement,
  parentElement: () => parentElement,
  pinch: () => pinch,
  previousElement: () => previousElement,
  react$: () => react$2,
  react$$: () => react$$2,
  saveScreenshot: () => saveScreenshot3,
  scrollIntoView: () => scrollIntoView,
  selectByAttribute: () => selectByAttribute,
  selectByIndex: () => selectByIndex,
  selectByVisibleText: () => selectByVisibleText,
  setFiles: () => setFiles,
  setValue: () => setValue,
  shadow$: () => shadow$,
  shadow$$: () => shadow$$,
  tap: () => tap,
  waitForClickable: () => waitForClickable,
  waitForDisplayed: () => waitForDisplayed,
  waitForEnabled: () => waitForEnabled,
  waitForExist: () => waitForExist,
  waitForStable: () => waitForStable,
  waitUntil: () => waitUntil2,
  zoom: () => zoom
});
var init_element = __esm({
  "src/commands/element.ts"() {
    "use strict";
    init__3();
    init__4();
    init_addValue();
    init_clearValue();
    init_click();
    init_custom3();
    init_custom4();
    init_doubleClick();
    init_dragAndDrop();
    init_execute2();
    init_getAttribute();
    init_getCSSProperty();
    init_getComputedRole();
    init_getComputedLabel();
    init_getElement();
    init_getHTML();
    init_getLocation();
    init_getProperty();
    init_getSize();
    init_getTagName();
    init_getText();
    init_getValue();
    init_isClickable();
    init_isDisplayed();
    init_isEnabled();
    init_isEqual();
    init_isExisting();
    init_isFocused();
    init_isSelected();
    init_isStable();
    init_moveTo();
    init_nextElement();
    init_parentElement();
    init_previousElement();
    init_react3();
    init_react4();
    init_saveScreenshot2();
    init_scrollIntoView();
    init_selectByAttribute();
    init_selectByIndex();
    init_selectByVisibleText();
    init_setFiles();
    init_setValue();
    init_shadow();
    init_shadow2();
    init_waitForClickable();
    init_waitForDisplayed();
    init_waitForEnabled();
    init_waitForExist();
    init_waitForStable();
    init_waitUntil2();
    init_dragAndDrop2();
    init_longPress();
    init_pinch();
    init_tap();
    init_zoom();
  }
});

// src/utils/thirdParty/querySelectorShadowDom.ts
function querySelectorAllDeep(findMany, s, r) {
  function normalizeSelector2(sel) {
    function saveUnmatched() {
      if (unmatched) {
        if (tokens.length > 0 && /^[~+>]$/.test(tokens[tokens.length - 1])) {
          tokens.push(" ");
        }
        tokens.push(unmatched);
      }
    }
    const tokens = [], state = [0], not_escaped_pattern = /(?:[^\\]|(?:^|[^\\])(?:\\\\)+)$/, whitespace_pattern = /^\s+$/, state_patterns = [
      /\s+|\/\*|["'>~+[(]/g,
      // general
      /\s+|\/\*|["'[\]()]/g,
      // [..] set
      /\s+|\/\*|["'[\]()]/g,
      // (..) set
      null,
      // string literal (placeholder)
      /\*\//g
      // comment
    ];
    let match, unmatched, regex, next_match_idx = 0, prev_match_idx;
    sel = sel.trim();
    while (true) {
      unmatched = "";
      regex = state_patterns[state[state.length - 1]];
      regex.lastIndex = next_match_idx;
      match = regex.exec(sel);
      if (match) {
        prev_match_idx = next_match_idx;
        next_match_idx = regex.lastIndex;
        if (prev_match_idx < next_match_idx - match[0].length) {
          unmatched = sel.substring(
            prev_match_idx,
            next_match_idx - match[0].length
          );
        }
        if (state[state.length - 1] < 3) {
          saveUnmatched();
          if (match[0] === "[") {
            state.push(1);
          } else if (match[0] === "(") {
            state.push(2);
          } else if (/^["']$/.test(match[0])) {
            state.push(3);
            state_patterns[3] = new RegExp(match[0], "g");
          } else if (match[0] === "/*") {
            state.push(4);
          } else if (/^[\])]$/.test(match[0]) && state.length > 0) {
            state.pop();
          } else if (/^(?:\s+|[~+>])$/.test(match[0])) {
            if (tokens.length > 0 && !whitespace_pattern.test(tokens[tokens.length - 1]) && state[state.length - 1] === 0) {
              tokens.push(" ");
            }
            if (state[state.length - 1] === 1 && tokens.length === 5 && tokens[2].charAt(tokens[2].length - 1) === "=") {
              tokens[4] = " " + tokens[4];
            }
            if (whitespace_pattern.test(match[0])) {
              continue;
            }
          }
          tokens.push(match[0]);
        } else {
          tokens[tokens.length - 1] += unmatched;
          if (not_escaped_pattern.test(tokens[tokens.length - 1])) {
            if (state[state.length - 1] === 4) {
              if (tokens.length < 2 || whitespace_pattern.test(tokens[tokens.length - 2])) {
                tokens.pop();
              } else {
                tokens[tokens.length - 1] = " ";
              }
              match[0] = "";
            }
            state.pop();
          }
          tokens[tokens.length - 1] += match[0];
        }
      } else {
        unmatched = sel.substr(next_match_idx);
        saveUnmatched();
        break;
      }
    }
    return tokens.join("").trim();
  }
  function _querySelectorDeep(selector, root, allElements = null) {
    selector = normalizeSelector2(selector);
    const lightElement = root.querySelector(selector);
    if (document.head.createShadowRoot || document.head.attachShadow) {
      if (!findMany && lightElement) {
        return lightElement;
      }
      const selectionsToMake = splitByCharacterUnlessQuoted(selector, ",");
      return selectionsToMake.reduce((acc, minimalSelector) => {
        if (!findMany && acc) {
          return acc;
        }
        const splitSelector = splitByCharacterUnlessQuoted(minimalSelector.replace(/^\s+/g, "").replace(/\s*([>+~]+)\s*/g, "$1"), " ").filter((entry) => !!entry).map((entry) => splitByCharacterUnlessQuoted(entry, ">"));
        const possibleElementsIndex = splitSelector.length - 1;
        const lastSplitPart = splitSelector[possibleElementsIndex][splitSelector[possibleElementsIndex].length - 1];
        const possibleElements = collectAllElementsDeep(lastSplitPart, root, allElements);
        const findElements2 = findMatchingElement(splitSelector, possibleElementsIndex, root);
        if (findMany) {
          acc = acc.concat(possibleElements.filter(findElements2));
          return acc;
        }
        acc = possibleElements.find(findElements2);
        return acc || null;
      }, findMany ? [] : null);
    }
    return !findMany ? lightElement : root.querySelectorAll(selector);
  }
  function findMatchingElement(splitSelector, possibleElementsIndex, root) {
    return (element) => {
      let position = possibleElementsIndex;
      let parent = element;
      let foundElement = false;
      while (parent && !isDocumentNode(parent)) {
        let foundMatch = true;
        if (splitSelector[position].length === 1) {
          foundMatch = parent.matches(splitSelector[position]);
        } else {
          const reversedParts = [].concat(splitSelector[position]).reverse();
          let newParent = parent;
          for (const part of reversedParts) {
            if (!newParent || !newParent.matches(part)) {
              foundMatch = false;
              break;
            }
            newParent = findParentOrHost(newParent, root);
          }
        }
        if (foundMatch && position === 0) {
          foundElement = true;
          break;
        }
        if (foundMatch) {
          position--;
        }
        parent = findParentOrHost(parent, root);
      }
      return foundElement;
    };
  }
  function splitByCharacterUnlessQuoted(selector, character) {
    return selector.match(/\\?.|^$/g).reduce((p, c) => {
      if (c === '"' && !p.sQuote) {
        p.quote ^= 1;
        p.a[p.a.length - 1] += c;
      } else if (c === "'" && !p.quote) {
        p.sQuote ^= 1;
        p.a[p.a.length - 1] += c;
      } else if (!p.quote && !p.sQuote && c === character) {
        p.a.push("");
      } else {
        p.a[p.a.length - 1] += c;
      }
      return p;
    }, { a: [""] }).a;
  }
  function isDocumentNode(node) {
    return node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.DOCUMENT_NODE;
  }
  function findParentOrHost(element, root) {
    const parentNode = element.parentNode;
    return parentNode && parentNode.host && parentNode.nodeType === 11 ? parentNode.host : parentNode === root ? null : parentNode;
  }
  function collectAllElementsDeep(selector = null, root, cachedElements = null) {
    let allElements = [];
    if (cachedElements) {
      allElements = cachedElements;
    } else {
      const findAllElements = function(nodes) {
        for (let i = 0; i < nodes.length; i++) {
          const el = nodes[i];
          allElements.push(el);
          if (el.shadowRoot) {
            findAllElements(el.shadowRoot.querySelectorAll("*"));
          }
        }
      };
      const shadowRoot = root.shadowRoot;
      if (shadowRoot) {
        findAllElements(shadowRoot.querySelectorAll("*"));
      }
      findAllElements(root.querySelectorAll("*"));
    }
    return selector ? allElements.filter((el) => el.matches(selector)) : allElements;
  }
  return _querySelectorDeep(s, r || document);
}
var init_querySelectorShadowDom = __esm({
  "src/utils/thirdParty/querySelectorShadowDom.ts"() {
    "use strict";
  }
});

// src/utils/index.ts
import cssValue from "css-value";
import rgb2hex from "rgb2hex";
import GraphemeSplitter from "grapheme-splitter";
import logger28 from "@wdio/logger";
import isPlainObject4 from "is-plain-obj";
import { ELEMENT_KEY as ELEMENT_KEY19 } from "webdriver";
import { UNICODE_CHARACTERS as UNICODE_CHARACTERS2, WDIO_KIND as WDIO_KIND2, getBrowserObject as getBrowserObject59, isLoadedElement as isLoadedElement2 } from "@wdio/utils";
import findByRole, { ACCESSIBILITY_API_MISSING } from "./scripts/findByRole.js";
function sanitizeCSS(value) {
  if (!value) {
    return value;
  }
  return value.trim().replace(/'/g, "").replace(/"/g, "").toLowerCase();
}
function parseCSS(cssPropertyValue, cssProperty) {
  const parsedValue = {
    property: cssProperty,
    value: cssPropertyValue.toLowerCase().trim(),
    parsed: {}
  };
  if (parsedValue.value?.indexOf("rgb") === 0) {
    parsedValue.value = parsedValue.value.replace(/\s/g, "");
    const color = parsedValue.value;
    parsedValue.parsed = rgb2hex(parsedValue.value);
    parsedValue.parsed.type = "color";
    const colorType = /[rgba]+/g.exec(color) || [];
    parsedValue.parsed[colorType[0]] = color;
  } else if (parsedValue.property === "font-family") {
    const font = cssValue(cssPropertyValue);
    const string = parsedValue.value;
    const value = cssPropertyValue.split(/,/).map(sanitizeCSS);
    parsedValue.value = sanitizeCSS(font[0].value || font[0].string);
    parsedValue.parsed = { value, type: "font", string };
  } else {
    try {
      const value = cssValue(cssPropertyValue);
      if (value.length === 1) {
        parsedValue.parsed = value[0];
      }
      if (parsedValue.parsed.type && parsedValue.parsed.type === "number" && parsedValue.parsed.unit === "") {
        parsedValue.value = parsedValue.parsed.value;
      }
    } catch {
    }
  }
  return parsedValue;
}
function checkUnicode(value) {
  if (value === Key.Ctrl) {
    return [value];
  }
  if (!Object.prototype.hasOwnProperty.call(UNICODE_CHARACTERS2, value)) {
    return new GraphemeSplitter().splitGraphemes(value);
  }
  return [UNICODE_CHARACTERS2[value]];
}
function strategyScope(scope, browserObject) {
  return "elementId" in scope ? browserObject : scope;
}
function fetchElementByJSFunction(selector, scope, referenceId) {
  if (!("elementId" in scope)) {
    return scope.execute(selector, referenceId);
  }
  const script = (function(elem, id) {
    return selector.call(elem, id);
  }).toString().replace("selector", `(${selector.toString()})`);
  const args = [scope];
  if (referenceId) {
    args.push(referenceId);
  }
  const browser = getBrowserObject59(scope);
  if (browser.isBidi && (heldBrowsingContext(scope) || isParallelContextActive())) {
    return scope.execute(
      `const result = (${script}).apply(null, arguments); return result && typeof result.length === "number" && typeof result !== "string" && !result.nodeType ? Array.from(result) : result`,
      ...args.slice(1)
    );
  }
  return browser.executeScript(`return (${script}).apply(null, arguments)`, args);
}
function isElement(o) {
  return typeof HTMLElement === "object" ? o instanceof HTMLElement : o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string";
}
function isStaleElementError(err) {
  return (
    // Chrome
    err.message.includes("stale element reference") || // Firefox
    err.message.includes("is no longer attached to the DOM") || // Safari
    err.message.toLowerCase().includes("stale element found") || // Chrome through JS execution
    err.message.includes("stale element not found in the current frame") || // BIDI
    err.message.includes("belongs to different document") || err.message.includes("no such node - The node with the reference")
  );
}
function isStaleElementToFindAgain(err) {
  if (!err || typeof err !== "object" || waitedFor(err)) {
    return false;
  }
  const { name, message } = err;
  return name === "stale element reference" || typeof message === "string" && isStaleElementError(err);
}
function transformClassicToBidiSelector(using, value) {
  if (using === "role") {
    const { role, name } = JSON.parse(value);
    return {
      type: "accessibility",
      value: name === void 0 ? { role } : { role, name }
    };
  }
  if (using === "css selector" || using === "tag name") {
    return { type: "css", value };
  }
  if (using === "xpath") {
    return { type: "xpath", value };
  }
  if (using === "link text") {
    return { type: "innerText", value };
  }
  if (using === "partial link text") {
    return { type: "innerText", value, matchType: "partial" };
  }
  if (using === "aria") {
    return {
      type: "accessibility",
      value: {
        name: value
      }
    };
  }
  throw new Error(`Can't transform classic selector ${using} to Bidi selector`);
}
function toClassicSelector(using, value) {
  if (using === "aria") {
    return { using: "xpath", value: getAriaXPathSelector(value) };
  }
  return { using, value };
}
function toAriaXPathLocator(value) {
  return { type: "xpath", value: getAriaXPathSelector(value) };
}
function getScopedElementId(ctx) {
  return ctx && "elementId" in ctx ? ctx.elementId : void 0;
}
async function findRoleElementsByScript(ctx, browser, value) {
  const { role, name } = JSON.parse(value);
  if (browser.isMobile && await browser.isNativeContext) {
    throw new Error(
      `The role selector "role/${role}" is not supported in a native app context. Use an accessibility id (\`~id\`) or a platform selector instead.`
    );
  }
  const root = getScopedElementId(ctx) ? ctx : null;
  const find = () => browser.execute(
    findByRole,
    role,
    name ?? null,
    -1,
    root
  );
  let result = await find();
  if (result === ACCESSIBILITY_API_MISSING) {
    await browser.execute(accessibilityScript);
    result = await find();
  }
  return (Array.isArray(result) ? result : []).filter((elem) => getElementFromResponse(elem));
}
async function findElementViaClassic(ctx, browser, using, value, shadowRoots = []) {
  const classic = toClassicSelector(using, value);
  const elementId = getScopedElementId(ctx);
  let lightDom;
  let lightDomError;
  try {
    lightDom = await (elementId ? ctx.findElementFromElement(elementId, classic.using, classic.value) : browser.findElement(classic.using, classic.value));
  } catch (err) {
    lightDomError = err;
  }
  if (getElementFromResponse(lightDom)) {
    return lightDom;
  }
  for (const rootId of shadowRoots.filter((id) => id !== elementId)) {
    try {
      const result = await browser.findElementFromElement(rootId, classic.using, classic.value);
      if (getElementFromResponse(result)) {
        return result;
      }
    } catch {
    }
  }
  if (lightDomError) {
    throw lightDomError;
  }
  return lightDom;
}
async function findElementsViaClassic(ctx, browser, using, value, shadowRoots = []) {
  const classic = toClassicSelector(using, value);
  const elementId = getScopedElementId(ctx);
  const collected = [];
  let lightDomError;
  try {
    const lightDom = await (elementId ? ctx.findElementsFromElement(elementId, classic.using, classic.value) : browser.findElements(classic.using, classic.value));
    if (Array.isArray(lightDom)) {
      collected.push(...lightDom.filter((node) => getElementFromResponse(node)));
    }
  } catch (err) {
    lightDomError = err;
  }
  for (const rootId of shadowRoots.filter((id) => id !== elementId)) {
    try {
      const result = await browser.findElementsFromElement(rootId, classic.using, classic.value);
      if (Array.isArray(result)) {
        collected.push(...result.filter((node) => getElementFromResponse(node)));
      }
    } catch {
    }
  }
  const ids = /* @__PURE__ */ new Set();
  const unique = collected.filter((node) => {
    const id = node[ELEMENT_KEY19];
    return Boolean(id) && !ids.has(id) && ids.add(id);
  });
  if (unique.length === 0 && lightDomError) {
    throw lightDomError;
  }
  return unique;
}
async function findInFrameByScript(scope, browser, using, value, index) {
  const held = heldBrowsingContext(scope);
  if (!held || !held.isFrame && !await foreignContextId(scope)) {
    return void 0;
  }
  const query = function(strategy, selector, at, root) {
    const css = strategy === "id" ? `#${CSS.escape(selector)}` : strategy === "class name" ? `.${selector.split(/\s+/).map((part) => CSS.escape(part)).join(".")}` : strategy === "name" ? `[name="${selector.replace(/"/g, '\\"')}"]` : strategy === "tag name" ? selector : selector;
    const matches = (base) => {
      if (strategy === "xpath") {
        const snapshot = document.evaluate(selector, base, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        const found2 = [];
        for (let i = 0; i < snapshot.snapshotLength; i++) {
          const node = snapshot.snapshotItem(i);
          if (node) {
            found2.push(node);
          }
        }
        return found2;
      }
      const scope2 = "querySelectorAll" in base ? base : document;
      if (strategy === "link text" || strategy === "partial link text") {
        return Array.from(scope2.querySelectorAll("a")).filter((link) => strategy === "link text" ? link.textContent === selector : (link.textContent || "").includes(selector));
      }
      const found = Array.from(scope2.querySelectorAll(css));
      for (const element of Array.from(scope2.querySelectorAll("*"))) {
        if (element.shadowRoot) {
          found.push(...matches(element.shadowRoot));
        }
      }
      return found;
    };
    const nodes = matches(root && "querySelectorAll" in root ? root : document);
    if (at === null) {
      return nodes.length;
    }
    return nodes[at] || null;
  };
  const rootId = scope[ELEMENT_KEY19];
  if (using === "role") {
    const { role, name } = JSON.parse(value);
    const roleParams = {
      functionDeclaration: createBidiFunctionDeclaration(findByRole),
      awaitPromise: true,
      arguments: [
        LocalValue.getArgument(role),
        LocalValue.getArgument(name ?? null),
        LocalValue.getArgument(index),
        rootId ? { sharedId: rootId } : LocalValue.getArgument(null)
      ],
      target: { context: held.contextId }
    };
    let found = parseScriptResult(roleParams, await browser.scriptCallFunction(roleParams));
    if (found === ACCESSIBILITY_API_MISSING) {
      await browser.scriptEvaluate({ expression: accessibilityScript, target: { context: held.contextId }, awaitPromise: false });
      found = parseScriptResult(roleParams, await browser.scriptCallFunction(roleParams));
    }
    if (typeof found === "number") {
      return found;
    }
    return found && typeof found === "object" && ELEMENT_KEY19 in found ? found : void 0;
  }
  const resolved = using === "aria" ? { using: "xpath", value: getAriaXPathSelector(value) } : { using, value };
  const params = {
    functionDeclaration: createBidiFunctionDeclaration(query),
    awaitPromise: true,
    arguments: [
      LocalValue.getArgument(resolved.using),
      LocalValue.getArgument(resolved.value),
      LocalValue.getArgument(index),
      rootId ? { sharedId: rootId } : LocalValue.getArgument(null)
    ],
    target: { context: held.contextId }
  };
  const parsed = parseScriptResult(params, await browser.scriptCallFunction(params));
  if (typeof parsed === "number") {
    return parsed;
  }
  if (parsed && typeof parsed === "object" && ELEMENT_KEY19 in parsed) {
    return parsed;
  }
  return void 0;
}
async function findAllInFrame(scope, browser, using, value) {
  const count = await findInFrameByScript(scope, browser, using, value, null);
  const total = typeof count === "number" ? count : 0;
  const nodes = [];
  for (let i = 0; i < total; i++) {
    const node = await findInFrameByScript(scope, browser, using, value, i);
    if (node && typeof node === "object") {
      nodes.push(node);
    }
  }
  return nodes;
}
async function findAriaElementViaXPathFallback(ctx, browser, using, value, context, startNodes, shadowRoots) {
  const xpathLocator = toAriaXPathLocator(value);
  const bidiOnly = isParallelContextActive();
  if (bidiOnly || startNodes && startNodes.length > 0) {
    try {
      const result = await browser.browsingContextLocateNodes({
        locator: xpathLocator,
        context,
        startNodes
      });
      const nodes = returnUniqueNodes(
        result.nodes.filter((node) => Boolean(node.sharedId)).map((node) => ({
          [ELEMENT_KEY19]: node.sharedId,
          locator: xpathLocator
        }))
      );
      if (nodes[0]) {
        return nodes[0];
      }
    } catch (err) {
      if (bidiOnly) {
        throw err;
      }
      log28.warn(`BiDi XPath fallback for "aria/${value}" failed due to ${err}, using Classic`);
    }
  }
  if (bidiOnly) {
    return void 0;
  }
  return findElementViaClassic(ctx, browser, using, value, shadowRoots);
}
async function findAriaElementsViaXPathFallback(ctx, browser, using, value, context, startNodes, shadowRoots) {
  const xpathLocator = toAriaXPathLocator(value);
  const bidiOnly = isParallelContextActive();
  if (bidiOnly || startNodes && startNodes.length > 0) {
    try {
      const result = await browser.browsingContextLocateNodes({
        locator: xpathLocator,
        context,
        startNodes
      });
      const nodes = returnUniqueNodes(
        result.nodes.filter((node) => Boolean(node.sharedId)).map((node) => ({
          [ELEMENT_KEY19]: node.sharedId,
          locator: xpathLocator
        }))
      );
      if (nodes.length > 0) {
        return nodes;
      }
    } catch (err) {
      if (bidiOnly) {
        throw err;
      }
      log28.warn(`BiDi XPath fallback for "aria/${value}" failed due to ${err}, using Classic`);
    }
  }
  if (bidiOnly) {
    return [];
  }
  return findElementsViaClassic(ctx, browser, using, value, shadowRoots);
}
function isFirefoxBidiRootSelectorBug(browser) {
  if (!browser.isFirefox) {
    return false;
  }
  const version = browser.capabilities?.browserVersion ?? "";
  const major = parseInt(version.match(/\d+/)?.[0] ?? "0", 10);
  return !isNaN(major) && major > 0 && major < 150;
}
function applyFirefoxRootSelectorWorkaround(using, value, isScopedContext, browser) {
  if (using === "css selector" && (value === "html" || value === ":root") && !isScopedContext && isFirefoxBidiRootSelectorBug(browser)) {
    return { using: "xpath", value: "/html" };
  }
  return { using, value };
}
async function findDeepElement(selector) {
  const browser = getBrowserObject59(this);
  const shadowRootManager = getShadowRootManager(browser);
  const context = await contextIdOf(this);
  let shadowRoots = await shadowRootManager.getShadowElementsByContextId(
    context,
    this.elementId
  );
  let { using, value } = findStrategy(selector, this.isMobile, this.isBidi);
  if (using === "link text" || using === "partial link text") {
    const held = await foreignContext(this);
    if (held) {
      const [first] = await findLinksInContext(held, using, value, this.elementId, 1);
      return first;
    }
  }
  if (heldBrowsingContext(this)?.isFrame) {
    return findInFrameByScript(this, browser, using, value, 0);
  }
  if (using === "xpath" && (value.startsWith("./") || value.startsWith("..")) && this.elementId) {
    if (isParallelContextActive()) {
      const [first] = await locateRelativeXPath(browser, context, this.elementId, value);
      return first;
    }
    return this.findElementFromElement(this.elementId, using, value);
  }
  const isScopedContext = shadowRoots.length > 0 || Boolean(this.elementId);
  ({ using, value } = applyFirefoxRootSelectorWorkaround(using, value, isScopedContext, browser));
  const locator = transformClassicToBidiSelector(using, value);
  const startNodes = this.elementId ? [
    { sharedId: this.elementId },
    ...shadowRoots.map((shadowRootNodeId) => ({ sharedId: shadowRootNodeId }))
  ] : shadowRoots.length > 0 ? shadowRoots.map((shadowRootNodeId) => ({ sharedId: shadowRootNodeId })) : void 0;
  const locateNodes = () => browser.browsingContextLocateNodes({ locator, context, startNodes }).catch(async (err) => {
    const message = String(err?.message);
    const staleNodes = message.includes("no such node") ? shadowRoots.filter((root) => message.includes(root)) : [];
    if (staleNodes.length === 0) {
      throw err;
    }
    for (const node of staleNodes) {
      shadowRootManager.forgetNode(context, node);
    }
    const scope = this.elementId;
    shadowRoots = await shadowRootManager.getShadowElementsByContextId(context, scope);
    return browser.browsingContextLocateNodes({
      locator,
      context,
      startNodes: scope ? [{ sharedId: scope }, ...shadowRoots.map((sharedId) => ({ sharedId }))] : shadowRoots.length > 0 ? shadowRoots.map((sharedId) => ({ sharedId })) : void 0
    });
  });
  const deepElementResult = await locateNodes().then(async (result) => {
    let nodes = result.nodes.filter((node) => Boolean(node.sharedId)).map((node) => ({
      [ELEMENT_KEY19]: node.sharedId,
      locator
    }));
    nodes = returnUniqueNodes(nodes);
    if (!this.elementId) {
      if (shadowRoots.length > 0 && nodes.length > 0) {
        const connected = await checkElementsConnected(
          browser,
          nodes.map((node) => node[ELEMENT_KEY19]),
          context
        );
        nodes.forEach((node, i) => {
          if (!connected[i]) {
            shadowRootManager.deleteShadowRoot(node[ELEMENT_KEY19], context);
          }
        });
        const firstConnected = nodes.find((_, i) => connected[i]);
        if (firstConnected) {
          return firstConnected;
        }
        log28.warn(`All ${nodes.length} BiDi results for "${value}" are detached, removed stale entries from shadow root tree`);
        return void 0;
      }
      return nodes[0];
    }
    const containment = await checkElementsContainedIn(
      browser,
      this.elementId,
      nodes.map((node) => node[ELEMENT_KEY19]),
      context
    );
    const scopedNodes = nodes.filter((_, i) => containment[i]);
    if (shadowRoots.length > 0) {
      const connected = await checkElementsConnected(
        browser,
        scopedNodes.map((node) => node[ELEMENT_KEY19]),
        context
      );
      scopedNodes.forEach((node, i) => {
        if (!connected[i]) {
          shadowRootManager.deleteShadowRoot(node[ELEMENT_KEY19], context);
        }
      });
      const firstConnected = scopedNodes.find((_, i) => connected[i]);
      if (firstConnected) {
        return firstConnected;
      }
      if (scopedNodes.length > 0) {
        log28.warn(`All ${scopedNodes.length} scoped BiDi results for "${value}" are detached, removed stale entries from shadow root tree`);
        return void 0;
      }
    }
    return scopedNodes[0];
  }).then(async (found) => {
    if (using === "aria" && !found) {
      log28.info(`BiDi accessibility locator found no nodes for "aria/${value}", falling back to XPath`);
      return findAriaElementViaXPathFallback(
        this,
        browser,
        using,
        value,
        context,
        startNodes,
        shadowRoots
      );
    }
    return found;
  }, async (err) => {
    log28.warn(`Failed to execute browser.browsingContextLocateNodes({ ... }) due to ${err}, falling back to regular WebDriver Classic command`);
    if (using === "role") {
      return (await findRoleElementsByScript(this, browser, value))[0];
    }
    if (using === "aria") {
      return findAriaElementViaXPathFallback(
        this,
        browser,
        using,
        value,
        context,
        startNodes,
        shadowRoots
      );
    }
    if (heldBrowsingContext(this)?.isFrame || await foreignContextId(this)) {
      return findInFrameByScript(this, browser, using, value, 0);
    }
    if (isParallelContextActive()) {
      throw err;
    }
    return findElementViaClassic(this, browser, using, value, shadowRoots);
  });
  return deepElementResult;
}
async function findDeepElements(selector) {
  const browser = getBrowserObject59(this);
  const shadowRootManager = getShadowRootManager(browser);
  const context = await contextIdOf(this);
  let shadowRoots = await shadowRootManager.getShadowElementsByContextId(
    context,
    this.elementId
  );
  let { using, value } = findStrategy(selector, this.isMobile, this.isBidi);
  if (using === "link text" || using === "partial link text") {
    const held = await foreignContext(this);
    if (held) {
      return findLinksInContext(held, using, value, this.elementId);
    }
  }
  if (heldBrowsingContext(this)?.isFrame) {
    return findAllInFrame(this, browser, using, value);
  }
  if (using === "xpath" && (value.startsWith("./") || value.startsWith("..")) && this.elementId) {
    if (isParallelContextActive()) {
      return locateRelativeXPath(browser, context, this.elementId, value);
    }
    return this.findElementsFromElement(this.elementId, using, value);
  }
  const isScopedContext = shadowRoots.length > 0 || Boolean(this.elementId);
  ({ using, value } = applyFirefoxRootSelectorWorkaround(using, value, isScopedContext, browser));
  const locator = transformClassicToBidiSelector(using, value);
  const startNodes = this.elementId ? [
    { sharedId: this.elementId },
    ...shadowRoots.map((shadowRootNodeId) => ({ sharedId: shadowRootNodeId }))
  ] : shadowRoots.length > 0 ? shadowRoots.map((shadowRootNodeId) => ({ sharedId: shadowRootNodeId })) : void 0;
  const locateNodes = () => browser.browsingContextLocateNodes({ locator, context, startNodes }).catch(async (err) => {
    const message = String(err?.message);
    const staleNodes = message.includes("no such node") ? shadowRoots.filter((root) => message.includes(root)) : [];
    if (staleNodes.length === 0) {
      throw err;
    }
    for (const node of staleNodes) {
      shadowRootManager.forgetNode(context, node);
    }
    const scope = this.elementId;
    shadowRoots = await shadowRootManager.getShadowElementsByContextId(context, scope);
    return browser.browsingContextLocateNodes({
      locator,
      context,
      startNodes: scope ? [{ sharedId: scope }, ...shadowRoots.map((sharedId) => ({ sharedId }))] : shadowRoots.length > 0 ? shadowRoots.map((sharedId) => ({ sharedId })) : void 0
    });
  });
  const deepElementResult = await locateNodes().then(async (result) => {
    let nodes = result.nodes.filter((node) => Boolean(node.sharedId)).map((node) => ({
      [ELEMENT_KEY19]: node.sharedId,
      locator
    }));
    nodes = returnUniqueNodes(nodes);
    if (!this.elementId) {
      if (shadowRoots.length > 0 && nodes.length > 0) {
        const connected = await checkElementsConnected(
          browser,
          nodes.map((node) => node[ELEMENT_KEY19]),
          context
        );
        nodes.forEach((node, i) => {
          if (!connected[i]) {
            shadowRootManager.deleteShadowRoot(node[ELEMENT_KEY19], context);
          }
        });
        const validNodes = nodes.filter((_, i) => connected[i]);
        if (validNodes.length > 0) {
          return validNodes;
        }
        return [];
      }
      return nodes;
    }
    const containment = await checkElementsContainedIn(
      browser,
      this.elementId,
      nodes.map((node) => node[ELEMENT_KEY19]),
      context
    );
    const scopedNodes = nodes.filter((_, i) => containment[i]);
    if (shadowRoots.length > 0) {
      const connected = await checkElementsConnected(
        browser,
        scopedNodes.map((node) => node[ELEMENT_KEY19]),
        context
      );
      scopedNodes.forEach((node, i) => {
        if (!connected[i]) {
          shadowRootManager.deleteShadowRoot(node[ELEMENT_KEY19], context);
        }
      });
      const connectedScopedNodes = scopedNodes.filter((_, i) => connected[i]);
      if (connectedScopedNodes.length > 0) {
        return connectedScopedNodes;
      }
      if (scopedNodes.length > 0) {
        return [];
      }
    }
    return scopedNodes;
  }).then(async (found) => {
    if (using === "aria" && (!found || found.length === 0)) {
      log28.info(`BiDi accessibility locator found no nodes for "aria/${value}", falling back to XPath`);
      return findAriaElementsViaXPathFallback(
        this,
        browser,
        using,
        value,
        context,
        startNodes,
        shadowRoots
      );
    }
    return found;
  }, async (err) => {
    log28.warn(`Failed to execute browser.browsingContextLocateNodes({ ... }) due to ${err}, falling back to regular WebDriver Classic command`);
    if (using === "role") {
      return findRoleElementsByScript(this, browser, value);
    }
    if (using === "aria") {
      return findAriaElementsViaXPathFallback(
        this,
        browser,
        using,
        value,
        context,
        startNodes,
        shadowRoots
      );
    }
    if (heldBrowsingContext(this)?.isFrame || await foreignContextId(this)) {
      return findAllInFrame(this, browser, using, value);
    }
    if (isParallelContextActive()) {
      throw err;
    }
    return findElementsViaClassic(this, browser, using, value, shadowRoots);
  });
  return deepElementResult;
}
function returnUniqueNodes(nodes) {
  const ids = /* @__PURE__ */ new Set();
  return nodes.filter((node) => !ids.has(node[ELEMENT_KEY19]) && ids.add(node[ELEMENT_KEY19]));
}
function buildNotFoundError(selector) {
  if (typeof selector === "string" && selector.startsWith(DEEP_SELECTOR)) {
    return new Error(`shadow selector "${selector.slice(DEEP_SELECTOR.length)}" did not return an HTMLElement`);
  }
  if (selector && typeof selector === "object" && typeof selector.strategy === "function") {
    const { strategyName } = selector;
    return new Error(`Custom Strategy "${strategyName}" did not return an HTMLElement`);
  }
  if (typeof selector === "function") {
    return new Error(`Function selector "${selector.toString()}" did not return an HTMLElement`);
  }
  if (isElement(selector)) {
    return new Error("DOM Node couldn't be found anymore");
  }
  return new Error(`Couldn't find element with selector "${String(selector)}"`);
}
async function findElement(selector) {
  const browserObject = getBrowserObject59(this);
  const shadowRootManager = getShadowRootManager(browserObject);
  if (this.isBidi && typeof selector === "string" && !selector.startsWith(DEEP_SELECTOR) && !shadowRootManager.isWithinFrame()) {
    const notFoundError = new Error(`Couldn't find element with selector "${selector}"`);
    const elem = await findDeepElement.call(this, selector);
    return getElementFromResponse(elem) ? elem : notFoundError;
  }
  if (typeof selector === "string" && selector.startsWith(DEEP_SELECTOR)) {
    const notFoundError = new Error(`shadow selector "${selector.slice(DEEP_SELECTOR.length)}" did not return an HTMLElement`);
    let elem = await browserObject.execute(
      querySelectorAllDeep,
      false,
      selector.slice(DEEP_SELECTOR.length),
      // hard conversion from element id to Element is done by browser driver
      this.elementId ? this : void 0
    );
    elem = Array.isArray(elem) ? elem[0] : elem;
    return getElementFromResponse(elem) ? elem : notFoundError;
  }
  if (selector && typeof selector === "object" && typeof selector.strategy === "function") {
    const { strategy, strategyName, strategyArguments } = selector;
    const notFoundError = new Error(`Custom Strategy "${strategyName}" did not return an HTMLElement`);
    let elem = await strategyScope(this, browserObject).execute(strategy, ...strategyArguments);
    elem = Array.isArray(elem) ? elem[0] : elem;
    return getElementFromResponse(elem) ? elem : notFoundError;
  }
  if (typeof selector === "string" && selector.startsWith(ROLE_SELECTOR)) {
    const { value } = findStrategy(selector, this.isMobile);
    const [elem] = await findRoleElementsByScript(this, browserObject, value);
    return elem || new Error(`Couldn't find element with selector "${selector}"`);
  }
  if (typeof selector === "string" || isPlainObject4(selector)) {
    const { using, value } = findStrategy(selector, this.isMobile);
    return this.elementId ? this.findElementFromElement(this.elementId, using, value) : this.findElement(using, value);
  }
  if (typeof selector === "function") {
    const notFoundError = new Error(`Function selector "${selector.toString()}" did not return an HTMLElement`);
    let elem = await fetchElementByJSFunction(selector, this);
    elem = Array.isArray(elem) ? elem[0] : elem;
    return getElementFromResponse(elem) ? elem : notFoundError;
  }
  if (isElement(selector)) {
    if (!window.__wdio_element) {
      window.__wdio_element = {};
    }
    const notFoundError = new Error("DOM Node couldn't be found anymore");
    const uid = Math.random().toString().slice(2);
    window.__wdio_element[uid] = selector;
    selector = ((id) => window.__wdio_element[id]);
    let elem = await fetchElementByJSFunction(selector, this, uid).catch((err) => {
      if (isStaleElementError(err)) {
        return void 0;
      }
      throw err;
    });
    elem = Array.isArray(elem) ? elem[0] : elem;
    return getElementFromResponse(elem) ? elem : notFoundError;
  }
  throw new Error(`${INVALID_SELECTOR_ERROR}, but found: \`${typeof selector}\``);
}
async function findElements(selector) {
  const browserObject = getBrowserObject59(this);
  if (typeof selector === "string" && selector.startsWith(DEEP_SELECTOR)) {
    const elems = await browserObject.execute(
      querySelectorAllDeep,
      true,
      selector.slice(DEEP_SELECTOR.length),
      // hard conversion from element id to Element is done by browser driver
      this.elementId ? this : void 0
    );
    const elemArray = Array.isArray(elems) ? elems : [elems];
    return elemArray.filter((elem) => elem && getElementFromResponse(elem));
  }
  if (isPlainObject4(selector) && typeof selector.strategy === "function") {
    const { strategy, strategyArguments } = selector;
    const elems = await strategyScope(this, browserObject).execute(strategy, ...strategyArguments);
    const elemArray = Array.isArray(elems) ? elems : [elems];
    return elemArray.filter((elem) => elem && getElementFromResponse(elem));
  }
  if (typeof selector === "string" && selector.startsWith(ROLE_SELECTOR)) {
    const { value } = findStrategy(selector, this.isMobile);
    return findRoleElementsByScript(this, browserObject, value);
  }
  if (typeof selector === "string" || isPlainObject4(selector)) {
    const { using, value } = findStrategy(selector, this.isMobile);
    return this.elementId ? this.findElementsFromElement(this.elementId, using, value) : this.findElements(using, value);
  }
  if (typeof selector === "function") {
    const elems = await fetchElementByJSFunction(selector, this);
    const elemArray = Array.isArray(elems) ? elems : [elems];
    return elemArray.filter((elem) => elem && getElementFromResponse(elem));
  }
  throw new Error(`${INVALID_SELECTOR_ERROR}, but found: \`${typeof selector}\``);
}
function verifyArgsAndStripIfElement(args) {
  function verify(arg) {
    if (isLoadedElement2(arg)) {
      if (!arg.elementId) {
        throw new Error(`The element with selector "${describeSelector(arg)}" you are trying to pass into the execute method wasn't found`);
      }
      return {
        [ELEMENT_KEY19]: arg.elementId
      };
    }
    return arg;
  }
  return !Array.isArray(args) ? verify(args) : args.map(verify);
}
async function getElementRect(scope) {
  const rect = isBidiCommandsEnabled(getBrowserObject59(scope)) ? await bidiGetRect(scope) : await scope.getElementRect(scope.elementId);
  const defaults = { x: 0, y: 0, width: 0, height: 0 };
  if (Object.keys(defaults).some((key) => rect[key] === void 0)) {
    const rectJs = await getBrowserObject59(scope).execute(function(el) {
      if (!el || !el.getBoundingClientRect) {
        return;
      }
      const { left, top, width, height } = el.getBoundingClientRect();
      return {
        x: left + this.scrollX,
        y: top + this.scrollY,
        width,
        height
      };
    }, scope);
    Object.keys(defaults).forEach((key) => {
      if (typeof rect[key] !== "undefined") {
        return;
      }
      if (rectJs && typeof rectJs[key] === "number") {
        rect[key] = Math.floor(rectJs[key]);
      } else {
        log28.error("getElementRect", { rect, rectJs, key });
        throw new Error("Failed to receive element rects via execute command");
      }
    });
  }
  return rect;
}
function validateUrl(url2, origError) {
  try {
    const urlObject = new URL(url2);
    return urlObject.href;
  } catch {
    if (origError) {
      throw origError;
    }
    return validateUrl(`http://${url2}`, new Error(`Invalid URL: ${url2}`));
  }
}
async function hasElementId(element) {
  if (!element.elementId) {
    element.elementId = (await findElementAgain(element))?.elementId;
    if (element.elementId) {
      element[ELEMENT_KEY19] = element.elementId;
      delete element.error;
    }
  }
  if (!element.elementId) {
    return false;
  }
  return true;
}
function addLocatorStrategyHandler(scope) {
  return (name, func) => {
    if (scope.strategies.get(name)) {
      throw new Error(`Strategy ${name} already exists`);
    }
    scope.strategies.set(name, func);
    if (scope.isMultiRemote) {
      const multiRemoteScope = scope;
      for (const instanceName of multiRemoteScope.instances) {
        const instance = multiRemoteScope.getInstance(instanceName);
        instance?.strategies?.set(name, func);
      }
    }
  };
}
function createFunctionDeclarationFromString(userScript) {
  if (typeof userScript === "string") {
    return `(${SCRIPT_PREFIX}function () {
${userScript.toString()}
}${SCRIPT_SUFFIX}).apply(this, arguments);`;
  }
  return new Function(`return (${SCRIPT_PREFIX}${userScript.toString()}${SCRIPT_SUFFIX}).apply(this, arguments);`).toString();
}
var log28, INVALID_SELECTOR_ERROR, IGNORED_COMMAND_FILE_EXPORTS, scopes, applyScopePrototype, getPrototype, getElementFromResponse, isStub;
var init_utils2 = __esm({
  "src/utils/index.ts"() {
    "use strict";
    init_browser();
    init_element();
    init_querySelectorShadowDom();
    init_elementChecks();
    init_constant();
    init_constants();
    init_findStrategy();
    init_constant();
    init_shadowRoot();
    init_context();
    init_browsingContext();
    init_foreignContext();
    init_elementCommands();
    init_locate();
    init_serialize();
    init_value();
    init_bidi();
    init_array();
    init_findElementAgain();
    init_describeSelector();
    init_elementNotFound();
    log28 = logger28("webdriverio");
    INVALID_SELECTOR_ERROR = "selector needs to be typeof `string` or `function`";
    IGNORED_COMMAND_FILE_EXPORTS = ["SESSION_MOCKS", "CDP_SESSIONS"];
    scopes = {
      browser: browser_exports,
      element: element_exports
    };
    applyScopePrototype = (prototype, scope) => {
      Object.entries(scopes[scope]).filter(([exportName]) => !IGNORED_COMMAND_FILE_EXPORTS.includes(exportName)).forEach(([commandName, command]) => {
        prototype[commandName] = { value: command };
      });
    };
    getPrototype = (scope) => {
      const prototype = {
        /**
         * used to store the puppeteer instance in the browser scope
         */
        puppeteer: { value: null, writable: true }
      };
      if (scope === "browser") {
        prototype.isNativeContext = {
          get: function() {
            const context = getContextManager(this);
            return context.isNativeContext;
          }
        };
        prototype.mobileContext = {
          get: function() {
            const context = getContextManager(this);
            return context.mobileContext;
          }
        };
      }
      applyScopePrototype(prototype, scope);
      prototype.strategies = { value: /* @__PURE__ */ new Map() };
      prototype[WDIO_KIND2] = { value: scope, configurable: true };
      return prototype;
    };
    getElementFromResponse = (res) => {
      if (!res) {
        return null;
      }
      if (res[ELEMENT_KEY19]) {
        return res[ELEMENT_KEY19];
      }
      return null;
    };
    isStub = (automationProtocol) => automationProtocol === "./protocol-stub.js";
  }
});

// src/utils/getElementObject.ts
var getElementObject_exports = {};
__export(getElementObject_exports, {
  getElement: () => getElement,
  getElements: () => getElements
});
import { shareCommands, unwrapCommand, webdriverMonad as webdriverMonad2, wrapCommand as wrapCommand2 } from "@wdio/utils";
import clone from "lodash.clonedeep";
import { ELEMENT_KEY as ELEMENT_KEY20 } from "webdriver";
import { getBrowserObject as getBrowserObject60 } from "@wdio/utils";
function elementProperties(parent, browser) {
  const browserCommandKeys = Object.keys(browser_exports);
  const propertiesObject = {
    /**
     * filter out browser commands from object
     */
    ...Object.entries(clone(browser.__propertiesObject__)).reduce((commands, [name, descriptor]) => {
      if (!browserCommandKeys.includes(name)) {
        if ("value" in descriptor) {
          descriptor.value = unwrapCommand(descriptor.value);
        }
        commands[name] = descriptor;
      }
      return commands;
    }, {}),
    ...getPrototype("element"),
    scope: { value: "element" }
  };
  routeElementEndpoints(propertiesObject);
  propertiesObject.emit = { value: parent.emit.bind(parent) };
  return propertiesObject;
}
function getElement(selector, res, propsParam = {}) {
  const props = { isReactElement: false, isShadowElement: false, ...propsParam };
  const browser = getBrowserObject60(this);
  const element = webdriverMonad2(this.options, (client) => {
    const elementId = getElementFromResponse(res);
    if (elementId) {
      client.elementId = elementId;
      client[ELEMENT_KEY20] = elementId;
      if (res && this.isBidi && "locator" in res) {
        client.locator = res.locator;
      }
    } else {
      client.error = res;
    }
    if (selector) {
      client.selector = selector;
    }
    client.parent = this;
    client.isReactElement = props.isReactElement;
    client.isShadowElement = props.isShadowElement;
    if (typeof props.strict === "boolean") {
      client.strict = props.strict;
    }
    if (props.reactOptions) {
      client[REACT_OPTIONS] = props.reactOptions;
    }
    return client;
  }, elementProperties(this, browser));
  const elementInstance = element(this.sessionId, elementErrorHandler(wrapCommand2));
  const origAddCommand = elementInstance.addCommand.bind(elementInstance);
  elementInstance.addCommand = (name, fn) => {
    browser.__propertiesObject__[name] = { value: fn };
    origAddCommand(name, fn);
  };
  return elementInstance;
}
var WebDriverError, getElements;
var init_getElementObject = __esm({
  "src/utils/getElementObject.ts"() {
    "use strict";
    init_utils2();
    init_middlewares();
    init_foreignContext();
    init_browser();
    init_findElementAgain();
    WebDriverError = class extends Error {
      constructor(obj) {
        const { name, stack } = obj;
        const { error, stacktrace } = obj;
        super(error || name || "");
        Object.assign(this, {
          message: obj.message,
          stack: stacktrace || stack
        });
      }
    };
    getElements = function getElements2(selector, elemResponse, props = { isReactElement: false, isShadowElement: false }) {
      if (elemResponse.length === 0) {
        return [];
      }
      const browser = getBrowserObject60(this);
      const commandWrapper = elementErrorHandler(wrapCommand2);
      const shareListCommands = () => shareCommands(this.options, elementProperties(this, browser), commandWrapper);
      let listProperties;
      const elements = [elemResponse].flat(1).map((res, i) => {
        if (res.selector && "$$" in res) {
          return res;
        }
        const element = webdriverMonad2(this.options, (client) => {
          const elementId = getElementFromResponse(res);
          if (elementId) {
            client.elementId = elementId;
            client[ELEMENT_KEY20] = elementId;
            if (res && this.isBidi && "locator" in res) {
              client.locator = res.locator;
            }
          } else {
            res = res;
            client.error = res instanceof Error ? res : new WebDriverError(res);
          }
          client.selector = Array.isArray(selector) ? selector[i].selector : selector;
          client.parent = this;
          client.index = i;
          client.isReactElement = props.isReactElement;
          client.isShadowElement = props.isShadowElement;
          client.strict = false;
          if (props.reactOptions) {
            client[REACT_OPTIONS] = props.reactOptions;
          }
          return client;
        }, listProperties ??= shareListCommands());
        const elementInstance = element(this.sessionId);
        const origAddCommand = elementInstance.addCommand.bind(elementInstance);
        elementInstance.addCommand = (name, fn) => {
          browser.__propertiesObject__[name] = { value: fn };
          origAddCommand(name, fn);
        };
        return elementInstance;
      });
      return elements;
    };
  }
});

// src/utils/refetchElement.ts
async function findItemAgain(item, parent) {
  const found = await findElementAgain(item, { parent });
  if (found) {
    return found;
  }
  const { getElements: getElements3 } = await Promise.resolve().then(() => (init_getElementObject(), getElementObject_exports));
  const error = new Error(`element with selector "${describeSelector(item)}" has no match at index ${item.index}`);
  const [notFound2] = getElements3.call(parent, item.selector, [error], {
    isReactElement: item.isReactElement,
    isShadowElement: item.isShadowElement,
    reactOptions: item[REACT_OPTIONS]
  });
  notFound2.index = item.index;
  return notFound2;
}
async function refetchElement(currentElement, commandName) {
  const chain = [];
  while (currentElement.elementId && currentElement.parent) {
    chain.push(currentElement);
    currentElement = currentElement.parent;
  }
  chain.reverse();
  const length = chain.length;
  return chain.reduce(async (elementPromise, element, currentIndex) => {
    const parent = await elementPromise;
    let nextElement2;
    try {
      nextElement2 = element.index !== void 0 ? await findItemAgain(element, parent) : await findElementAgain(element, { parent });
    } catch (err) {
      if (waitedFor(err) && notFoundElement(err) === void 0) {
        recordNotFound(err, parent);
      }
      throw err;
    }
    try {
      return await implicitWait(nextElement2, currentIndex + 1 < length ? "$" : commandName);
    } catch (err) {
      if (waitedFor(err)) {
        recordNotFound(err, element);
      }
      throw err;
    }
  }, Promise.resolve(currentElement));
}
var init_refetchElement = __esm({
  "src/utils/refetchElement.ts"() {
    "use strict";
    init_implicitWait();
    init_elementNotFound();
    init_findElementAgain();
    init_describeSelector();
  }
});

// src/middlewares.ts
import { ELEMENT_KEY as ELEMENT_KEY21 } from "webdriver";
import { ELEMENT_ARRAY_COMMANDS, ELEMENT_ARRAY_WRAP as ELEMENT_ARRAY_WRAP2, getBrowserObject as getBrowserObject61 } from "@wdio/utils";
import {
  WebDriverProtocol,
  AppiumProtocol,
  ChromiumProtocol,
  GeckoProtocol,
  SauceLabsProtocol,
  SeleniumProtocol
} from "@wdio/protocols";
function withElementId(commandName, args, staleId, newId) {
  if (!staleId || !newId || !ELEMENT_ID_COMMANDS.has(commandName) || args[0] !== staleId) {
    return args;
  }
  return [newId, ...args.slice(1)];
}
function adoptElement(element, found) {
  element.elementId = found.elementId;
  element[ELEMENT_KEY21] = found.elementId;
  element.parent = found.parent;
}
async function invokeElementCommand(element, commandName, args, execute3) {
  if (IMPLICIT_WAIT_EXCLUSION_LIST.includes(commandName)) {
    return execute3(args);
  }
  const fetched = await implicitWait(element, commandName);
  element.elementId = fetched.elementId;
  element[ELEMENT_KEY21] = fetched.elementId;
  const calledWithId = fetched.elementId;
  try {
    const result = await execute3(args);
    const caps = getBrowserObject61(element).capabilities;
    if (caps?.browserName === "safari" && result?.error === "no such element") {
      const errorName = "stale element reference";
      const err = new Error(errorName);
      err.name = errorName;
      throw err;
    }
    return result;
  } catch (_err) {
    const err = _err;
    if (isElementNotFoundAgain(err)) {
      nameNotFoundAgain(err, element, commandName);
    }
    if (err.name === "element not interactable") {
      try {
        await fetched.waitForClickable();
        adoptElement(element, fetched);
        return await execute3(withElementId(commandName, args, calledWithId, fetched.elementId));
      } catch {
        const elementHTML = await fetched.getHTML();
        err.name = "webdriverio(middleware): element did not become interactable";
        err.message = `Element ${elementHTML} did not become interactable`;
        err.stack = err.stack ?? Error.captureStackTrace(err) ?? "";
      }
    }
    const stale = isStaleElementToFindAgain(err);
    if (stale) {
      try {
        const refetched = await refetchElement(element, commandName);
        adoptElement(element, refetched);
        return await execute3(withElementId(commandName, args, calledWithId, refetched.elementId));
      } catch (refetchErr) {
        if (refetchErr instanceof StrictSelectorError) {
          throw refetchErr;
        }
        if (waitedFor(refetchErr)) {
          if (refetchErr instanceof Error && notFoundElement(refetchErr) !== void 0) {
            nameNotFoundAgain(refetchErr, element, commandName, err);
          }
          throw refetchErr;
        }
        if (!(refetchErr instanceof Error) || !isStaleElementToFindAgain(refetchErr)) {
          throw err;
        }
        throw refetchErr;
      }
    }
    throw err;
  }
}
var IMPLICIT_WAIT_EXCLUSION_LIST, ELEMENT_ID_COMMANDS, elementErrorHandler, multiRemoteHandler;
var init_middlewares = __esm({
  "src/middlewares.ts"() {
    "use strict";
    init_refetchElement();
    init_implicitWait();
    init_elementNotFound();
    init_utils2();
    init_strictSelectorError();
    IMPLICIT_WAIT_EXCLUSION_LIST = ["getElement", "getElements"];
    ELEMENT_ID_COMMANDS = new Set(
      [WebDriverProtocol, AppiumProtocol, ChromiumProtocol, GeckoProtocol, SauceLabsProtocol, SeleniumProtocol].flatMap((protocol) => Object.values(protocol).flatMap((endpoint) => Object.values(endpoint))).filter((info) => info?.variables?.[0]?.name === "elementId").map((info) => info.command)
    );
    elementErrorHandler = (fn) => (commandName, commandFn) => {
      const wrap = () => ELEMENT_ARRAY_COMMANDS.includes(commandName) ? fn(commandName, function(...commandArgs) {
        const list = commandFn.apply(this, commandArgs);
        const wrapList = list?.[ELEMENT_ARRAY_WRAP2];
        if (typeof wrapList === "function") {
          const element = this;
          wrapList(async (load2) => invokeElementCommand(element, commandName, [], () => load2()));
        }
        return list;
      }) : fn(commandName, async function elementErrorHandlerCallbackFn(...callArgs) {
        return invokeElementCommand(this, commandName, callArgs, (args) => commandFn.apply(this, args));
      });
      let wrapped;
      return function elementErrorHandlerCallback(...args) {
        return (wrapped ??= wrap()).apply(this, args);
      };
    };
    multiRemoteHandler = (wrapCommand5) => (commandName) => {
      return wrapCommand5(commandName, function(...args) {
        const commandResults = this.instances.map((instanceName) => {
          const instance = this.getInstance(instanceName);
          if (!instance) {
            throw new Error(`Multi-remote object has no instance named "${instanceName}"`);
          }
          const command = instance[commandName];
          return command.call(instance, ...args);
        });
        return Promise.all(commandResults);
      });
    };
  }
});

// src/node.ts
import os from "node:os";
import { AsyncLocalStorage } from "node:async_hooks";
import fs8 from "node:fs";
import process2 from "node:process";
import { setCommandHookStore } from "@wdio/utils";

// src/node/downloadFile.ts
import fs from "node:fs";
import path from "node:path";
import JSZip from "jszip";
import logger from "@wdio/logger";
var log = logger("webdriverio");
async function downloadFile(fileName, targetDirectory) {
  if (typeof fileName !== "string" || typeof targetDirectory !== "string") {
    throw new Error("number or type of arguments don't agree with downloadFile command");
  }
  if (typeof this.download !== "function") {
    throw new Error(`The downloadFile command is not available in ${this.capabilities.browserName} and only available when using Selenium Grid`);
  }
  const response = await this.download(fileName);
  const base64Content = response.contents;
  if (!targetDirectory.endsWith("/")) {
    targetDirectory += "/";
  }
  fs.mkdirSync(targetDirectory, { recursive: true });
  const zipFilePath = path.join(targetDirectory, `${fileName}.zip`);
  const binaryString = atob(base64Content);
  const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
  fs.writeFileSync(zipFilePath, bytes);
  const zipData = fs.readFileSync(zipFilePath);
  const filesData = [];
  try {
    const zip = await JSZip.loadAsync(zipData);
    const keys2 = Object.keys(zip.files);
    for (let i = 0; i < keys2.length; i++) {
      const fileData = await zip.files[keys2[i]].async("nodebuffer");
      const dir = path.resolve(targetDirectory, keys2[i]);
      fs.writeFileSync(dir, fileData);
      log.info(`File extracted: ${keys2[i]}`);
      filesData.push(dir);
    }
  } catch (error) {
    log.error("Error unzipping file:", error);
  }
  return Promise.resolve({
    files: filesData
  });
}

// src/node/extensionArchive.ts
import fs2 from "node:fs";
import path2 from "node:path";
import { ZipArchive } from "archiver";
var ARCHIVE_EXTENSIONS = /* @__PURE__ */ new Set([".zip", ".xpi", ".crx"]);
async function extensionDataFromPath(input, remoteSession) {
  const resolved = path2.resolve(input);
  const kind = ARCHIVE_EXTENSIONS.has(path2.extname(resolved).toLowerCase()) ? "archive" : "directory";
  if (!remoteSession) {
    return kind === "archive" ? { type: "archivePath", path: resolved } : { type: "path", path: resolved };
  }
  const value = await readExtensionBase64(resolved, kind);
  return { type: "base64", value };
}
async function readExtensionBase64(absolutePath, kind) {
  if (kind === "archive") {
    try {
      const bytes = await fs2.promises.readFile(absolutePath);
      return bytes.toString("base64");
    } catch (err) {
      throw new Error(`installExtension could not read archive ${absolutePath} to send it to the remote browser: ${errorMessage(err)}`);
    }
  }
  let stat;
  try {
    stat = await fs2.promises.stat(absolutePath);
  } catch (err) {
    throw new Error(`installExtension could not read directory ${absolutePath} to send it to the remote browser: ${errorMessage(err)}`);
  }
  if (!stat.isDirectory()) {
    throw new Error(`installExtension expected a directory at ${absolutePath}`);
  }
  const zip = await zipDirectory(absolutePath);
  return zip.toString("base64");
}
function zipDirectory(dir) {
  return new Promise((resolve, reject) => {
    const chunks = [];
    const archive = new ZipArchive();
    let settled = false;
    const fail = (err) => {
      if (settled) {
        return;
      }
      settled = true;
      reject(err instanceof Error ? err : new Error(errorMessage(err)));
    };
    archive.on("error", fail);
    archive.on("data", (chunk) => chunks.push(chunk));
    archive.on("end", () => {
      if (settled) {
        return;
      }
      settled = true;
      resolve(Buffer.concat(chunks));
    });
    try {
      appendDirectory(archive, dir, "", /* @__PURE__ */ new Set());
    } catch (err) {
      fail(err);
      return;
    }
    archive.finalize();
  });
}
function appendDirectory(archive, dir, prefix, seen) {
  const realDir = fs2.realpathSync(dir);
  if (seen.has(realDir)) {
    return;
  }
  seen.add(realDir);
  try {
    for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
      const full = path2.join(dir, entry.name);
      const name = prefix ? `${prefix}/${entry.name}` : entry.name;
      let stat;
      try {
        stat = fs2.statSync(full);
      } catch (err) {
        if (isNotFound(err)) {
          continue;
        }
        throw new Error(`installExtension could not read ${full}: ${errorMessage(err)}`);
      }
      if (stat.isDirectory()) {
        appendDirectory(archive, full, name, seen);
      } else if (stat.isFile()) {
        archive.append(fs2.createReadStream(full), { name });
      }
    }
  } finally {
    seen.delete(realDir);
  }
}
function isNotFound(err) {
  return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
}
function errorMessage(err) {
  return err instanceof Error ? err.message : String(err);
}

// src/node/savePDF.ts
init_context();
init_browsingContext();
import fs4 from "node:fs";
import path4 from "node:path";
import { getBrowserObject as getBrowserObject2 } from "@wdio/utils";

// src/node/utils.ts
import path3 from "node:path";
import fs3 from "node:fs/promises";
async function assertDirectoryExists(filepath) {
  const exist = await fs3.access(path3.dirname(filepath)).then(() => true, () => false);
  if (!exist) {
    throw new Error(`directory (${path3.dirname(filepath)}) doesn't exist`);
  }
}

// src/node/savePDF.ts
async function savePDF(filepath, options) {
  if (typeof filepath !== "string" || !filepath.endsWith(".pdf")) {
    throw new Error('savePDF expects a filepath of type string and ".pdf" file ending');
  }
  const printOptions = options ?? {};
  assertOrientation(printOptions.orientation);
  const absoluteFilepath = path4.resolve(filepath);
  await assertDirectoryExists(absoluteFilepath);
  const base64 = this.isBidi ? await printBidi.call(this, printOptions) : await printClassic.call(this, printOptions);
  const page = Buffer.from(base64, "base64");
  fs4.writeFileSync(absoluteFilepath, page);
  return page;
}
function assertOrientation(orientation) {
  if (orientation === void 0) {
    return void 0;
  }
  if (orientation !== "portrait" && orientation !== "landscape") {
    throw new Error(`savePDF expects orientation to be "portrait" or "landscape", received "${orientation}"`);
  }
  return orientation;
}
function printClassic(options) {
  return this.printPage(
    options?.orientation,
    options?.scale,
    options?.background,
    options?.width,
    options?.height,
    options?.top,
    options?.bottom,
    options?.left,
    options?.right,
    options?.shrinkToFit,
    options?.pageRanges
  );
}
async function printBidi(options) {
  const browser = getBrowserObject2(this);
  const context = await topLevelBrowsingContext(browser, await contextIdOf(this));
  const { data } = await browser.browsingContextPrint(toPrintParameters(context, options));
  return data;
}
async function topLevelBrowsingContext(browser, start) {
  const contextManager = getContextManager(browser);
  let context = start ?? await contextManager.getCurrentContext();
  const { contexts } = await browser.browsingContextGetTree({});
  let parent = contextManager.findParentContext(context, contexts);
  const seen = /* @__PURE__ */ new Set();
  while (parent && !seen.has(parent.context)) {
    seen.add(context);
    context = parent.context;
    parent = contextManager.findParentContext(context, contexts);
  }
  return context;
}
function toPrintParameters(context, options) {
  const printOptions = options ?? {};
  const params = { context };
  const orientation = assertOrientation(printOptions.orientation);
  if (orientation !== void 0) {
    params.orientation = orientation;
  }
  if (printOptions.scale !== void 0) {
    params.scale = printOptions.scale;
  }
  if (printOptions.background !== void 0) {
    params.background = printOptions.background;
  }
  if (printOptions.shrinkToFit !== void 0) {
    params.shrinkToFit = printOptions.shrinkToFit;
  }
  if (printOptions.pageRanges !== void 0) {
    params.pageRanges = printOptions.pageRanges;
  }
  const page = {};
  if (printOptions.width !== void 0) {
    page.width = printOptions.width;
  }
  if (printOptions.height !== void 0) {
    page.height = printOptions.height;
  }
  if (printOptions.width !== void 0 || printOptions.height !== void 0) {
    params.page = page;
  }
  const margin = {};
  if (printOptions.top !== void 0) {
    margin.top = printOptions.top;
  }
  if (printOptions.bottom !== void 0) {
    margin.bottom = printOptions.bottom;
  }
  if (printOptions.left !== void 0) {
    margin.left = printOptions.left;
  }
  if (printOptions.right !== void 0) {
    margin.right = printOptions.right;
  }
  if (printOptions.top !== void 0 || printOptions.bottom !== void 0 || printOptions.left !== void 0 || printOptions.right !== void 0) {
    params.margin = margin;
  }
  return params;
}

// src/node/saveRecordingScreen.ts
import fs5 from "node:fs";
import path5 from "node:path";
async function saveRecordingScreen(filepath) {
  if (typeof filepath !== "string") {
    throw new Error("saveRecordingScreen expects a filepath");
  }
  const absoluteFilepath = path5.resolve(filepath);
  await assertDirectoryExists(absoluteFilepath);
  const videoBuffer = await this.stopRecordingScreen();
  const video = Buffer.from(videoBuffer, "base64");
  fs5.writeFileSync(absoluteFilepath, video);
  return video;
}

// src/node/saveScreenshot.ts
import fs6 from "node:fs/promises";
import path6 from "node:path";
import { getBrowserObject as getBrowserObject3 } from "@wdio/utils";
init_context();
init_browsingContext();
init_frameOffset();
init_screenshotEvents();
async function saveScreenshot(filepath, options) {
  if (typeof filepath !== "string") {
    throw new Error('saveScreenshot expects a filepath of type string and ".png" file ending');
  }
  const absoluteFilepath = path6.resolve(filepath);
  await assertDirectoryExists(absoluteFilepath);
  const screenBuffer = this.isBidi ? await takeScreenshotBidi.call(this, filepath, options) : await takeScreenshotClassic.call(this, filepath, options);
  const screenshot = Buffer.from(screenBuffer, "base64");
  await fs6.writeFile(absoluteFilepath, screenshot);
  return screenshot;
}
function takeScreenshotClassic(filepath, options) {
  if (options) {
    throw new Error("saveScreenshot does not support options in WebDriver Classic mode");
  }
  const fileExtension = path6.extname(filepath).slice(1);
  if (fileExtension !== "png") {
    throw new Error('Invalid file extension, use ".png" for PNG format');
  }
  return this.takeScreenshot();
}
async function takeScreenshotBidi(filepath, options) {
  const browser = getBrowserObject3(this);
  const contextManager = getContextManager(browser);
  const context = await contextIdOf(this);
  const tree = await browser.browsingContextGetTree({});
  const origin = options?.fullPage ? "document" : "viewport";
  const givenFormat = options?.format || path6.extname(filepath).slice(1);
  const imageFormat = givenFormat === "png" ? "image/png" : givenFormat === "jpeg" || givenFormat === "jpg" ? "image/jpeg" : void 0;
  if (!imageFormat) {
    throw new Error(`Invalid image format, use 'png', 'jpg' or 'jpeg', got '${options?.format}'`);
  }
  if (imageFormat === "image/jpeg" && path6.extname(filepath) !== ".jpeg" && path6.extname(filepath) !== ".jpg") {
    throw new Error('Invalid file extension, use ".jpeg" or ".jpg" for JPEG format');
  } else if (imageFormat === "image/png" && path6.extname(filepath) !== ".png") {
    throw new Error('Invalid file extension, use ".png" for PNG format');
  }
  const quality = typeof options?.quality === "number" ? options.quality / 100 : void 0;
  if (typeof options?.quality === "number" && (options?.quality < 0 || options?.quality > 100)) {
    throw new Error(`Invalid quality, use a number between 0 and 100, got '${options?.quality}'`);
  }
  if (typeof options?.quality === "number" && imageFormat !== "image/jpeg") {
    throw new Error('Invalid option "quality" for PNG format');
  }
  const format = {
    type: imageFormat,
    quality
  };
  const clip = options?.clip ? {
    type: "box",
    x: options.clip.x,
    y: options.clip.y,
    width: options.clip.width,
    height: options.clip.height
  } : void 0;
  if (clip) {
    if (typeof clip.x !== "number" || typeof clip.y !== "number" || typeof clip.width !== "number" || typeof clip.height !== "number") {
      throw new Error("Invalid clip, use an object with x, y, width and height properties");
    }
  }
  if (isBrowsingContext(this) && this.isFrame) {
    const { top, x, y } = await frameOffset(this);
    const html = await this.execute(() => {
      const rect = document.documentElement.getBoundingClientRect();
      return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
    });
    return withScreenshotEvents(browser, "takeScreenshot", () => browser.browsingContextCaptureScreenshot({
      context: top.contextId,
      origin: "viewport",
      format,
      clip: {
        type: "box",
        x: Math.round(x + html.x),
        y: Math.round(y + html.y),
        width: Math.round(html.width),
        height: Math.round(html.height)
      }
    }).then(({ data }) => data));
  }
  if (contextManager.findParentContext(context, tree.contexts)) {
    const el = await browser.$("html").getElement();
    return browser.takeElementScreenshot(el.elementId);
  }
  return withScreenshotEvents(browser, "takeScreenshot", () => browser.browsingContextCaptureScreenshot({ context, origin, format, clip }).then(({ data }) => data));
}

// src/node/saveElementScreenshot.ts
import fs7 from "node:fs/promises";
import path7 from "node:path";
import { getBrowserObject as getBrowserObject5 } from "@wdio/utils";
init_elementCommands();
init_foreignContext();
async function saveElementScreenshot(filepath) {
  if (typeof filepath !== "string" || !filepath.endsWith(".png")) {
    throw new Error('saveScreenshot expects a filepath of type string and ".png" file ending');
  }
  const absoluteFilepath = path7.resolve(filepath);
  await assertDirectoryExists(absoluteFilepath);
  const browser = getBrowserObject5(this);
  const screenBuffer = isBidiCommandsEnabled(browser) && !await foreignContext(this) ? await browser.takeElementScreenshot(this.elementId) : await this.takeElementScreenshot(this.elementId);
  const screenshot = Buffer.from(screenBuffer, "base64");
  await fs7.writeFile(absoluteFilepath, screenshot);
  return screenshot;
}

// src/index.ts
import logger29 from "@wdio/logger";
import WebDriver, { DEFAULTS } from "webdriver";
import { validateConfig } from "@wdio/config";
import { enableFileLogging, wrapCommand as wrapCommand4, isBidi, resolveCustomCommandOptions as resolveCustomCommandOptions3 } from "@wdio/utils";

// src/multiRemote.ts
init_middlewares();
import clone2 from "lodash.clonedeep";
import { setWdioKind as setWdioKind5, shareCommands as shareCommands2, webdriverMonad as webdriverMonad3, wrapCommand as wrapCommand3 } from "@wdio/utils";

// src/multiRemoteMock.ts
import { setWdioKind as setWdioKind4 } from "@wdio/utils";
var MISSING_INSTANCE = (name) => `Multi-remote object has no instance named "${name}"`;
var MultiRemoteMock = class {
  instances;
  isMultiRemote = true;
  #mocks = /* @__PURE__ */ new Map();
  constructor(instanceNames, mocks) {
    if (instanceNames.length !== mocks.length) {
      throw new Error(
        `Cannot build a multi-remote mock: instance names (${instanceNames.length}) and mocks (${mocks.length}) differ`
      );
    }
    this.instances = [...instanceNames];
    instanceNames.forEach((name, index) => {
      this.#mocks.set(name, mocks[index]);
    });
  }
  /**
   * The mock registered on one instance.
   */
  getInstance(name) {
    const found = this.#mocks.get(name);
    if (!found) {
      throw new Error(MISSING_INSTANCE(name));
    }
    return found;
  }
  abort(...args) {
    return this.#each("abort", args);
  }
  abortOnce(...args) {
    return this.#each("abortOnce", args);
  }
  clear(...args) {
    return this.#each("clear", args);
  }
  reset(...args) {
    return this.#each("reset", args);
  }
  redirect(...args) {
    return this.#each("redirect", args);
  }
  redirectOnce(...args) {
    return this.#each("redirectOnce", args);
  }
  request(...args) {
    return this.#each("request", args);
  }
  requestOnce(...args) {
    return this.#each("requestOnce", args);
  }
  respond(...args) {
    return this.#each("respond", args);
  }
  respondOnce(...args) {
    return this.#each("respondOnce", args);
  }
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  on(event, callback) {
    return this.#each("on", [event, callback]);
  }
  async restore(...args) {
    const pending = this.instances.map((name) => {
      try {
        return Promise.resolve(this.getInstance(name).restore(...args));
      } catch (error) {
        return Promise.reject(error);
      }
    });
    const settled = await Promise.allSettled(pending);
    this.#throwIfFailed("restore", settled.flatMap((result, index) => result.status === "rejected" ? [{ name: this.instances[index], error: result.reason }] : []));
    return this;
  }
  waitForResponse(...args) {
    return Promise.all(this.instances.map((name) => this.getInstance(name).waitForResponse(...args)));
  }
  /**
   * Run `method` on every instance. A throw from one instance does not skip
   * the rest; the original error is rethrown, or an `AggregateError` when
   * more than one instance failed.
   */
  #each(method, args) {
    const failures = [];
    for (const name of this.instances) {
      const mock2 = this.getInstance(name);
      const fn = mock2[method];
      try {
        fn.apply(mock2, args);
      } catch (error) {
        failures.push({ name, error });
      }
    }
    this.#throwIfFailed(method, failures);
    return this;
  }
  #throwIfFailed(method, failures) {
    if (failures.length === 0) {
      return;
    }
    if (failures.length === 1) {
      throw failures[0].error;
    }
    const names = failures.map(({ name }) => name).join(", ");
    throw new AggregateError(
      failures.map(({ error }) => error),
      `Multi-remote mock ${method}() failed for ${names}`
    );
  }
};
setWdioKind4(MultiRemoteMock.prototype, "mock");

// src/multiRemote.ts
init_array();
init_utils2();
init_browser();
var overridableCommands = new Set(Object.keys(browser_exports));
var SINGLE_QUERIES = /* @__PURE__ */ new Set(["$", "custom$", "react$", "shadow$", "nextElement", "previousElement", "parentElement"]);
var LIST_QUERIES2 = /* @__PURE__ */ new Set(["$$", "custom$$", "react$$", "shadow$$"]);
function zipElements(lists) {
  const length = Math.max(0, ...lists.map((list) => list.length));
  return Array.from({ length }, (_, index) => lists.map((list) => index < list.length ? list[index] : void 0));
}
var MultiRemote = class _MultiRemote {
  /**
   * Browser sessions in capability order. Instance names are map keys,
   * not properties of the browser client.
   */
  instances = /* @__PURE__ */ new Map();
  baseInstance;
  sessionId;
  /**
   * add instance to multibrowser instance
   */
  async addInstance(browserName, client) {
    this.instances.set(browserName, client);
    return client;
  }
  /**
   * modifier for multibrowser instance
   */
  modifier(wrapperClient) {
    const modifierThis = this;
    const propertiesObject = Object.fromEntries(
      Object.entries(wrapperClient.__propertiesObject__ ?? {}).map(([name, descriptor]) => [name, { ...descriptor }])
    );
    propertiesObject.commandList = { value: wrapperClient.commandList };
    propertiesObject.options = { value: wrapperClient.options };
    propertiesObject.getInstance = {
      value: (browserName) => {
        const instance = this.instances.get(browserName);
        if (!instance) {
          throw new Error(`Multi-remote object has no instance named "${browserName}"`);
        }
        return instance;
      }
    };
    propertiesObject.select = {
      value: function select(...instanceNames) {
        const newMultiRemote = new _MultiRemote();
        for (const name of instanceNames) {
          const instance = modifierThis.instances.get(name);
          if (instance) {
            newMultiRemote.instances.set(name, instance);
          }
        }
        if (newMultiRemote.instances.size === 0) {
          throw new Error("None of the following requested instances are valid: " + instanceNames.join(", "));
        }
        return newMultiRemote.modifier(this);
      },
      configurable: true,
      writable: true
    };
    for (const commandName of wrapperClient.commandList) {
      if (!Object.prototype.hasOwnProperty.call(wrapperClient, commandName) && overridableCommands.has(commandName)) {
        delete propertiesObject[commandName];
        continue;
      }
      const isFunction = typeof wrapperClient[commandName] === "function";
      propertiesObject[commandName] = {
        value: isFunction ? this.commandWrapper(commandName) : wrapperClient[commandName],
        configurable: true
      };
    }
    const inheritedStrategies = wrapperClient.__propertiesObject__?.strategies?.value;
    propertiesObject.strategies = { value: inheritedStrategies ?? /* @__PURE__ */ new Map() };
    propertiesObject.__propertiesObject__ = {
      value: propertiesObject
    };
    this.baseInstance = new MultiRemoteDriver(this.instances, propertiesObject);
    const client = Object.create(this.baseInstance, propertiesObject);
    if (Object.prototype.hasOwnProperty.call(wrapperClient, "addLocatorStrategy")) {
      client.addLocatorStrategy = addLocatorStrategyHandler(client);
    }
    return client;
  }
  /**
   * the descriptors of a multi-remote element: the commands of the multi-remote browser and
   * the element commands
   */
  static elementProperties(propertiesObject) {
    return { ...propertiesObject, ...clone2(getPrototype("element")), scope: { value: "element" } };
  }
  /**
   * the command wrapper of a multi-remote element, which runs a command in every instance
   */
  static elementCommandWrapper(scope) {
    return multiRemoteHandler(scope.commandWrapper.bind(scope));
  }
  /**
   * The properties of the entries of one multi-remote list: the entries share their wrapped
   * commands and the command wrapper, see `shareCommands`
   */
  static listElements(propertiesObject, scope) {
    return shareCommands2({}, _MultiRemote.elementProperties(propertiesObject), _MultiRemote.elementCommandWrapper(scope));
  }
  /**
   * helper method to generate element objects from results, so that we can call, e.g.
   *
   * ```
   * const elem = $('#elem')
   * elem.getHTML()
   * ```
   *
   * or in case multi-remote is used
   *
   * ```
   * const elems = $$('div')
   * elems[0].getHTML()
   * ```
   */
  static elementWrapper(instances, result, propertiesObject, scope, listProperties) {
    const prototype = listProperties ?? _MultiRemote.elementProperties(propertiesObject);
    const results = Array.isArray(result) ? result : [];
    const element = webdriverMonad3({}, (client) => {
      const byName = /* @__PURE__ */ new Map();
      let index = 0;
      for (const identifier of instances.keys()) {
        byName.set(identifier, results[index]);
        index++;
      }
      client.instances = [...instances.keys()];
      client.isMultiRemote = true;
      setWdioKind5(client, "element");
      const firstElement = results.find(Boolean);
      if (firstElement) {
        client.selector = firstElement.selector;
      }
      delete client.sessionId;
      Object.defineProperty(client, "getInstance", {
        configurable: true,
        writable: true,
        value(browserName) {
          const found = byName.get(browserName);
          if (!found) {
            throw new Error(`Multi-remote object has no instance named "${browserName}"`);
          }
          return found;
        }
      });
      client.select = function select(...instanceNames) {
        const selectedResults = [];
        const selectedInstances = /* @__PURE__ */ new Map();
        for (const name of instanceNames) {
          if (!client.instances.includes(name)) {
            continue;
          }
          const browserInstance = scope.instances.get(name);
          if (!browserInstance) {
            continue;
          }
          selectedInstances.set(name, browserInstance);
          selectedResults.push(client.getInstance(name));
        }
        if (selectedInstances.size === 0) {
          throw new Error("None of the following requested instances are valid: " + instanceNames.join(", "));
        }
        return _MultiRemote.elementWrapper(selectedInstances, selectedResults, propertiesObject, scope);
      };
      return client;
    }, prototype);
    const sessionId = this.sessionId;
    return element(sessionId, listProperties ? void 0 : _MultiRemote.elementCommandWrapper(scope));
  }
  /**
   * handle commands for multi-remote instances
   */
  commandWrapper(commandName) {
    const instances = this.instances;
    const self = this;
    return wrapCommand3(commandName, function(...args) {
      const execute3 = async () => {
        const thisElement = this;
        const isElementScope = Boolean(thisElement.selector);
        const scopeEntries = isElementScope ? thisElement.instances.map((instanceName) => [instanceName, thisElement.getInstance(instanceName)]) : [...instances.entries()];
        const result = await Promise.all(
          scopeEntries.map(([, instance]) => {
            const command = instance[commandName];
            return command.call(instance, ...args);
          })
        );
        const activeInstances = isElementScope ? new Map(thisElement.instances.map((instanceName) => {
          const browserInstance = instances.get(instanceName);
          if (!browserInstance) {
            throw new Error(`Multi-remote object has no instance named "${instanceName}"`);
          }
          return [instanceName, browserInstance];
        })) : instances;
        return { result, activeInstances, scopeEntries };
      };
      if (LIST_QUERIES2.has(commandName)) {
        const [selector, ...props] = args;
        let loadedInstances = instances;
        const wrapMultiRemote = (elements, listProperties) => _MultiRemote.elementWrapper(
          loadedInstances,
          elements,
          this.__propertiesObject__,
          self,
          listProperties
        );
        return ElementArray.fromAsyncCallback(async () => {
          const { result, activeInstances } = await execute3();
          loadedInstances = activeInstances;
          let listProperties;
          return zipElements(result).map((elements) => wrapMultiRemote(elements, listProperties ??= _MultiRemote.listElements(this.__propertiesObject__, self)));
        }, {
          selector,
          foundWith: commandName,
          parent: this,
          /**
           * the arguments after the selector, so that
           * `parent[foundWith](selector, ...props)` runs the same query again
           */
          props,
          isMultiRemote: true,
          wrapMultiRemote
        });
      }
      return (async () => {
        const { result, activeInstances, scopeEntries } = await execute3();
        if (SINGLE_QUERIES.has(commandName)) {
          return _MultiRemote.elementWrapper(activeInstances, result, this.__propertiesObject__, self);
        } else if (commandName === "mock") {
          return new MultiRemoteMock(
            scopeEntries.map(([instanceName]) => instanceName),
            result
          );
        }
        return result;
      })();
    });
  }
};
var MultiRemoteDriver = class {
  instances;
  isMultiRemote = true;
  __propertiesObject__;
  constructor(instances, propertiesObject) {
    this.instances = [...instances.keys()];
    this.__propertiesObject__ = propertiesObject;
  }
  on(eventName, emitter) {
    this.instances.forEach((instanceName) => this.getInstance(instanceName).on(eventName, emitter));
    return void 0;
  }
  once(eventName, emitter) {
    this.instances.forEach((instanceName) => this.getInstance(instanceName).once(eventName, emitter));
    return void 0;
  }
  emit(eventName, emitter) {
    return this.instances.map(
      (instanceName) => this.getInstance(instanceName).emit(eventName, emitter)
    ).some(Boolean);
  }
  eventNames() {
    return this.instances.map(
      (instanceName) => this.getInstance(instanceName).eventNames()
    );
  }
  getMaxListeners() {
    return this.instances.map(
      (instanceName) => this.getInstance(instanceName).getMaxListeners()
    );
  }
  listenerCount(eventName) {
    return this.instances.map(
      (instanceName) => this.getInstance(instanceName).listenerCount(eventName)
    );
  }
  listeners(eventName) {
    return this.instances.map(
      (instanceName) => this.getInstance(instanceName).listeners(eventName)
    ).reduce((prev, cur) => {
      prev.concat(cur);
      return prev;
    }, []);
  }
  removeListener(eventName, emitter) {
    this.instances.forEach((instanceName) => this.getInstance(instanceName).removeListener(eventName, emitter));
    return void 0;
  }
  removeAllListeners(eventName) {
    this.instances.forEach((instanceName) => this.getInstance(instanceName).removeAllListeners(eventName));
    return void 0;
  }
};
setWdioKind5(MultiRemoteDriver.prototype, "browser");

// src/utils/SevereServiceError.ts
var SevereServiceError = class extends Error {
  constructor(message = "Severe Service Error occurred.") {
    super(message);
    this.name = "SevereServiceError";
  }
};

// src/utils/detectBackend.ts
var DEFAULT_HOSTNAME = "127.0.0.1";
var DEFAULT_PORT = 4444;
var DEFAULT_PROTOCOL = "http";
var DEFAULT_PATH = "/";
var LEGACY_PATH = "/wd/hub";
var REGION_MAPPING = {
  "us": "us-west-1.",
  // default endpoint
  "eu": "eu-central-1.",
  "eu-central-1": "eu-central-1.",
  "us-east-4": "us-east-4.",
  "asia-south-2": "asia-south-2."
};
function getSauceEndpoint(region, { isRDC, isVisual } = {}) {
  const shortRegion = REGION_MAPPING[region] ? region : "us";
  if (isRDC) {
    return `${shortRegion}1.appium.testobject.com`;
  } else if (isVisual) {
    return "hub.screener.io";
  }
  return `ondemand.${REGION_MAPPING[shortRegion]}saucelabs.com`;
}
function detectBackend(options = {}) {
  const { port, hostname, user, key, protocol, region, path: path9, capabilities } = options;
  if (typeof user === "string" && typeof key === "string" && key.length === 20) {
    return {
      protocol: protocol || "https",
      hostname: hostname || "hub-cloud.browserstack.com",
      port: port || 443,
      path: path9 || LEGACY_PATH
    };
  }
  if (typeof user === "string" && typeof key === "string" && key.length === 32) {
    return {
      protocol: protocol || "https",
      hostname: hostname || "hub.testingbot.com",
      port: port || 443,
      path: path9 || LEGACY_PATH
    };
  }
  const isVisual = Boolean(!Array.isArray(capabilities) && capabilities && capabilities["sauce:visual"]?.apiKey);
  if (typeof user === "string" && typeof key === "string" && key.length === 36 || // Or only RDC or visual
  isVisual) {
    const sauceRegion = region;
    return {
      protocol: protocol || "https",
      hostname: hostname || getSauceEndpoint(sauceRegion, { isVisual }),
      port: port || 443,
      path: path9 || LEGACY_PATH
    };
  }
  if (typeof user === "string" && typeof key === "string" && key.length === 50) {
    return {
      protocol: protocol || DEFAULT_PROTOCOL,
      hostname: hostname || "hub.lambdatest.com",
      port: port || 80,
      path: path9 || LEGACY_PATH
    };
  }
  if (
    /**
     * user and key are set in config
     */
    (typeof user === "string" || typeof key === "string") && /**
     * but no custom WebDriver endpoint was configured
     */
    !hostname
  ) {
    throw new Error(
      'A "user" or "key" was provided but could not be connected to a known cloud service (Sauce Labs, Browerstack, Testingbot or Lambdatest). Please check if given user and key properties are correct!'
    );
  }
  if (hostname || port || protocol || path9) {
    return {
      hostname: hostname || DEFAULT_HOSTNAME,
      port: port || DEFAULT_PORT,
      protocol: protocol || DEFAULT_PROTOCOL,
      path: path9 || DEFAULT_PATH
    };
  }
  return { hostname, port, protocol, path: path9 };
}

// src/utils/driver.ts
init_utils2();

// src/protocol-stub.ts
import { capabilitiesEnvironmentDetector, resolveCustomCommandOptions as resolveCustomCommandOptions2 } from "@wdio/utils";
var NOOP2 = () => {
};
var ProtocolStub = class {
  static async newSession(options) {
    const capabilities = emulateSessionCapabilities(options.capabilities);
    const customCommands = [];
    const overwrittenCommands = [];
    const browser = {
      options,
      capabilities,
      requestedCapabilities: capabilities,
      customCommands,
      // internally used to transfer custom commands to the actual protocol instance
      overwrittenCommands,
      // internally used to transfer overwritten commands to the actual protocol instance
      commandList: [],
      getWindowHandle: NOOP2,
      on: NOOP2,
      off: NOOP2,
      addCommand(name, fn, commandOptions) {
        customCommands.push([
          name,
          fn,
          resolveCustomCommandOptions2("addCommand", commandOptions)
        ]);
      },
      overwriteCommand(name, fn, commandOptions) {
        overwrittenCommands.push([
          name,
          fn,
          resolveCustomCommandOptions2("overwriteCommand", commandOptions)
        ]);
      },
      ...capabilitiesEnvironmentDetector(capabilities)
    };
    return browser;
  }
  /**
   * added just in case user wants to somehow reload webdriver before it was started.
   */
  static reloadSession() {
    throw new Error("Protocol Stub: Make sure to start the session before reloading it.");
  }
  static attachToSession(options, modifier) {
    if (options || !modifier) {
      throw new Error("You are trying to attach to a protocol stub, this should never occur, please file an issue.");
    }
    return modifier({
      commandList: []
    });
  }
};
function emulateSessionCapabilities(caps) {
  const capabilities = {};
  Object.entries(caps).forEach(([key, value]) => {
    const newKey = key.replace("appium:", "");
    capabilities[newKey] = value;
  });
  const c = "alwaysMatch" in caps ? caps.alwaysMatch : caps;
  if (c.browserName && c.browserName.toLowerCase() === "chrome") {
    capabilities["goog:chromeOptions"] = {};
  }
  return capabilities;
}

// src/utils/driver.ts
var webdriverImport;
async function getProtocolDriver(options) {
  if (isStub(options.automationProtocol)) {
    return { Driver: ProtocolStub, options };
  }
  if (typeof options.user === "string" && typeof options.key === "string") {
    Object.assign(options, detectBackend(options));
  }
  const Driver = webdriverImport || (await import(
    /* @vite-ignore */
    options.automationProtocol || "webdriver"
  )).default;
  return { Driver, options };
}

// src/index.ts
init_constants();
init_utils2();
init_session2();
init_scriptTimeout();
init_browsingContext2();
init_environment();
init_browserOverwrites();
init_middlewares();
init_types2();
init_context();
init_strictMode();
init_context();
init_deviceDescriptorsSource();
import { WDIO_KIND as WDIO_KIND3, WDIO_CHAINABLE } from "@wdio/utils";
var Key2 = Key;
var SevereServiceError2 = SevereServiceError;
var remote = async function(params, remoteModifier) {
  const keysToKeep = Object.keys(environment.value.variables.WDIO_WORKER_ID ? params : DEFAULTS);
  const config = validateConfig(WDIO_DEFAULTS, params, keysToKeep);
  await enableFileLogging(config.outputDir, { keepLogPath: true });
  logger29.setLogLevelsConfig(config.logLevels, config.logLevel);
  const modifier = (client, options2) => {
    Object.assign(options2, Object.entries(config).reduce((a, [k, v]) => typeof v === "undefined" ? a : { ...a, [k]: v }, {}));
    if (typeof remoteModifier === "function") {
      client = remoteModifier(client, options2);
    }
    return client;
  };
  const { Driver, options } = await getProtocolDriver({ ...params, ...config });
  const prototype = getPrototype("browser");
  const instance = await Driver.newSession(options, modifier, prototype, wrapCommand4, IMPLICIT_WAIT_EXCLUSION_LIST);
  if (!isStub(options.automationProtocol)) {
    enableBrowsingContextCommands(instance);
  }
  if (params.framework && !isStub(params.automationProtocol)) {
    instance.addCommand = instance.addCommand.bind(instance);
    instance.overwriteCommand = instance.overwriteCommand.bind(instance);
  }
  instance.addLocatorStrategy = addLocatorStrategyHandler(instance);
  if (!isStub(options.automationProtocol)) {
    await registerSessionManager(instance);
  }
  applyBidiBrowserOverwrites(instance);
  return instance;
};
var attach = async function(attachOptions) {
  const params = {
    automationProtocol: "webdriver",
    ...detectBackend(attachOptions.options),
    ...attachOptions.options,
    ...attachOptions,
    capabilities: attachOptions.capabilities || {},
    requestedCapabilities: attachOptions.requestedCapabilities || {}
  };
  const prototype = getPrototype("browser");
  const { Driver } = await getProtocolDriver(params);
  const driver = Driver.attachToSession(
    params,
    void 0,
    prototype,
    wrapCommand4
  );
  enableBrowsingContextCommands(driver);
  driver.addLocatorStrategy = addLocatorStrategyHandler(driver);
  markAttachedSession(driver);
  if (isBidi(driver.capabilities) && "_bidiHandler" in driver) {
    await driver["_bidiHandler"].waitForConnected();
  }
  await registerSessionManager(driver);
  applyBidiBrowserOverwrites(driver);
  return driver;
};
var multiRemote = async function(params, { automationProtocol } = {}) {
  const multibrowser = new MultiRemote();
  const browserNames = Object.keys(params);
  const started = [];
  let startupFailed = false;
  const pending = browserNames.map(async (browserName) => {
    const instance = await remote(params[browserName]);
    if (startupFailed) {
      await instance.deleteSession();
      return [browserName, instance];
    }
    started.push(instance);
    return [browserName, instance];
  });
  let sessions;
  try {
    sessions = await Promise.all(pending);
  } catch (err) {
    startupFailed = true;
    const orphaned = started.splice(0);
    void Promise.allSettled(pending).then(() => {
      return Promise.allSettled(started.splice(0).map((instance) => instance.deleteSession()));
    });
    await Promise.allSettled(orphaned.map((instance) => instance.deleteSession()));
    throw err;
  }
  for (const [browserName, instance] of sessions) {
    await multibrowser.addInstance(browserName, instance);
  }
  const prototype = getPrototype("browser");
  const firstBrowser = multibrowser.instances.get(browserNames[0]);
  const sessionParams = isStub(automationProtocol) || !firstBrowser ? void 0 : {
    sessionId: "",
    logLevel: firstBrowser.options.logLevel
  };
  const ProtocolDriver = typeof automationProtocol === "string" ? (await import(
    /* @vite-ignore */
    automationProtocol
  )).default : WebDriver;
  const driver = ProtocolDriver.attachToSession(
    sessionParams,
    multibrowser.modifier.bind(multibrowser),
    prototype,
    wrapCommand4
  );
  if (!isStub(automationProtocol)) {
    const origAddCommand = driver.addCommand.bind(driver);
    driver.addCommand = function(name, fn, options) {
      const resolved = resolveCustomCommandOptions3("addCommand", options);
      driver.instances.forEach(
        (instanceName) => driver.getInstance(instanceName).addCommand(name, fn, resolved)
      );
      if (resolved.attachToBrowsingContext) {
        return;
      }
      return origAddCommand(
        name,
        fn,
        {
          attachToElement: resolved.attachToElement,
          proto: Object.getPrototypeOf(multibrowser.baseInstance),
          instances: Object.fromEntries(multibrowser.instances)
        }
      );
    };
    const origOverwriteCommand = driver.overwriteCommand.bind(driver);
    driver.overwriteCommand = ((name, fn, options) => {
      const resolved = resolveCustomCommandOptions3("overwriteCommand", options);
      if (resolved.attachToBrowsingContext) {
        driver.instances.forEach(
          (instanceName) => driver.getInstance(instanceName).overwriteCommand(name, fn, resolved)
        );
        return;
      }
      return origOverwriteCommand(
        name,
        fn,
        {
          attachToElement: resolved.attachToElement,
          proto: Object.getPrototypeOf(multibrowser.baseInstance),
          instances: Object.fromEntries(multibrowser.instances)
        }
      );
    });
  }
  driver.addLocatorStrategy = addLocatorStrategyHandler(driver);
  return driver;
};

// src/node.ts
init_environment();
init_context();
setParallelContextStore(new AsyncLocalStorage());
setCommandHookStore(new AsyncLocalStorage());
environment.value = {
  osType: () => os.type(),
  readFileSync: fs8.readFileSync,
  downloadFile,
  savePDF,
  saveRecordingScreen,
  extensionDataFromPath,
  saveScreenshot,
  saveElementScreenshot,
  variables: process2.env
};
export {
  DEFAULT_DURATION_MOVES,
  Key2 as Key,
  KeyAction,
  MobileScrollDirection,
  PARALLEL_CONTEXT_STORE_KEY,
  PointerAction,
  SevereServiceError2 as SevereServiceError,
  StrictSelectorError,
  WDIO_CHAINABLE,
  WDIO_KIND3 as WDIO_KIND,
  WheelAction,
  attach,
  buttonValue,
  deviceDescriptorsSource,
  getContextManager,
  multiRemote,
  remote,
  toBidiActions
};
/*!
 * ensure that timeout and interval are set properly
 */