webdriverio
Version:
Next-gen browser and mobile automation test framework for Node.js
228 lines (183 loc) • 5.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.findStrategy = void 0;
var _constants = require("../constants");
var _lodash = _interopRequireDefault(require("lodash.isplainobject"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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'];
const XPATH_SELECTOR_REGEXP = [/^([a-z0-9|-]*)/, /(?:(\.|#)(-?[_a-zA-Z]+[_a-zA-Z0-9-]*))?/, /(?:\[(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)(?:=(?:"|')([a-zA-z0-9\-_. ]+)(?:"|'))?\])?/, /(\*)?=(.+)$/];
const IMAGEPATH_MOBILE_SELECTORS_ENDSWITH = ['.jpg', '.jpeg', '.gif', '.png', '.bmp', '.svg'];
const defineStrategy = function (selector) {
if ((0, _lodash.default)(selector)) {
if (JSON.stringify(selector).indexOf('test.espresso.matcher.ViewMatchers') < 0) return '-android datamatcher';
return '-android viewmatcher';
}
if (selector.match(DIRECT_SELECTOR_REGEXP)) {
return 'directly';
}
if (IMAGEPATH_MOBILE_SELECTORS_ENDSWITH.some(path => selector.toLowerCase().endsWith(path))) {
return '-image';
}
if (XPATH_SELECTORS_START.some(option => selector.startsWith(option))) {
return 'xpath';
}
if (selector.startsWith('=')) {
return 'link text';
}
if (selector.startsWith('*=')) {
return 'partial link text';
}
if (selector.startsWith('id=')) {
return 'id';
}
if (selector.startsWith('android=')) {
return '-android uiautomator';
}
if (selector.startsWith('ios=')) {
return '-ios uiautomation';
}
if (selector.startsWith('~')) {
return 'accessibility id';
}
if (NAME_MOBILE_SELECTORS_START.some(option => selector.toLowerCase().startsWith(option))) {
return 'class name';
}
if (selector.search(/<[0-9a-zA-Z-]+( \/)*>/g) >= 0) {
return 'tag name';
}
if (selector.search(/^\[name=("|')([a-zA-z0-9\-_.@=[\] ']+)("|')]$/) >= 0) {
return 'name';
}
if (selector === '..' || selector === '.') {
return 'xpath';
}
if (selector.match(new RegExp(XPATH_SELECTOR_REGEXP.map(rx => rx.source).join('')))) {
return 'xpath extended';
}
};
const findStrategy = function (selector, isW3C, isMobile) {
let using = DEFAULT_STRATEGY;
let value = selector;
switch (defineStrategy(selector)) {
case 'directly':
{
const match = selector.match(DIRECT_SELECTOR_REGEXP);
if (!isMobile && isW3C && !_constants.W3C_SELECTOR_STRATEGIES.includes(match[1])) {
throw new Error('InvalidSelectorStrategy');
}
using = match[1];
value = match[2];
break;
}
case 'xpath':
{
using = 'xpath';
break;
}
case 'id':
{
using = 'id';
value = selector.slice(3);
break;
}
case 'link text':
{
using = 'link text';
value = selector.slice(1);
break;
}
case 'partial link text':
{
using = 'partial link text';
value = selector.slice(2);
break;
}
case '-android uiautomator':
{
using = '-android uiautomator';
value = selector.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 = selector.slice(4);
break;
}
case 'accessibility id':
{
using = 'accessibility id';
value = selector.slice(1);
break;
}
case 'class name':
{
using = 'class name';
break;
}
case 'tag name':
{
using = 'tag name';
value = selector.replace(/<|>|\/|\s/g, '');
break;
}
case 'name':
{
if (isMobile || !isW3C) {
using = 'name';
value = selector.match(/^\[name=("|')([a-zA-z0-9\-_.@=[\] ']+)("|')]$/)[2];
}
break;
}
case 'xpath extended':
{
using = 'xpath';
const match = selector.match(new RegExp(XPATH_SELECTOR_REGEXP.map(rx => rx.source).join('')));
const PREFIX_NAME = {
'.': 'class',
'#': 'id'
};
const conditions = [];
const [tag, prefix, name, attrName, attrValue, partial, query] = match.slice(1);
if (prefix) {
conditions.push(`contains(@${PREFIX_NAME[prefix]}, "${name}")`);
}
if (attrName) {
conditions.push(attrValue ? `contains(@${attrName}, "${attrValue}")` : `@${attrName}`);
}
conditions.push(partial ? `contains(., "${query}")` : `normalize-space() = "${query}"`);
value = `.//${tag || '*'}[${conditions.join(' and ')}]`;
break;
}
case '-image':
{
using = '-image';
break;
}
}
if (!isMobile && isW3C && !_constants.W3C_SELECTOR_STRATEGIES.includes(using)) {
throw new Error('InvalidSelectorStrategy');
}
return {
using,
value
};
};
exports.findStrategy = findStrategy;