flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
478 lines • 22.4 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.BrowserElement = void 0;
const puppeteer_element_1 = require("./puppeteer-element");
const util_1 = require("../util");
const csstoxpath_1 = require("csstoxpath");
const value_promise_1 = require("../value-promise");
class BrowserElement extends puppeteer_element_1.PuppeteerElement {
constructor(input, context, name, path) {
super(input, context, name, path);
this._input = input;
this._path = path || "";
}
get $() {
return this._input;
}
static create(input, context, name, path) {
return new Promise((resolve) => {
const element = new BrowserElement(input, context, name, path);
if (name === null) {
element._name = String(path);
}
Promise.all([element._getTagName(), element._getSourceCode()]).then(() => {
resolve(element);
});
});
}
find(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const element = yield this.$.$(selector);
const name = `${selector} under ${this.name}`;
const path = `${this.path} ${selector}`;
if (element !== null) {
return BrowserElement.create(element, this.context, name, path);
}
return this._wrapAsValue(null, name);
}));
}
findAll(selector) {
return __awaiter(this, void 0, void 0, function* () {
const elements = yield this.$.$$(selector);
const out = [];
yield util_1.asyncForEach(elements, (element, i) => __awaiter(this, void 0, void 0, function* () {
out.push(yield BrowserElement.create(element, this.context, `${selector}[${i}] under ${this.name}`, `${this.path} ${selector}[${i}]`));
}));
return out;
});
}
getAncestors(selector) {
return __awaiter(this, void 0, void 0, function* () {
return this._elementHandlesToValueArray(yield this._xQuery("ancestor::", selector), `Ancestors ${selector} of ${this.name}`, `${this.path}[ancestor::${selector}]`);
});
}
getAncestorOrSelf(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
return this._elementHandlesToFirstValue(yield this._xQuery("ancestor-or-self::", selector, "[1]"), `Ansestor or self ${selector} of ${this.name}`, `ancestor-or-self::${selector}[1]`);
}));
}
getFirstChild(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
return this._elementHandlesToFirstValue(yield this._xQuery("child::", selector, "[1]"), `Child ${selector} of ${this.name}`, `child::${selector}[1]`);
}));
}
getLastChild(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
return this._elementHandlesToFirstValue(yield this._xQuery("child::", selector, "[last()]"), `Last child ${selector} of ${this.name}`, `child::${selector}[last()]`);
}));
}
getFirstSibling(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const siblings = yield this.getSiblings(selector);
return siblings[0];
}));
}
getLastSibling(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const siblings = yield this.getSiblings(selector);
return siblings[siblings.length - 1];
}));
}
getChildOrSelf(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const self = yield this._xQuery("self::", selector);
const elements = self.length
? self
: yield this._xQuery("child::", selector);
return this._elementHandlesToFirstValue(elements, `Child or self ${selector} of ${this.name}`, `self or child::${selector}[0]`);
}));
}
getDescendantOrSelf(selector) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
return this._elementHandlesToFirstValue(yield this._xQuery("descendant-or-self::", selector), `Descendant or self ${selector} of ${this.name}`, `descendant-or-self::${selector}[0]`);
}));
}
getDescendants(selector) {
return __awaiter(this, void 0, void 0, function* () {
return this._elementHandlesToValueArray(yield this._xQuery("descendant::", selector), `Descendants ${selector} of ${this.name}`, `${this.path}[descendant::${selector}]`);
});
}
getAncestor(selector = "*") {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const closest = yield this._xQuery("ancestor::", selector);
const name = `Ancestor ${selector} of ${this.name}`;
const path = `${this.path}[ancestor::${selector}]`;
return closest.length > 0
? BrowserElement.create(closest[0], this.context, name, path)
: this._wrapAsValue(null, name, this);
}));
}
getChildren(selector = "*") {
return __awaiter(this, void 0, void 0, function* () {
const children = yield this._xQuery("child::", selector);
const out = [];
yield util_1.asyncForEach(children, (child, i) => __awaiter(this, void 0, void 0, function* () {
const name = `Child ${selector} ${i} of ${this.name}`;
const path = `${this.path}[child::${selector}][${i}]`;
out.push(yield BrowserElement.create(child, this.context, name, path));
}));
return out;
});
}
getParent() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const parents = yield this.$.$x("..");
const name = `Parent of ${this.name}`;
const path = `${this.path}[..]`;
if (parents.length > 0) {
return BrowserElement.create(parents[0], this.context, name, path);
}
return this._wrapAsValue(null, name, this);
}));
}
getSiblings(selector = "*") {
return __awaiter(this, void 0, void 0, function* () {
const prevSiblings = yield this._xQuery("preceding-sibling::", selector);
const nextSiblings = yield this._xQuery("following-sibling::", selector);
const siblings = [];
yield util_1.asyncForEach(prevSiblings.concat(nextSiblings), (sibling, i) => __awaiter(this, void 0, void 0, function* () {
const name = `Sibling ${i} of ${this.name}`;
const path = `${this.path}[sibling::${selector}][${i}]`;
siblings.push(yield BrowserElement.create(sibling, this.context, name, path));
}));
return siblings;
});
}
getPreviousSibling(selector = "*") {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const siblings = yield this._xQuery("preceding-sibling::", selector);
const name = `Previous Sibling of ${this.name}`;
const path = `${this.path}[preceding-sibling::${selector}][0]`;
if (siblings.length > 0) {
return BrowserElement.create(siblings[0], this.context, name, path);
}
return this._wrapAsValue(null, name, this);
}));
}
getPreviousSiblings(selector = "*") {
return __awaiter(this, void 0, void 0, function* () {
const siblingElements = yield this._xQuery("preceding-sibling::", selector);
const siblings = [];
yield util_1.asyncForEach(siblingElements, (sibling, i) => __awaiter(this, void 0, void 0, function* () {
const name = `Previous Sibling ${i} of ${this.name}`;
const path = `${this.path}[preceding-sibling::${selector}][${i}]`;
siblings.push(yield BrowserElement.create(sibling, this.context, name, path));
}));
return siblings;
});
}
getNextSibling(selector = "*") {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const siblings = yield this._xQuery("following-sibling::", selector);
const name = `Next Sibling of ${this.name}`;
const path = `${this.path}[following-sibling::${selector}][0]`;
if (siblings.length > 0) {
return BrowserElement.create(siblings[0], this.context, name, path);
}
return this._wrapAsValue(null, name, this);
}));
}
getNextSiblings(selector = "*") {
return __awaiter(this, void 0, void 0, function* () {
const siblingElements = yield this._xQuery("following-sibling::", selector);
const siblings = [];
yield util_1.asyncForEach(siblingElements, (sibling, i) => __awaiter(this, void 0, void 0, function* () {
const name = `Next Sibling ${i} of ${this.name}`;
const path = `${this.path}/following-sibling::${selector}[${i}]`;
siblings.push(yield BrowserElement.create(sibling, this.context, name, path));
}));
return siblings;
});
}
getBounds(boxType = "border") {
return __awaiter(this, void 0, void 0, function* () {
const allowedTypes = ["content", "padding", "border", "margin"];
if (allowedTypes.indexOf(boxType) < 0) {
throw new Error(`${boxType} is not a valid box type. Must be one of the following: ${allowedTypes.join(", ")}.`);
}
const boxModel = yield this._input.boxModel();
if (boxModel !== null) {
return {
x: boxModel[boxType][0].x,
y: boxModel[boxType][0].y,
width: boxModel.width,
height: boxModel.height,
left: boxModel[boxType][0].x,
right: boxModel[boxType][0].x + boxModel.width,
top: boxModel[boxType][0].y,
bottom: boxModel[boxType][0].y + boxModel.height,
middle: {
x: boxModel[boxType][0].x + boxModel.width / 2,
y: boxModel[boxType][0].y + boxModel.height / 2,
},
points: boxModel[boxType],
};
}
return null;
});
}
focus() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.focus();
this._completedAction("FOCUS");
return this;
}));
}
blur() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.evaluate((node) => { var _a; return (_a = node.parentElement) === null || _a === void 0 ? void 0 : _a.focus(); });
this._completedAction("BLUR");
return this;
}));
}
hover() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.hover();
this._completedAction("HOVER");
return this;
}));
}
tap() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.tap();
this._completedAction("TAP");
return this;
}));
}
press(key, opts) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.press(key, opts || {});
this._completedAction("PRESS", key);
return this;
}));
}
type(textToType, opts = {}) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.type(textToType, opts);
this._completedAction("TYPE", (yield this._isPasswordField())
? textToType.replace(/./g, "*")
: textToType);
return this;
}));
}
clear() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this._input.click({ clickCount: 3 });
yield this._page.keyboard.press("Backspace");
this._completedAction("CLEAR");
return this;
}));
}
fillForm(a, b) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
const isForm = yield this._isFormTag();
if (!isForm) {
throw new Error("This is not a form element.");
}
const attributeName = typeof a === "string" ? a : "name";
const formData = (typeof a === "string" ? b : a) || {};
for (const name in formData) {
const value = formData[name];
const selector = `${this._path} [${attributeName}="${name}"]`;
const inputs = yield this._page.$$(selector);
if (inputs.length == 0) {
this.context.logOptionalFailure(`Could not set form field ${name} to ${value}, because the field did not exist.`, selector);
}
else {
const input = inputs[0];
const tagName = String(yield (yield input.getProperty("tagName")).jsonValue()).toLowerCase();
const inputType = String(yield (yield input.getProperty("type")).jsonValue()).toLowerCase();
yield this._page.focus(selector);
if (tagName == "select") {
yield this._page.select(selector, value);
}
else if (tagName == "input") {
if (inputType == "radio" || inputType == "checkbox") {
const multiValues = util_1.toType(value) == "array" ? value : [value];
for (let i = 0; i < inputs.length; i++) {
const checkbox = inputs[i];
const isChecked = !!(yield (yield checkbox.getProperty("checked")).jsonValue());
const checkboxValue = String(yield (yield checkbox.getProperty("value")).jsonValue());
if ((multiValues.indexOf(checkboxValue) >= 0 && !isChecked) ||
(multiValues.indexOf(checkboxValue) < 0 && isChecked)) {
yield checkbox.click();
}
}
}
else if (inputType == "button" ||
inputType == "submit" ||
inputType == "reset") {
}
else {
yield this.context.clearThenType(selector, value);
}
}
else if (tagName == "button") {
}
}
this._completedAction("FILL");
}
return this;
}));
}
submit() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
if (!this._isFormTag()) {
throw new Error("You can only use .submit() with a form element.");
}
const scenario = this.context.scenario;
if (scenario.page === null) {
throw new Error("Page was null");
}
yield scenario.page.evaluate((form) => form.submit(), this.$);
this._completedAction("SUBMIT");
return this;
}));
}
click() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
this._completedAction("CLICK");
yield this.$.click();
return this;
}));
}
screenshot(a, b) {
const localFilePath = typeof a == "string" ? a : undefined;
const opts = (typeof a !== "string" ? a : b) || {};
return this._input.screenshot({
path: localFilePath || opts.path,
encoding: "binary",
omitBackground: opts.omitBackground || false,
});
}
selectOption(valuesToSelect) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
valuesToSelect = util_1.toArray(valuesToSelect);
this._completedAction("SELECT", valuesToSelect.join(", "));
const valuesSelected = yield this.$.select.apply(this.$, valuesToSelect);
this.context
.assert(`Select values on ${this.name}`, valuesToSelect.length == valuesSelected.length)
.equals(true);
return this;
}));
}
pressEnter() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this.$.press("Enter");
this._completedAction("ENTER");
return this;
}));
}
scrollTo() {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
yield this.$.evaluate((e) => e.scrollIntoView());
return this;
}));
}
isHidden() {
return __awaiter(this, void 0, void 0, function* () {
return !(yield this.isVisible());
});
}
isVisible() {
return __awaiter(this, void 0, void 0, function* () {
const isVisibleHandle = yield this._page.evaluateHandle((e) => {
const style = window.getComputedStyle(e);
return (style &&
style.display !== "none" &&
style.visibility !== "hidden" &&
style.opacity !== "0");
}, this.$);
const visible = yield isVisibleHandle.jsonValue();
const box = yield this.$.boxModel();
return !!visible && !!box;
});
}
_getInnerText() {
return __awaiter(this, void 0, void 0, function* () {
return String(yield this._eval((e) => e.innerText, this.$));
});
}
_getInnerHtml() {
return __awaiter(this, void 0, void 0, function* () {
return String(yield this._eval((e) => e.innerHTML, this.$));
});
}
_getOuterHtml() {
return __awaiter(this, void 0, void 0, function* () {
return String(yield this._eval((e) => e.outerHTML, this.$));
});
}
_getValue() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this._input.getProperty("value")).jsonValue();
});
}
_getText() {
return __awaiter(this, void 0, void 0, function* () {
const textNode = yield this._input.getProperty("textContent");
return String(yield textNode.jsonValue());
});
}
_getClassName() {
return __awaiter(this, void 0, void 0, function* () {
const classNode = yield this._input.getProperty("className");
return String(yield classNode.jsonValue());
});
}
_getTagName() {
return __awaiter(this, void 0, void 0, function* () {
const handle = yield this._input.getProperty("tagName");
const value = String(yield handle.jsonValue());
this._tagName = value.toLowerCase();
return value;
});
}
_getAttribute(key) {
return __awaiter(this, void 0, void 0, function* () {
const value = yield this._page.evaluate((el, key) => el.getAttribute(key), this._input, key);
return value === null ? null : String(value);
});
}
_isPasswordField() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this.getAttribute("type")).$ == "password";
});
}
_elementHandlesToFirstValue(elements, name, path) {
return value_promise_1.ValuePromise.execute(() => __awaiter(this, void 0, void 0, function* () {
return elements.length > 0
? yield BrowserElement.create(elements[0], this.context, name, path)
: this._wrapAsValue(null, name, path);
}));
}
_elementHandlesToValueArray(elements, name, path) {
return __awaiter(this, void 0, void 0, function* () {
const out = [];
yield util_1.asyncMap(elements, (child, i) => __awaiter(this, void 0, void 0, function* () {
return yield BrowserElement.create(child, this.context, `${name} [${i}]`, `${path} [${i}]`);
}));
return out;
});
}
_xQuery(prefix, selector = "*", suffix = "") {
const path = `${prefix}${csstoxpath_1.default(selector)}${suffix}`;
return this.$.$x(path);
}
}
exports.BrowserElement = BrowserElement;
//# sourceMappingURL=browser-element.js.map