UNPKG

appium-xcuitest-driver

Version:

Appium driver for iOS using XCUITest for backend

425 lines 24 kB
"use strict"; 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 bluebird_1 = __importDefault(require("bluebird")); const session_1 = require("../helpers/session"); const desired_1 = require("../desired"); const helpers_1 = require("./helpers"); const support_1 = require("appium/support"); const asyncbox_1 = require("asyncbox"); 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 DEFAULT_CAPS = (0, desired_1.amendCapabilities)(desired_1.SAFARI_CAPS, { 'appium:safariInitialUrl': helpers_1.GUINEA_PIG_PAGE, // 'appium:safariLogAllCommunication': true, // adding 'safariIgnoreWebHostnames' to validate that adding blacklist URL's doesn't break anything 'appium:safariIgnoreWebHostnames': 'www.yahoo.com,www.bing.com,www.google.com,about:blank', }); describe('Safari - basics -', function () { this.timeout(session_1.MOCHA_TIMEOUT); let driver; describe('basics', function () { before(async function () { const caps = (0, desired_1.amendCapabilities)(DEFAULT_CAPS, { 'appium:safariIgnoreFraudWarning': false, 'appium:showSafariConsoleLog': true, }); driver = await (0, session_1.initSession)(caps); }); after(async function () { await (0, session_1.deleteSession)(); }); // TODO: in appium-remote-debugger, figure out how to check if a page is loaded describe.skip('page load timeouts', function () { describe('small timeout, slow page load', function () { it('should go to the requested page', async function () { await driver.setTimeout({ pageLoad: 3000 }); await (0, helpers_1.openPage)(driver, `${helpers_1.GUINEA_PIG_PAGE}?delay=30000`); // the page should not have time to load await (0, chai_1.expect)(driver.getPageSource()).to.eventually.include(`Let's browse!`); }); }); describe('no timeout, very slow page', function () { const startMs = Date.now(); it('should go to the requested page', async function () { // await driver.setCommandTimeout(12000); await driver.setTimeout({ pageLoad: 0 }); await (0, helpers_1.openPage)(driver, `${helpers_1.GUINEA_PIG_PAGE}?delay=3000`); // the page should load after 70000 await (0, chai_1.expect)(driver.getPageSource()).to.eventually.include('I am some page content'); (0, chai_1.expect)(Date.now() - startMs).to.be.above(3000); }); }); }); describe('context', function () { it('should be able to get current context initially', async function () { await bluebird_1.default.delay(500); await (0, chai_1.expect)(driver.getContext()).to.eventually.be.ok; }); it('should get full context list through mobile: getContexts', async function () { const ctxs = await driver.executeScript('mobile: getContexts', []); const webviews = ctxs.filter((ctx) => ctx.id !== 'NATIVE_APP'); (0, chai_1.expect)(webviews.every((ctx) => support_1.util.hasValue(ctx.title) && support_1.util.hasValue(ctx.url))).to.be.true; }); }); describe('implicit wait', function () { after(async function () { await driver.setTimeout({ implicit: 0 }); }); it('should set the implicit wait for finding web elements', async function () { await driver.setTimeout({ implicit: 5000 }); const before = new Date().getTime(); (0, chai_1.expect)((await driver.$('<dsfsdfsdfdsfsd />')).error.error).to.eql('no such element'); const after = new Date().getTime(); (0, chai_1.expect)(after - before >= 5 * 1000).to.be.ok; }); }); describe('window title', function () { it('should return a valid title on web view', async function () { await (0, chai_1.expect)(driver.getTitle()).to.eventually.include('I am a page title'); }); }); describe('element handling', function () { beforeEach(async function () { await (0, helpers_1.openPage)(driver, helpers_1.GUINEA_PIG_PAGE); }); it('should find a web element in the web view', async function () { (0, chai_1.expect)(await driver.$('#i_am_an_id')).to.exist; }); it('should find multiple web elements in the web view', async function () { (0, chai_1.expect)(await driver.$$('<a />')).to.have.length.at.least(5); }); it('should fail gracefully to find multiple missing web elements in the web view', async function () { (0, chai_1.expect)(await driver.$$('<blar />')).to.have.length(0); }); it('should find element from another element', async function () { const el = await driver.$('.border'); (0, chai_1.expect)(await el.$('./form')).to.exist; }); it('should be able to click links', async function () { const el = await driver.$('=i am a link'); await el.click(); await (0, helpers_1.spinTitleEquals)(driver, 'I am another page title'); }); it('should retrieve an element attribute', async function () { const el = await driver.$('#i_am_an_id'); await (0, chai_1.expect)(el.getAttribute('id')).to.eventually.equal('i_am_an_id'); (0, chai_1.expect)(await el.getAttribute('blar')).to.be.null; }); it('should retrieve implicit attributes', async function () { const els = await driver.$$('<option />'); (0, chai_1.expect)(els).to.have.length(3); await (0, chai_1.expect)(els[2].getAttribute('index')).to.eventually.equal('2'); }); it('should retrieve an element text', async function () { const el = await driver.$('#i_am_an_id'); await (0, chai_1.expect)(el.getText()).to.eventually.equal('I am a div'); }); // TODO: figure out what equality means here it.skip('should check if two elements are equal', async function () { const el1 = await driver.$('#i_am_an_id'); const el2 = await driver.$('#i_am_an_id'); (0, chai_1.expect)(el1).to.equal(el2); }); it('should return the page source', async function () { const source = await driver.getPageSource(); (0, chai_1.expect)(source).to.include('<html'); (0, chai_1.expect)(source).to.include('I am a page title'); (0, chai_1.expect)(source).to.include('i appear 3 times'); (0, chai_1.expect)(source).to.include('</html>'); }); it('should get current url', async function () { await (0, chai_1.expect)(driver.getUrl()).to.eventually.include('test/guinea-pig'); }); it('should get updated URL without breaking window handles', async function () { const el = await driver.$('=i am an anchor link'); await el.click(); // allow the click to happen await bluebird_1.default.delay(500); await (0, chai_1.expect)(driver.getUrl()).to.eventually.contain('#anchor'); await (0, chai_1.expect)(driver.getWindowHandles()).to.eventually.be.ok; }); it('should send keystrokes to specific element', async function () { const el = await driver.$('#comments'); await el.clearValue(); await el.setValue('hello world'); (0, chai_1.expect)(['how world', 'hello world']).to.include((await el.getAttribute('value')).toLowerCase()); }); it('should send keystrokes to active element', async function () { const el = await driver.$('#comments'); await el.click(); await el.setValue('hello world'); (0, chai_1.expect)(['how world', 'hello world']).to.include((await el.getAttribute('value')).toLowerCase()); }); it('should clear element', async function () { const el = await driver.$('#comments'); await el.setValue('hello world'); await (0, chai_1.expect)(el.getAttribute('value')).to.eventually.have.length.above(0); await el.clearValue(); await (0, chai_1.expect)(el.getAttribute('value')).to.eventually.equal(''); }); it('should say whether an input is selected', async function () { const el = await driver.$('#unchecked_checkbox'); await (0, chai_1.expect)(el.isSelected()).to.eventually.not.be.ok; await el.click(); await (0, asyncbox_1.retryInterval)(10, 1000, async function () { await (0, chai_1.expect)(el.isSelected()).to.eventually.be.ok; }); }); it('should be able to retrieve css properties', async function () { const el = await driver.$('#fbemail'); (0, chai_1.expect)((await el.getCSSProperty('background-color')).value).to.contain('rgb'); }); it('should retrieve an element size', async function () { const el = await driver.$('#i_am_an_id'); const size = await el.getSize(); (0, chai_1.expect)(size.width).to.be.above(0); (0, chai_1.expect)(size.height).to.be.above(0); }); it('should get location of an element', async function () { const el = await driver.$('#fbemail'); const loc = await el.getLocation(); (0, chai_1.expect)(loc.x).to.be.above(0); (0, chai_1.expect)(loc.y).to.be.above(0); }); // getTagName not supported by mjwp it.skip('should retrieve tag name of an element', async function () { const el = await driver.$('#fbemail'); const a = await driver.$('<a />'); await (0, chai_1.expect)(el.getTagName()).to.eventually.equal('input'); await (0, chai_1.expect)(a.getTagName()).to.eventually.equal('a'); }); it('should retrieve a window size', async function () { const size = await driver.getWindowRect(); (0, chai_1.expect)(size.height).to.be.above(0); (0, chai_1.expect)(size.width).to.be.above(0); }); // TODO: Update for WdIO compatibility it.skip('should submit a form', async function () { const el = await driver.$('#comments'); const form = await driver.$('#jumpContact'); await el.setValue('This is a comment'); await form.submit(); await (0, helpers_1.spinWait)(async function () { const comments = await driver.$('#your_comments'); await (0, chai_1.expect)(comments.getText()).to.eventually.equal('Your comments: This is a comment'); }); }); it('should return true when the element is displayed', async function () { const el = await driver.$('=i am a link'); await (0, chai_1.expect)(el.isDisplayed()).to.eventually.be.ok; }); it('should return false when the element is not displayed', async function () { const el = await driver.$('#invisible div'); await (0, chai_1.expect)(el.isDisplayed()).to.eventually.not.be.ok; }); it('should return true when the element is enabled', async function () { const el = await driver.$('=i am a link'); await (0, chai_1.expect)(el.isEnabled()).to.eventually.be.ok; }); it('should return false when the element is not enabled', async function () { await driver.executeScript(`$('#fbemail').attr('disabled', 'disabled');`, []); const el = await driver.$('#fbemail'); await (0, chai_1.expect)(el.isEnabled()).to.eventually.not.be.ok; }); it('should return the active element', async function () { const testText = 'hi there'; const el = await driver.$('#i_am_a_textbox'); await el.setValue(testText); const activeElId = await driver.getActiveElement(); const activeEl = await driver.$(activeElId); await (0, chai_1.expect)(activeEl.getAttribute('value')).to.eventually.equal(testText); }); it('should properly navigate to anchor', async function () { const el = await driver.$('=i am an anchor link'); await el.click(); // let the click happen await bluebird_1.default.delay(500); const url = await driver.getUrl(); await (0, helpers_1.openPage)(driver, url); await (0, chai_1.expect)(driver.getUrl()).to.eventually.include('#anchor'); }); it('should be able to refresh', async function () { await driver.refresh(); }); }); // TODO: Update for WdIO compatibility // describe('console logging', function () { // beforeEach(async function () { // // get the logs to clear anything out // await driver.log('safariConsole'); // await driver.get(GUINEA_PIG_SCROLLABLE_PAGE); // }); // // there can be other things logged, so check that the text is there somewhere // function checkTexts (logs, expectedTexts) { // const logText = _.map(logs, (el) => el.message || el.text).join(','); // for (const line of expectedTexts) { // logText.should.include(line); // } // } // it('should get console logs for JS on the page', async function () { // // reload the page to execute JS // await openPage(driver, GUINEA_PIG_PAGE); // const logs = await driver.log('safariConsole'); // checkTexts(logs, ['Hello from Appium', 'Loading guinea-pig page', 'Done']); // }); // it('should get console logs for JS on the page with error', async function () { // // reload the page to execute JS // await openPage(driver, `${GUINEA_PIG_PAGE}?throwError=xcuitest-error`); // const logs = await driver.log('safariConsole'); // checkTexts(logs, ['Hello from Appium', 'Loading guinea-pig page', 'Done', 'JavaScript Error: xcuitest-error']); // }); // it('should get console logs for inserted JS', async function () { // const strings = [ // 'Log something to debug', // 'Log something to warn', // 'Log something to error', // ]; // for (const line of strings) { // await driver.execute(`console.log('${line}');`); // } // const logs = await driver.log('safariConsole'); // checkTexts(logs, strings); // // execute some more and see that we don't have overlap // await driver.execute(`console.log('HELLO WORLD')`); // // new logs should _just_ be the above statement // const logs2 = await driver.log('safariConsole'); // logs2.should.have.length(1); // // there should be no overlap // _.intersection(logs, logs2).should.have.length(0); // }); // }); describe('cookies', function () { describe('within iframe webview', function () { it('should be able to get cookies for a page with none', async function () { await (0, helpers_1.openPage)(driver, helpers_1.GUINEA_PIG_IFRAME_PAGE); await driver.deleteAllCookies(); await (0, asyncbox_1.retryInterval)(5, 1000, async function () { await (0, chai_1.expect)(driver.getAllCookies()).to.eventually.have.length(0); }); }); }); describe('within webview', function () { describe('insecure', function () { beforeEach(async function () { await (0, helpers_1.openPage)(driver, helpers_1.GUINEA_PIG_PAGE); await driver.deleteCookie(helpers_1.newCookie.name); }); it('should be able to get cookies for a page', async function () { const cookies = await driver.getAllCookies(); (0, chai_1.expect)(cookies.length).to.equal(2); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie1); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie2); }); it('should be able to set a cookie for a page', async function () { await driver.addCookie(helpers_1.newCookie); const cookies = await driver.getAllCookies(); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.newCookie); // should not clobber old cookies (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie1); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie2); }); it('should be able to set a cookie with expiry', async function () { const expiredCookie = { ...helpers_1.newCookie, expiry: parseInt(String(Date.now() / 1000), 10) - 1000, // set cookie in past name: 'expiredcookie', }; let cookies = await driver.getAllCookies(); (0, helpers_1.doesNotIncludeCookie)(cookies, expiredCookie); await driver.addCookie(expiredCookie); cookies = await driver.getAllCookies(); // should not include cookie we just added because of expiry (0, helpers_1.doesNotIncludeCookie)(cookies, expiredCookie); // should not clobber old cookies (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie1); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie2); await driver.deleteCookie(expiredCookie.name); }); it('should be able to delete one cookie', async function () { await driver.addCookie(helpers_1.newCookie); let cookies = await driver.getAllCookies(); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.newCookie); await driver.deleteCookie(helpers_1.newCookie.name); cookies = await driver.getAllCookies(); (0, helpers_1.doesNotIncludeCookie)(cookies, helpers_1.newCookie); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie1); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.oldCookie2); }); it('should be able to delete all cookies', async function () { await driver.addCookie(helpers_1.newCookie); let cookies = await driver.getAllCookies(); (0, helpers_1.doesIncludeCookie)(cookies, helpers_1.newCookie); await driver.deleteAllCookies(); cookies = await driver.getAllCookies(); (0, chai_1.expect)(cookies.length).to.equal(0); (0, helpers_1.doesNotIncludeCookie)(cookies, helpers_1.oldCookie1); (0, helpers_1.doesNotIncludeCookie)(cookies, helpers_1.oldCookie2); }); describe('native context', function () { const notImplementedRegExp = /Method is not implemented/; let context; beforeEach(async function () { context = await driver.getContext(); await driver.switchContext('NATIVE_APP'); }); afterEach(async function () { if (context) { await driver.switchContext(context); } }); it('should reject all functions', async function () { await (0, chai_1.expect)(driver.addCookie(helpers_1.newCookie)).to.be.rejectedWith(notImplementedRegExp); await (0, chai_1.expect)(driver.getAllCookies()).to.be.rejectedWith(notImplementedRegExp); await (0, chai_1.expect)(driver .deleteCookie(helpers_1.newCookie.name)).to.be.rejectedWith(notImplementedRegExp); await (0, chai_1.expect)(driver.deleteAllCookies()).to.be.rejectedWith(notImplementedRegExp); }); }); }); describe('secure', function () { /* * secure cookie tests are in `./safari-ssl-e2e-specs.ts` */ }); }); }); }); }); //# sourceMappingURL=safari-basic-e2e-specs.js.map