smartexpect/test/test.both.ts

222 lines
7.0 KiB
TypeScript

import { tap } from '@push.rocks/tapbundle';
// Import the built library (dist_ts) so all matcher implementations are available
import * as smartexpect from '../dist_ts/index.js';
tap.test('basic type assertions', async () => {
// String type checks
smartexpect.expect('hello').type.toBeTypeofString();
smartexpect.expect(1).not.type.toBeTypeofString();
// Boolean type checks
smartexpect.expect(true).type.toBeTypeofBoolean();
smartexpect.expect(false).type.toBeTypeofBoolean();
smartexpect.expect(1).not.type.toBeTypeofBoolean();
// Number type checks
smartexpect.expect(42).type.toBeTypeofNumber();
smartexpect.expect(true).not.type.toBeTypeofNumber();
// Generic type checks with new method
smartexpect.expect(() => {}).type.toBeTypeOf('function');
smartexpect.expect(class Test {}).type.toBeTypeOf('function');
smartexpect.expect({}).type.toBeTypeOf('object');
smartexpect.expect(Symbol('test')).type.toBeTypeOf('symbol');
});
tap.test('async tests', async (toolsArg) => {
const deferred = toolsArg.defer();
toolsArg.delayFor(1000).then(() => {
deferred.resolve('hello');
});
// Using .resolves to test promise resolution with timeout
await smartexpect.expect(deferred.promise).resolves.withTimeout(2000).type.toBeTypeofString();
await smartexpect.expect(deferred.promise).resolves.not.type.toBeTypeofBoolean();
// Test async timeout handling
const longOperation = toolsArg.defer();
toolsArg.delayFor(3000).then(() => {
longOperation.resolve('completed');
});
try {
// Assert that resolution must occur within timeout
await smartexpect.expect(longOperation.promise).resolves.withTimeout(1000).toBeDefined();
throw new Error('Should have timed out');
} catch (err) {
// Successfully caught timeout error from .withTimeout
console.log('Successfully caught timeout:', err.message);
}
});
tap.test('equality and matching assertions', async () => {
// Basic equality
smartexpect.expect('hithere').object.toEqual('hithere');
smartexpect.expect('hithere').not.object.toEqual('hithere2');
// Object equality
const obj1 = { a: 1, b: { c: true } };
const obj2 = { a: 1, b: { c: true } };
const obj3 = { a: 1, b: { c: false } };
smartexpect.expect(obj1).object.toEqual(obj2);
smartexpect.expect(obj1).not.object.toEqual(obj3);
// RegExp matching
smartexpect.expect('hithere').string.toMatch(/hi/);
smartexpect.expect('hithere').string.toMatch(/^hithere$/);
smartexpect.expect('hithere').not.string.toMatch(/ho/);
// String inclusion
smartexpect.expect('hithere').string.toInclude('hit');
smartexpect.expect('hithere').not.string.toInclude('missing');
// String start/end
smartexpect.expect('hithere').string.toStartWith('hi');
smartexpect.expect('hithere').string.toEndWith('ere');
});
tap.test('object property assertions', async () => {
const testObject = {
topLevel: 'hello',
nested: {
prop: 42,
deeplyNested: {
array: [1, 2, 3],
},
},
};
// Basic property checks
smartexpect.expect(testObject).object.toHaveProperty('topLevel');
smartexpect.expect(testObject).object.toHaveProperty('topLevel', 'hello');
smartexpect.expect(testObject).not.object.toHaveProperty('missing');
// Drill-down property navigation
smartexpect.expect(testObject).property('nested').object.toHaveProperty('prop', 42);
smartexpect
.expect(testObject)
.property('nested')
.property('deeplyNested')
.property('array')
.array.toBeArray();
// Deep property checks
smartexpect.expect(testObject).object.toHaveDeepProperty(['nested', 'deeplyNested', 'array']);
// Array item navigation
smartexpect
.expect(testObject)
.property('nested')
.property('deeplyNested')
.property('array')
.arrayItem(0)
.number.toEqual(1); // numeric equality via number namespace
});
tap.test('numeric comparison assertions', async () => {
// Greater/less than
smartexpect.expect(4).number.toBeGreaterThan(3);
smartexpect.expect(4).number.toBeLessThan(5);
smartexpect.expect(4).number.toBeGreaterThanOrEqual(4);
smartexpect.expect(4).number.toBeLessThanOrEqual(4);
// Approximate equality
smartexpect.expect(0.1 + 0.2).number.toBeCloseTo(0.3, 10);
});
tap.test('array assertions', async () => {
const obj1 = { id: 1 };
const obj2 = { id: 2 };
const testArray = [1, 'two', obj1, true];
// Basic array checks
smartexpect.expect(testArray).array.toBeArray();
smartexpect.expect(testArray).array.toHaveLength(4);
// Content checks
smartexpect.expect(testArray).array.toContain('two');
smartexpect.expect(testArray).array.toContain(obj1);
smartexpect.expect(testArray).not.array.toContain(obj2);
// Array with equal items (not same reference)
smartexpect.expect([{ a: 1 }, { b: 2 }]).array.toContainEqual({ a: 1 });
// Multiple values
smartexpect.expect(testArray).array.toContainAll([1, 'two']);
smartexpect.expect(testArray).array.toExclude('missing');
// Empty array
smartexpect.expect([]).array.toBeEmptyArray();
// Length comparisons
smartexpect.expect(testArray).array.toHaveLengthGreaterThan(3);
smartexpect.expect(testArray).array.toHaveLengthLessThan(5);
});
tap.test('boolean assertions', async () => {
// True/False
smartexpect.expect(true).boolean.toBeTrue();
smartexpect.expect(false).boolean.toBeFalse();
// Truthy/Falsy
smartexpect.expect('something').boolean.toBeTruthy();
smartexpect.expect(0).boolean.toBeFalsy();
// Null/Undefined
smartexpect.expect(null).object.toBeNull();
smartexpect.expect(undefined).object.toBeUndefined();
smartexpect.expect(null).object.toBeNullOrUndefined();
smartexpect.expect(undefined).object.toBeNullOrUndefined();
});
tap.test('function assertions', async () => {
// Function that throws
const throwingFn = () => {
throw new Error('test error');
};
smartexpect.expect(throwingFn).function.toThrow();
smartexpect.expect(throwingFn).function.toThrow(Error);
// Function that doesn't throw
const nonThrowingFn = () => 'safe';
smartexpect.expect(nonThrowingFn).not.function.toThrow();
});
tap.test('date assertions', async () => {
const now = new Date();
const past = new Date(Date.now() - 10000);
const future = new Date(Date.now() + 10000);
smartexpect.expect(now).date.toBeDate();
smartexpect.expect(now).date.toBeAfterDate(past);
smartexpect.expect(now).date.toBeBeforeDate(future);
});
tap.test('custom assertions', async () => {
// Custom validation logic
smartexpect.expect(42).customAssertion((value) => value % 2 === 0, 'Expected number to be even');
// With fail message
smartexpect.expect('test').setFailMessage('Custom fail message for assertion').string.toHaveLength(4);
});
tap.test('logging and debugging', async () => {
// Using log() for debugging
const complexObject = {
level1: {
level2: {
value: 'nested value',
},
},
};
// This logs the current value in the chain for debugging
smartexpect
.expect(complexObject)
.property('level1')
.property('level2')
.log()
.property('value')
.object.toEqual('nested value');
});
export default tap.start();