UNPKG

@luminati-io/webdriverio8

Version:

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

328 lines 26.2 kB
import fs from 'node:fs'; import { roleElements } from 'aria-query'; import { DEEP_SELECTOR, ARIA_SELECTOR } from '../constants.js'; const DEFAULT_STRATEGY = 'css selector'; const 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):(.+)/; const XPATH_SELECTORS_START = [ '/', '(', '../', './', '*/' ]; const NAME_MOBILE_SELECTORS_START = [ 'uia', 'xcuielementtype', 'android.widget', 'cyi', 'android.view' ]; const 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 /(\*)?=(.+)$/, ]; const IMAGEPATH_MOBILE_SELECTORS_ENDSWITH = [ '.jpg', '.jpeg', '.gif', '.png', '.bmp', '.svg' ]; const defineStrategy = function (selector) { // Condition with checking isPlainObject(selector) should be first because // in case of "selector" argument is a plain object then .match() will cause // an error like "selector.match is not a function" // Use '-android datamatcher' or '-android viewmatcher' strategy if selector is a plain object (Android only) if (typeof selector === 'object') { if (JSON.stringify(selector).indexOf('test.espresso.matcher.ViewMatchers') < 0) { return '-android datamatcher'; } return '-android viewmatcher'; } const stringSelector = selector; // Check if user has specified locator strategy directly if (stringSelector.match(DIRECT_SELECTOR_REGEXP)) { return 'directly'; } // Use appium image strategy if selector ends with certain text(.jpg,.gif..) if (IMAGEPATH_MOBILE_SELECTORS_ENDSWITH.some(path => { const selector = stringSelector.toLowerCase(); return selector.endsWith(path) && selector !== path; })) { return '-image'; } // Use xPath strategy if selector starts with // if (XPATH_SELECTORS_START.some(option => stringSelector.startsWith(option))) { return 'xpath'; } // Use link text strategy if selector starts with = if (stringSelector.startsWith('=')) { return 'link text'; } // Use partial link text strategy if selector starts with *= if (stringSelector.startsWith('*=')) { return 'partial link text'; } // Use id strategy if the selector starts with id= if (stringSelector.startsWith('id=')) { return 'id'; } // use shadow dom selector if (stringSelector.startsWith(DEEP_SELECTOR)) { return 'shadow'; } // use aria selector if (stringSelector.startsWith(ARIA_SELECTOR)) { return 'aria'; } // Recursive element search using the UiAutomator library (Android only) if (stringSelector.startsWith('android=')) { return '-android uiautomator'; } // Recursive element search using the UIAutomation library (iOS-only) if (stringSelector.startsWith('ios=')) { return '-ios uiautomation'; } // Recursive element search using accessibility id if (stringSelector.startsWith('~')) { return 'accessibility id'; } // Class name mobile selector // for iOS = UIA... // for Android = android.widget if (NAME_MOBILE_SELECTORS_START.some(option => stringSelector.toLowerCase().startsWith(option))) { return 'class name'; } // Use tag name strategy if selector contains a tag // e.g. "<div>" or "<div />" if (stringSelector.search(/<[0-9a-zA-Z-]+( \/)*>/g) >= 0) { return 'tag name'; } // Use name strategy if selector queries elements with name attributes for JSONWP // or if isMobile is used even when w3c is used // e.g. "[name='myName']" or '[name="myName"]' if (stringSelector.search(/^\[name=(?:"(.[^"]*)"|'(.[^']*)')]$/) >= 0) { return 'name'; } // Allow to move up to the parent or select current element if (selector === '..' || selector === '.') { return 'xpath'; } // Any element with given class, id, or attribute and content // e.g. h1.header=Welcome or [data-name=table-row]=Item or #content*=Intro if (stringSelector.match(new RegExp(XPATH_SELECTOR_REGEXP.map(rx => rx.source).join('')))) { return 'xpath extended'; } if (stringSelector.match(/^\[role=[A-Za-z]+]$/)) { return 'role'; } }; export const findStrategy = function (selector, isW3C, isMobile) { 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'); // ToDo: move error to wdio-error package } 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 'aria': { const label = stringSelector.slice(ARIA_SELECTOR.length); const conditions = [ // aria label is recevied by other element with aria-labelledBy // https://www.w3.org/TR/accname-1.1/#step2B `.//*[@aria-labelledby=(//*[normalize-space(text()) = "${label}"]/@id)]`, // aria label is recevied by other element with aria-labelledBy // https://www.w3.org/TR/accname-1.1/#step2B `.//*[@aria-describedby=(//*[normalize-space(text()) = "${label}"]/@id)]`, // element has direct aria label // https://www.w3.org/TR/accname-1.1/#step2C `.//*[@aria-label = "${label}"]`, // input and textarea with a label // https://www.w3.org/TR/accname-1.1/#step2D `.//input[@id = (//label[normalize-space() = "${label}"]/@for)]`, `.//textarea[@id = (//label[normalize-space() = "${label}"]/@for)]`, // input and textarea with a label as parent // https://www.w3.org/TR/accname-1.1/#step2D `.//input[//ancestor::label[normalize-space(text()) = "${label}"]]`, `.//textarea[//ancestor::label[normalize-space(text()) = "${label}"]]`, // aria label is received by a placeholder // https://www.w3.org/TR/accname-1.1/#step2D `.//input[@placeholder="${label}"]`, `.//textarea[@placeholder="${label}"]`, // aria label is received by a aria-placeholder // https://www.w3.org/TR/accname-1.1/#step2D `.//input[@aria-placeholder="${label}"]`, `.//textarea[@aria-placeholder="${label}"]`, // aria label is received by a title // https://www.w3.org/TR/accname-1.1/#step2D `.//*[not(self::label)][@title="${label}"]`, // images with an alt tag // https://www.w3.org/TR/accname-1.1/#step2D `.//img[@alt="${label}"]`, // aria label is received from element text content // https://www.w3.org/TR/accname-1.1/#step2G `.//*[not(self::label)][normalize-space(text()) = "${label}"]` ]; using = 'xpath'; value = conditions.join(' | '); 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 || !isW3C) { 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 === '.') { // trick to match a class name exactly 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 getValue = () => `.//${tag || '*'}[${conditions.join(' and ')}]`; value = getValue(); if (!partial) { conditions.pop(); conditions.push(`not(${value})`, `normalize-space() = "${insensitive ? query.toLowerCase() : query}"`); value = value + ' | ' + getValue(); } break; } case '-image': { using = '-image'; value = fs.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 }; }; const 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; }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmluZFN0cmF0ZWd5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2ZpbmRTdHJhdGVneS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFFeEIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUV6QyxPQUFPLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBRTlELE1BQU0sZ0JBQWdCLEdBQUcsY0FBYyxDQUFBO0FBQ3ZDLE1BQU0sc0JBQXNCLEdBQUcsOE9BQThPLENBQUE7QUFDN1EsTUFBTSxxQkFBcUIsR0FBRztJQUMxQixHQUFHLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsSUFBSTtDQUM5QixDQUFBO0FBQ0QsTUFBTSwyQkFBMkIsR0FBRztJQUNoQyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLGNBQWM7Q0FDcEUsQ0FBQTtBQUNELE1BQU0scUJBQXFCLEdBQUc7SUFDMUIsV0FBVztJQUNYLGdCQUFnQjtJQUNoQixnQ0FBZ0M7SUFDaEMseUNBQXlDO0lBQ3pDLGlEQUFpRDtJQUNqRCw4RUFBOEU7SUFDOUUsNEJBQTRCO0lBQzVCLE9BQU87SUFDUCxvQkFBb0I7SUFDcEIsYUFBYTtDQUNoQixDQUFBO0FBQ0QsTUFBTSxtQ0FBbUMsR0FBRztJQUN4QyxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU07Q0FDbEQsQ0FBQTtBQUlELE1BQU0sY0FBYyxHQUFHLFVBQVUsUUFBMEI7SUFDdkQsMEVBQTBFO0lBQzFFLDRFQUE0RTtJQUM1RSxtREFBbUQ7SUFDbkQsNkdBQTZHO0lBQzdHLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDL0IsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FB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