135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
|
|
/**
|
||
|
|
* Tests for Timeout Handler Utility
|
||
|
|
* FE-TEST-004: Test timeout handler utility functions
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||
|
|
import {
|
||
|
|
TIMEOUT_CONFIG,
|
||
|
|
TIMEOUT_MESSAGES,
|
||
|
|
createTimeoutPromise,
|
||
|
|
withTimeout,
|
||
|
|
getTimeoutForRequestType,
|
||
|
|
isTimeoutError,
|
||
|
|
getTimeoutMessage,
|
||
|
|
withRequestTimeout,
|
||
|
|
} from './timeoutHandler';
|
||
|
|
|
||
|
|
// Mock react-hot-toast
|
||
|
|
vi.mock('react-hot-toast', () => ({
|
||
|
|
default: {
|
||
|
|
loading: vi.fn(() => 'toast-id'),
|
||
|
|
dismiss: vi.fn(),
|
||
|
|
},
|
||
|
|
}));
|
||
|
|
|
||
|
|
describe('timeoutHandler utilities', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.useFakeTimers();
|
||
|
|
vi.clearAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
vi.useRealTimers();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('TIMEOUT_CONFIG', () => {
|
||
|
|
it('should have timeout configs', () => {
|
||
|
|
expect(TIMEOUT_CONFIG.default).toBe(10000);
|
||
|
|
expect(TIMEOUT_CONFIG.fast).toBe(5000);
|
||
|
|
expect(TIMEOUT_CONFIG.slow).toBe(30000);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('createTimeoutPromise', () => {
|
||
|
|
it('should reject after timeout', async () => {
|
||
|
|
const promise = createTimeoutPromise(1000, 'Timeout');
|
||
|
|
vi.advanceTimersByTime(1000);
|
||
|
|
await expect(promise).rejects.toThrow('Timeout');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('withTimeout', () => {
|
||
|
|
it('should resolve if promise completes before timeout', async () => {
|
||
|
|
const promise = Promise.resolve('success');
|
||
|
|
const result = withTimeout(promise, { timeout: 1000 });
|
||
|
|
vi.advanceTimersByTime(500);
|
||
|
|
await expect(result).resolves.toBe('success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should reject on timeout', async () => {
|
||
|
|
const promise = new Promise((resolve) => {
|
||
|
|
setTimeout(() => resolve('success'), 2000);
|
||
|
|
});
|
||
|
|
const result = withTimeout(promise, { timeout: 1000 });
|
||
|
|
vi.advanceTimersByTime(1000);
|
||
|
|
await expect(result).rejects.toThrow();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should call onTimeout callback', async () => {
|
||
|
|
const onTimeout = vi.fn();
|
||
|
|
const promise = new Promise((resolve) => {
|
||
|
|
setTimeout(() => resolve('success'), 2000);
|
||
|
|
});
|
||
|
|
const result = withTimeout(promise, { timeout: 1000, onTimeout });
|
||
|
|
vi.advanceTimersByTime(1000);
|
||
|
|
try {
|
||
|
|
await result;
|
||
|
|
} catch {
|
||
|
|
// Expected
|
||
|
|
}
|
||
|
|
expect(onTimeout).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('getTimeoutForRequestType', () => {
|
||
|
|
it('should return timeout for request type', () => {
|
||
|
|
expect(getTimeoutForRequestType('fast')).toBe(5000);
|
||
|
|
expect(getTimeoutForRequestType('normal')).toBe(10000);
|
||
|
|
expect(getTimeoutForRequestType('slow')).toBe(30000);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should default to normal', () => {
|
||
|
|
expect(getTimeoutForRequestType()).toBe(10000);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('isTimeoutError', () => {
|
||
|
|
it('should return true for timeout error', () => {
|
||
|
|
const error = new Error('Request timeout');
|
||
|
|
expect(isTimeoutError(error)).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return true for timeout in message', () => {
|
||
|
|
const error = new Error('Request expired');
|
||
|
|
expect(isTimeoutError(error)).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return true for ECONNABORTED', () => {
|
||
|
|
expect(isTimeoutError({ code: 'ECONNABORTED' })).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return false for other errors', () => {
|
||
|
|
const error = new Error('Other error');
|
||
|
|
expect(isTimeoutError(error)).toBe(false);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('getTimeoutMessage', () => {
|
||
|
|
it('should return message for request type', () => {
|
||
|
|
expect(getTimeoutMessage('fast')).toBeTruthy();
|
||
|
|
expect(getTimeoutMessage('normal')).toBeTruthy();
|
||
|
|
expect(getTimeoutMessage('slow')).toBeTruthy();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('withRequestTimeout', () => {
|
||
|
|
it('should wrap API call with timeout', async () => {
|
||
|
|
const apiCall = vi.fn().mockResolvedValue('success');
|
||
|
|
const result = withRequestTimeout(apiCall, 'normal');
|
||
|
|
vi.advanceTimersByTime(500);
|
||
|
|
await expect(result).resolves.toBe('success');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|