UNPKG

@sprucelabs/test-utils

Version:

Helpful utilities to make asserting more complicated conditions quick and easy! ⚡️

265 lines (264 loc) 11.2 kB
"use strict"; 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'); }