UNPKG

appium-xcuitest-driver

Version:

Appium driver for iOS using XCUITest for backend

419 lines β€’ 21.6 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 }); // eslint-disable-next-line const sinon_1 = require("sinon"); const driver_1 = require("../../../lib/driver"); 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); describe('element commands', function () { let sandbox; /** @type {XCUITestDriver} */ let driver; /** @type {sinon.SinonStubbedMember<XCUITestDriver['proxyCommand']>} */ let proxyStub; before(async function () { driver = new driver_1.XCUITestDriver({}); }); beforeEach(function () { sandbox = (0, sinon_1.createSandbox)(); proxyStub = sandbox.stub(driver, 'proxyCommand'); }); afterEach(function () { sandbox.restore(); }); describe('setValueImmediate', function () { beforeEach(function () { sandbox.stub(driver, 'setValue'); }); it('should call setValue', async function () { await driver.setValueImmediate('hello', '2'); (0, chai_1.expect)(driver.setValue.calledOnceWithExactly('hello', '2')).to.be.true; (0, chai_1.expect)(driver.setValue.returned(undefined)).to.be.true; }); }); describe('getAttribute', function () { const elementId = 2; const attribute = 'enabled'; afterEach(function () { (0, chai_1.expect)(proxyStub.calledOnce).to.be.true; }); it('should properly parse boolean true attribute presented as integer', async function () { proxyStub.resolves(1); (0, chai_1.expect)(await driver.getAttribute(attribute, elementId)).to.eql('true'); }); it('should properly parse boolean false attribute presented as integer', async function () { proxyStub.resolves(0); (0, chai_1.expect)(await driver.getAttribute(attribute, elementId)).to.eql('false'); }); it('should properly parse integer attribute presented as string', async function () { proxyStub.resolves('0'); (0, chai_1.expect)(await driver.getAttribute(attribute, elementId)).to.eql('0'); }); it('should properly parse boolean attribute presented as bool', async function () { proxyStub.resolves(false); (0, chai_1.expect)(await driver.getAttribute(attribute, elementId)).to.eql('false'); }); it('should properly parse null attribute', async function () { proxyStub.resolves(null); await chai_1.default.expect(driver.getAttribute(attribute, elementId)).to.eventually.be.null; }); it('should properly parse string attribute', async function () { proxyStub.resolves('value'); (0, chai_1.expect)(await driver.getAttribute(attribute, elementId)).to.eql('value'); }); }); describe('getProperty', function () { const elementId = 2; const property = 'enabled'; afterEach(function () { (0, chai_1.expect)(proxyStub.calledOnce).to.be.true; }); it('should properly parse boolean true attribute presented as integer', async function () { proxyStub.resolves(1); (0, chai_1.expect)(await driver.getProperty(property, elementId)).to.eql('true'); }); it('should properly parse boolean false attribute presented as integer', async function () { proxyStub.resolves(0); (0, chai_1.expect)(await driver.getProperty(property, elementId)).to.eql('false'); }); it('should properly parse integer attribute presented as string', async function () { proxyStub.resolves('0'); (0, chai_1.expect)(await driver.getProperty(property, elementId)).to.eql('0'); }); it('should properly parse boolean attribute presented as bool', async function () { proxyStub.resolves(false); (0, chai_1.expect)(await driver.getProperty(property, elementId)).to.eql('false'); }); it('should properly parse null attribute', async function () { proxyStub.resolves(null); await chai_1.default.expect(driver.getProperty(property, elementId)).to.eventually.be.null; }); it('should properly parse string attribute', async function () { proxyStub.resolves('value'); (0, chai_1.expect)(await driver.getProperty(property, elementId)).to.eql('value'); }); }); describe('getAttribute - special contentSize', function () { it('should call the internal method instead of WDA', async function () { const getContentSizeStub = sandbox.stub(driver, 'getContentSize'); getContentSizeStub.resolves('foo'); (0, chai_1.expect)(await driver.getAttribute('contentSize', 2)).to.eql('foo'); (0, chai_1.expect)(proxyStub.called).to.be.false; (0, chai_1.expect)(getContentSizeStub.calledOnce).to.be.true; }); }); describe('getContentSize', function () { const el = { ELEMENT: '1234' }; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getAttribute']>} */ let getAttrStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getElementRect']>} */ let getRectStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['findElOrEls']>} */ let findElStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getSize']>} */ let getSizeStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getLocationInView']>} */ let getLocationStub; beforeEach(function () { getAttrStub = sandbox.stub(driver, 'getAttribute'); getRectStub = sandbox.stub(driver, 'getElementRect'); findElStub = sandbox.stub(driver, 'findElOrEls'); getSizeStub = sandbox.stub(driver, 'getSize'); getLocationStub = sandbox.stub(driver, 'getLocationInView'); }); describe('web context', function () { /** @type {XCUITestDriver['curContext']} */ let oldContext; beforeEach(function () { oldContext = driver.curContext; driver.curContext = 'WEBVIEW'; }); afterEach(function () { driver.curContext = oldContext; }); it('should throw when in a web context', async function () { await (0, chai_1.expect)(driver.getContentSize(el)).to.be.rejectedWith(/not yet implemented/); }); }); it('should throw if trying to get contentSize of something other than table or collection', async function () { getAttrStub.resolves('XCUIElementTypeStatusBar'); await (0, chai_1.expect)(driver.getContentSize(el)).to.be.rejectedWith(/Can't get content size for type/); }); it('should simply get the rect if just one child', async function () { getAttrStub.resolves('XCUIElementTypeTable'); findElStub.resolves([{ ELEMENT: 'foo' }]); getRectStub.resolves({ x: 0, y: 0, height: 100, width: 200 }); getSizeStub.resolves({ height: 100, width: 200 }); getLocationStub.resolves({ x: 0, y: 0 }); const contentSizeObj = JSON.parse(await driver.getContentSize(el)); (0, chai_1.expect)(contentSizeObj).to.eql({ width: 200, height: 100, top: 0, left: 0, scrollableOffset: 100, }); (0, chai_1.expect)(getRectStub.calledOnce).to.be.true; }); it('should get simple difference in element positions of a table', async function () { const el1 = { ELEMENT: 1 }; const el2 = { ELEMENT: 2 }; getAttrStub.resolves('XCUIElementTypeTable'); findElStub.resolves([el1, el2]); getRectStub.withArgs(el1).resolves({ x: 0, y: 10, width: 50, height: 60 }); getRectStub.withArgs(el2).resolves({ x: 10, y: 80, width: 60, height: 100 }); getSizeStub.resolves({ height: 100, width: 200 }); getLocationStub.resolves({ x: 0, y: 0 }); const contentSizeObj = JSON.parse(await driver.getContentSize(el)); (0, chai_1.expect)(contentSizeObj).to.eql({ width: 200, height: 100, top: 0, left: 0, scrollableOffset: 170, }); (0, chai_1.expect)(getRectStub.calledTwice).to.be.true; }); it('should be sensitive to row items in the case of a collection view', async function () { // set up a collection view with 3 rows of 2 elements. // give the last row just one element const fixtures = [ { id: 1, x: 0, y: 0, height: 50, width: 50 }, { id: 2, x: 50, y: 0, height: 50, width: 50 }, { id: 3, x: 0, y: 60, height: 50, width: 50 }, { id: 4, x: 50, y: 60, height: 50, width: 50 }, { id: 5, x: 0, y: 120, height: 50, width: 50 }, ]; const scrollableOffset = 170; // 3 rows plus space between two getAttrStub.resolves('XCUIElementTypeCollectionView'); findElStub.resolves(fixtures.map((el) => ({ ELEMENT: el.id }))); for (const item of fixtures) { getRectStub.withArgs({ ELEMENT: item.id }).resolves(item); } getSizeStub.resolves({ height: 100, width: 200 }); getLocationStub.resolves({ x: 0, y: 0 }); const contentSizeObj = JSON.parse(await driver.getContentSize(el)); (0, chai_1.expect)(contentSizeObj).to.eql({ width: 200, height: 100, top: 0, left: 0, scrollableOffset, }); (0, chai_1.expect)(getRectStub.calledThrice).to.be.true; }); }); describe('setValue', function () { describe('Native contest', function () { const elementId = 2; const expectedEndpoint = `/element/${elementId}/value`; const expectedMethod = 'POST'; describe('success', function () { it('should proxy string as array of characters', async function () { await driver.setValue('hello\uE006', elementId); (0, chai_1.expect)(proxyStub.calledOnceWithExactly(expectedEndpoint, expectedMethod, { value: ['h', 'e', 'l', 'l', 'o', '\n'], })).to.be.true; }); it('should proxy string with smileys as array of characters', async function () { await driver.setValue('helloπŸ˜€πŸ˜Ž', elementId); (0, chai_1.expect)(proxyStub.calledOnceWithExactly(expectedEndpoint, expectedMethod, { value: ['h', 'e', 'l', 'l', 'o', 'πŸ˜€', '😎'], })).to.be.true; }); it('should proxy number as array of characters', async function () { await driver.setValue(1234.56, elementId); (0, chai_1.expect)(proxyStub.calledOnceWithExactly(expectedEndpoint, expectedMethod, { value: ['1', '2', '3', '4', '.', '5', '6'], })).to.be.true; }); it('should proxy string array as array of characters', async function () { await driver.setValue(['hel', 'lo'], elementId); (0, chai_1.expect)(proxyStub.calledOnceWithExactly(expectedEndpoint, expectedMethod, { value: ['h', 'e', 'l', 'l', 'o'], })).to.be.true; }); it('should proxy integer array as array of characters', async function () { await driver.setValue([1234], elementId); (0, chai_1.expect)(proxyStub.calledOnceWithExactly(expectedEndpoint, expectedMethod, { value: ['1', '2', '3', '4'], })).to.be.true; }); }); describe('failure', function () { it('should throw invalid argument exception for null', async function () { await (0, chai_1.expect)(driver.setValue(null, elementId)).to.be.rejectedWith(/supported/); }); it('should throw invalid argument exception for object', async function () { await (0, chai_1.expect)(driver.setValue({ hi: 'there' }, elementId)).to.be.rejectedWith(/supported/); }); }); }); describe('Web contest', function () { const elementId = 2; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getAtomsElement']>} */ let atomElement; /** @type {sinon.SinonStubbedMember<XCUITestDriver['executeAtom']>} */ let executeAtom; /** @type {sinon.SinonStubbedMember<XCUITestDriver['setValueWithWebAtom']>} */ let setValueWithWebAtom; const webEl = { ELEMENT: '5000', 'element-6066-11e4-a52e-4f735466cecf': '5000' }; beforeEach(function () { driver.curContext = 'fake web context'; atomElement = sandbox.stub(driver, 'getAtomsElement').returns(webEl); executeAtom = sandbox.stub(driver, 'executeAtom'); setValueWithWebAtom = sandbox.stub(driver, 'setValueWithWebAtom'); }); afterEach(function () { sandbox.restore(); }); describe('setValueWithWebAtom', function () { it('with default', async function () { driver.opts.sendKeyStrategy = undefined; await driver.setValue('hello\uE006πŸ˜€', elementId); (0, chai_1.expect)(atomElement.calledOnce).to.be.true; (0, chai_1.expect)(executeAtom.calledOnce).to.be.true; (0, chai_1.expect)(setValueWithWebAtom.calledOnceWithExactly(webEl, 'hello\uE006πŸ˜€')).to.be.true; }); it('with oneByOne', async function () { driver.opts.sendKeyStrategy = 'oneByOne'; await driver.setValue('hello\uE006πŸ˜€', elementId); (0, chai_1.expect)(atomElement.calledOnce).to.be.true; (0, chai_1.expect)(executeAtom.calledOnce).to.be.true; (0, chai_1.expect)(setValueWithWebAtom.getCall(0).args).to.eql([webEl, 'h']); (0, chai_1.expect)(setValueWithWebAtom.getCall(1).args).to.eql([webEl, 'e']); (0, chai_1.expect)(setValueWithWebAtom.getCall(2).args).to.eql([webEl, 'l']); (0, chai_1.expect)(setValueWithWebAtom.getCall(3).args).to.eql([webEl, 'l']); (0, chai_1.expect)(setValueWithWebAtom.getCall(4).args).to.eql([webEl, 'o']); (0, chai_1.expect)(setValueWithWebAtom.getCall(5).args).to.eql([webEl, '\n']); (0, chai_1.expect)(setValueWithWebAtom.getCall(6).args).to.eql([webEl, 'πŸ˜€']); }); }); }); }); describe('getLocation for web elements', function () { /** @type {XCUITestDriver} */ let driver; const webEl = { ELEMENT: '5000', 'element-6066-11e4-a52e-4f735466cecf': '5000' }; const fixtureXOffset = 100; const fixtureYOffset = 200; /** @type {sinon.SinonStubbedMember<XCUITestDriver['execute']>} */ let executeStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['executeAtom']>} */ let atomStub; beforeEach(function () { driver = new driver_1.XCUITestDriver({}); driver.curContext = 'fake web context'; executeStub = sandbox.stub(driver, 'execute').resolves([fixtureXOffset, fixtureYOffset]); sandbox.stub(driver, 'getAtomsElement').resolvesArg(0); atomStub = sandbox.stub(driver, 'executeAtom').resolves({ x: 0, y: 0 }); proxyStub = sandbox.stub(driver, 'proxyCommand'); }); afterEach(function () { sandbox.restore(); }); it('should get location relative to scroll by default', async function () { const loc = await driver.getLocation(webEl); (0, chai_1.expect)(executeStub.calledOnce).to.be.false; (0, chai_1.expect)(atomStub.calledOnce).to.be.true; (0, chai_1.expect)(atomStub.firstCall.args[0]).to.eql('get_top_left_coordinates'); (0, chai_1.expect)(loc.x).to.equal(0); (0, chai_1.expect)(loc.y).to.equal(0); }); it('should get location relative to document with absoluteWebLocations cap', async function () { driver.opts.absoluteWebLocations = true; const loc = await driver.getLocation(webEl); (0, chai_1.expect)(executeStub.calledOnce).to.be.true; (0, chai_1.expect)(atomStub.calledOnce).to.be.true; (0, chai_1.expect)(atomStub.firstCall.args[0]).to.eql('get_top_left_coordinates'); (0, chai_1.expect)(loc.x).to.equal(fixtureXOffset); (0, chai_1.expect)(loc.y).to.equal(fixtureYOffset); }); }); describe('getElementRect', function () { /** @type {XCUITestDriver} */ let driver; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getNativeRect']>} */ let getNativeRectStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getLocationInView']>} */ let getLocationStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['getSize']>} */ let getSizeStub; /** @type {sinon.SinonStubbedMember<XCUITestDriver['isWebContext']>} */ let isWebContextStub; const elem = { ELEMENT: '5000' }; beforeEach(function () { driver = new driver_1.XCUITestDriver({}); getNativeRectStub = sandbox .stub(driver, 'getNativeRect') .resolves({ x: 0, y: 50, width: 100, height: 200 }); getLocationStub = sandbox.stub(driver, 'getLocation').resolves({ x: 0, y: 50 }); getSizeStub = sandbox.stub(driver, 'getSize').resolves({ width: 100, height: 200 }); }); afterEach(function () { sandbox.restore(); }); it('should get element rect in native context', async function () { isWebContextStub = sandbox.stub(driver, 'isWebContext').returns(false); const rect = await driver.getElementRect(elem); (0, chai_1.expect)(isWebContextStub.calledOnce).to.be.true; (0, chai_1.expect)(getNativeRectStub.calledOnce).to.be.true; (0, chai_1.expect)(getLocationStub.calledOnce).to.be.false; (0, chai_1.expect)(getSizeStub.calledOnce).to.be.false; (0, chai_1.expect)(rect.x).to.eql(0); (0, chai_1.expect)(rect.y).to.eql(50); (0, chai_1.expect)(rect.width).to.eql(100); (0, chai_1.expect)(rect.height).to.eql(200); }); it('should get element rect in Web context', async function () { isWebContextStub = sandbox.stub(driver, 'isWebContext').returns(true); const rect = await driver.getElementRect(elem); (0, chai_1.expect)(isWebContextStub.calledOnce).to.be.true; (0, chai_1.expect)(getNativeRectStub.calledOnce).to.be.false; (0, chai_1.expect)(getLocationStub.calledOnce).to.be.true; (0, chai_1.expect)(getSizeStub.calledOnce).to.be.true; (0, chai_1.expect)(rect.x).to.eql(0); (0, chai_1.expect)(rect.y).to.eql(50); (0, chai_1.expect)(rect.width).to.eql(100); (0, chai_1.expect)(rect.height).to.eql(200); }); }); }); //# sourceMappingURL=element-specs.js.map