UNPKG

appium-xcuitest-driver

Version:

Appium driver for iOS using XCUITest for backend

161 lines 5.96 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.findElOrEls = findElOrEls; exports.findNativeElementOrElements = findNativeElementOrElements; exports.doNativeFind = doNativeFind; exports.getFirstVisibleChild = getFirstVisibleChild; const lodash_1 = __importDefault(require("lodash")); const css_converter_1 = require("../css-converter"); const driver_1 = require("appium/driver"); const support_1 = require("appium/support"); async function findElOrEls(strategy, selector, mult, context) { if (this.isWebview()) { return mult ? await this.findWebElementOrElements(strategy, selector, true, context) : await this.findWebElementOrElements(strategy, selector, false, context); } return mult ? await this.findNativeElementOrElements(strategy, selector, true, context) : await this.findNativeElementOrElements(strategy, selector, false, context); } async function findNativeElementOrElements(strategy, selector, mult, context) { const initSelector = selector; let rewroteSelector = false; if (strategy === '-ios predicate string') { strategy = 'predicate string'; } else if (strategy === '-ios class chain') { strategy = WDA_CLASS_CHAIN_STRATEGY; } else if (strategy === 'css selector') { strategy = WDA_CLASS_CHAIN_STRATEGY; selector = css_converter_1.CssConverter.toIosClassChainSelector(selector); } if (strategy === 'class name') { if (selector.startsWith('UIA')) { selector = selector.substring(3); } if (!selector.startsWith('XCUIElementType')) { selector = stripViewFromSelector(`XCUIElementType${selector}`); rewroteSelector = true; } } if (strategy === 'xpath' && MAGIC_FIRST_VIS_CHILD_SEL.test(selector)) { return await this.getFirstVisibleChild(mult, context); } else if (strategy === 'xpath' && MAGIC_SCROLLABLE_SEL.test(selector)) { [strategy, selector] = rewriteMagicScrollable(mult, this.log); } else if (strategy === 'xpath') { selector = selector.replace(/(^|\/)(UIA)([^[/]+)/g, (str, g1, _g2, g3) => { rewroteSelector = true; return g1 + stripViewFromSelector(`XCUIElementType${g3}`); }); } if (rewroteSelector) { this.log.info(`Rewrote incoming selector from '${initSelector}' to ` + `'${selector}' to match XCUI type. You should consider ` + `updating your tests to use the new selectors directly`); } return mult ? await this.doNativeFind(strategy, selector, true, context) : await this.doNativeFind(strategy, selector, false, context); } async function doNativeFind(strategy, selector, mult, context) { const ctx = support_1.util.unwrapElement(context ?? null); const endpoint = `/element${ctx ? `/${ctx}/element` : ''}${mult ? 's' : ''}`; const body = { using: strategy, value: selector, }; const method = 'POST'; let els = []; try { await this.implicitWaitForCondition(async () => { try { els = (await this.proxyCommand(endpoint, method, body)); } catch { els = []; } return !lodash_1.default.isEmpty(els); }); } catch (err) { if (err.message?.match(/Condition unmet/)) { els = []; } else { throw err; } } if (mult) { return Array.isArray(els) ? els : [els]; } if (Array.isArray(els)) { if (lodash_1.default.isEmpty(els)) { throw new driver_1.errors.NoSuchElementError(); } return els[0]; } if (!els) { throw new driver_1.errors.NoSuchElementError(); } return els; } /** * Finds the first visible child element inside a context. */ async function getFirstVisibleChild(mult, context) { this.log.info(`Getting first visible child`); if (mult) { throw new Error('Cannot get multiple first visible children!'); } if (!context) { throw new Error('Cannot get first visible child without a context element'); } let index = 1; while (true) { const strategy = WDA_CLASS_CHAIN_STRATEGY; const selector = `*[${index}]`; const nthChild = (await this.doNativeFind(strategy, selector, false, context)); const visible = await this.getAttribute('visible', nthChild); if (visible === 'true') { this.log.info(`Found first visible child at position ${index}`); return nthChild; } index++; } } const MAGIC_FIRST_VIS_CHILD_SEL = /\/\*\[@firstVisible\s*=\s*('|")true\1\]/; const MAGIC_SCROLLABLE_SEL = /\/\/\*\[@scrollable\s*=\s*('|")true\1\]/; const WDA_CLASS_CHAIN_STRATEGY = 'class chain'; function stripViewFromSelector(selector) { const keepView = [ 'XCUIElementTypeScrollView', 'XCUIElementTypeCollectionView', 'XCUIElementTypeTextView', 'XCUIElementTypeWebView', ].includes(selector); if (!keepView && selector.indexOf('View') === selector.length - 4) { return selector.substring(0, selector.length - 4); } return selector; } function rewriteMagicScrollable(mult, log = null) { const pred = ['ScrollView', 'Table', 'CollectionView', 'WebView'] .map((t) => `type == "XCUIElementType${t}"`) .join(' OR '); const strategy = WDA_CLASS_CHAIN_STRATEGY; let selector = '**/*[`' + pred + '`]'; if (!mult) { selector += '[1]'; } log?.info('Rewrote request for scrollable descendants to class chain ' + `format with selector '${selector}'`); return [strategy, selector]; } //# sourceMappingURL=find.js.map