UNPKG

flagpole

Version:

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

521 lines 22.2 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 }); const value_1 = require("./value"); const assertionresult_1 = require("./logging/assertionresult"); const assertionschema_1 = require("./assertionschema"); const Ajv = require("ajv"); const util_1 = require("./util"); const imagecompare_1 = require("./imagecompare"); class Assertion { constructor(context, thisValue, message) { this._not = false; this._optional = false; this._result = null; this._finishedResolver = () => { }; this._statement = null; this._assertionMade = false; this._defaultMessages = ["True", "False"]; this._context = context; this._input = thisValue; this._message = typeof message == "undefined" ? null : message; this._finishedPromise = new Promise(resolve => { this._finishedResolver = resolve; }); } get and() { this._resolveAssertion(); const assertion = new Assertion(this._context, this._input, this._message ? `&& ${this._message}` : null); this._not && assertion.not; this._optional && assertion.optional; return assertion; } get type() { this._resolveAssertion(); const type = new value_1.Value(util_1.toType(this._getCompareValue(this._input)), this._context, `Type of ${this._getSubject()}`); const assertion = new Assertion(this._context, type, this._message); this._not && assertion.not; this._optional && assertion.optional; return assertion; } get length() { this._resolveAssertion(); const length = (() => { const thisValue = this._getCompareValue(this._input); return thisValue && thisValue.length ? thisValue.length : 0; })(); const assertion = new Assertion(this._context, new value_1.Value(length, this._context, `Length of ${this._getSubject()}`), this._message); this._not && assertion.not; this._optional && assertion.optional; return assertion; } get keys() { this._resolveAssertion(); const keys = (() => { const thisValue = this._getCompareValue(this._input); return util_1.isNullOrUndefined(thisValue) ? [] : Object.keys(thisValue); })(); const assertion = new Assertion(this._context, new value_1.Value(keys, this._context, `Keys of ${this._getSubject()}`), this._message); this._not && assertion.not; this._optional && assertion.optional; return assertion; } get values() { this._resolveAssertion(); const values = (() => { const thisValue = this._getCompareValue(this._input); return util_1.isNullOrUndefined(thisValue) ? [] : Object.values(thisValue); })(); const assertion = new Assertion(this._context, new value_1.Value(values, this._context, `Values of ${this._getSubject()}`), this._message); this._not && assertion.not; this._optional && assertion.optional; return assertion; } get not() { this._not = true; return this; } get optional() { this._optional = true; return this; } get result() { return this._finishedPromise; } get assertionMade() { return this._assertionMade || this._finishedPromise.isResolved(); } get isFinalized() { return this._result !== null || this._statement !== null; } get name() { return this._message || String(this._input); } get passed() { return this._statement; } static create(context, thisValue, message) { return __awaiter(this, void 0, void 0, function* () { return new Assertion(context, thisValue, message); }); } exactly(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); this._setDefaultMessages(`${this._getSubject()} is not exactly ${thatValue}`, `${this._getSubject()} is exactly ${thatValue}`); return this._evalulate(thisValue === thatValue, thisValue); } equals(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); this._setDefaultMessages(`${this._getSubject()} does not equal ${thatValue}`, `${this._getSubject()} equals ${thatValue}`); return this._evalulate(thisValue == thatValue, thisValue); } like(value) { const thisValue = String(this._getCompareValue(this._input)) .toLowerCase() .trim(); const thatValue = String(this._getCompareValue(value)) .toLowerCase() .trim(); this._setDefaultMessages(`${this._getSubject()} is not like ${thatValue}`, `${this._getSubject()} is like ${thatValue}`); return this._evalulate(thisValue == thatValue, thisValue); } greaterThan(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); this._setDefaultMessages(`${this._getSubject()} is not greater than ${thatValue}`, `${this._getSubject()} is greater than ${thatValue}`); return this._evalulate(parseFloat(thisValue) > parseFloat(thatValue), thisValue); } greaterThanOrEquals(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); this._setDefaultMessages(`${this._getSubject()} is not greater than or equal to ${thatValue}`, `${this._getSubject()} is greater than or equal to ${thatValue}`); return this._evalulate(parseFloat(thisValue) >= parseFloat(thatValue), thisValue); } lessThan(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); this._setDefaultMessages(`${this._getSubject()} is not less than ${thatValue}`, `${this._getSubject()} is less than ${thatValue}`); return this._evalulate(parseFloat(thisValue) < parseFloat(thatValue), thisValue); } lessThanOrEquals(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); this._setDefaultMessages(`${this._getSubject()} is not less than or equal to ${thatValue}`, `${this._getSubject()} is less than or equal to ${thatValue}`); return this._evalulate(parseFloat(thisValue) <= parseFloat(thatValue), thisValue); } between(min, max) { const thisValue = this._getCompareValue(this._input); const thatMin = parseFloat(this._getCompareValue(min)); const thatMax = parseFloat(this._getCompareValue(max)); this._setDefaultMessages(`${this._getSubject()} is not between ${min} and ${max}`, `${this._getSubject()} is between ${min} and ${max}`); return this._evalulate(parseFloat(thisValue) >= thatMin && parseFloat(thisValue) <= thatMax, thisValue); } matches(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); const pattern = util_1.toType(value) == "regexp" ? thatValue : new RegExp(value); this._setDefaultMessages(`${this._getSubject()} does not match ${String(pattern)}`, `${this._getSubject()} matches ${String(pattern)}`); return this._evalulate(pattern.test(thisValue), thisValue); } contains(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); const bool = (() => { if (util_1.isNullOrUndefined(this._input)) { return thisValue === thatValue; } else if (util_1.toType(this._input) == "array") { return thisValue.indexOf(thatValue) >= 0; } else if (util_1.toType(this._input) == "object") { return typeof this._input[thatValue] !== "undefined"; } else { return String(this._input).indexOf(thatValue) >= 0; } })(); this._setDefaultMessages(`${this._getSubject()} does not contain ${thatValue}`, `${this._getSubject()} contains ${thatValue}`); return this._evalulate(bool, thisValue); } looksLike(controlImage, allowedDifference = 0) { this._setDefaultMessages(`Images do not match.`, `Images match.`); let assertionPassed = false; let details = ""; const imageCompare = new imagecompare_1.ImageCompare(this._context, this._getCompareValue(this._input), controlImage); const percentDifferenceAllowed = (() => { if (typeof allowedDifference === "number") { return allowedDifference >= 0 && allowedDifference < 1 ? allowedDifference * 100 : 0; } const n = parseFloat(allowedDifference); return !isNaN(n) && n >= 0 && n < 100 ? n : 0; })(); try { const result = imageCompare.compare({ threshold: 0.1 }); assertionPassed = result.percentDifferent <= percentDifferenceAllowed; if (!assertionPassed) { details = result.percentDifferent.toFixed(2) + `% of the image did not match (${result.pixelsDifferent} pixels).` + ` This is over the allowed difference of ${percentDifferenceAllowed}%.` + ` Diff image: ${result.diffPath}`; } } catch (err) { details = err; } return this._evalulate(assertionPassed, details); } startsWith(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); const bool = (() => { if (util_1.toType(thisValue) == "array") { return thisValue[0] == value; } if (!util_1.isNullOrUndefined(thisValue)) { return String(thisValue).indexOf(thatValue) === 0; } return false; })(); this._setDefaultMessages(`${this._getSubject()} does not start with ${thatValue}`, `${this._getSubject()} starts with ${thatValue}`); return this._evalulate(bool, String(thisValue)); } endsWith(value) { const thisValue = this._getCompareValue(this._input); const thatValue = this._getCompareValue(value); const bool = (() => { if (util_1.toType(thisValue) == "array") { return thisValue[thisValue.length - 1] == thatValue; } if (!util_1.isNullOrUndefined(thisValue)) { return (String(thisValue).substr(0, String(thisValue).length - String(thatValue).length) == thatValue); } return false; })(); this._setDefaultMessages(`${this._getSubject()} does not end with ${thatValue}`, `${this._getSubject()} ends with ${thatValue}`); return this._evalulate(bool, String(this._input)); } in(values) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} is not in list: ${values.join(", ")}`, `${this._getSubject()} is in list: ${values.join(", ")}`); return this._evalulate(values.indexOf(thisValue) >= 0, thisValue); } includes(value) { const thisValue = this._getCompareValue(this._input); const thatValue = String(this._getCompareValue(value)); const bool = (() => { if (thisValue && thisValue.indexOf) { return thisValue.indexOf(thatValue) >= 0; } return false; })(); this._setDefaultMessages(`${this._getSubject()} does not include ${thatValue}`, `${this._getSubject()} includes ${thatValue}`); return this._evalulate(bool, thisValue); } exists() { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} does not exist`, `${this._getSubject()} exists`); return this._evalulate(!util_1.isNullOrUndefined(thisValue), this._getName(this._input), thisValue && thisValue.path ? thisValue.path .split(" ") .pop() .replace(/[\. "'=\[\]]/g, "") : null); } resolves(continueOnReject = false) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} was not resolved`, `${this._getSubject()} was resolved`); return new Promise((resolve, reject) => { const result = (bool) => { const assertion = this._evalulate(bool, bool); if (bool) { resolve(assertion); } else { continueOnReject ? resolve(assertion) : reject(); } }; if (util_1.toType(thisValue) == "promise") { thisValue .then(() => { result(true); }) .catch(() => { result(false); }); } else { result(false); } }); } rejects(continueOnReject = false) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} was not rejected`, `${this._getSubject()} was rejected`); return new Promise((resolve, reject) => { const result = (bool) => { const assertion = this._evalulate(bool, bool); if (bool) { resolve(assertion); } else { continueOnReject ? resolve(assertion) : reject(); } }; if (util_1.toType(thisValue) == "promise") { thisValue .then(() => { result(false); }) .catch(() => { result(true); }); } else { result(false); } }); } none(callback) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} some were true`, `${this._getSubject()} none were true`); if (util_1.toType(thisValue) !== "array") { throw new Error("Input value must be an array."); } return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { resolve(this._evalulate(yield util_1.asyncNone(thisValue, callback), thisValue)); })); } every(callback) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} some were true`, `${this._getSubject()} none were true`); if (util_1.toType(thisValue) !== "array") { throw new Error("Input value must be an array."); } return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { resolve(this._evalulate(yield util_1.asyncEvery(thisValue, callback), thisValue)); })); } everySync(callback) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} some were true`, `${this._getSubject()} none were true`); if (util_1.toType(thisValue) !== "array") { throw new Error("Input value must be an array."); } return this._evalulate(thisValue.every((value, index, array) => { return callback(value, index, array); }), thisValue); } some(callback) { const thisValue = this._getCompareValue(this._input); this._setDefaultMessages(`${this._getSubject()} none were true`, `${this._getSubject()} some were true`); if (util_1.toType(thisValue) !== "array") { throw new Error("Input value must be an array."); } return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { resolve(this._evalulate(yield util_1.asyncSome(thisValue, callback), thisValue)); })); } schema(schema, simple = false) { return __awaiter(this, void 0, void 0, function* () { const validator = simple ? new assertionschema_1.AssertionSchema() : yield this._loadSchemaValidator(); const isValid = yield validator.validate(schema, this._getCompareValue(this._input)); const errors = validator.errors; let error = ""; if (typeof errors != "undefined" && errors !== null) { errors.forEach((err) => { error += err.message + " "; }); } this._setDefaultMessages(`${this._getSubject()} does not match schema`, `${this._getSubject()} matches schema`); return this._evalulate(isValid, error); }); } assert(a, b) { return this._context.assert(a, b); } comment(input) { this._context.comment(input); return this; } as(aliasName) { this._context.set(aliasName, this._input); return this; } _loadSchemaValidator() { return __awaiter(this, void 0, void 0, function* () { if (typeof this._ajv == "undefined") { return (Promise.resolve().then(() => require("ajv")).then(ajv => { this._ajv = new Ajv(); return this._ajv; }) .catch(e => { this._ajv = new assertionschema_1.AssertionSchema(); return this._ajv; })); } else { return this._ajv; } }); } _returnsPromise(callback, values) { return (util_1.isAsyncCallback(callback) || (values.length > 0 && util_1.toType(callback(values[0], 0, values)) === "promise")); } _getMessage() { return this._message ? this._message : this._not ? this._defaultMessages[0] : this._defaultMessages[1]; } _getSourceCode() { let source = this._input && this._input.sourceCode ? this._input.sourceCode : ""; if (source.length > 500) { source = source.substring(0, 500); } return source; } _getHighlightText(actualValue, highlightText) { return highlightText ? highlightText : this._input && this._input.highlight ? this._input.highlight : String(actualValue); } _getActualValueText(actualValue) { return `Actual value: ${String(actualValue)}`; } _evalulate(bool, actualValue, highlightText = null) { if (this.isFinalized) { throw new Error("Assertion result is immutable."); } this._statement = this._not ? !bool : bool; if (!!this._statement) { this._result = new assertionresult_1.AssertionPass(this._getMessage()); } else { this._result = this._optional ? new assertionresult_1.AssertionFailOptional(this._getMessage(), this._getActualValueText(actualValue)) : new assertionresult_1.AssertionFail(this._getMessage(), this._getActualValueText(actualValue), this._getSourceCode(), this._getHighlightText(actualValue, highlightText)); } this._context.scenario.result(this._result); this._finishedResolver(this._result); return this; } _getCompareValue(value) { this._assertionMade = true; const type = util_1.toType(value); if (type == "value") { return value.$; } else { return value; } } _getName(value) { if (value && value["path"]) { return value["tagName"] ? `<${value["tagName"]}> @ ${value.path}` : value.path; } return this._input.toString().substr(0, 255); } _getSubject() { const type = util_1.toType(this._input); let name; if (this._input && this._input.name) { name = this._input.name; } else if (type == "array") { name = "Array"; } else if (type == "object") { name = "Object"; } else if (type == "domelement") { name = "DOM Element"; } else if (type == "cssrule") { name = "CSS Rule"; } else { name = String(this._input); } if (String(name).length > 64) { name = name.substr(0, 61) + "..."; } return util_1.isNullOrUndefined(name) || String(name).length == 0 ? "It" : String(name); } _resolveAssertion() { if (this._statement === null) { this._statement = false; this._finishedResolver(null); } } _setDefaultMessages(standardMessage, notMessage) { this._defaultMessages = [standardMessage, notMessage || standardMessage]; } } exports.Assertion = Assertion; //# sourceMappingURL=assertion.js.map