appium-xcuitest-driver
Version:
Appium driver for iOS using XCUITest for backend
419 lines β’ 21.6 kB
JavaScript
;
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