@luminati-io/webdriverio8
Version:
Next-gen browser and mobile automation test framework for Node.js
453 lines • 35.9 kB
JavaScript
import fs from 'node:fs/promises';
import path from 'node:path';
import { URL } from 'node:url';
import cssValue from 'css-value';
import rgb2hex from 'rgb2hex';
import GraphemeSplitter from 'grapheme-splitter';
import logger from '@wdio/logger';
import isPlainObject from 'is-plain-obj';
import { UNICODE_CHARACTERS } from '@wdio/utils';
import * as browserCommands from '../commands/browser.js';
import * as elementCommands from '../commands/element.js';
import querySelectorAllDeep from './thirdParty/querySelectorShadowDom.js';
import { ELEMENT_KEY, DEEP_SELECTOR, Key } from '../constants.js';
import { findStrategy } from './findStrategy.js';
const log = logger('webdriverio');
const INVALID_SELECTOR_ERROR = 'selector needs to be typeof `string` or `function`';
const IGNORED_COMMAND_FILE_EXPORTS = ['SESSION_MOCKS', 'CDP_SESSIONS'];
const scopes = {
browser: browserCommands,
element: elementCommands
};
const applyScopePrototype = (prototype, scope) => {
Object.entries(scopes[scope])
.filter(([exportName]) => !IGNORED_COMMAND_FILE_EXPORTS.includes(exportName))
.forEach(([commandName, command]) => {
prototype[commandName] = { value: command };
});
};
/**
* enhances objects with element commands
*/
export const getPrototype = (scope) => {
const prototype = {
/**
* used to store the puppeteer instance in the browser scope
*/
puppeteer: { value: null, writable: true }
};
/**
* register action commands
*/
applyScopePrototype(prototype, scope);
prototype.strategies = { value: new Map() };
return prototype;
};
/**
* get element id from WebDriver response
* @param {?Object|undefined} res body object from response or null
* @return {?string} element id or null if element couldn't be found
*/
export const getElementFromResponse = (res) => {
/**
* a function selector can return null
*/
if (!res) {
return null;
}
/**
* deprecated JSONWireProtocol response
*/
if (res.ELEMENT) {
return res.ELEMENT;
}
/**
* W3C WebDriver response
*/
if (res[ELEMENT_KEY]) {
return res[ELEMENT_KEY];
}
return null;
};
/**
* traverse up the scope chain until browser element was reached
*/
export function getBrowserObject(elem) {
const elemObject = elem;
return elemObject.parent ? getBrowserObject(elemObject.parent) : elem;
}
function sanitizeCSS(value) {
/* istanbul ignore next */
if (!value) {
return value;
}
return value.trim().replace(/'/g, '').replace(/"/g, '').toLowerCase();
}
/**
* parse css values to a better format
* @param {string} cssPropertyValue result of WebDriver call
* @param {string} cssProperty name of css property to parse
* @return {object} parsed css property
*/
export function parseCSS(cssPropertyValue, cssProperty) {
const parsedValue = {
property: cssProperty,
value: cssPropertyValue.toLowerCase().trim(),
parsed: {}
};
if (parsedValue.value?.indexOf('rgb') === 0) {
/**
* remove whitespaces in rgb values
*/
parsedValue.value = parsedValue.value.replace(/\s/g, '');
/**
* parse color values
*/
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 {
/**
* parse other css properties
*/
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 (err) {
// TODO improve css-parse lib to handle properties like
// `-webkit-animation-timing-function : cubic-bezier(0.25, 0.1, 0.25, 1)
}
}
return parsedValue;
}
/**
* check for unicode character or split string into literals
* @param {string} value text
* @return {Array} set of characters or unicode symbols
*/
export function checkUnicode(value, isDevTools = false) {
/**
* "Ctrl" key is specially handled based on OS in action class
*/
if (value === Key.Ctrl) {
return [value];
}
/**
* when sending emoji characters like 😄 or a value that is not a special character defined
* by the WebDriver protocol
*/
if (!Object.prototype.hasOwnProperty.call(UNICODE_CHARACTERS, value)) {
return new GraphemeSplitter().splitGraphemes(value);
}
if (isDevTools) {
return [value];
}
return [UNICODE_CHARACTERS[value]];
}
function fetchElementByJSFunction(selector, scope, referenceId) {
if (!('elementId' in scope)) {
return scope.execute(selector, referenceId);
}
/**
* use a regular function because IE does not understand arrow functions
*/
const script = (function (elem, id) {
return selector.call(elem, id);
}).toString().replace('selector', `(${selector.toString()})`);
const args = [scope];
if (referenceId) {
args.push(referenceId);
}
return getBrowserObject(scope).execute(`return (${script}).apply(null, arguments)`, ...args);
}
export function isElement(o) {
return (typeof HTMLElement === 'object'
? o instanceof HTMLElement
: o && typeof o === 'object' && o !== null && o.nodeType === 1 && typeof o.nodeName === 'string');
}
/**
* logic to find an element
*/
export async function findElement(selector) {
const browserObject = getBrowserObject(this);
/**
* check if shadow DOM integration is used
*/
if (!this.isDevTools && 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(`return (${querySelectorAllDeep}).apply(null, arguments)`, false, selector.slice(DEEP_SELECTOR.length),
// hard conversion from element id to Element is done by browser driver
(this.elementId ? this : undefined));
elem = Array.isArray(elem) ? elem[0] : elem;
return getElementFromResponse(elem) ? elem : notFoundError;
}
/**
* fetch element using custom strategy function
*/
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 browserObject.execute(strategy, ...strategyArguments);
elem = Array.isArray(elem) ? elem[0] : elem;
return getElementFromResponse(elem) ? elem : notFoundError;
}
/**
* fetch element using regular protocol command
*/
if (typeof selector === 'string' || isPlainObject(selector)) {
const { using, value } = findStrategy(selector, this.isW3C, this.isMobile);
return this.elementId
// casting to any necessary given weak type support of protocol commands
? this.findElementFromElement(this.elementId, using, value)
: this.findElement(using, value);
}
/**
* fetch element with JS function
*/
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;
}
/**
* handle DOM element transformation
* Note: this runs in the browser
*/
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);
elem = Array.isArray(elem) ? elem[0] : elem;
return getElementFromResponse(elem) ? elem : notFoundError;
}
throw new Error(INVALID_SELECTOR_ERROR);
}
/**
* logic to find a elements
*/
export async function findElements(selector) {
const browserObject = getBrowserObject(this);
/**
* check if shadow DOM integration is used
*/
if (!this.isDevTools && typeof selector === 'string' && selector.startsWith(DEEP_SELECTOR)) {
const elems = await browserObject.execute(`return (${querySelectorAllDeep}).apply(null, arguments)`, true, selector.slice(DEEP_SELECTOR.length),
// hard conversion from element id to Element is done by browser driver
(this.elementId ? this : undefined));
const elemArray = Array.isArray(elems) ? elems : [elems];
return elemArray.filter((elem) => elem && getElementFromResponse(elem));
}
/**
* fetch elements using custom strategy function
*/
if (isPlainObject(selector) && typeof selector.strategy === 'function') {
const { strategy, strategyArguments } = selector;
const elems = await browserObject.execute(strategy, ...strategyArguments);
const elemArray = Array.isArray(elems) ? elems : [elems];
return elemArray.filter((elem) => elem && getElementFromResponse(elem));
}
/**
* fetch element using regular protocol command
*/
if (typeof selector === 'string' || isPlainObject(selector)) {
const { using, value } = findStrategy(selector, this.isW3C, this.isMobile);
return this.elementId
// casting to any necessary given weak type support of protocol commands
? this.findElementsFromElement(this.elementId, using, value)
: this.findElements(using, value);
}
/**
* fetch element with JS function
*/
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);
}
/**
* Strip element object and return w3c and jsonwp compatible keys
*/
export function verifyArgsAndStripIfElement(args) {
function verify(arg) {
if (arg && typeof arg === 'object' && arg.constructor.name === 'Element') {
const elem = arg;
if (!elem.elementId) {
throw new Error(`The element with selector "${elem.selector}" you are trying to pass into the execute method wasn't found`);
}
return {
[ELEMENT_KEY]: elem.elementId,
ELEMENT: elem.elementId
};
}
return arg;
}
return !Array.isArray(args) ? verify(args) : args.map(verify);
}
/**
* getElementRect
*/
export async function getElementRect(scope) {
const rect = await scope.getElementRect(scope.elementId);
const defaults = { x: 0, y: 0, width: 0, height: 0 };
/**
* getElementRect workaround for Safari 12.0.3
* if one of [x, y, height, width] is undefined get rect with javascript
*/
if (Object.keys(defaults).some((key) => rect[key] === undefined)) {
/* istanbul ignore next */
const rectJs = await getBrowserObject(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);
// try set proper value
Object.keys(defaults).forEach((key) => {
if (typeof rect[key] !== 'undefined') {
return;
}
if (rectJs && typeof rectJs[key] === 'number') {
rect[key] = Math.floor(rectJs[key]);
}
else {
log.error('getElementRect', { rect, rectJs, key });
throw new Error('Failed to receive element rects via execute command');
}
});
}
return rect;
}
export function getAbsoluteFilepath(filepath) {
return filepath.startsWith('/') || filepath.startsWith('\\') || filepath.match(/^[a-zA-Z]:\\/)
? filepath
: path.join(process.cwd(), filepath);
}
/**
* check if directory exists
*/
export async function assertDirectoryExists(filepath) {
const exist = await fs.access(path.dirname(filepath)).then(() => true, () => false);
if (!exist) {
throw new Error(`directory (${path.dirname(filepath)}) doesn't exist`);
}
}
/**
* check if urls are valid and fix them if necessary
* @param {string} url url to navigate to
* @param {Boolean} [retryCheck=false] true if an url was already check and still failed with fix applied
* @return {string} fixed url
*/
export function validateUrl(url, origError) {
try {
const urlObject = new URL(url);
return urlObject.href;
}
catch (err) {
/**
* if even adding http:// doesn't help, fail with original error
*/
if (origError) {
throw origError;
}
return validateUrl(`http://${url}`, new Error(`Invalid URL: ${url}`));
}
}
export async function hasElementId(element) {
/*
* This is only necessary as isDisplayed is on the exclusion list for the middleware
*/
if (!element.elementId) {
const command = element.isReactElement
? element.parent.react$.bind(element.parent)
: element.isShadowElement
? element.parent.shadow$.bind(element.parent)
: element.parent.$.bind(element.parent);
element.elementId = (await command(element.selector)).elementId;
}
/*
* if element was still not found it also is not displayed
*/
if (!element.elementId) {
return false;
}
return true;
}
export function addLocatorStrategyHandler(scope) {
return (name, func) => {
if (scope.strategies.get(name)) {
throw new Error(`Strategy ${name} already exists`);
}
scope.strategies.set(name, func);
};
}
/**
* Enhance elements array with data required to refetch it
* @param {object[]} elements elements
* @param {object} parent element or browser
* @param {string|Function} selector string or function, or strategy name for `custom$$`
* @param {string} foundWith name of the command elements were found with, ex `$$`, `react$$`, etc
* @param {Array} props additional properties required to fetch elements again
* @returns {object[]} elements
*/
export const enhanceElementsArray = (elements, parent, selector, foundWith = '$$', props = []) => {
/**
* if we have an element collection, e.g. `const elems = $$([elemA, elemB])`
* we cna't assign a common selector to the element array
*/
if (!Array.isArray(selector)) {
elements.selector = selector;
}
elements.parent = parent;
elements.foundWith = foundWith;
elements.props = props;
return elements;
};
/**
* is protocol stub
* @param {string} automationProtocol
*/
export const isStub = (automationProtocol) => automationProtocol === './protocol-stub.js';
/**
* compare if an object (`base`) contains the same values as another object (`match`)
* @param {object} base object to compare to
* @param {object} match object that needs to match thebase
*/
export const containsHeaderObject = (base, match) => {
for (const [key, value] of Object.entries(match)) {
if (typeof base[key] === 'undefined' || base[key] !== value) {
return false;
}
}
return true;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDakMsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFBO0FBQzVCLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFFOUIsT0FBTyxRQUFRLE1BQU0sV0FBVyxDQUFBO0FBQ2hDLE9BQU8sT0FBTyxNQUFNLFNBQVMsQ0FBQTtBQUM3QixPQUFPLGdCQUFnQixNQUFNLG1CQUFtQixDQUFBO0FBQ2hELE9BQU8sTUFBTSxNQUFNLGNBQWMsQ0FBQTtBQUNqQyxPQUFPLGFBQWEsTUFBTSxjQUFjLENBQUE7QUFDeEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sYUFBYSxDQUFBO0FBR2hELE9BQU8sS0FBSyxlQUFlLE1BQU0sd0JBQXdCLENBQUE7QUFDekQsT0FBTyxLQUFLLGVBQWUsTUFBTSx3QkFBd0IsQ0FBQTtBQUN6RCxPQUFPLG9CQUFvQixNQUFNLHdDQUF3QyxDQUFBO0FBQ3pFLE9BQU8sRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLEdBQUcsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ2pFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUloRCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUE7QUFDakMsTUFBTSxzQkFBc0IsR0FBRyxvREFBb0QsQ0FBQTtBQUNuRixNQUFNLDRCQUE0QixHQUFHLENBQUMsZUFBZSxFQUFFLGNBQWMsQ0FBQyxDQUFBO0FBTXRFLE1BQU0sTUFBTSxHQUFHO0lBQ1gsT0FBTyxFQUFFLGVBQWU7SUFDeEIsT0FBTyxFQUFFLGVBQWU7Q0FDM0IsQ0FBQTtBQUVELE1BQU0sbUJBQW1CLEdBQUcsQ0FDeEIsU0FBNkMsRUFDN0MsS0FBNEIsRUFBRSxFQUFFO0lBQ2hD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