import { describe, it, expect } from 'vitest'; import { coalesce, present } from './Option'; describe('Option', () => { describe('coalesce()', () => { it('should return the value when it is defined', () => { expect(coalesce('defined', 'fallback')).toBe('defined'); expect(coalesce(42, 0)).toBe(42); expect(coalesce(true, false)).toBe(true); }); it('should return the fallback when value is undefined', () => { expect(coalesce(undefined, 'fallback')).toBe('fallback'); expect(coalesce(undefined, 42)).toBe(42); expect(coalesce(undefined, true)).toBe(true); }); it('should return the fallback when value is null', () => { expect(coalesce(null, 'fallback')).toBe('fallback'); expect(coalesce(null, 42)).toBe(42); expect(coalesce(null, true)).toBe(true); }); it('should handle complex fallback values', () => { const fallback = { id: 0, name: 'default' }; expect(coalesce(undefined, fallback)).toEqual(fallback); expect(coalesce(null, fallback)).toEqual(fallback); expect(coalesce({ id: 1, name: 'actual' }, fallback)).toEqual({ id: 1, name: 'actual' }); }); it('should handle array values', () => { const fallback = [1, 2, 3]; expect(coalesce(undefined, fallback)).toEqual([1, 2, 3]); expect(coalesce([4, 5], fallback)).toEqual([4, 5]); }); it('should handle zero and empty string as valid values', () => { expect(coalesce(0, 999)).toBe(0); expect(coalesce('', 'fallback')).toBe(''); expect(coalesce(false, true)).toBe(false); }); }); describe('present()', () => { it('should return the value when it is defined and not null', () => { expect(present('value')).toBe('value'); expect(present(42)).toBe(42); expect(present(true)).toBe(true); expect(present({})).toEqual({}); expect(present([])).toEqual([]); }); it('should return undefined when value is undefined', () => { expect(present(undefined)).toBe(undefined); }); it('should return undefined when value is null', () => { expect(present(null)).toBe(undefined); }); it('should handle zero and empty string as valid values', () => { expect(present(0)).toBe(0); expect(present('')).toBe(''); expect(present(false)).toBe(false); }); it('should handle complex objects', () => { const obj = { id: 1, name: 'test', nested: { value: 'data' } }; expect(present(obj)).toEqual(obj); }); it('should handle arrays', () => { const arr = [1, 2, 3, 'test']; expect(present(arr)).toEqual(arr); }); }); describe('Option behavior', () => { it('should work together for optional value handling', () => { // Example: providing a default when value might be missing const maybeValue: string | undefined = undefined; const result = coalesce(maybeValue, 'default'); expect(result).toBe('default'); // Example: filtering out null/undefined const values: (string | null | undefined)[] = ['a', null, 'b', undefined, 'c']; const filtered = values.map(present).filter((v): v is string => v !== undefined); expect(filtered).toEqual(['a', 'b', 'c']); }); it('should support conditional value assignment', () => { const config: { timeout?: number } = {}; const timeout = coalesce(config.timeout, 5000); expect(timeout).toBe(5000); config.timeout = 3000; const timeout2 = coalesce(config.timeout, 5000); expect(timeout2).toBe(3000); }); it('should handle nested optional properties', () => { interface User { profile?: { name?: string; email?: string; }; } const user1: User = {}; const user2: User = { profile: {} }; const user3: User = { profile: { name: 'John' } }; const user4: User = { profile: { name: 'John', email: 'john@example.com' } }; expect(coalesce(user1.profile?.name, 'Anonymous')).toBe('Anonymous'); expect(coalesce(user2.profile?.name, 'Anonymous')).toBe('Anonymous'); expect(coalesce(user3.profile?.name, 'Anonymous')).toBe('John'); expect(coalesce(user4.profile?.name, 'Anonymous')).toBe('John'); }); }); });