flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
611 lines • 25.3 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppiumResponse = void 0;
const fs_1 = require("fs");
const Jimp = require("jimp");
const response_1 = require("../response");
const value_promise_1 = require("../value-promise");
const helpers_1 = require("../helpers");
const jpath_1 = require("../json/jpath");
const helpers_2 = require("../helpers");
const appium_helpers_1 = require("./appium-helpers");
const appium_element_1 = require("./appium-element");
const util_1 = require("../util");
const fs = fs_1.promises;
class AppiumResponse extends response_1.ProtoResponse {
constructor(scenario) {
super(scenario);
this.scenario = scenario;
}
init(res) {
super.init(res);
this._sessionId = res.jsonBody.value.sessionId;
this._capabilities = res.jsonBody.value.capabilities;
this.scenario.nextPrepend(() => __awaiter(this, void 0, void 0, function* () {
yield this.setDeviceProperties(this.scenario.opts.data.devProperties || {});
}));
this.scenario.after((scenario) => __awaiter(this, void 0, void 0, function* () {
yield appium_helpers_1.appiumSessionDestroy(scenario, String(this._sessionId));
}));
}
get isAndroid() {
var _a, _b, _c, _d;
return (((_b = (_a = this.capabilities) === null || _a === void 0 ? void 0 : _a.automationName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === "uiautomator2" ||
((_d = (_c = this.capabilities) === null || _c === void 0 ? void 0 : _c.automationName) === null || _d === void 0 ? void 0 : _d.toLowerCase()) === "espresso");
}
get isIos() {
var _a, _b;
return ((_b = (_a = this.capabilities) === null || _a === void 0 ? void 0 : _a.automationName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === "xcuitest";
}
getRoot() {
return this.jsonBody.$;
}
eval() {
return __awaiter(this, void 0, void 0, function* () {
throw "This type of scenario does not support eval.";
});
}
get sessionId() {
return this._sessionId || "";
}
set sessionId(sessionId) {
this._sessionId = sessionId;
}
get capabilities() {
return this._capabilities;
}
getGeolocation() {
return __awaiter(this, void 0, void 0, function* () {
if (this._geolocation) {
return this._geolocation;
}
else {
const res = yield this.get("location");
this._geolocation = res.jsonRoot.value;
return this._geolocation;
}
});
}
find(selector, a, b) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const params = helpers_1.getFindParams(a, b);
if (params.matches) {
throw "Appium does not support finding element by RegEx";
}
else if (params.contains || params.opts) {
return helpers_1.findOne(this, selector, params);
}
const usingValue = selector.split(/\/(.+)/);
const res = yield this.post("element", {
using: usingValue[0],
value: usingValue[1],
});
if (res.jsonRoot.value.ELEMENT) {
const element = yield appium_element_1.AppiumElement.create(selector, this.context, selector, res.jsonRoot.value.ELEMENT);
return element;
}
else {
return helpers_1.wrapAsValue(this.context, null, selector);
}
}));
}
findAll(selector, a, b) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const usingValue = selector.split(/\/(.+)/);
let elements = [];
const params = helpers_1.getFindParams(a, b);
let res = new jpath_1.JsonDoc({});
if (params.matches) {
throw "Appium does not support finding elements by RegEx";
}
else if (params.contains) {
if (this.capabilities.automationName.toLowerCase() === "uiautomator2") {
const values = yield appium_helpers_1.appiumFindByUiAutomator(this, selector, params.contains, params.opts);
for (let i = 0; i < (values === null || values === void 0 ? void 0 : values.length); i++) {
const element = yield appium_element_1.AppiumElement.create(selector, this.context, selector, values[i].$);
elements.push(element);
}
return elements;
}
else if (this.capabilities.automationName.toLowerCase() === "espresso") {
res = yield this.post("elements", {
using: "text",
value: params.contains,
});
}
else if (this.isIos) {
res = yield this.post("elements", {
using: "-ios predicate string",
value: `label == "${params.contains}"`,
});
}
}
else {
res = yield this.post("elements", {
using: usingValue[0],
value: usingValue[1],
});
}
for (let i = 0; i < ((_a = res.jsonRoot.value) === null || _a === void 0 ? void 0 : _a.length); i++) {
elements.push(yield appium_element_1.AppiumElement.create(selector, this.context, selector, res.jsonRoot.value[i].ELEMENT));
}
if (params.opts) {
elements = helpers_1.applyOffsetAndLimit(params.opts, elements);
}
return elements;
});
}
hideKeyboard() {
return __awaiter(this, void 0, void 0, function* () {
yield this.post("appium/device/hide_keyboard", {});
});
}
movePointer(...pointers) {
return __awaiter(this, void 0, void 0, function* () {
if (!pointers.length)
return this;
const actions = [];
pointers.forEach((pointer, i) => {
if (!pointer.end)
pointer.end = pointer.start;
if (!pointer.type || pointer.type == "default")
pointer.type = "touch";
if (!pointer.duration)
pointer.duration = 500;
if (!pointer.disposition) {
pointer.disposition = {
start: "down",
end: "up",
};
}
actions.push({
type: "pointer",
id: `pointer_${i}`,
parameters: {
pointerType: pointer.type,
},
actions: [
{
type: "pointerMove",
duration: 0,
x: pointer.start[0],
y: pointer.start[1],
origin: "viewport",
},
{
type: pointer.disposition.start == "up" ? "pointerUp" : "pointerDown",
button: 0,
},
{
type: "pointerMove",
duration: pointer.duration,
x: pointer.end[0],
y: pointer.end[1],
origin: "viewport",
},
{
type: "pause",
duration: 10,
},
{
type: pointer.disposition.end == "down" ? "pointerDown" : "pointerUp",
button: 0,
},
],
});
});
yield this.post("actions", {
actions,
});
return this;
});
}
gesture(type, opts) {
return __awaiter(this, void 0, void 0, function* () {
if (!opts.amount) {
throw "Error: must specify amount of pixels to gesture";
}
if (!opts.start) {
throw "Error: must specify starting coordinates";
}
const start = {
pointer1: [opts.start[0] - 10, opts.start[1] - 10],
pointer2: [opts.start[0] + 10, opts.start[1] + 10],
};
const end = {
pointer1: type == "stretch"
? [
start.pointer1[0] - opts.amount[0],
start.pointer1[1] - opts.amount[1],
]
: [
start.pointer1[0] + opts.amount[0],
start.pointer1[1] + opts.amount[1],
],
pointer2: type == "stretch"
? [
start.pointer2[0] + opts.amount[0],
start.pointer2[1] + opts.amount[1],
]
: [
start.pointer2[0] - opts.amount[0],
start.pointer2[1] - opts.amount[1],
],
};
yield this.movePointer({
type: "touch",
duration: opts.duration || 500,
start: start.pointer1,
end: end.pointer1,
}, {
type: "touch",
duration: opts.duration || 500,
start: start.pointer2,
end: end.pointer2,
});
return this;
});
}
rotateScreen(rotation) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof rotation === "number") {
throw "Appium only supports rotating by a string.";
}
else if (rotation.toLowerCase() !== "portrait" &&
rotation.toLowerCase() !== "landscape") {
throw "Appium rotation must be either PORTRAIT or LANDSCAPE.";
}
const res = yield this.post("orientation", {
orientation: rotation,
});
return res.jsonRoot.value;
});
}
getScreenProperties() {
return __awaiter(this, void 0, void 0, function* () {
const rotationRes = yield this.get("orientation");
const dimensionsRes = yield this.get("window/current/size");
const rotation = rotationRes.jsonRoot.value;
return {
angle: rotation,
dimensions: {
height: dimensionsRes.jsonRoot.value.height,
width: dimensionsRes.jsonRoot.value.width,
},
orientation: rotation,
};
});
}
waitForExists(selector, a, b) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const timeout = typeof a === "number" ? a : typeof b === "number" ? b : 30000;
let timedOut = false;
let elementCheckStr = "";
let element = {};
setTimeout(() => (timedOut = true), timeout);
while (!elementCheckStr) {
if (timedOut)
throw "Timed out";
if (typeof a === "string") {
element = yield this.find(selector, a);
elementCheckStr = element.$;
}
else if (util_1.toType(a) === "regexp") {
throw "Appium does not support finding element by RegEx";
}
else {
element = yield this.find(selector);
elementCheckStr = element.$;
}
yield helpers_2.delay(10);
}
return element;
}));
}
waitForXPath(xPath, timeout) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
let timedOut = false;
let elementCheckStr = "";
let element = {};
setTimeout(() => (timedOut = true), timeout || 30000);
while (!elementCheckStr) {
if (timedOut)
throw "Timed out";
element = yield this.find(xPath);
elementCheckStr = element.$;
yield helpers_2.delay(10);
}
return element;
}));
}
waitForVisible(selector, timeout) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
let timedOut = false;
let elementCheckStr = "";
let element = {};
let isVisible = false;
setTimeout(() => (timedOut = true), timeout || 30000);
while (!elementCheckStr) {
if (timedOut)
return helpers_1.wrapAsValue(this.context, null, selector);
element = yield this.find(selector);
elementCheckStr = element.$;
yield helpers_2.delay(10);
}
while (!isVisible) {
if (timedOut)
return helpers_1.wrapAsValue(this.context, null, selector);
isVisible = yield this.isVisible(element);
yield helpers_2.delay(10);
}
return element;
}));
}
waitForHidden(selector, timeout) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
let timedOut = false;
let elementCheckStr = "";
let element = {};
let isVisible = true;
setTimeout(() => (timedOut = true), timeout || 30000);
while (!elementCheckStr) {
if (timedOut)
return helpers_1.wrapAsValue(this.context, null, selector);
element = (yield this.find(selector));
elementCheckStr = element.$;
yield helpers_2.delay(10);
}
while (isVisible) {
if (timedOut)
return helpers_1.wrapAsValue(this.context, null, selector);
isVisible = yield this.isVisible(element);
yield helpers_2.delay(10);
}
return element;
}));
}
isVisible(element) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.get(`element/${element}/displayed`);
return res.jsonRoot.value;
});
}
setDeviceProperties(devProperties) {
return __awaiter(this, void 0, void 0, function* () {
yield appium_helpers_1.setDevProperties(this.sessionId, this.scenario, devProperties);
});
}
isAppInstalled(bundleId) {
return __awaiter(this, void 0, void 0, function* () {
let res = new jpath_1.JsonDoc("");
if (this.isAndroid) {
res = yield this.post("appium/device/app_installed", {
bundleId: bundleId,
});
}
else if (this.isIos) {
res = yield this.post("execute", {
script: "mobile: isAppInstalled",
args: [
{
bundleId: bundleId,
},
],
});
}
return res.jsonRoot.value;
});
}
type(selector, textToType, opts = {}) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () { return this.find(selector, opts).type(textToType); }));
}
clear(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () { return this.find(selector).clear(); }));
}
clearThenType(selector, textToType, opts = {}) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () { return this.find(selector).clear().type(textToType, opts); }));
}
getDeviceProperties() {
return __awaiter(this, void 0, void 0, function* () {
const devProperties = {};
const location = yield this.getGeolocation();
devProperties.location = {
latitude: location.latitude,
longitude: location.longitude,
altitude: location.altitude,
};
if (this.isAndroid) {
const wifiState = yield appium_helpers_1.sendAdbCommand(this.sessionId, this.scenario, "settings", ["get", "global", "wifi_on"]);
const mobileDataState = yield appium_helpers_1.sendAdbCommand(this.sessionId, this.scenario, "settings", ["get", "global", "mobile_data"]);
const locationServicesState = yield appium_helpers_1.sendAdbCommand(this.sessionId, this.scenario, "settings", ["get", "secure", "location_mode"]);
const airplaneModeState = yield appium_helpers_1.sendAdbCommand(this.sessionId, this.scenario, "settings", ["get", "global", "airplane_mode_on"]);
devProperties.network = {
wifi: wifiState == 0 ? false : true,
mobileData: mobileDataState == 0 ? false : true,
locationServices: locationServicesState == 0 ? false : true,
airplaneMode: airplaneModeState == 0 ? false : true,
};
}
else if (this.isIos) {
const wifiState = yield this._siriQueryAndResponse("Wi-Fi");
const dataState = yield this._siriQueryAndResponse("Cellular Data");
const locationSvcsState = yield this._siriQueryAndResponse("Location Services");
const airplaneModeState = yield this._siriQueryAndResponse("Airplane Mode");
yield appium_helpers_1.sendSiriCommand(this.sessionId, this.scenario, "Close Siri");
yield helpers_2.delay(3500);
devProperties.network = {
wifi: wifiState,
mobileData: dataState,
locationServices: locationSvcsState,
airplaneMode: airplaneModeState,
};
}
return devProperties;
});
}
_siriQueryAndResponse(setting) {
return __awaiter(this, void 0, void 0, function* () {
yield appium_helpers_1.sendSiriCommand(this.sessionId, this.scenario, `Get ${setting} status`);
const res = yield appium_helpers_1.getSiriEffect(this.sessionId, this.scenario, setting);
return res === "On" ? true : false;
});
}
getSource() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const res = yield this.get("source");
return helpers_1.wrapAsValue(this.context, res.jsonRoot.value, "XML source for current viewport");
}));
}
get(suffix) {
return __awaiter(this, void 0, void 0, function* () {
return appium_helpers_1.sendAppiumRequest(this.scenario, `/session/${this.sessionId}/${suffix}`, {
method: "get",
});
});
}
post(suffix, data) {
return __awaiter(this, void 0, void 0, function* () {
return appium_helpers_1.sendAppiumRequest(this.scenario, `/session/${this.sessionId}/${suffix}`, {
method: "post",
data,
});
});
}
terminateApp(app, timeout) {
return __awaiter(this, void 0, void 0, function* () {
if (this.isAndroid) {
if (timeout) {
yield this.post("appium/device/terminate_app", {
appId: app,
options: {
timeout: timeout,
},
});
}
else {
yield this.post("appium/device/terminate_app", {
appId: app,
});
}
}
else if (this.isIos) {
const res = yield this.post("execute", {
script: "mobile: terminateApp",
args: [{ bundleId: app }],
});
return res.jsonRoot.value;
}
});
}
screenshot(a, b) {
return __awaiter(this, void 0, void 0, function* () {
const opts = (typeof a !== "string" ? a : b) || {};
let localFilePath = typeof a == "string" ? a : undefined;
if (!localFilePath && opts.path) {
localFilePath = opts.path;
}
const res = yield this.get("screenshot");
const encodedData = res.jsonRoot.value;
let buff = Buffer.from(encodedData, "base64");
if (opts.clip) {
yield Jimp.read(buff)
.then((image) => {
image
.crop(opts.clip.x, opts.clip.y, opts.clip.width, opts.clip.height)
.quality(100)
.getBufferAsync(Jimp.MIME_PNG)
.then((buffer) => {
buff = buffer;
})
.catch((err) => {
if (err)
return err;
});
})
.catch((err) => {
if (err)
return err;
});
}
if (localFilePath) {
yield fs.writeFile(localFilePath, buff);
}
return buff;
});
}
resetApp() {
return __awaiter(this, void 0, void 0, function* () {
yield this.post("appium/app/reset", {});
});
}
launchApp(app, args, environment) {
return __awaiter(this, void 0, void 0, function* () {
if (this.isAndroid) {
yield this.post("appium/app/launch", {});
}
else if (this.isIos) {
if (!app)
throw "App bundleId required for launching an iOS app";
yield this.post("execute", {
script: "mobile: launchApp",
args: {
bundleId: app,
arguments: args,
environment: environment,
},
});
}
});
}
getAppiumContexts() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield appium_helpers_1.sendAppiumRequest(this.scenario, `/session/${this.sessionId}/contexts`, {
method: "get",
});
return res.jsonRoot.value;
});
}
setAppiumContext(appiumContext) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const res = yield appium_helpers_1.sendAppiumRequest(this.scenario, `/session/${this.sessionId}/context`, {
method: "post",
data: {
name: appiumContext,
},
});
if ((_a = res.jsonRoot.value) === null || _a === void 0 ? void 0 : _a.error) {
throw res.jsonRoot.value.message;
}
});
}
goBack() {
return __awaiter(this, void 0, void 0, function* () {
yield this.post("back", {});
});
}
backgroundApp(seconds = -1) {
return __awaiter(this, void 0, void 0, function* () {
if (seconds > -1) {
yield this.post("appium/app/background", {
seconds: seconds,
});
}
else {
yield this.post("appium/app/background", {});
}
});
}
}
exports.AppiumResponse = AppiumResponse;
//# sourceMappingURL=appium-response.js.map