type-fns
Version:
A set of types, type checks, and type guards for simpler, safer, and easier to read code.
131 lines • 7.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const test_fns_1 = require("test-fns");
const withAssure_1 = require("../wrappers/withAssure");
const assure_1 = require("./assure");
describe('assure', () => {
// example type guards for testing
const isString = (input) => typeof input === 'string';
const isNumber = (input) => typeof input === 'number';
const isPositive = (input) => input > 0;
const isNonEmptyString = (input) => input.length > 0;
describe('happy path', () => {
it('should return the value when it satisfies a string check', () => {
const result = (0, assure_1.assure)('hello', isString);
expect(result).toEqual('hello');
});
it('should return the value when it satisfies a number check', () => {
const result = (0, assure_1.assure)(42, isNumber);
expect(result).toEqual(42);
});
it('should return the value when it satisfies a narrowing check on already-typed input', () => {
const result = (0, assure_1.assure)(5, isPositive);
expect(result).toEqual(5);
});
});
describe('rejection boundaries', () => {
it('should throw when string check receives a number', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)(123, isString));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isString'");
});
it('should throw when number check receives a string', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('not a number', isNumber));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isNumber'");
});
it('should throw when positive check receives zero', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)(0, isPositive));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isPositive'");
});
it('should throw when positive check receives a negative number', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)(-1, isPositive));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isPositive'");
});
it('should throw when non-empty string check receives an empty string', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('', isNonEmptyString));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isNonEmptyString'");
});
});
describe('edge cases', () => {
it('should handle null input', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)(null, isString));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isString'");
});
it('should handle undefined input and include it in error context', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)(undefined, isString));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
expect(error.message).toContain("input does not satisfy type.check 'isString'");
});
it('should handle falsy values that pass the check', () => {
const result = (0, assure_1.assure)(0, isNumber);
expect(result).toEqual(0);
});
it('should handle empty string that passes a string check', () => {
const result = (0, assure_1.assure)('', isString);
expect(result).toEqual('');
});
});
describe('custom name option', () => {
it('should use custom name in error message when provided', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('test', isNumber, { name: 'customNumberCheck' }));
expect(error.message).toContain("input does not satisfy type.check 'customNumberCheck'");
});
it('should use function name when custom name is not provided', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('test', isNumber));
expect(error.message).toContain("input does not satisfy type.check 'isNumber'");
});
it('should handle anonymous functions gracefully', () => {
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('test', (input) => typeof input === 'number'));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
});
});
describe('type narrowing', () => {
it('should narrow union types', () => {
const input = 'hello';
const result = (0, assure_1.assure)(input, isString); // narrows to string
// @ts-expect-error - result is string, not number
const badResult = (0, assure_1.assure)(input, isString);
expect(result).toBeDefined();
expect(badResult).toBeDefined();
});
it('should narrow unknown to specific type', () => {
const input = 42;
const result = (0, assure_1.assure)(input, isNumber); // narrows to number
// @ts-expect-error - result is number, not string
const badResult = (0, assure_1.assure)(input, isNumber);
expect(result).toBeDefined();
expect(badResult).toBeDefined();
});
it('should work with branded types', () => {
const isUserId = (input) => input.startsWith('user_');
const result = (0, assure_1.assure)('user_123', isUserId); // narrows to UserId
// @ts-expect-error - result is UserId, not number
const badResult = (0, assure_1.assure)('user_123', isUserId);
expect(result).toBeDefined();
expect(badResult).toBeDefined();
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('invalid', isUserId));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
});
it('should work with enum checks', () => {
let Status;
(function (Status) {
Status["ACTIVE"] = "ACTIVE";
Status["INACTIVE"] = "INACTIVE";
})(Status || (Status = {}));
const isStatus = (input) => Object.values(Status).includes(input);
const result = (0, assure_1.assure)('ACTIVE', isStatus); // narrows to Status
// @ts-expect-error - result is Status, not number
const badResult = (0, assure_1.assure)('ACTIVE', isStatus);
expect(result).toBeDefined();
expect(badResult).toBeDefined();
const error = (0, test_fns_1.getError)(() => (0, assure_1.assure)('INVALID', isStatus));
expect(error).toBeInstanceOf(withAssure_1.AssureIsOfTypeRejectionError);
});
});
});
//# sourceMappingURL=assure.test.js.map