/** * Utility Functions Tests */ import { formatPercentage, formatProgress, calculateTrend, isValidPostcode, debounce, } from '@/lib/utils'; describe('formatPercentage', () => { it('formats percentages correctly', () => { expect(formatPercentage(75.5)).toBe('75.5%'); expect(formatPercentage(100)).toBe('100.0%'); expect(formatPercentage(0)).toBe('0.0%'); }); it('handles null values', () => { expect(formatPercentage(null)).toBe('-'); }); }); describe('formatProgress', () => { it('formats progress scores correctly', () => { expect(formatProgress(2.5)).toBe('+2.5'); expect(formatProgress(-1.3)).toBe('-1.3'); expect(formatProgress(0)).toBe('0.0'); }); it('handles null values', () => { expect(formatProgress(null)).toBe('-'); }); }); describe('calculateTrend', () => { it('calculates upward trend', () => { expect(calculateTrend(75, 70)).toBe('up'); }); it('calculates downward trend', () => { expect(calculateTrend(70, 75)).toBe('down'); }); it('calculates same trend', () => { expect(calculateTrend(75, 75)).toBe('same'); }); it('handles null previous value', () => { expect(calculateTrend(75, null)).toBe('same'); }); it('handles null current value', () => { expect(calculateTrend(null, 75)).toBe('same'); }); }); describe('isValidPostcode', () => { it('validates correct UK postcodes', () => { expect(isValidPostcode('SW1A 1AA')).toBe(true); expect(isValidPostcode('M1 1AE')).toBe(true); expect(isValidPostcode('B33 8TH')).toBe(true); }); it('rejects invalid postcodes', () => { expect(isValidPostcode('INVALID')).toBe(false); expect(isValidPostcode('12345')).toBe(false); expect(isValidPostcode('')).toBe(false); }); }); describe('debounce', () => { jest.useFakeTimers(); it('delays function execution', () => { const mockFn = jest.fn(); const debouncedFn = debounce(mockFn, 300); debouncedFn('test'); expect(mockFn).not.toHaveBeenCalled(); jest.advanceTimersByTime(300); expect(mockFn).toHaveBeenCalledWith('test'); expect(mockFn).toHaveBeenCalledTimes(1); }); it('cancels previous calls', () => { const mockFn = jest.fn(); const debouncedFn = debounce(mockFn, 300); debouncedFn('first'); jest.advanceTimersByTime(150); debouncedFn('second'); jest.advanceTimersByTime(150); debouncedFn('third'); jest.advanceTimersByTime(300); expect(mockFn).toHaveBeenCalledWith('third'); expect(mockFn).toHaveBeenCalledTimes(1); }); jest.useRealTimers(); });