@sprucelabs/test-utils
Version:
Helpful utilities to make asserting more complicated conditions quick and easy! ⚡️
265 lines (264 loc) • 11.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = __importDefault(require("chalk"));
const deep_equal_1 = __importDefault(require("deep-equal"));
const escapeRegExp_1 = __importDefault(require("lodash/escapeRegExp"));
const isObjectLike_1 = __importDefault(require("lodash/isObjectLike"));
const ts_expect_1 = require("ts-expect");
const variable_diff_1 = __importDefault(require("variable-diff"));
const assert_utility_1 = __importDefault(require("./assert.utility"));
__exportStar(require("./assert.utility"), exports);
const stringify = assert_utility_1.default.stringify.bind(assert_utility_1.default);
function isExactType(_) { }
const assert = {
areSameType() { },
isType: ts_expect_1.expectType,
isExactType,
isNumber(actual, message) {
if (typeof actual !== 'number') {
this.fail(buildErrorMessage(`${stringify(actual)} is not a number!`, message));
}
},
isEqual(actual, expected, message) {
if (actual !== expected) {
this.fail(buildErrorMessage(`${stringify(actual)}\n\n does not equal \n\n${stringify(expected)}`, message));
}
},
isNotEqual(actual, expected, message) {
if (actual === expected) {
this.fail(buildErrorMessage(`${stringify(actual)}\n\n should not equal ${stringify(expected)}\n\n`, message));
}
},
isEqualDeep(actual, expected, message, shouldAppendDelta = true) {
if (!(0, deep_equal_1.default)(actual, expected, { strict: true })) {
let result = (0, variable_diff_1.default)(actual, expected);
this.fail(buildErrorMessage(`${`Deep equal failed.\n\nActual would need the following changes to match expected:`}${shouldAppendDelta ? `\n\n${result.text}` : ``}`, message));
}
},
isNotEqualDeep(actual, expected, message) {
this.doesThrow(() => this.isEqualDeep(actual, expected), undefined, buildErrorMessage(`The objects you passed are deep equal! They should not be!`, message));
},
isAbove(actual, floor, message) {
if (typeof actual !== 'number') {
this.fail(buildErrorMessage(`${stringify(actual)} is not a number!`, message));
}
if (actual <= floor) {
this.fail(buildErrorMessage(`${stringify(actual)} is not above ${stringify(floor)}`, message));
}
},
isBelow(actual, ceiling, message) {
if (typeof actual !== 'number') {
this.fail(buildErrorMessage(`${stringify(actual)} is not a number!`, message));
}
if (actual >= ceiling) {
this.fail(buildErrorMessage(`${stringify(actual)} is not below ${stringify(ceiling)}`, message));
}
},
isUndefined(actual, message) {
if (typeof actual !== 'undefined') {
this.fail(buildErrorMessage(`${stringify(actual)} is not undefined`, message));
}
},
isTruthy(actual, message) {
if (actual === false ||
actual === null ||
typeof actual === 'undefined' ||
actual === 0) {
this.fail(buildErrorMessage(`${stringify(actual)} is not truthy`, message));
}
},
isFalsy(actual, message) {
if (actual) {
this.fail(buildErrorMessage(`${stringify(actual)} is not falsy`, message));
}
},
isNull(actual, message) {
if (actual !== null) {
this.fail(buildErrorMessage(`${stringify(actual)} is not null`, message));
}
},
isString(actual, message) {
assert_utility_1.default.assertTypeof(actual, 'string', message);
},
isFunction(actual, message) {
assert_utility_1.default.assertTypeof(actual, 'function', message);
},
isTrue(actual, message) {
//@ts-ignore
this.isEqual(actual, true, message);
},
isFalse(actual, message) {
//@ts-ignore
this.isEqual(actual, false, message);
},
isObject(actual, message) {
if (!(0, isObjectLike_1.default)(actual)) {
throw this.fail(buildErrorMessage(`${stringify(actual)} is not an object`, message));
}
},
isArray(actual, message) {
if (!Array.isArray(actual)) {
throw this.fail(buildErrorMessage(`${stringify(actual)} is not an array`, message));
}
},
isLength(actual, expected, message) {
if (!actual) {
throw this.fail(buildErrorMessage(`Expected array of length ${expected}, but got ${stringify(actual)}`, message));
}
//@ts-ignore
this.isEqual(actual.length, expected, buildErrorMessage(`Your array is not the expected length!`, message));
},
doesNotInclude(haystack, needle, message) {
let doesInclude = false;
try {
this.doesInclude(haystack, needle, message);
doesInclude = true;
}
catch {
doesInclude = false;
}
if (doesInclude) {
this.fail(buildErrorMessage(`${stringify(haystack)} should not include ${stringify(needle)}, but it does`, message));
}
},
doesInclude(haystack, needle, message) {
let msg = `Could not find ${stringify(needle)} in ${stringify(haystack)}`;
const isNeedleString = typeof needle === 'string';
const isNeedleRegex = needle instanceof RegExp;
if (typeof haystack === 'string' &&
(isNeedleString || isNeedleRegex) &&
haystack.search(isNeedleString ? (0, escapeRegExp_1.default)(needle) : needle) > -1) {
return;
}
const isHaystackObject = (0, isObjectLike_1.default)(haystack);
const { needleHasArrayNotation, path, expected } = assert_utility_1.default.parseIncludeNeedle(needle);
if (Array.isArray(haystack)) {
let cleanedNeedle = needle;
if (path && path.substr(0, 3) === '[].') {
cleanedNeedle = { [path.substr(3)]: expected };
}
const found = assert_utility_1.default.doHaystacksPassCheck(haystack, cleanedNeedle, this.doesInclude.bind(this));
if (found) {
return;
}
}
if (isHaystackObject && (0, isObjectLike_1.default)(needle)) {
try {
//@ts-ignore
this.isEqualDeep(haystack, needle, message);
return;
}
catch { }
}
if (assert_utility_1.default.foundUsing3rdPartyIncludes(haystack, needle, isHaystackObject)) {
return;
}
if (!Array.isArray(haystack) &&
isHaystackObject &&
(0, isObjectLike_1.default)(needle) &&
Object.keys(needle).length === 1 &&
!needleHasArrayNotation &&
path) {
const actual = assert_utility_1.default.valueAtPath(haystack, path);
if (typeof actual === 'undefined') {
msg = `The path ${stringify(path)} was not found in ${stringify(haystack)}`;
}
else {
msg = `Expected:\n${chalk_1.default.green(stringify(needle[path]))}\nbut found:\n${chalk_1.default.red(stringify(actual))}\nat:\n${stringify(path)}\nin:\n${stringify(haystack)}`;
}
if (typeof expected === 'string' &&
typeof actual === 'string' &&
actual.search(expected) > -1) {
return;
}
else if (expected instanceof RegExp && expected.exec(actual)) {
return;
}
else {
//@ts-ignore
this.isEqualDeep(expected, actual, buildErrorMessage(msg, message), false);
}
return;
}
if (isHaystackObject && (0, isObjectLike_1.default)(needle) && path) {
const { actualBeforeArray, pathAfterFirstArray } = assert_utility_1.default.splitPathBasedOnArrayNotation(path, haystack);
if (!Array.isArray(actualBeforeArray)) {
this.fail(buildErrorMessage(msg, message));
}
const found = assert_utility_1.default.doHaystacksPassCheck(actualBeforeArray, {
[pathAfterFirstArray]: expected,
}, this.doesInclude.bind(this));
if (found) {
return;
}
msg = `Could not find match ${stringify(expected)} at ${stringify(pathAfterFirstArray)} in ${stringify(actualBeforeArray)}.`;
}
this.fail(buildErrorMessage(msg, message));
},
hasAllFunctions(obj, functionNames, message) {
functionNames.forEach((name) => {
if (typeof obj[name] !== 'function') {
this.fail(buildErrorMessage(`A function named "${name}" does not exist on ${stringify(obj)}`, message));
}
});
},
doesThrow(cb, matcher, msg) {
try {
cb();
}
catch (err) {
assert_utility_1.default.assertErrorIncludes(matcher, err, msg);
return err;
}
this.fail(buildErrorMessage('Expected a thrown error, but never got one!', msg));
},
async doesThrowAsync(cb, matcher, msg) {
try {
await cb();
}
catch (err) {
assert_utility_1.default.assertErrorIncludes(matcher, err, msg);
return err;
}
this.fail(buildErrorMessage('Expected a thrown error, but never got one!', msg));
},
fail: assert_utility_1.default.fail,
isInstanceOf(actual, Class, message) {
assert.isTrue(actual instanceof Class, buildErrorMessage(`${assert_utility_1.default.stringify(actual)} is not an instance of:\n\n${Class}`, message));
},
isBetween(actual, floor, ceiling, message) {
assert.isBelow(actual, ceiling, message);
assert.isAbove(actual, floor, message);
},
isBetweenInclusive(actual, floor, ceiling, message) {
//@ts-ignore
this.isNumber(actual, message);
if (actual >= floor && actual <= ceiling) {
return;
}
assert.fail(buildErrorMessage(`${actual} is not between ${floor} and ${ceiling} (inclusive)`, message));
},
};
exports.default = assert;
function buildErrorMessage(defaultMessage, customMessage) {
return ((customMessage
? `${customMessage}\n\n${defaultMessage}`
: defaultMessage) + '\n\n');
}