flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
425 lines • 16.8 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.AppiumElement = void 0;
const fs_1 = require("fs");
const Jimp = require("jimp");
const dom_element_1 = require("../html/dom-element");
const value_promise_1 = require("../value-promise");
const jpath_1 = require("../json/jpath");
const helpers_1 = require("../helpers");
const appium_helpers_1 = require("./appium-helpers");
const fs = fs_1.promises;
class AppiumElement extends dom_element_1.DOMElement {
constructor(input, context, name, elementId) {
super(input, context, name || "Appium Element", input);
this._elementId = elementId || "";
}
get session() {
return this.context.response;
}
static create(input, context, name, elementId) {
return __awaiter(this, void 0, void 0, function* () {
const element = new AppiumElement(input, context, name, elementId);
element._tagName = yield element._getTagName();
if (name === null || name === "") {
if (element._tagName !== null) {
element._name = `<${element.tagName}>`;
}
}
return element;
});
}
click(opts) {
if (!opts) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this.session.post(`element/${this._elementId}/click`, {});
return this;
}));
}
return this.tap(opts);
}
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.session.post(`element/${this._elementId}/element`, {
using: usingValue[0],
value: usingValue[1],
});
if (res.jsonRoot.value.ELEMENT) {
const element = yield AppiumElement.create(selector, this.session.context, selector, res.jsonRoot.value.ELEMENT);
return element;
}
else {
return helpers_1.wrapAsValue(this.session.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.session.capabilities.automationName.toLowerCase() ===
"uiautomator2") {
const values = yield appium_helpers_1.appiumFindByUiAutomator(this.session, selector, params.contains, params.opts, this._elementId);
for (let i = 0; i < (values === null || values === void 0 ? void 0 : values.length); i++) {
const element = yield AppiumElement.create(selector, this.session.context, selector, values[i].$);
elements.push(element);
}
return elements;
}
else if (this.session.capabilities.automationName.toLowerCase() === "espresso") {
res = yield this.session.post(`element/${this._elementId}/elements`, {
using: "text",
value: params.contains,
});
}
else if (this.session.capabilities.automationName.toLowerCase() === "xcuitest") {
res = yield this.session.post(`element/${this._elementId}/elements`, {
using: "-ios predicate string",
value: `label == "${params.contains}"`,
});
}
}
else {
res = yield this.session.post(`element/${this._elementId}/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 AppiumElement.create(selector, this.context, selector, res.jsonRoot.value[i].ELEMENT));
}
if (params.opts) {
elements = helpers_1.applyOffsetAndLimit(params.opts, elements);
}
return elements;
});
}
type(input) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
var _a;
const res = yield this.session.post(`element/${this._elementId}/value`, {
text: input,
});
if ((_a = res.jsonRoot.value) === null || _a === void 0 ? void 0 : _a.error) {
throw "Element cannot be typed into. Did you choose the correct element?";
}
return this;
}));
}
clear() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this.session.post(`element/${this._elementId}/clear`, {});
return this;
}));
}
clearThenType(input) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this.clear();
yield this.type(input);
return this;
}));
}
isVisible() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.session.get(`element/${this._elementId}/displayed`);
return !!res.jsonRoot.value;
});
}
getBounds() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.session.get(`element/${this._elementId}/rect`);
if (res.jsonRoot.value.error)
return null;
const bounds = {
x: res.jsonRoot.value.x,
y: res.jsonRoot.value.y,
height: res.jsonRoot.value.height,
width: res.jsonRoot.value.width,
left: res.jsonRoot.value.x,
right: res.jsonRoot.value.x + res.jsonRoot.value.width,
top: res.jsonRoot.value.y,
bottom: res.jsonRoot.value.y + res.jsonRoot.value.height,
middle: {
x: res.jsonRoot.value.x + res.jsonRoot.value.width / 2,
y: res.jsonRoot.value.y + res.jsonRoot.value.height / 2,
},
points: [
{
x: res.jsonRoot.value.x,
y: res.jsonRoot.value.y,
},
{
x: res.jsonRoot.value.x + res.jsonRoot.value.width / 2,
y: res.jsonRoot.value.y + res.jsonRoot.value.height / 2,
},
{
x: res.jsonRoot.value.x + res.jsonRoot.value.width,
y: res.jsonRoot.value.y + res.jsonRoot.value.height,
},
],
};
return bounds;
});
}
gesture(type, opts) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const bounds = yield this.getBounds();
if (!bounds)
throw "Error: element bounds not acquired";
if (!opts.amount) {
opts.amount = [bounds.width / 2, bounds.height / 2];
}
const start = {
pointer1: type == "stretch"
? [bounds.middle.x - 10, bounds.middle.y - 10]
: [bounds.left, bounds.top],
pointer2: type == "stretch"
? [bounds.middle.x + 10, bounds.middle.y + 10]
: [bounds.right, bounds.bottom],
};
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.session.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;
}));
}
tap(opts) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const bounds = yield this.getBounds();
if (!bounds)
throw "Error: element bounds not acquired";
const duration = opts.duration || 200;
const count = opts.count || 1;
const delay = opts.delay || 200;
const type = opts.type || "touch";
for (let i = 0; i < count; i++) {
yield this.session.movePointer({
type,
duration,
start: [bounds.middle.x, bounds.middle.y],
});
yield this.context.pause(delay);
}
return this;
}));
}
longpress(opts) {
return this.tap({
type: opts.type || "touch",
duration: opts.duration || 2000,
delay: opts.delay || 200,
count: opts.count || 1,
});
}
_getValue() {
return __awaiter(this, void 0, void 0, function* () {
throw "_getValue not implemented";
});
}
_getText() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.session.get(`element/${this._elementId}/text`);
return res.jsonRoot.value;
});
}
_getTagName() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.session.get(`element/${this._elementId}/name`);
return res.jsonRoot.value || null;
});
}
_getProperty(property) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.session.get(`element/${this._elementId}/css/${property}`);
return res.jsonRoot.value || null;
});
}
_getOuterHtml() {
return __awaiter(this, void 0, void 0, function* () {
throw "_getOuterHtml not implemented";
});
}
_getInnerHtml() {
return __awaiter(this, void 0, void 0, function* () {
throw "_getInnerHtml not implemented";
});
}
_getInnerText() {
return __awaiter(this, void 0, void 0, function* () {
throw "_getInnerText not implemented";
});
}
_getClassName() {
return __awaiter(this, void 0, void 0, function* () {
throw "_getClassName not implemented";
});
}
_getAttribute(key) {
return __awaiter(this, void 0, void 0, function* () {
const possibleAttributesAndroid = [
"checkable",
"checked",
"class",
"className",
"clickable",
"content-desc",
"contentDescription",
"enabled",
"focusable",
"focused",
"long-clickable",
"longClickable",
"package",
"password",
"resource-id",
"resourceId",
"scrollable",
"selection-start",
"selection-end",
"selected",
"text",
"name",
"bounds",
"displayed",
"contentSize",
];
const possibleAttributesIos = [
"accessibilityContainer",
"accessible",
"enabled",
"frame",
"index",
"label",
"name",
"rect",
"selected",
"type",
"value",
"visible",
"wdAccessibilityContainer",
"wdAccessible",
"wdEnabled",
"wdFrame",
"wdIndex",
"wdLabel",
"wdName",
"wdRect",
"wdSelected",
"wdType",
"wdUID",
"wdValue",
"wdVisible",
];
if (this.session.isAndroid && !possibleAttributesAndroid.includes(key)) {
throw `Invalid attribute: must be one of ${possibleAttributesAndroid.join(", ")}`;
}
else if (this.session.isIos && !possibleAttributesIos.includes(key)) {
throw `Invalid attribute: must be one of ${possibleAttributesIos.join(", ")}`;
}
const res = yield this.session.get(`element/${this._elementId}/attribute/${key}`);
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 bounds = yield this.getBounds();
const res = yield this.session.get("screenshot");
const encodedData = res.jsonRoot.value;
let buff = Buffer.from(encodedData, "base64");
let x = bounds.x;
let y = bounds.y;
let width = bounds.width;
let height = bounds.height;
if (opts.clip) {
x = opts.clip.x + bounds.x;
y = opts.clip.y + bounds.y;
width = opts.clip.width;
height = opts.clip.height;
}
yield Jimp.read(buff)
.then((image) => {
image
.crop(x, y, width, 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;
});
}
toString() {
return this._elementId;
}
}
exports.AppiumElement = AppiumElement;
//# sourceMappingURL=appium-element.js.map