appium-xcuitest-driver
Version:
Appium driver for iOS using XCUITest for backend
96 lines • 3.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClassChainEmitter = void 0;
const driver_1 = require("appium/driver");
const utils_1 = require("../utils");
const BOOLEAN_ATTRS = new Set(['visible', 'accessible', 'accessibility-container', 'enabled']);
const STRING_ATTRS = new Set(['label', 'name', 'value', 'type']);
/** Converts parsed CSS selectors into class chain strings. */
class ClassChainEmitter {
strategy;
constructor(strategy) {
this.strategy = strategy;
}
emit(parsed) {
return this.emitRule(parsed.rule);
}
emitRule(rule) {
if (rule.classes.length) {
throw new driver_1.errors.InvalidSelectorError(`'${rule.classes.join('.')}' is not a valid class. Must be a single string ` +
`(e.g.: XCUIElementTypeWindow) without dots separating them`);
}
let tagName = rule.tag ?? '';
if (tagName && tagName !== '*' && !tagName.toLowerCase().startsWith('xcuielementtype')) {
const capitalizedTagName = tagName.charAt(0).toUpperCase() + tagName.slice(1);
tagName = `XCUIElementType${capitalizedTagName}`;
}
let classChainSelector = tagName || '*';
const attrs = [];
if (rule.id) {
attrs.push(`name == "${rule.id}"`);
}
for (const attr of rule.attributes) {
attrs.push(this.formatEntity(attr));
}
for (const pseudo of rule.pseudos) {
attrs.push(this.formatEntity(pseudo));
}
const nonIndexAttrs = attrs.filter((attr) => typeof attr === 'string');
if (!(0, utils_1.isEmpty)(nonIndexAttrs)) {
classChainSelector += `[\`${nonIndexAttrs.join(' AND ')}\`]`;
}
const indexAttr = attrs.find((attr) => typeof attr === 'object' && attr !== null && attr.index !== undefined);
if (indexAttr) {
classChainSelector += `[${indexAttr.index}]`;
}
if (rule.nested) {
classChainSelector += `/${this.emitRule(rule.nested)}`;
}
return rule.combinator === 'child' ? classChainSelector : `**/${classChainSelector}`;
}
formatEntity(attr) {
if (attr.name === 'index') {
return this.formatIndex(attr.value);
}
if (BOOLEAN_ATTRS.has(attr.name)) {
return this.formatBooleanAttr(attr.name, attr.value);
}
if (STRING_ATTRS.has(attr.name)) {
return this.formatStringAttr(attr);
}
}
formatIndex(value) {
return { index: value ?? '' };
}
formatBooleanAttr(name, value) {
return `${this.toCamelCase(name)} == ${value ?? '1'}`;
}
formatStringAttr(attr) {
const attrName = this.toCamelCase(attr.name);
const value = attr.value ?? '';
if (value === '') {
return `[${attrName} LIKE ${value}]`;
}
switch (attr.operator) {
case '=':
return `${attrName} == "${value}"`;
case '*=':
return `${attrName} MATCHES "${(0, utils_1.escapeRegExp)(value)}"`;
case '^=':
return `${attrName} BEGINSWITH "${value}"`;
case '$=':
return `${attrName} ENDSWITH "${value}"`;
case '~=':
return `${attrName} CONTAINS "${value}"`;
default:
return `${attrName} == "${value}"`;
}
}
toCamelCase(str) {
const tokens = str.split('-').map((token) => token.charAt(0).toUpperCase() + token.slice(1).toLowerCase());
const out = tokens.join('');
return out.charAt(0).toLowerCase() + out.slice(1);
}
}
exports.ClassChainEmitter = ClassChainEmitter;
//# sourceMappingURL=class-chain-emitter.js.map