appium-xcuitest-driver
Version:
Appium driver for iOS using XCUITest for backend
323 lines • 17.9 kB
JavaScript
;
/* 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