@sprucelabs/test-utils
Version:
Helpful utilities to make asserting more complicated conditions quick and easy! ⚡️
195 lines (194 loc) • 8.57 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NULL_PLACEHOLDER = exports.CIRCULAR_PLACEHOLDER = exports.FUNCTION_PLACEHOLDER = exports.UNDEFINED_PLACEHOLDER = void 0;
const chalk_1 = __importDefault(require("chalk"));
const escapeRegExp_1 = __importDefault(require("lodash/escapeRegExp"));
const get_1 = __importDefault(require("lodash/get"));
const includes_1 = __importDefault(require("lodash/includes"));
const isObject_1 = __importDefault(require("lodash/isObject"));
const isObjectLike_1 = __importDefault(require("lodash/isObjectLike"));
const AssertionError_1 = __importDefault(require("../AssertionError"));
exports.UNDEFINED_PLACEHOLDER = '_____________undefined_____________';
exports.FUNCTION_PLACEHOLDER = '_____________function_____________';
exports.CIRCULAR_PLACEHOLDER = '_____________circular_____________';
exports.NULL_PLACEHOLDER = '_____________null_____________';
const assertUtil = {
fail(message, stack) {
throw new AssertionError_1.default(message ?? 'Fail!', stack);
},
stringify(object) {
let stringified;
if (Array.isArray(object)) {
stringified = `[\n${object.map((o) => this.stringify(o).split('\n').join('\n\t'))}\n]`;
}
else if (typeof object === 'number') {
// this hack allows the Spruce Test Reporter to render number errors (they got eaten by terminal-kit's style regex)
stringified = chalk_1.default.bgBlack.white(` ${object} `);
}
else if (object instanceof Error) {
stringified = `${object.stack ?? object.message}`;
}
else if (object instanceof RegExp) {
stringified = `${object.toString()}`;
}
else if (typeof object === 'undefined') {
stringified = 'undefined';
}
else if (typeof object === 'string') {
stringified = `"${object}"`;
}
else {
stringified = JSON.stringify(assertUtil.dropInPlaceholders(object), undefined, 2).replace(/\\/g, '');
}
if (stringified.length > 5000) {
stringified =
stringified.substr(0, 1000) +
'\n\n... big object ...\n\n' +
stringified.substr(stringified.length - 1000);
}
stringified = assertUtil.replacePlaceholders(stringified);
return `${chalk_1.default.bold(stringified)}`;
},
replacePlaceholders(str) {
return str
.replace(new RegExp(`"${exports.UNDEFINED_PLACEHOLDER}"`, 'g'), chalk_1.default.italic('undefined'))
.replace(new RegExp(`"${exports.FUNCTION_PLACEHOLDER}"`, 'g'), chalk_1.default.italic('Function'))
.replace(new RegExp(`"${exports.NULL_PLACEHOLDER}"`, 'g'), chalk_1.default.italic('NULL'));
},
dropInPlaceholders(obj) {
const checkedObjects = [
{ obj, depth: 0 },
];
let updated = this.dropInPlaceholder(obj, (obj, depth) => {
if ((0, isObject_1.default)(obj) &&
checkedObjects.some((checked) => {
return checked.obj === obj && checked.depth < depth;
})) {
return true;
}
checkedObjects.push({ obj, depth });
return false;
}, exports.CIRCULAR_PLACEHOLDER);
updated = this.dropInPlaceholder(updated, (obj) => typeof obj === 'undefined', exports.UNDEFINED_PLACEHOLDER);
updated = this.dropInPlaceholder(updated, (obj) => typeof obj === 'function', exports.FUNCTION_PLACEHOLDER);
updated = this.dropInPlaceholder(updated, (obj) => obj === null, exports.NULL_PLACEHOLDER);
return updated;
},
dropInPlaceholder(obj, checker, placeholder, depth = 1) {
if (!(0, isObject_1.default)(obj)) {
return obj;
}
const updated = Array.isArray(obj)
? []
: {};
Object.keys(obj).forEach((key) => {
//@ts-ignore
updated[key] =
// @ts-ignore
checker(obj[key], depth) ? placeholder : obj[key];
//@ts-ignore
if (typeof updated[key] !== 'function' && (0, isObject_1.default)(updated[key])) {
//@ts-ignore
updated[key] = this.dropInPlaceholder(
//@ts-ignore
updated[key], checker, placeholder, depth + 1);
}
});
return updated;
},
doHaystacksPassCheck(haystacks, needle, check) {
return !!haystacks.find((haystack) => {
try {
check(haystack, needle);
return true;
}
catch {
return false;
}
});
},
assertTypeof(actual, type, message) {
if (typeof actual !== type) {
this.fail(message ?? `${JSON.stringify(actual)} is not a ${type}`);
}
},
assertErrorIncludes(matcher, err, msg) {
const originalErrorMessage = err.message ?? '';
const errorMessage = originalErrorMessage.toLowerCase();
const needle = typeof matcher === 'string' ? matcher.toLowerCase() : matcher;
if (typeof needle === 'string' &&
errorMessage.search(needle) === -1 &&
!errorMessage.includes(needle)) {
this.fail(msg ??
`Expected thrown error whose message contains: \n\n${chalk_1.default.bold(matcher)}\n\nbut got back:\n\n\`${chalk_1.default.bold(originalErrorMessage)}\`.`, '\n\nStack: ' + err.stack);
}
else if (needle instanceof RegExp &&
errorMessage.search(needle) === -1 &&
originalErrorMessage.search(needle) === -1) {
this.fail(msg ??
`Expected thrown error whose message matches the regex: \n\n${chalk_1.default.bold(matcher)}\n\nbut got back:\n\n\`${chalk_1.default.bold(originalErrorMessage)}\`.`, '\n\nStack: ' + err.stack);
}
},
partialContains(object, subObject) {
const objProps = object ? Object.getOwnPropertyNames(object) : [];
const subProps = subObject ? Object.getOwnPropertyNames(subObject) : [];
if (objProps.length == 0 || subProps.length === 0) {
return;
}
if (subProps.length > objProps.length) {
return false;
}
for (const subProp of subProps) {
if (!Object.prototype.hasOwnProperty.call(object, subProp)) {
return false;
}
if ((!(0, isObjectLike_1.default)(object[subProp]) ||
!(0, isObjectLike_1.default)(subObject[subProp])) &&
object[subProp] !== subObject[subProp]) {
return false;
}
if ((0, isObjectLike_1.default)(object[subProp]) &&
(0, isObjectLike_1.default)(subObject[subProp]) &&
!this.partialContains(object[subProp], subObject[subProp])) {
return false;
}
}
return true;
},
valueAtPath(object, path) {
return (0, get_1.default)(object, path);
},
parseIncludeNeedle(needle) {
const path = Object.keys(needle)[0];
const expected = path && needle[path];
const needleHasArrayNotation = !!(path && path.search(/\[\]\./) > -1);
return { needleHasArrayNotation, path, expected };
},
splitPathBasedOnArrayNotation(path, haystack) {
const pathParts = path.split('[].');
const pathToFirstArray = pathParts.shift() ?? '';
const pathAfterFirstArray = pathParts.join('[].');
const actualBeforeArray = this.valueAtPath(haystack, pathToFirstArray);
return { actualBeforeArray, pathAfterFirstArray };
},
foundUsing3rdPartyIncludes(haystack, needle, isHaystackObject) {
let passed = false;
const escapedNeedle = typeof needle === 'string' ? (0, escapeRegExp_1.default)(needle) : needle;
if (typeof haystack === 'string' &&
typeof needle === 'string' &&
haystack.search(escapedNeedle) > -1) {
passed = true;
}
if (isHaystackObject && (0, includes_1.default)(haystack, escapedNeedle)) {
passed = true;
}
if (isHaystackObject && this.partialContains(haystack, escapedNeedle)) {
passed = true;
}
return passed;
},
};
exports.default = assertUtil;