@push.rocks/smartexpect
Version:
A testing library to manage expectations in code, offering both synchronous and asynchronous assertion methods.
415 lines • 34 kB
JavaScript
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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