UNPKG

appium-xcuitest-driver

Version:

Appium driver for iOS using XCUITest for backend

323 lines 17.9 kB
"use strict"; /* eslint-disable mocha/no-nested-tests */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = __importDefault(require("lodash")); const session_1 = require("../helpers/session"); const desired_1 = require("../desired"); const helpers_1 = require("./helpers"); const asyncbox_1 = require("asyncbox"); const bluebird_1 = __importDefault(require("bluebird")); const element_1 = require("../helpers/element"); const chai_1 = __importStar(require("chai")); const chai_as_promised_1 = __importDefault(require("chai-as-promised")); chai_1.default.use(chai_as_promised_1.default); const caps = (0, desired_1.amendCapabilities)(desired_1.SAFARI_CAPS, { 'appium:safariInitialUrl': helpers_1.GUINEA_PIG_PAGE, 'appium:nativeWebTap': true, }); const SPIN_RETRIES = 25; const PAGE_3_LINK = 'i am a link to page 3'; const PAGE_3_TITLE = 'Another Page: page 3'; const SCROLL_AMT = 1400; describe('Safari - coordinate conversion -', function () { this.timeout(session_1.MOCHA_TIMEOUT * 2); const devices = [desired_1.DEVICE_NAME, desired_1.DEVICE_NAME_FOR_SAFARI_IPAD]; before(async function () { if (process.env.CI) { return this.skip(); } async function loadPage(driver, url) { await (0, asyncbox_1.retryInterval)(5, 1000, async function () { await (0, helpers_1.openPage)(driver, url); await (0, chai_1.expect)((0, helpers_1.spinTitle)(driver)).to.eventually.not.include('Cannot Open Page'); }); } // Close all tabs in Safari before running tests because left over tabs can affect the test results. // If possible, it's probably better to kick com.apple.mobilesafari.settings.DeleteAllDataAndCachesTask // task in com.apple.Preferences app or something equivalent rather than closing tabs via GUI. async function closeAllTabsViaSettingsApp(deviceName) { const newCaps = { 'appium:deviceName': deviceName, }; const localSettingsCaps = (0, desired_1.amendCapabilities)(desired_1.SETTINGS_CAPS, newCaps); const driver = await (0, session_1.initSession)(localSettingsCaps); //// // To open Safari menu in Settings app //// const openSafariMenuIOS18 = async () => { const windowRect = await driver.getWindowRect(); const scrollAction = [ { type: 'pointer', id: 'touch', actions: [ { type: 'pointerMove', duration: 0, x: windowRect.width / 2, y: windowRect.height * 0.8 }, { type: 'pointerDown', button: 0 }, { type: 'pause', duration: 500 }, { type: 'pointerMove', duration: 0, x: windowRect.width / 2, y: windowRect.height * 0.2 }, { type: 'pointerUp', button: 0 }, ] } ]; await driver.performActions(scrollAction); await driver.$(`-ios predicate string:type='XCUIElementTypeStaticText' AND label='Apps'`).click(); // to check the view transition to be completed await driver.$(`-ios predicate string:label='Default Apps'`); await driver.performActions(scrollAction); await driver.$(`-ios predicate string:type='XCUIElementTypeStaticText' AND label='Safari'`).click(); }; const openSafariMenuIOS17AndBelow = async () => { await driver .$(element_1.CLASS_CHAIN_SEARCH + ':**/XCUIElementTypeStaticText[`label == "Safari"`]') .click(); }; //// // To clear history and data in the safari menue //// const clearHistoryIOS18 = async () => { await driver .$(`-ios predicate string:type='XCUIElementTypeStaticText' AND label='All history'`) .click(); const closeTabEl = await driver .$(`-ios predicate string:type='XCUIElementTypeSwitch' AND label='Close All Tabs'`); if (await closeTabEl.getValue() === '0') { await closeTabEl.click(); } await driver .$(`-ios predicate string:type='XCUIElementTypeButton' AND label='Clear History'`) .click(); }; const clearHistoryIOS17 = async () => { await driver .$(`-ios predicate string:type='XCUIElementTypeSwitch' AND label='Close All Tabs'`) .click(); await driver.$$('~Clear History')[1].click(); }; const clearHistoryIOS16AndBelow = async () => { if ((await driver.$$('~Clear').length) > 0) { // for iPad await driver.$('~Clear').click(); } else { // for iPhone await driver.$('~Clear History and Data').click(); } if ((0, desired_1.isIosVersionAtLeast)('16.0')) { await driver .$(element_1.CLASS_CHAIN_SEARCH + ':**/XCUIElementTypeButton[`label == "Close Tabs"`]') .click(); } }; if ((0, desired_1.isIosVersionAtLeast)('18.0')) { await openSafariMenuIOS18(); } else { await openSafariMenuIOS17AndBelow(); } await driver.$('~CLEAR_HISTORY_AND_DATA').click(); if ((0, desired_1.isIosVersionAtLeast)('18.0')) { await clearHistoryIOS18(); } else if ((0, desired_1.isIosVersionAtLeast)('17.0')) { await clearHistoryIOS17(); } else { await clearHistoryIOS16AndBelow(); } await (0, session_1.deleteSession)(); } // define the tests, for each device for (const deviceName of devices) { describe(`${deviceName} -`, function () { this.timeout(session_1.MOCHA_TIMEOUT * 2); let driver; const localCaps = (0, desired_1.amendCapabilities)(caps, { 'appium:deviceName': deviceName }); let skipped = false; before(async function () { skipped = false; try { await closeAllTabsViaSettingsApp(deviceName); driver = await (0, session_1.initSession)(localCaps); } catch (err) { if (err.message.includes('Invalid device type') || err.message.includes('Incompatible device')) { skipped = true; return this.skip(); } throw err; } if (process.env.CI) { await driver.setTimeouts(10000); } }); after(async function () { await (0, session_1.deleteSession)(); }); beforeEach(async function () { await driver.updateSettings({ nativeWebTapStrict: false, }); }); it('should be able to tap on an element', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); it('should be able to tap on an element when the app banner is up', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_APP_BANNER_PAGE); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); it('should be able to bypass measuring the offset of banner', async function () { await driver.updateSettings({ nativeWebTapStrict: true, }); await loadPage(driver, helpers_1.GUINEA_PIG_APP_BANNER_PAGE); await (0, helpers_1.spinTitleEquals)(driver, 'I am a page title', SPIN_RETRIES); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); await driver.updateSettings({ nativeWebTapSmartAppBannerVisibility: 'invisible' }); await loadPage(driver, helpers_1.GUINEA_PIG_APP_BANNER_PAGE); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); it('should be able to tap on an element after scrolling', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_SCROLLABLE_PAGE); // FIXME mobile: scroll is broken in safari; it selects text instead of scrolling // for now we'll just use JS to scroll //await driver.execute('mobile: scroll', {direction: 'down'}); await driver.execute(`window.scrollBy(0, ${SCROLL_AMT})`); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); it('should be able to tap on a button', async function () { this.retries(5); await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); (0, chai_1.expect)(await driver.getPageSource()).to.not.include('Your comments: Hello'); const comments = await driver.$('[name="comments"]'); await driver.elementSendKeys(comments.elementId, 'Hello'); await driver.$('[name="submit"]').click(); await (0, asyncbox_1.retryInterval)(5, 500, async function () { const src = await driver.getPageSource(); (0, chai_1.expect)(src).to.include('Your comments: Hello'); }); }); it('should be able to handle an alert', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); await driver.$('#alert1').click(); await (0, asyncbox_1.retryInterval)(5, 1000, driver.acceptAlert.bind(driver)); await (0, chai_1.expect)(driver.getTitle()).to.eventually.include('I am a page title'); }); describe('with tabs -', function () { before(async function () { if (skipped || !deviceName.toLowerCase().includes('ipad')) { return this.skip(); } await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); // open a new tab and go to it await driver.execute('arguments[0].click();', await driver.$(`=i am a new window link`)); await (0, asyncbox_1.retryInterval)(10, 1000, async function () { await (0, chai_1.expect)(driver.getTitle()).to.eventually.eql('I am another page title'); }); }); it('should be able to tap on an element', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); await driver.back(); // try again, just to make sure await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); it('should be able to bypass measuring the offset', async function () { await driver.updateSettings({ nativeWebTapStrict: true, }); await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await driver.updateSettings({ nativeWebTapTabBarVisibility: 'visible' }); await loadPage(driver, helpers_1.GUINEA_PIG_PAGE); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); }); it('should be able to tap on an element after scrolling', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_SCROLLABLE_PAGE); // FIXME mobile: scroll is broken in safari; it selects text instead of scrolling // for now we'll just use JS to scroll //await driver.execute('mobile: scroll', {direction: 'down'}); await driver.execute(`window.scrollBy(0, ${SCROLL_AMT})`); await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); it('should be able to tap on an element after scrolling, when the url bar is present', async function () { await loadPage(driver, helpers_1.GUINEA_PIG_SCROLLABLE_PAGE); // FIXME mobile: scroll is broken in safari; it selects text instead of scrolling // for now we'll just use JS to scroll //await driver.execute('mobile: scroll', {direction: 'down'}); await driver.execute(`window.scrollBy(0, ${SCROLL_AMT})`); // to get the url bar, click on the URL bar const ctx = await driver.getContext(); try { await driver.switchContext('NATIVE_APP'); // get the reload button, as multi-element find to bypass // the implicit wait if (lodash_1.default.isEmpty(await driver.$$('~ReloadButton'))) { // when there is no reload button, the URL bar is minimized // so tap on it to bring it up await driver.$('~Address Bar').click(); } // time for things to happen await bluebird_1.default.delay(500); } finally { await driver.switchContext(ctx); } await driver.execute('arguments[0].click();', await driver.$(`=${PAGE_3_LINK}`)); await (0, helpers_1.spinTitleEquals)(driver, PAGE_3_TITLE, SPIN_RETRIES); }); }); }); } }); it.skip('should have devices array set', function () { // this block is just here so that the `before` block is run // it does not, however, need to actually run. Mocha FTW! }); }); //# sourceMappingURL=safari-nativewebtap-e2e-specs.js.map