import { describe, it, expect } from 'vitest'; import { Result } from './Result'; describe('Result', () => { describe('Result.ok()', () => { it('should create a success result with a value', () => { const result = Result.ok('success-value'); expect(result.isOk()).toBe(true); expect(result.isErr()).toBe(false); expect(result.unwrap()).toBe('success-value'); }); it('should create a success result with undefined value', () => { const result = Result.ok(undefined); expect(result.isOk()).toBe(true); expect(result.isErr()).toBe(false); expect(result.unwrap()).toBe(undefined); }); it('should create a success result with null value', () => { const result = Result.ok(null); expect(result.isOk()).toBe(true); expect(result.isErr()).toBe(false); expect(result.unwrap()).toBe(null); }); it('should create a success result with complex object', () => { const complexValue = { id: 123, name: 'test', nested: { data: 'value' } }; const result = Result.ok(complexValue); expect(result.isOk()).toBe(true); expect(result.unwrap()).toEqual(complexValue); }); it('should create a success result with array', () => { const arrayValue = [1, 2, 3, 'test']; const result = Result.ok(arrayValue); expect(result.isOk()).toBe(true); expect(result.unwrap()).toEqual(arrayValue); }); }); describe('Result.err()', () => { it('should create an error result with an error', () => { const error = new Error('test error'); const result = Result.err(error); expect(result.isOk()).toBe(false); expect(result.isErr()).toBe(true); expect(result.unwrapErr()).toBe(error); }); it('should create an error result with string error', () => { const result = Result.err('string error'); expect(result.isOk()).toBe(false); expect(result.isErr()).toBe(true); expect(result.unwrapErr()).toBe('string error'); }); it('should create an error result with object error', () => { const error = { code: 'VALIDATION_ERROR', message: 'Invalid input' }; const result = Result.err(error); expect(result.isOk()).toBe(false); expect(result.isErr()).toBe(true); expect(result.unwrapErr()).toEqual(error); }); it('should create an error result with custom error type', () => { interface CustomError { code: string; details: Record; } const error: CustomError = { code: 'NOT_FOUND', details: { id: '123' } }; const result = Result.err(error); expect(result.isOk()).toBe(false); expect(result.isErr()).toBe(true); expect(result.unwrapErr()).toEqual(error); }); }); describe('Result.isOk()', () => { it('should return true for success results', () => { const result = Result.ok('value'); expect(result.isOk()).toBe(true); }); it('should return false for error results', () => { const result = Result.err(new Error('error')); expect(result.isOk()).toBe(false); }); }); describe('Result.isErr()', () => { it('should return false for success results', () => { const result = Result.ok('value'); expect(result.isErr()).toBe(false); }); it('should return true for error results', () => { const result = Result.err(new Error('error')); expect(result.isErr()).toBe(true); }); }); describe('Result.unwrap()', () => { it('should return the value for success results', () => { const result = Result.ok('test-value'); expect(result.unwrap()).toBe('test-value'); }); it('should throw error for error results', () => { const result = Result.err(new Error('test error')); expect(() => result.unwrap()).toThrow('Called unwrap on an error result'); }); it('should return complex values for success results', () => { const complexValue = { id: 123, data: { nested: 'value' } }; const result = Result.ok(complexValue); expect(result.unwrap()).toEqual(complexValue); }); it('should return arrays for success results', () => { const arrayValue = [1, 2, 3]; const result = Result.ok(arrayValue); expect(result.unwrap()).toEqual(arrayValue); }); }); describe('Result.unwrapOr()', () => { it('should return the value for success results', () => { const result = Result.ok('actual-value'); expect(result.unwrapOr('default-value')).toBe('actual-value'); }); it('should return default value for error results', () => { const result = Result.err(new Error('error')); expect(result.unwrapOr('default-value')).toBe('default-value'); }); it('should return default value when value is undefined', () => { const result = Result.ok(undefined); expect(result.unwrapOr('default-value')).toBe(undefined); }); it('should return default value when value is null', () => { const result = Result.ok(null); expect(result.unwrapOr('default-value')).toBe(null); }); }); describe('Result.unwrapErr()', () => { it('should return the error for error results', () => { const error = new Error('test error'); const result = Result.err(error); expect(result.unwrapErr()).toBe(error); }); it('should throw error for success results', () => { const result = Result.ok('value'); expect(() => result.unwrapErr()).toThrow('Called unwrapErr on a success result'); }); it('should return string errors', () => { const result = Result.err('string error'); expect(result.unwrapErr()).toBe('string error'); }); it('should return object errors', () => { const error = { code: 'ERROR', message: 'Something went wrong' }; const result = Result.err(error); expect(result.unwrapErr()).toEqual(error); }); }); describe('Result.map()', () => { it('should transform success values', () => { const result = Result.ok(5); const mapped = result.map((x) => x * 2); expect(mapped.isOk()).toBe(true); expect(mapped.unwrap()).toBe(10); }); it('should not transform error results', () => { const error = new Error('test error'); const result = Result.err(error); const mapped = result.map((x) => x * 2); expect(mapped.isErr()).toBe(true); expect(mapped.unwrapErr()).toBe(error); }); it('should handle complex transformations', () => { const result = Result.ok({ id: 1, name: 'test' }); const mapped = result.map((obj) => ({ ...obj, name: obj.name.toUpperCase() })); expect(mapped.isOk()).toBe(true); expect(mapped.unwrap()).toEqual({ id: 1, name: 'TEST' }); }); it('should handle array transformations', () => { const result = Result.ok([1, 2, 3]); const mapped = result.map((arr) => arr.map((x) => x * 2)); expect(mapped.isOk()).toBe(true); expect(mapped.unwrap()).toEqual([2, 4, 6]); }); }); describe('Result.mapErr()', () => { it('should transform error values', () => { const error = new Error('original error'); const result = Result.err(error); const mapped = result.mapErr((e) => new Error(`wrapped: ${e.message}`)); expect(mapped.isErr()).toBe(true); expect(mapped.unwrapErr().message).toBe('wrapped: original error'); }); it('should not transform success results', () => { const result = Result.ok('value'); const mapped = result.mapErr((e) => new Error(`wrapped: ${e.message}`)); expect(mapped.isOk()).toBe(true); expect(mapped.unwrap()).toBe('value'); }); it('should handle string error transformations', () => { const result = Result.err('error message'); const mapped = result.mapErr((e) => e.toUpperCase()); expect(mapped.isErr()).toBe(true); expect(mapped.unwrapErr()).toBe('ERROR MESSAGE'); }); it('should handle object error transformations', () => { const error = { code: 'ERROR', message: 'Something went wrong' }; const result = Result.err(error); const mapped = result.mapErr((e) => ({ ...e, code: `WRAPPED_${e.code}` })); expect(mapped.isErr()).toBe(true); expect(mapped.unwrapErr()).toEqual({ code: 'WRAPPED_ERROR', message: 'Something went wrong' }); }); }); describe('Result.andThen()', () => { it('should chain success results', () => { const result1 = Result.ok(5); const result2 = result1.andThen((x) => Result.ok(x * 2)); expect(result2.isOk()).toBe(true); expect(result2.unwrap()).toBe(10); }); it('should propagate errors through chain', () => { const error = new Error('first error'); const result1 = Result.err(error); const result2 = result1.andThen((x) => Result.ok(x * 2)); expect(result2.isErr()).toBe(true); expect(result2.unwrapErr()).toBe(error); }); it('should handle error in chained function', () => { const result1 = Result.ok(5); const result2 = result1.andThen((x) => Result.err(new Error(`error at ${x}`))); expect(result2.isErr()).toBe(true); expect(result2.unwrapErr().message).toBe('error at 5'); }); it('should support multiple chaining steps', () => { const result = Result.ok(2) .andThen((x) => Result.ok(x * 3)) .andThen((x) => Result.ok(x + 1)) .andThen((x) => Result.ok(x * 2)); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBe(14); // ((2 * 3) + 1) * 2 = 14 }); it('should stop chaining on first error', () => { const result = Result.ok(2) .andThen((x) => Result.ok(x * 3)) .andThen((x) => Result.err(new Error('stopped here'))) .andThen((x) => Result.ok(x + 1)); // This should not execute expect(result.isErr()).toBe(true); expect(result.unwrapErr().message).toBe('stopped here'); }); }); describe('Result.value getter', () => { it('should return value for success results', () => { const result = Result.ok('test-value'); expect(result.value).toBe('test-value'); }); it('should return undefined for error results', () => { const result = Result.err(new Error('error')); expect(result.value).toBe(undefined); }); it('should return undefined for success results with undefined value', () => { const result = Result.ok(undefined); expect(result.value).toBe(undefined); }); }); describe('Result.error getter', () => { it('should return error for error results', () => { const error = new Error('test error'); const result = Result.err(error); expect(result.error).toBe(error); }); it('should return undefined for success results', () => { const result = Result.ok('value'); expect(result.error).toBe(undefined); }); it('should return string errors', () => { const result = Result.err('string error'); expect(result.error).toBe('string error'); }); }); describe('Result type safety', () => { it('should work with custom error codes', () => { type MyErrorCode = 'NOT_FOUND' | 'VALIDATION_ERROR' | 'PERMISSION_DENIED'; const successResult = Result.ok('data'); const errorResult = Result.err('NOT_FOUND'); expect(successResult.isOk()).toBe(true); expect(errorResult.isErr()).toBe(true); }); it('should work with ApplicationErrorCode pattern', () => { interface ApplicationErrorCode { code: Code; details?: Details; } type MyErrorCodes = 'USER_NOT_FOUND' | 'INVALID_EMAIL'; const successResult = Result.ok>('user'); const errorResult = Result.err>({ code: 'USER_NOT_FOUND', details: { userId: '123' } }); expect(successResult.isOk()).toBe(true); expect(errorResult.isErr()).toBe(true); expect(errorResult.unwrapErr().code).toBe('USER_NOT_FOUND'); }); }); });