flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
540 lines • 23 kB
JavaScript
;
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 assertionschema_1 = require("./assertionschema");
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 trim() {
this._resolveAssertion();
const trimmedValue = (() => {
const thisValue = String(this._getCompareValue(this._input));
return thisValue.trim();
})();
const assertion = new Assertion(this._context, new value_1.Value(trimmedValue, this._context, `Trim 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 thisValue = this._getCompareValue(this._input);
if (typeof schema === "string") {
const schemaName = schema;
try {
schema = assertionschema_1.getSchema(schemaName);
}
catch (_a) {
this._context.comment(`Created new schema snapshot called ${schemaName}`);
schema = assertionschema_1.writeSchema(thisValue, schemaName);
}
}
const validator = simple
? new assertionschema_1.AssertionSchema()
: yield this._loadSchemaValidator();
const isValid = yield validator.validate(schema, thisValue);
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(() => {
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 = this._context.logPassing(this._getMessage());
}
else {
this._result = this._optional
? this._context.logOptionalFailure(this._getMessage(), this._getActualValueText(actualValue))
: this._context.logFailure(this._getMessage(), this._getActualValueText(actualValue), this._getSourceCode(), this._getHighlightText(actualValue, highlightText));
}
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