flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
829 lines • 30.2 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const response_1 = require("./response");
const _1 = require(".");
const link_1 = require("./link");
const assertionresult_1 = require("./assertionresult");
let $ = require('cheerio');
var NodeType;
(function (NodeType) {
NodeType[NodeType["Generic"] = 0] = "Generic";
NodeType[NodeType["Element"] = 1] = "Element";
NodeType[NodeType["StyleAttribute"] = 2] = "StyleAttribute";
NodeType[NodeType["Property"] = 3] = "Property";
NodeType[NodeType["Value"] = 4] = "Value";
})(NodeType = exports.NodeType || (exports.NodeType = {}));
class Node {
constructor(response, name, obj) {
this._typeOfNode = NodeType.Generic;
this._selector = null;
this._response = response;
this._name = name;
this._input = obj;
}
get $() {
return this._input;
}
get name() {
return this._name;
}
get response() {
return this._response;
}
isNullOrUndefined() {
return _1.Flagpole.isNullOrUndefined(this.$);
}
isDomElement() {
return this.getType() == 'cheerio';
}
isBrowserSelector() {
return this.getType() == 'browserselector';
}
isElementHandle() {
return this.getType() == 'elementhandle';
}
getName() {
return this.name;
}
tagName() {
return new Node(this.response, 'Tag of ' + this.name, this.getTagName());
}
getTagName() {
if (this.isDomElement()) {
return this.$.get(0).tagName;
}
return null;
}
getAttribute(name) {
if (this.isDomElement()) {
return (typeof this.$.get(0).attribs[name] !== 'undefined') ?
this.$.get(0).attribs[name] : null;
}
return null;
}
getUrl() {
if (this.isDomElement()) {
let tagName = this.getTagName();
if (tagName !== null) {
if (['img', 'script', 'video', 'audio', 'object', 'iframe'].indexOf(tagName) >= 0) {
return this.getAttribute('src');
}
else if (['a', 'link'].indexOf(tagName) >= 0) {
return this.getAttribute('href');
}
else if (['form'].indexOf(tagName) >= 0) {
return this.getAttribute('action') || this.response.scenario.getUrl();
}
}
}
else if (this.isString()) {
if (this.response.type == response_1.ResponseType.json) {
return this.toString().trim();
}
else if (this.response.type == response_1.ResponseType.html) {
return this.toString().trim().replace(/^url\(['"]?/, '').replace(/['"]?\)$/, '');
}
}
return null;
}
isFormElement() {
if (this.isDomElement()) {
return this.getTagName() === 'form';
}
return false;
}
isButtonElement() {
if (this.isDomElement()) {
return this.getTagName() === 'button';
}
return false;
}
isLinkElement() {
if (this.isDomElement()) {
return this.getTagName() === 'a' &&
this.getAttribute('href') !== null;
}
return false;
}
isImageElement() {
if (this.isDomElement()) {
return (this.getTagName() === 'img' && this.getAttribute('src') !== null);
}
return false;
}
isVideoElement() {
if (this.isDomElement()) {
return ((this.getTagName() === 'video' && this.getAttribute('src') !== null) ||
(this.getTagName() === 'source' && this.getAttribute('src') !== null && /video/i.test(this.getAttribute('type') || '')));
}
return false;
}
isAudioElement() {
if (this.isDomElement()) {
return ((this.getTagName() === 'audio' && this.getAttribute('src') !== null) ||
(this.getTagName() === 'bgsound' && this.getAttribute('src') !== null) ||
(this.getTagName() === 'source' && this.getAttribute('src') !== null && /video/i.test(this.getAttribute('type') || '')));
}
return false;
}
isScriptElement() {
if (this.isDomElement()) {
return this.getTagName() === 'script' &&
this.getAttribute('src') !== null;
}
return false;
}
isStylesheetElement() {
if (this.isDomElement()) {
return this.getTagName() === 'link' &&
(this.getAttribute('rel') || '').toLowerCase() == 'stylesheet' &&
this.getAttribute('href') !== null;
}
return false;
}
isCookie() {
return (this.$ && this.$.cookieString);
}
isClickable() {
return (this.isLinkElement() || this.isButtonElement());
}
isArray() {
return this.getType() == 'array';
}
isString() {
return this.getType() == 'string';
}
isObject() {
return this.getType() == 'object';
}
hasProperty(key) {
return this.$.hasOwnProperty && this.$.hasOwnProperty(key);
}
pass(message) {
return this.response.scenario.logResult(assertionresult_1.AssertionResult.pass(message));
}
fail(message) {
return this.response.scenario.logResult(assertionresult_1.AssertionResult.fail(message));
}
get(index) {
if (typeof index !== 'undefined') {
if (this.isArray()) {
return this.$[index];
}
else if (this.isDomElement()) {
return this.$.eq(index);
}
}
return this.$;
}
toString() {
if (this.isDomElement()) {
return (this.$.text() || this.$.val()).toString();
}
else if (!this.isNullOrUndefined() && this.$.toString) {
return this.$.toString();
}
else {
return String(this.$);
}
}
select(path, findIn) {
let node = this.response.select(path, findIn);
node._typeOfNode = NodeType.Value;
node._selector = path;
return node;
}
headers(key) {
return this.response.headers(key);
}
and() {
return this.response.and();
}
not() {
this.response.not();
return this;
}
comment(message) {
this.response.scenario.comment(message);
return this;
}
label(message) {
this.response.label(message);
return this;
}
echo() {
this.comment(this.name + ' = ' + this.$);
return this;
}
click(scenarioOrTitle, impliedAssertion = false) {
let scenario = this.getLambdaScenario(scenarioOrTitle, impliedAssertion);
if (this.isLinkElement()) {
const link = new link_1.Link(this.getAttribute('href') || '', this.response.context);
(link.isNavigation()) ?
scenario.open(link.getUri()) :
scenario.skip('Not a navigation link');
}
else if (this.isButtonElement()) {
let formNode = new Node(this.response, 'form', this.$.parents('form'));
(this.attribute('type').toString().toLowerCase() === 'submit' || !formNode.isFormElement()) ?
formNode.submit(scenario) :
scenario.skip('Button does not submit anything');
}
else {
this.fail('Not a clickable element');
scenario.skip();
}
return scenario;
}
submit(scenarioOrTitle, impliedAssertion = false) {
let scenario = this.getLambdaScenario(scenarioOrTitle, impliedAssertion);
let link = new link_1.Link(this.getUrl() || '', this.response.context);
if (this.isFormElement() && link.isNavigation()) {
let uri;
let method = this.getAttribute('method') || 'get';
scenario.method(method);
if (method == 'get') {
uri = link.getUri(this.$.serializeArray());
}
else {
let formDataArray = this.$.serializeArray();
let formData = {};
uri = link.getUri();
formDataArray.forEach(function (input) {
formData[input.name] = input.value;
});
scenario.form(formData);
}
scenario.open(uri);
}
else {
scenario.skip('Nothing to submit');
}
return scenario;
}
fillForm(formData) {
if (this.isFormElement()) {
this.comment('Filling out form');
if (_1.Flagpole.toType(formData) === 'object') {
let form = this.$;
for (let name in formData) {
this.assert(form.find('[name="' + name + '"]').val(formData[name]).val() == formData[name], 'Form field ' + name + ' equals ' + formData[name]);
}
}
}
else {
this.fail('Not a form');
}
return this;
}
getLambdaScenario(scenarioOrTitle, impliedAssertion = false) {
let node = this;
let scenario = (function () {
if (typeof scenarioOrTitle == 'string') {
let path = node.getUrl() || '';
if (node.isImageElement() ||
(node._typeOfNode == NodeType.StyleAttribute && node._selector == 'background-image') ||
/\.(jpe?g|gif|png|svg|bmp|webp|tiff?|psd)$/i.test(path)) {
return node.response.scenario.suite.Image(scenarioOrTitle);
}
else if (node.isVideoElement() ||
/\.(mp[245]|og[gv]|m3u8?|mov|mpe?g|avi|flv|f4v|webm|vp[89]|wmv|m4[vp]|ts)$/i.test(path)) {
return node.response.scenario.suite.Video(scenarioOrTitle);
}
else if (node.isStylesheetElement() ||
/\.css$/i.test(path)) {
return node.response.scenario.suite.Stylesheet(scenarioOrTitle);
}
else if (node.isScriptElement() ||
/\.js$/i.test(path)) {
return node.response.scenario.suite.Script(scenarioOrTitle);
}
else if ((node.isFormElement() || node.isClickable()) ||
/\.(html?|php|aspx?|jsp)$/i.test(path)) {
return node.response.scenario.suite.Html(scenarioOrTitle);
}
else {
return node.response.scenario.suite.Resource(scenarioOrTitle);
}
}
return scenarioOrTitle;
})();
if (impliedAssertion) {
scenario.assertions(function () {
});
}
return scenario;
}
load(scenarioOrTitle, impliedAssertion = false) {
const relativePath = this.getUrl();
const link = new link_1.Link(relativePath || '', this.response.context);
const scenario = this.getLambdaScenario(scenarioOrTitle, impliedAssertion);
if (relativePath === null) {
scenario.skip('No URL to load');
}
else if (link.isNavigation()) {
scenario.open(link.getUri());
}
else {
scenario.skip('Nothing to load');
}
return scenario;
}
find(selector) {
let node = this.response.select(selector, this.$);
node._selector = selector;
node._typeOfNode = NodeType.Element;
return node;
}
closest(selector) {
let name = 'closest ' + selector;
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().closest(selector)));
}
else if (this.isObject()) {
let arrPath = (this.response.getLastElementPath() || '').split('.');
let found = false;
let i = arrPath.length - 1;
for (; i >= 0; i--) {
if (arrPath[i] == selector) {
found = true;
break;
}
}
if (found) {
return this.select(arrPath.slice(0, i + 1).join('.'));
}
}
return this.response.setLastElement('', new Node(this.response, name, null));
}
parents(selector) {
let name = 'parent ' + selector;
if (typeof selector == 'undefined') {
return this.parent();
}
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().parents(selector)));
}
else if (this.isObject()) {
let arrPath = (this.response.getLastElementPath() || '').split('.');
if (arrPath.length > 1) {
let found = false;
let i = arrPath.length - 2;
for (; i >= 0; i--) {
if (arrPath[i] == selector) {
found = true;
break;
}
}
if (found) {
return this.select(arrPath.slice(0, i + 1).join('.'));
}
}
}
return this.response.setLastElement(null, new Node(this.response, name, null));
}
parent() {
let name = 'parent';
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().parent()));
}
else if (this.isObject()) {
let arrPath = (this.response.getLastElementPath() || '').split('.');
if (arrPath.length > 1) {
return this.select(arrPath.slice(0, arrPath.length - 1).join('.'));
}
else {
return this.response.setLastElement('', new Node(this.response, name, this.response.getRoot()));
}
}
return this.response.setLastElement(null, new Node(this.response, name, null));
}
siblings(selector) {
let name = 'siblings ' + selector;
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().siblings(selector)));
}
else if (this.isObject()) {
return this.parent().children(selector);
}
return this.response.setLastElement(null, new Node(this.response, name, null));
}
children(selector) {
let name = 'children ' + selector;
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().children(selector)));
}
else if (this.isObject() || this.isArray()) {
let obj = this.get();
if (typeof selector !== 'undefined') {
return this.select(selector, obj);
}
return this.response.setLastElement(null, new Node(this.response, name, obj));
}
return this.response.setLastElement(null, new Node(this.response, name, null));
}
next(selector) {
let name = 'next ' + selector;
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().next(selector)));
}
else if (this.isObject()) {
return this.parent().children(selector);
}
return this.response.setLastElement(null, new Node(this.response, name, null));
}
prev(selector) {
let name = 'next ' + selector;
if (this.isDomElement()) {
return this.response.setLastElement(null, new Node(this.response, name, this.get().prev(selector)));
}
else if (this.isObject()) {
return this.parent().children(selector);
}
return this.response.setLastElement(null, new Node(this.response, name, null));
}
eq(i) {
return this.nth(i);
}
nth(i) {
let obj = null;
if (i >= 0) {
if (this.isArray()) {
obj = this.$[i];
}
else if (this.isDomElement()) {
obj = this.$.eq(i);
}
}
return this.response.setLastElement(null, new Node(this.response, this.name + '[' + i + ']', obj));
}
first() {
return this.nth(0);
}
last() {
return this.nth((this.$ && this.$.length) ? (this.$.length - 1) : -1);
}
slice(start, end) {
let name = this.name + ' slice(' + start + (end ? ' to ' + end : '') + ')';
if (this.isDomElement() ||
this.isArray() ||
this.isString()) {
return new Node(this.response, name, this.get().slice(start, end));
}
return this;
}
css(key) {
let text = null;
if (this.isDomElement()) {
text = this.$.css(key);
}
let node = new Node(this.response, this.name + '[style][' + key + ']', text);
node._typeOfNode = NodeType.StyleAttribute;
node._selector = key;
return node;
}
attribute(key) {
let text = null;
if (this.isDomElement()) {
text = this.$.attr(key);
}
else if (!_1.Flagpole.isNullOrUndefined(this.$) && this.hasProperty(key)) {
text = this.$[key];
}
else if (this.response.getLastElement().isDomElement()) {
text = this.response.getLastElement().get().attr(key);
}
this._typeOfNode = NodeType.Property;
this._selector = key;
return new Node(this.response, this.name + '[' + key + ']', text);
}
property(key) {
let text;
if (this.isDomElement()) {
text = this.$.prop(key);
}
else if (!this.isNullOrUndefined() && this.hasProperty(key)) {
text = this.$[key];
}
else if (this.response.getLastElement().isDomElement()) {
text = this.response.getLastElement().get().prop(key);
}
this._typeOfNode = NodeType.Property;
this._selector = key;
return new Node(this.response, this.name + '[' + key + ']', text);
}
prop(key) {
return this.property(key);
}
data(key) {
let text = null;
if (this.isDomElement()) {
text = this.$.data(key);
}
else if (!this.isNullOrUndefined() && this.hasProperty(key)) {
text = this.$[key];
}
else if (this.response.getLastElement().isDomElement()) {
text = this.response.getLastElement().get().data(key);
}
this._typeOfNode = NodeType.Property;
this._selector = key;
return new Node(this.response, this.name + '[' + key + ']', text);
}
val() {
let text = null;
if (this.isDomElement()) {
text = this.$.val();
}
else if (!this.isNullOrUndefined()) {
text = this.$;
}
this._typeOfNode = NodeType.Value;
this._selector = null;
return new Node(this.response, 'Value of ' + this.name, text);
}
text() {
let text = null;
if (this.isDomElement()) {
text = this.$.text();
}
else if (this.isCookie()) {
text = this.$.value;
}
else if (!this.isNullOrUndefined()) {
text = this.$.toString();
}
return new Node(this.response, 'Text of ' + this.name, text);
}
length() {
let count = (this.$ && this.$.length) ?
this.$.length : 0;
return new Node(this.response, 'Length of ' + this.name, count);
}
type() {
return new Node(this.response, 'Type of ' + this.name, this.getType());
}
getType() {
return _1.Flagpole.toType(this.$);
}
parseFloat() {
return new Node(this.response, 'Float of ' + this.name, parseFloat(this.toString()));
}
parseInt() {
return new Node(this.response, 'Integer of ' + this.name, parseInt(this.toString()));
}
trim() {
let text = this.toString().trim();
return new Node(this.response, 'Trimmed text of ' + this.name, text);
}
toLowerCase() {
let text = this.toString().toLowerCase();
return new Node(this.response, 'Lowercased text of ' + this.name, text);
}
toUpperCase() {
let text = this.toString().toUpperCase();
return new Node(this.response, 'Uppercased text of ' + this.name, text);
}
decodeURI() {
let text = decodeURI(this.toString());
return new Node(this.response, 'Unescaped text of ' + this.name, text);
}
decodeURIComponent() {
let text = decodeURIComponent(this.toString());
return new Node(this.response, 'Unescaped text of ' + this.name, text);
}
encodeURI() {
let text = encodeURI(this.toString());
return new Node(this.response, 'Escaped text of ' + this.name, text);
}
encodeURIComponent() {
let text = encodeURIComponent(this.toString());
return new Node(this.response, 'Escaped text of ' + this.name, text);
}
replace(search, replace) {
let text = this.toString().replace(search, replace);
return new Node(this.response, 'Replaced text of ' + this.name, text);
}
each(callback) {
let name = this.name;
let response = this.response;
if (this.isDomElement()) {
this.$.each(function (index, el) {
el = $(el);
callback(new Node(response, name + '[' + index + ']', el), index);
});
}
else if (this.isArray()) {
this.$.forEach(function (el, index) {
callback(new Node(response, name + '[' + index + ']', el), index);
});
}
else if (this.getType() == 'object') {
let obj = this.$;
this.$.keys().forEach(function (key) {
callback(new Node(response, name + '[' + key + ']', obj[key]), key);
});
}
else if (this.getType() == 'string') {
this.$.toString().trim().split(' ').forEach(function (word, index) {
callback(new Node(response, name + '[' + index + ']', word), index);
});
}
return this;
}
every(callback) {
let name = this.name;
let response = this.response;
let every = true;
let node = this;
this.response.ignore(function () {
if (node.isDomElement()) {
node.$.each(function (index, el) {
el = $(el);
let element = new Node(response, name + '[' + index + ']', el);
if (!callback(element)) {
every = false;
}
});
}
else if (node.isArray()) {
every = node.$.every(function (el, index) {
return callback(new Node(response, name + '[' + index + ']', el));
});
}
else if (node.isObject()) {
let obj = node.$;
every = node.$.keys().every(function (key) {
return callback(new Node(response, name + '[' + key + ']', obj[key]));
});
}
else if (node.isString()) {
every = node.$.toString().trim().split(' ').every(function (word, index) {
return callback(new Node(response, name + '[' + index + ']', word));
});
}
});
this.assert(every, 'Every ' + this.name + ' passed');
return this;
}
some(callback) {
let name = this.name;
let response = this.response;
let some = false;
let node = this;
this.response.ignore(function () {
if (node.isDomElement()) {
node.$.each(function (index, el) {
el = $(el);
let element = new Node(response, name + '[' + index + ']', el);
if (callback(element)) {
some = true;
}
});
}
else if (node.isArray()) {
some = node.$.some(function (el, index) {
return callback(new Node(response, name + '[' + index + ']', el));
});
}
else if (node.isObject()) {
let obj = node.$;
some = node.$.keys().some(function (key) {
return callback(new Node(response, name + '[' + key + ']', obj[key]));
});
}
else if (node.isString()) {
some = node.$.toString().trim().split(' ').some(function (word, index) {
return callback(new Node(response, name + '[' + index + ']', word));
});
}
});
this.assert(some, 'Some ' + this.name + ' passed');
return this;
}
any(callback) {
return this.some(callback);
}
hasClass(className) {
if (this.isDomElement()) {
this.assert(this.$.hasClass(className), this.name + ' has class ' + className);
}
return this;
}
greaterThan(value) {
return this.assert(this.$ > value, this.name + ' is greater than ' + value + ' (' + this.$ + ')');
}
greaterThanOrEquals(value) {
return this.assert(this.$ >= value, this.name + ' is greater than or equal to ' + value + ' (' + this.$ + ')');
}
lessThan(value) {
return this.assert(this.$ < value, this.name + ' is less than ' + value + ' (' + this.$ + ')');
}
lessThanOrEquals(value) {
return this.assert(this.$ <= value, this.name + ' is less than or equal to ' + value + ' (' + this.$ + ')');
}
between(minValue, maxValue) {
return this.assert(this.$ >= minValue && this.$ <= maxValue, this.name + ' is between ' + minValue + ' and ' + maxValue + ' (' + this.$ + ')');
}
assert(statement, message, actualValue) {
this.response.assert(statement, message, actualValue);
return this;
}
contains(string) {
let contains = false;
if (this.isArray()) {
contains = (this.$.indexOf(string) >= 0);
}
else if (this.isBrowserSelector()) {
contains = (this.toString().indexOf(string) >= 0);
}
else if (this.isObject()) {
contains = (this.$.hasOwnProperty(string));
}
else if (!this.isNullOrUndefined()) {
contains = (this.toString().indexOf(string) >= 0);
}
return this.assert(contains, this.name + ' contains "' + string + '"');
}
contain(string) {
return this.contains(string);
}
matches(pattern) {
let value = this.toString();
return this.assert(pattern.test(value), this.name + ' matches ' + String(pattern), value);
}
startsWith(matchText) {
let assert = false;
let value = '';
if (!this.isNullOrUndefined()) {
value = this.toString();
assert = (value.indexOf(matchText) === 0);
}
return this.assert(assert, this.name + ' starts with "' + matchText + '"', matchText);
}
endsWith(matchText) {
let assert = false;
let value = '';
if (!this.isNullOrUndefined()) {
value = this.toString();
assert = (value.indexOf(matchText) === value.length - matchText.length);
}
return this.assert(assert, this.name + ' ends with "' + matchText + '"', matchText);
}
is(type) {
const myType = String(this.getType());
return this.assert((myType == type.toLocaleLowerCase()), this.name + ' is type ' + type, myType);
}
_exists() {
if (this.isDomElement()) {
return (this.$.length > 0);
}
else if (!this.isNullOrUndefined()) {
return true;
}
return false;
}
exists(message) {
return this.assert(this._exists(), message || this.name + ' exists');
}
asyncExists(message) {
return __awaiter(this, void 0, void 0, function* () {
let exists = this._exists();
if (this.isBrowserSelector() && this.response.scenario) {
const page = yield this.response.scenario.getBrowser().getPage();
if (page !== null) {
exists = (yield page.$$(this.toString())).length > 0;
}
}
return this.assert(exists, message || this.name + ' exists');
});
}
equals(value, permissiveMatching = false) {
let matchValue = this.toString();
let equals = 'equals';
let messageValue = (typeof value == 'string') ? '"' + value + '"' : value;
if (permissiveMatching) {
value = value.toLowerCase().trim();
matchValue = matchValue.toLowerCase().trim();
equals = 'is similar to';
}
return this.assert(matchValue == value, this.name + ' ' + equals + ' ' + messageValue, matchValue);
}
similarTo(value) {
return this.equals(value, true);
}
in(arrayOfValues) {
let value = this.toString();
return this.assert(arrayOfValues.indexOf(value) >= 0, this.name + ' is in list: ' + arrayOfValues.join(','), value);
}
}
exports.Node = Node;
//# sourceMappingURL=node.js.map