UNPKG

flagpole

Version:

Simple and fast DOM integration, headless or headful browser, and REST API testing framework.

611 lines 25.3 kB
"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