105 lines
2.5 KiB
TypeScript
105 lines
2.5 KiB
TypeScript
|
|
/**
|
||
|
|
* 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();
|
||
|
|
});
|