UNPKG

flagpole

Version:

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

829 lines 30.2 kB
"use strict"; 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