webdriverio
Version:
Next-gen browser and mobile automation test framework for Node.js
1,261 lines (1,226 loc) • 388 kB
JavaScript
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/node.ts
import os from "node:os";
import fs8 from "node:fs";
// 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 zip2 = await JSZip.loadAsync(zipData);
const keys2 = Object.keys(zip2.files);
for (let i = 0; i < keys2.length; i++) {
const fileData = await zip2.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/savePDF.ts
import fs3 from "node:fs";
// src/node/utils.ts
import path2 from "node:path";
import fs2 from "node:fs/promises";
async function assertDirectoryExists(filepath) {
const exist = await fs2.access(path2.dirname(filepath)).then(() => true, () => false);
if (!exist) {
throw new Error(`directory (${path2.dirname(filepath)}) doesn't exist`);
}
}
function getAbsoluteFilepath(filepath) {
return filepath.startsWith("/") || filepath.startsWith("\\") || filepath.match(/^[a-zA-Z]:\\/) ? filepath : path2.join(process.cwd(), filepath);
}
// 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 absoluteFilepath = getAbsoluteFilepath(filepath);
await assertDirectoryExists(absoluteFilepath);
const pdf = await this.printPage(
options?.orientation,
options?.scale,
options?.background,
options?.width,
options?.height,
options?.top,
options?.bottom,
options?.left,
options?.right,
options?.shrinkToFit,
options?.pageRanges
);
const page = Buffer.from(pdf, "base64");
fs3.writeFileSync(absoluteFilepath, page);
return page;
}
// src/node/saveRecordingScreen.ts
import fs4 from "node:fs";
async function saveRecordingScreen(filepath) {
if (typeof filepath !== "string") {
throw new Error("saveRecordingScreen expects a filepath");
}
const absoluteFilepath = getAbsoluteFilepath(filepath);
await assertDirectoryExists(absoluteFilepath);
const videoBuffer = await this.stopRecordingScreen();
const video = Buffer.from(videoBuffer, "base64");
fs4.writeFileSync(absoluteFilepath, video);
return video;
}
// src/node/uploadFile.ts
import fs5 from "node:fs";
import path3 from "node:path";
import archiver from "archiver";
async function uploadFile(localPath) {
if (typeof localPath !== "string") {
throw new Error("number or type of arguments don't agree with uploadFile command");
}
if (typeof this.file !== "function") {
throw new Error(`The uploadFile command is not available in ${this.capabilities.browserName}`);
}
const zipData = [];
const source = fs5.createReadStream(localPath);
return new Promise((resolve, reject) => {
archiver("zip").on("error", (err) => reject(err)).on("data", (data) => zipData.push(data)).on("end", () => this.file(Buffer.concat(zipData).toString("base64")).then((localPath2) => resolve(localPath2), reject)).append(source, { name: path3.basename(localPath) }).finalize();
});
}
// src/node/saveScreenshot.ts
import fs6 from "node:fs/promises";
import path4 from "node:path";
import { getBrowserObject } from "@wdio/utils";
// src/session/context.ts
import logger2 from "@wdio/logger";
// src/session/session.ts
var sessionManager = /* @__PURE__ */ new Map();
var listenerRegisteredSession = /* @__PURE__ */ new Set();
var SessionManager = class {
#browser;
#scope;
/**
* 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(browser2, scope) {
this.#browser = browser2;
this.#scope = scope;
const registrationId = `${this.#browser.sessionId}-${this.#scope}`;
if (!listenerRegisteredSession.has(registrationId)) {
this.#browser.on("command", this.#onCommand.bind(this));
listenerRegisteredSession.add(registrationId);
}
}
#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.#onCommand.bind(this));
}
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
!process.env.WDIO_UNIT_TESTS
);
}
static getSessionManager(browser2, Manager) {
const scope = Manager.name;
let sessionManagerInstances = sessionManager.get(scope);
if (!sessionManagerInstances) {
sessionManagerInstances = /* @__PURE__ */ new Map();
sessionManager.set(scope, sessionManagerInstances);
}
let sessionManagerInstance = sessionManagerInstances.get(browser2);
if (!sessionManagerInstance) {
sessionManagerInstance = new Manager(browser2);
sessionManagerInstances.set(browser2, sessionManagerInstance);
}
return sessionManagerInstance;
}
};
// src/utils/mobile.ts
var appiumKeys = ["app", "bundleId", "appPackage", "appActivity", "appWaitActivity", "appWaitPackage"];
function getNativeContext({ capabilities, isMobile }) {
if (!capabilities || typeof capabilities !== "object" || !isMobile) {
return false;
}
const isAppiumAppCapPresent = (capabilities2) => {
return appiumKeys.some((key) => capabilities2[key] !== void 0 || capabilities2["appium:options"]?.[key] !== void 0 || capabilities2["lt:options"]?.[key] !== void 0);
};
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 && isAppiumAppCapPresent(capabilities) && 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: browser2, duration, scale }) {
const deviceScreenSize = (browser2.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: browser2, 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 = browser2.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 ? browser2.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: browser2.isIOS && gesture === "zoom" ? scale * 10 : scale
};
}
// src/session/context.ts
var log2 = logger2("webdriverio:context");
var COMMANDS_REQUIRING_RESET = ["deleteSession", "refresh", "switchToParentFrame"];
function getContextManager(browser2) {
return SessionManager.getSessionManager(browser2, ContextManager);
}
var ContextManager = class _ContextManager extends SessionManager {
#browser;
#currentContext;
#mobileContext;
#isNativeContext;
#getContextSupport = true;
constructor(browser2) {
super(browser2, _ContextManager.name);
this.#browser = browser2;
const capabilities = this.#browser.capabilities;
this.#isNativeContext = getNativeContext({ capabilities, isMobile: this.#browser.isMobile });
this.#mobileContext = getMobileContext({
capabilities,
isAndroid: this.#browser.isAndroid,
isNativeContext: this.#isNativeContext
});
this.#browser.on("result", this.#onCommandResultBidiAndClassic.bind(this));
if (!this.isEnabled() && !this.#browser.isMobile) {
return;
}
this.#browser.on("command", this.#onCommand.bind(this));
if (this.#browser.isMobile) {
this.#browser.on("result", this.#onCommandResultMobile.bind(this));
} else {
this.#browser.sessionSubscribe({
events: ["browsingContext.navigationStarted"]
});
this.#browser.on("browsingContext.navigationStarted", async (nav) => {
if (!this.#currentContext || nav.context === this.#currentContext) {
return;
}
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);
this.#browser.switchToWindow(this.#currentContext);
return;
}
});
}
}
removeListeners() {
super.removeListeners();
this.#browser.off("result", this.#onCommandResultBidiAndClassic.bind(this));
this.#browser.off("command", this.#onCommand.bind(this));
if (this.#browser.isMobile) {
this.#browser.off("result", this.#onCommandResultMobile.bind(this));
}
}
#onCommandResultBidiAndClassic(event) {
if (event.command === "closeWindow") {
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);
}
}
#onCommand(event) {
if (event.command === "switchToParentFrame") {
if (!this.#currentContext) {
return;
}
return this.#browser.browsingContextGetTree({}).then(({ contexts }) => {
const parentContext = this.findParentContext(this.#currentContext, contexts);
if (!parentContext) {
return;
}
this.setCurrentContext(parentContext.context);
});
}
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.setCurrentContext(event.result.value);
}
if (event.command === "switchAppiumContext" && event.result.value === null && this.#mobileContext) {
this.setCurrentContext(this.#mobileContext);
}
}
/**
* set context at the start of the session
*/
async initialize() {
if (process.env.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 windowHandle = this.#mobileContext || await this.#browser.getWindowHandle();
this.setCurrentContext(windowHandle);
return windowHandle;
}
setCurrentContext(context) {
this.#currentContext = context;
if (this.#browser.isMobile) {
this.#isNativeContext = context ? context === "NATIVE_APP" : this.#isNativeContext;
this.#mobileContext = context || void 0;
}
}
async getCurrentContext() {
if (!this.#currentContext) {
return this.initialize();
}
return this.#currentContext;
}
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;
}
};
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;
}
// src/node/saveScreenshot.ts
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 = getAbsoluteFilepath(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 = path4.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 browser2 = getBrowserObject(this);
const contextManager = getContextManager(browser2);
const context = await contextManager.getCurrentContext();
const tree = await this.browsingContextGetTree({});
const origin = options?.fullPage ? "document" : "viewport";
const givenFormat = options?.format || path4.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" && path4.extname(filepath) !== ".jpeg" && path4.extname(filepath) !== ".jpg") {
throw new Error('Invalid file extension, use ".jpeg" or ".jpg" for JPEG format');
} else if (imageFormat === "image/png" && path4.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");
}
}
const { data } = contextManager.findParentContext(context, tree.contexts) ? await browser2.$("html").getElement().then(
(el) => this.takeElementScreenshot(el.elementId).then((data2) => ({ data: data2 }))
) : await this.browsingContextCaptureScreenshot({ context, origin, format, clip });
return data;
}
// src/node/saveElementScreenshot.ts
import fs7 from "node:fs/promises";
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 = getAbsoluteFilepath(filepath);
await assertDirectoryExists(absoluteFilepath);
const screenBuffer = await this.takeElementScreenshot(this.elementId);
const screenshot = Buffer.from(screenBuffer, "base64");
await fs7.writeFile(absoluteFilepath, screenshot);
return screenshot;
}
// src/index.ts
import logger28 from "@wdio/logger";
import WebDriver, { DEFAULTS } from "webdriver";
import { validateConfig } from "@wdio/config";
import { enableFileLogging, wrapCommand as wrapCommand3, isBidi } from "@wdio/utils";
// src/multiremote.ts
import zip from "lodash.zip";
import clone2 from "lodash.clonedeep";
import { webdriverMonad as webdriverMonad2, wrapCommand as wrapCommand2 } from "@wdio/utils";
// src/middlewares.ts
import { ELEMENT_KEY as ELEMENT_KEY21 } from "webdriver";
import { getBrowserObject as getBrowserObject37 } from "@wdio/utils";
// src/utils/implicitWait.ts
import logger3 from "@wdio/logger";
import { getBrowserObject as getBrowserObject2 } from "@wdio/utils";
var log3 = logger3("webdriverio");
async function implicitWait(currentElement, commandName) {
const browser2 = getBrowserObject2(currentElement);
const skipForMobileScroll = browser2.isMobile && await browser2.isNativeContext && (commandName === "scrollIntoView" || commandName === "tap");
if (!currentElement.elementId && !/(waitUntil|waitFor|isExisting|is?\w+Displayed|is?\w+Clickable)/.test(commandName) && !skipForMobileScroll) {
log3.debug(
`command ${commandName} was called on an element ("${currentElement.selector}") that wasn't found, waiting for it...`
);
try {
await currentElement.waitForExist();
return currentElement.parent.$(currentElement.selector).getElement();
} catch {
if (currentElement.selector.toString().includes("this.previousElementSibling")) {
throw new Error(
`Can't call ${commandName} on previous element of element with selector "${currentElement.parent.selector}" because sibling wasn't found`
);
}
if (currentElement.selector.toString().includes("this.nextElementSibling")) {
throw new Error(
`Can't call ${commandName} on next element of element with selector "${currentElement.parent.selector}" because sibling wasn't found`
);
}
if (currentElement.selector.toString().includes("this.parentElement")) {
throw new Error(
`Can't call ${commandName} on parent element of element with selector "${currentElement.parent.selector}" because it wasn't found`
);
}
throw new Error(
`Can't call ${commandName} on element with selector "${currentElement.selector}" because element wasn't found`
);
}
}
return currentElement;
}
// src/utils/refetchElement.ts
async function refetchElement(currentElement, commandName) {
const selectors = [];
while (currentElement.elementId && currentElement.parent) {
selectors.push({ selector: currentElement.selector, index: currentElement.index || 0 });
currentElement = currentElement.parent;
}
selectors.reverse();
const length = selectors.length;
return selectors.reduce(async (elementPromise, { selector, index }, currentIndex) => {
const resolvedElement = await elementPromise;
let nextElement2 = index > 0 ? await resolvedElement.$$(selector)[index]?.getElement() : null;
nextElement2 = nextElement2 || await resolvedElement.$(selector).getElement();
return await implicitWait(nextElement2, currentIndex + 1 < length ? "$" : commandName);
}, Promise.resolve(currentElement));
}
// src/utils/index.ts
import cssValue from "css-value";
import rgb2hex from "rgb2hex";
import GraphemeSplitter from "grapheme-splitter";
import logger27 from "@wdio/logger";
import isPlainObject from "is-plain-obj";
import { ELEMENT_KEY as ELEMENT_KEY20 } from "webdriver";
import { UNICODE_CHARACTERS as UNICODE_CHARACTERS2, asyncIterators, getBrowserObject as getBrowserObject36 } from "@wdio/utils";
// src/commands/browser.ts
var browser_exports = {};
__export(browser_exports, {
$: () => $,
$$: () => $$,
SESSION_MOCKS: () => SESSION_MOCKS,
action: () => action,
actions: () => actions,
addInitScript: () => addInitScript,
call: () => call,
custom$: () => custom$,
custom$$: () => custom$$,
debug: () => debug,
deepLink: () => deepLink,
deleteCookies: () => deleteCookies,
downloadFile: () => downloadFile2,
emulate: () => emulate,
execute: () => execute,
executeAsync: () => executeAsync,
getContext: () => getContext,
getContexts: () => getContexts,
getCookies: () => getCookies,
getPuppeteer: () => getPuppeteer,
getWindowSize: () => getWindowSize,
keys: () => keys,
mock: () => mock,
mockClearAll: () => mockClearAll,
mockRestoreAll: () => mockRestoreAll,
newWindow: () => newWindow,
pause: () => pause,
react$: () => react$,
react$$: () => react$$,
relaunchActiveApp: () => relaunchActiveApp,
reloadSession: () => reloadSession,
restore: () => restore,
savePDF: () => savePDF2,
saveRecordingScreen: () => saveRecordingScreen2,
saveScreenshot: () => saveScreenshot2,
scroll: () => scroll,
setCookies: () => setCookies,
setTimeout: () => setTimeout2,
setViewport: () => setViewport,
setWindowSize: () => setWindowSize,
swipe: () => swipe,
switchContext: () => switchContext,
switchFrame: () => switchFrame,
switchWindow: () => switchWindow,
tap: () => tap,
throttle: () => throttle,
throttleCPU: () => throttleCPU,
throttleNetwork: () => throttleNetwork,
touchAction: () => touchAction2,
uploadFile: () => uploadFile2,
url: () => url,
waitUntil: () => waitUntil
});
// src/utils/getElementObject.ts
import { webdriverMonad, wrapCommand } from "@wdio/utils";
import clone from "lodash.clonedeep";
import { ELEMENT_KEY } from "webdriver";
import { getBrowserObject as getBrowserObject3 } from "@wdio/utils";
var 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
});
}
};
function getElement(selector, res, props = { isReactElement: false, isShadowElement: false }) {
const browser2 = getBrowserObject3(this);
const browserCommandKeys = Object.keys(browser_exports);
const propertiesObject = {
/**
* filter out browser commands from object
*/
...Object.entries(clone(browser2.__propertiesObject__)).reduce((commands, [name, descriptor]) => {
if (!browserCommandKeys.includes(name)) {
commands[name] = descriptor;
}
return commands;
}, {}),
...getPrototype("element"),
scope: { value: "element" }
};
propertiesObject.emit = { value: this.emit.bind(this) };
const element = webdriverMonad(this.options, (client) => {
const elementId = getElementFromResponse(res);
if (elementId) {
client.elementId = elementId;
client[ELEMENT_KEY] = 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;
return client;
}, propertiesObject);
const elementInstance = element(this.sessionId, elementErrorHandler(wrapCommand));
const origAddCommand = elementInstance.addCommand.bind(elementInstance);
elementInstance.addCommand = (name, fn) => {
browser2.__propertiesObject__[name] = { value: fn };
origAddCommand(name, fn);
};
return elementInstance;
}
var getElements = function getElements2(selector, elemResponse, props = { isReactElement: false, isShadowElement: false }) {
const browser2 = getBrowserObject3(this);
const browserCommandKeys = Object.keys(browser_exports);
const propertiesObject = {
/**
* filter out browser commands from object
*/
...Object.entries(clone(browser2.__propertiesObject__)).reduce((commands, [name, descriptor]) => {
if (!browserCommandKeys.includes(name)) {
commands[name] = descriptor;
}
return commands;
}, {}),
...getPrototype("element")
};
if (elemResponse.length === 0) {
return [];
}
const elements = [elemResponse].flat(1).map((res, i) => {
if (res.selector && "$$" in res) {
return res;
}
propertiesObject.scope = { value: "element" };
propertiesObject.emit = { value: this.emit.bind(this) };
const element = webdriverMonad(this.options, (client) => {
const elementId = getElementFromResponse(res);
if (elementId) {
client.elementId = elementId;
client[ELEMENT_KEY] = 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;
return client;
}, propertiesObject);
const elementInstance = element(this.sessionId, elementErrorHandler(wrapCommand));
const origAddCommand = elementInstance.addCommand.bind(elementInstance);
elementInstance.addCommand = (name, fn) => {
browser2.__propertiesObject__[name] = { value: fn };
origAddCommand(name, fn);
};
return elementInstance;
});
return elements;
};
// src/constants.ts
import { UNICODE_CHARACTERS, HOOK_DEFINITION } from "@wdio/utils";
var 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
},
/**
* Hooks
*/
onReload: HOOK_DEFINITION,
beforeCommand: HOOK_DEFINITION,
afterCommand: HOOK_DEFINITION
};
var FF_REMOTE_DEBUG_ARG = "-remote-debugging-port";
var DEEP_SELECTOR = ">>>";
var ARIA_SELECTOR = "aria/";
var restoreFunctions = /* @__PURE__ */ new Map();
var 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
async function $$(selector) {
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);
return enhanceElementsArray(elements3, this, selector);
}
const res2 = await findDeepElements.call(this, selector);
const elements2 = await getElements.call(this, selector, res2);
return enhanceElementsArray(elements2, getParent.call(this, res2), selector);
}
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);
return enhanceElementsArray(elements, getParent.call(this, res), selector);
}
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;
}
// src/commands/browser/$.ts
import { ELEMENT_KEY as ELEMENT_KEY2 } from "webdriver";
async function $(selector) {
if (globalThis.wdio && typeof selector === "string" && !selector.startsWith(DEEP_SELECTOR)) {
const res2 = "elementId" in this ? await globalThis.wdio.executeWithScope("$", this.elementId, selector) : await globalThis.wdio.execute("$", selector);
return getElement.call(this, selector, res2);
}
if (typeof selector === "object") {
const elementRef = selector;
if (typeof elementRef[ELEMENT_KEY2] === "string") {
return getElement.call(this, void 0, elementRef);
}
}
const res = await findElement.call(this, selector);
return getElement.call(this, selector, res);
}
// src/utils/actions/base.ts
import { ELEMENT_KEY as ELEMENT_KEY3 } from "webdriver";
var actionIds = 0;
var BaseAction = class {
constructor(instance, type, params) {
this.instance = instance;
this.#instance = instance;
this.#id = params?.id || `action${++actionIds}`;
this.#type = type;
this.#parameters = params?.parameters || {};
}
#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) {
for (const seq of this.sequence) {
if (!seq.origin || typeof seq.origin === "string") {
continue;
}
if (typeof seq.origin.then === "function") {
await seq.origin.waitForExist();
seq.origin = await seq.origin;
}
if (!seq.origin[ELEMENT_KEY3]) {
throw new Error(`Couldn't find element for "${seq.type}" action sequence`);
}
seq.origin = { [ELEMENT_KEY3]: seq.origin[ELEMENT_KEY3] };
}
await this.#instance.performActions([this.toJSON()]);
if (!skipRelease) {
await this.#instance.releaseActions();
}
}
};
// src/environment.ts
var isNode = !!(typeof process !== "undefined" && process.version);
var 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 uploadFile() {
throw new Error("The `uploadFile` command is not available 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";
}
}
};
// src/utils/actions/key.ts
var 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
var buttonNumbers = [0, 1, 2];
var buttonNames = ["left", "middle", "right"];
var buttonValue = [...buttonNumbers, ...buttonNames];
var ORIGIN_DEFAULT = "viewport";
var BUTTON_DEFAULT = 0;
var POINTER_TYPE_DEFAULT = "mouse";
var UP_PARAM_DEFAULTS = {
button: BUTTON_DEFAULT
};
var PARAM_DEFAULTS = {
...UP_PARAM_DEFAULTS,
width: 0,
height: 0,
pressure: 0,
tangentialPressure: 0,
tiltX: 0,
tiltY: 0,
twist: 0,
altitudeAngle: 0,
azimuthAngle: 0
};
var MOVE_PARAM_DEFAULTS = {
x: 0,
y: 0,
duration: 100,
origin: ORIGIN_DEFAULT
};
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 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);
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 = {
x: 0,
y: 0,
deltaX: 0,
deltaY: 0,
duration: 0
};
var 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/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"`);
}
// src/commands/browser/actions.ts
async function actions(actions2) {
await this.performActions(actions2.map((action2) => action2.toJSON()));
await this.releaseActions();
}
// src/utils/bidi/index.ts
import { ELEMENT_KEY as ELEMENT_KEY4 } from "webdriver";
// src/commands/constant.ts
var TOUCH_ACTIONS = ["press", "longPress", "tap", "moveTo", "wait", "release"];
var POS_ACTIONS = TOUCH_ACTIONS.slice(0, 4);
var ACCEPTED_OPTIONS = ["x", "y", "element"];
var SCRIPT_PREFIX = "/* __wdio script__ */";
var SCRIPT_SUFFIX = "/* __wdio script end__ */";
var resqScript = `!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.resq=e():(t.window=t.window||{},t.window.resq=e())}(window,(function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)r.d(n,o,function(e){return t[e]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=16)}([function(t,e,r){"use strict";r.d(e,"a",(function(){return m})),r.d(e,"d",(function(){return j})),r.d(e,"b",(function(){return M})),r.d(e,"c",(function(){return P}));var n=r(1),o=r.n(n),u=r(14),i=r.n(u),c=r(2),f=r.n(c),s=r(15),a=r.n(s);function l(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}var p=Array.isArray,d=Object.keys;function x(t){return"function"==typeof t}function y(t){return t instanceof HTMLElement||t instanceof Text}function h(t){return"object"===f()(t)&&!p(t)}function b(t){if(!t||"string"==typeof t)return t;var e=function(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{};e%2?l(Object(r),!0).forEach((function(e){i()(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}({},t);return delete e.children,e}function v(t,e){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return!(!p(t)||!p(e))&&(r?t.length===e.length&&!t.find((function(t){return!e.includes(t)})):t.some((function(t){return e.includes(t)})))}function _(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n=[];if(!d(t).length)return!0;if(null===e||!d(e).length)return!1;if(r)return a()(t,e);var o=d(t).filter((function(t){return d(e).includes(t)}));return o.forEach((function(r){h(t[r])&&h(e[r])&&(n=n.concat(_(t[r],e[r]))),(t[r]===e[r]||v(t[r],e[r]))&&n.push(e)})),n.length>0&&n.filter((function(t){return t})).length===o.length}function m(t){var e,r={children:[]};if(!t)return r;r.name=x(e=t.type)?e.displayName||e.name:e,r.props=b(t.memoizedProps),r.state=function(t){if(t){var e=t.baseState;return e||t}}(t.memoizedState);var n=t.child;if(n)for(r.children.push(n);n.sibling;)r.children.push(n.sibling),n=n.sibling;return r.children=r.children.map((function(t){return m(t)})),x(t.type)&&function(t){return t.children.length>1}(r)?(r.node=function(t){return t.children.map((function(t){return t.node})).filter((function(t){return!!t}))}(r),r.isFragment=!0):r.node=function(t){return y(t.stateNode)?t.stateNode:t.child&&y(t.child.stateNode)?t.child.stateNode:null}(t),r}function g(t){for(;t.length;){var e=t.shift();if(e.node)return e.node;e.children&&Array.isArray(e.children)&&t.push.apply(t,o()(e.children))}}function O(t,e){for(var r=[];t.length;){var n=t.shift().children;n&&Array.isArray(n)&&n.forEach((function(n){e(n)&&(!n.node&&Array.isArray(n.children)&&(n.node=g(n.children.concat([]))),r.push(n)),t.push(n)}))}return r}function w(t,e){var r=function(t){if(t){var e=t.split("(");return 1===e.length?t:e.find((function(t){return t.includes(")")})).replace(/\\)*/g,"")}}(e);return new RegExp("^"+t.split("*").map((function(t){return t.replace(/([.*+?^=!:\${}()|[\\]/\\\\])/g,"\\\\$1")})).join(".+")+"$").test(r)}function j(t,e){var r=arguments.length>3?arguments[3]:void 0;return t.reduce((function(t,e){return t.concat(O(t,r&&"function"==typeof r?r:function(t){return"string"==typeof t.name?w(e,t.name):null!==t.name&&"object"===f()(t.name)&&w(e,t.name.displayName)}))}),[e])}function M(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]&&arguments[3];return x(r)?(console.warn("Functions are not supported as filter matchers"),[]):t.filter((function(t){return h(r)&&_(r,t[e],n)||p(r)&&v(r,t[e],n)||t[e]===r}))}function P(t){if(t.hasOwnProperty("_reactRootContainer"))return t._reactRootContainer._internalRoot.current;var e=Object.keys(t).find((function(t){return t.startsWith("__reactInternalInstance")||t.startsWith("__reactFiber")||t.startsWith("__reactContainer")}));return e?t[e]:void 0}},function(t,e,r){var n=r(17),o=r(18),u=r(19),i=r(20);t.exports=function(t){return n(t)||o(t)||u(t)||i()},t.exports.default=t.exports,t.exports.__esModule=!0},function(t,e){function r(e){return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?(t.exports=r=function(t){return typeof t},t.exports.default=t.exports,t.exports.__esModule=!0):(t.exports=r=function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol