UNPKG

@push.rocks/smartexpect

Version:

A testing library to manage expectations in code, offering both synchronous and asynchronous assertion methods.

415 lines 34 kB
import * as plugins from './plugins.js'; import { StringMatchers, ArrayMatchers, NumberMatchers, BooleanMatchers, ObjectMatchers, FunctionMatchers, DateMatchers, TypeMatchers, } from './namespaces/index.js'; /** * Core assertion class. Generic over the current value type T. */ /** * Internal matcher classes for expect.any and expect.anything */ export class AnyMatcher { constructor(expectedConstructor) { this.expectedConstructor = expectedConstructor; } } export class AnythingMatcher { } export class Assertion { /** Registry of user-defined custom matchers */ static { this.customMatchers = {}; } constructor(baseReferenceArg, executionModeArg) { this.propertyDrillDown = []; this.notSetting = false; this.timeoutSetting = 0; /** Flag for Promise rejection assertions */ this.isRejects = false; /** Flag for Promise resolution assertions (default for async) */ this.isResolves = false; this.baseReference = baseReferenceArg; this.executionMode = executionModeArg; } /** * Register custom matchers to be available on all assertions. * @param matchers An object whose keys are matcher names and values are matcher functions. */ static extend(matchers) { for (const [name, fn] of Object.entries(matchers)) { if (Assertion.prototype[name]) { throw new Error(`Cannot extend. Matcher '${name}' already exists on Assertion.`); } // store in registry Assertion.customMatchers[name] = fn; // add method to prototype Assertion.prototype[name] = function (...args) { return this.runCheck(() => { const received = this.getObjectToTestReference(); const result = fn(received, ...args); const pass = result.pass; const msg = result.message; if (!pass) { const message = typeof msg === 'function' ? msg() : msg; throw new Error(message || `Custom matcher '${name}' failed`); } }); }; } } getObjectToTestReference() { let returnObjectToTestReference = this.baseReference; for (const property of this.propertyDrillDown) { if (returnObjectToTestReference == null) { // if it's null or undefined, stop break; } // We just directly access with bracket notation. // If property is a string, it's like obj["someProp"]; // If property is a number, it's like obj[0]. returnObjectToTestReference = returnObjectToTestReference[property]; } return returnObjectToTestReference; } formatDrillDown() { if (!this.propertyDrillDown || this.propertyDrillDown.length === 0) { return ''; } const path = this.propertyDrillDown.map(prop => { if (typeof prop === 'number') { return `[${prop}]`; } else { return `.${prop}`; } }).join(''); return path; } formatValue(value) { if (value === null) { return 'null'; } else if (value === undefined) { return 'undefined'; } else if (typeof value === 'object') { try { return JSON.stringify(value); } catch (e) { return `[Object ${value.constructor.name}]`; } } else if (typeof value === 'function') { return `[Function${value.name ? ': ' + value.name : ''}]`; } else if (typeof value === 'string') { return `"${value}"`; } else { return String(value); } } createErrorMessage(message) { if (this.failMessage) { return this.failMessage; } const testValue = this.getObjectToTestReference(); const formattedValue = this.formatValue(testValue); const drillDown = this.formatDrillDown(); // Replace placeholders in the message return message .replace('{value}', formattedValue) .replace('{path}', drillDown || ''); } /** * Compute a negated failure message by inserting 'not' into the positive message. */ computeNegationMessage(message) { const idx = message.indexOf(' to '); if (idx !== -1) { return message.slice(0, idx) + ' not' + message.slice(idx); } return 'Negated: ' + message; } get not() { this.notSetting = true; return this; } /** * Assert that a Promise resolves. */ /** * Switch to async (resolve) mode. Subsequent matchers return Promises. */ get resolves() { return new Assertion(this.baseReference, 'async'); } /** * Assert that a Promise rejects. */ /** * Switch to async (reject) mode. Subsequent matchers return Promises. */ get rejects() { const a = new Assertion(this.baseReference, 'async'); // mark to expect rejection a.isRejects = true; return a; } /** * @deprecated use `.withTimeout(ms)` instead for clarity * Set a timeout (in ms) for async assertions (Promise must settle before timeout). */ timeout(millisArg) { // eslint-disable-next-line no-console console.warn('[DEPRECATED] .timeout() is deprecated. Use .withTimeout(ms)'); this.timeoutSetting = millisArg; return this; } /** * Set a timeout (in ms) for async assertions (Promise must settle before timeout). */ withTimeout(millisArg) { this.timeoutSetting = millisArg; return this; } setFailMessage(failMessageArg) { this.failMessage = failMessageArg; return this; } setSuccessMessage(successMessageArg) { this.successMessage = successMessageArg; return this; } // Internal check runner: returns Promise in async mode, else sync Assertion // Internal check runner; returns Promise or this at runtime, but typed via customAssertion runCheck(checkFunction) { const runDirectOrNegated = (checkFunction) => { if (!this.notSetting) { return checkFunction(); } else { let isOk = false; try { // attempt positive assertion and expect it to throw checkFunction(); } catch (e) { isOk = true; } if (!isOk) { const msg = this.failMessage || this.negativeMessage || 'Negated assertion failed'; throw new Error(msg); } } }; if (this.executionMode === 'async') { const done = plugins.smartpromise.defer(); const isThenable = this.baseReference && typeof this.baseReference.then === 'function'; if (!isThenable) { done.reject(new Error(`Expected a Promise but received: ${this.formatValue(this.baseReference)}`)); return done.promise; } if (this.timeoutSetting) { plugins.smartdelay.delayFor(this.timeoutSetting).then(() => { if (done.status === 'pending') { done.reject(new Error(`Promise timed out after ${this.timeoutSetting}ms`)); } }); } if (this.isRejects) { this.baseReference.then((res) => { done.reject(new Error(`Expected Promise to reject but it resolved with ${this.formatValue(res)}`)); }, (err) => { this.baseReference = err; try { runDirectOrNegated(checkFunction); done.resolve(this); } catch (e) { done.reject(e); } }); } else { this.baseReference.then((res) => { this.baseReference = res; try { runDirectOrNegated(checkFunction); done.resolve(this); } catch (e) { done.reject(e); } }, (err) => { done.reject(err); }); } // return a promise resolving to this for chaining return done.promise.then(() => this); } // sync: run and return this for chaining runDirectOrNegated(checkFunction); return this; } /** * Execute a custom assertion. Returns a Promise in async mode, else returns this. */ customAssertion(assertionFunction, errorMessage) { // Prepare negation message based on the positive error template, if static if (typeof errorMessage === 'string') { this.negativeMessage = this.computeNegationMessage(errorMessage); } return this.runCheck(() => { const value = this.getObjectToTestReference(); if (!assertionFunction(value)) { const msg = this.failMessage || (typeof errorMessage === 'function' ? errorMessage(value) : errorMessage); throw new Error(msg); } }); } /** * Drill into a property of an object. * @param propertyName Name of the property to navigate into. * @returns Assertion of the property type. */ property(propertyName) { this.propertyDrillDown.push(propertyName); return this; } /** * Drill into an array element by index. * @param index Index of the array item. * @returns Assertion of the element type. */ arrayItem(index) { this.propertyDrillDown.push(index); return this; } log() { console.log(`Current value:`); console.log(JSON.stringify(this.getObjectToTestReference(), null, 2)); console.log(`Path: ${this.formatDrillDown() || '(root)'}`); return this; } // Direct (flat) matcher aliases toEqual(expected) { return this.customAssertion((v) => plugins.fastDeepEqual(v, expected), `Expected value to equal ${JSON.stringify(expected)}`); } toBeTrue() { return this.boolean.toBeTrue(); } toBeFalse() { return this.boolean.toBeFalse(); } toBeTruthy() { return this.boolean.toBeTruthy(); } toBeFalsy() { return this.boolean.toBeFalsy(); } toThrow(expectedError) { return this.function.toThrow(expectedError); } toBeGreaterThan(value) { return this.number.toBeGreaterThan(value); } toBeLessThan(value) { return this.number.toBeLessThan(value); } toBeGreaterThanOrEqual(value) { return this.number.toBeGreaterThanOrEqual(value); } toBeLessThanOrEqual(value) { return this.number.toBeLessThanOrEqual(value); } toBeCloseTo(value, precision) { return this.number.toBeCloseTo(value, precision); } toBeArray() { return this.array.toBeArray(); } toContain(item) { return this.array.toContain(item); } toContainEqual(item) { return this.array.toContainEqual(item); } toContainAll(items) { return this.array.toContainAll(items); } toExclude(item) { return this.array.toExclude(item); } toBeEmptyArray() { return this.array.toBeEmptyArray(); } toStartWith(prefix) { return this.string.toStartWith(prefix); } toEndWith(suffix) { return this.string.toEndWith(suffix); } toInclude(substring) { return this.string.toInclude(substring); } toMatch(regex) { return this.string.toMatch(regex); } toBeOneOf(values) { return this.string.toBeOneOf(values); } toHaveProperty(property, value) { // Forward only provided arguments to object matcher to preserve argument count if (arguments.length === 2) { return this.object.toHaveProperty(property, value); } return this.object.toHaveProperty(property); } toHaveOwnProperty(property, value) { return this.object.toHaveOwnProperty(property, value); } toMatchObject(expected) { return this.object.toMatchObject(expected); } toBeInstanceOf(constructor) { return this.object.toBeInstanceOf(constructor); } toHaveDeepProperty(path) { return this.object.toHaveDeepProperty(path); } toBeNull() { return this.object.toBeNull(); } toBeUndefined() { return this.object.toBeUndefined(); } toBeNullOrUndefined() { return this.object.toBeNullOrUndefined(); } toBeDate() { return this.date.toBeDate(); } toBeBeforeDate(date) { return this.date.toBeBeforeDate(date); } toBeAfterDate(date) { return this.date.toBeAfterDate(date); } toBeTypeofString() { return this.type.toBeTypeofString(); } toBeTypeofNumber() { return this.type.toBeTypeofNumber(); } toBeTypeofBoolean() { return this.type.toBeTypeofBoolean(); } toBeTypeOf(typeName) { return this.type.toBeTypeOf(typeName); } toBeDefined() { return this.type.toBeDefined(); } // Additional missing direct aliases for completeness // String/Array namespace - intelligently delegate based on value type toHaveLength(length) { // Determine if value is string or array and delegate accordingly const value = this.getObjectToTestReference(); if (typeof value === 'string') { return this.string.toHaveLength(length); } else if (Array.isArray(value)) { return this.array.toHaveLength(length); } else { return this.customAssertion(() => false, 'Expected value to be string or array to check length'); } } toBeEmpty() { // Determine if value is string or array and delegate accordingly const value = this.getObjectToTestReference(); if (typeof value === 'string') { return this.string.toBeEmpty(); } else if (Array.isArray(value)) { return this.array.toBeEmpty(); } else { return this.customAssertion(() => false, 'Expected value to be string or array to check if empty'); } } // Number namespace toBeNaN() { return this.number.toBeNaN(); } toBeFinite() { return this.number.toBeFinite(); } toBeWithinRange(min, max) { return this.number.toBeWithinRange(min, max); } // Array namespace length comparisons toHaveLengthGreaterThan(length) { return this.array.toHaveLengthGreaterThan(length); } toHaveLengthLessThan(length) { return this.array.toHaveLengthLessThan(length); } // Object namespace toHaveKeys(keys) { return this.object.toHaveKeys(keys); } toHaveOwnKeys(keys) { return this.object.toHaveOwnKeys(keys); } // Function namespace toThrowErrorMatching(regex) { return this.function.toThrowErrorMatching(regex); } toThrowErrorWithMessage(message) { return this.function.toThrowErrorWithMessage(message); } // Namespaced matcher accessors /** String-specific matchers */ get string() { return new StringMatchers(this); } /** Array-specific matchers */ get array() { return new ArrayMatchers(this); } /** Number-specific matchers */ get number() { return new NumberMatchers(this); } /** Boolean-specific matchers */ get boolean() { return new BooleanMatchers(this); } /** Object-specific matchers */ get object() { return new ObjectMatchers(this); } /** Function-specific matchers */ get function() { return new FunctionMatchers(this); } /** Date-specific matchers */ get date() { return new DateMatchers(this); } /** Type-based matchers */ get type() { return new TypeMatchers(this); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRleHBlY3QuY2xhc3Nlcy5hc3NlcnRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGV4cGVjdC5jbGFzc2VzLmFzc2VydGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQ0wsY0FBYyxFQUNkLGFBQWEsRUFDYixjQUFjLEVBQ2QsZUFBZSxFQUNmLGNBQWMsRUFDZCxnQkFBZ0IsRUFDaEIsWUFBWSxFQUNaLFlBQVksR0FDYixNQUFNLHVCQUF1QixDQUFDO0FBTy9COztHQUVHO0FBQ0g7O0dBRUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUNyQixZQUFtQixtQkFBd0I7UUFBeEIsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFLO0lBQUcsQ0FBQztDQUNoRDtBQUNELE1BQU0sT0FBTyxlQUFlO0NBQUc7QUFFL0IsTUFBTSxPQUFPLFNBQVM7SUFPcEIsK0NBQStDO2FBQ2hDLG1CQUFjLEdBQTZCLEVBQUUsQUFBL0IsQ0FBZ0M7SUFVN0QsWUFBWSxnQkFBcUIsRUFBRSxnQkFBbUI7UUFmdEQsc0JBQWlCLEdBQTJCLEVBQUUsQ0FBQztRQUV2QyxlQUFVLEdBQUcsS0FBSyxDQUFDO1FBQ25CLG1CQUFjLEdBQUcsQ0FBQyxDQUFDO1FBRzNCLDRDQUE0QztRQUNwQyxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBQzFCLGlFQUFpRTtRQUN6RCxlQUFVLEdBQUcsS0FBSyxDQUFDO1FBT3pCLElBQUksQ0FBQyxhQUFhLEdBQUcsZ0JBQWdCLENBQUM7UUFDdEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxnQkFBZ0IsQ0FBQztJQUN4QyxDQUFDO0lBQ0Q7OztPQUdHO0lBQ0ksTUFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFrQztRQUNyRCxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFB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