/** * Tests for useFormError Hook * Verifies form error handling and API error integration */ import { renderHook, act } from '@testing-library/react'; import { useForm } from 'react-hook-form'; import { useFormError } from '@/components/forms/useFormError'; interface TestFormData { email: string; password: string; username: string; } // Helper to render both hooks together in one scope function useTestForm(defaultValues?: Partial) { const form = useForm({ defaultValues: defaultValues || {}, }); const formError = useFormError(form); return { form, formError }; } describe('useFormError', () => { describe('Initial State', () => { it('initializes with null serverError', () => { const { result } = renderHook(() => useTestForm()); expect(result.current.formError.serverError).toBeNull(); }); it('provides all expected functions', () => { const { result } = renderHook(() => useTestForm()); expect(typeof result.current.formError.setServerError).toBe('function'); expect(typeof result.current.formError.handleFormError).toBe('function'); expect(typeof result.current.formError.clearErrors).toBe('function'); }); }); describe('setServerError', () => { it('sets server error message', () => { const { result } = renderHook(() => useTestForm()); act(() => { result.current.formError.setServerError('Custom error message'); }); expect(result.current.formError.serverError).toBe('Custom error message'); }); it('clears server error when set to null', () => { const { result } = renderHook(() => useTestForm()); act(() => { result.current.formError.setServerError('Error message'); }); act(() => { result.current.formError.setServerError(null); }); expect(result.current.formError.serverError).toBeNull(); }); }); describe('handleFormError - API Error Array', () => { it('handles API error with general error message', () => { const { result } = renderHook(() => useTestForm()); const apiError = [{ code: 'AUTH_001', message: 'Invalid credentials' }]; act(() => { result.current.formError.handleFormError(apiError); }); expect(result.current.formError.serverError).toBe('Invalid credentials'); }); it('handles multiple general errors (takes first non-field error)', () => { const { result } = renderHook(() => useTestForm()); const apiError = [ { code: 'AUTH_001', message: 'Authentication failed' }, { code: 'AUTH_002', message: 'Account is inactive' }, ]; act(() => { result.current.formError.handleFormError(apiError); }); // Should take the first general error expect(result.current.formError.serverError).toBe('Authentication failed'); }); it('handles API errors with field-specific errors without crashing', () => { const { result } = renderHook(() => useTestForm({ email: '', password: '', username: '' })); const apiError = [ { code: 'VAL_004', message: 'Email is required', field: 'email' }, { code: 'VAL_003', message: 'Password too short', field: 'password' }, ]; // Should not throw even though fields aren't registered expect(() => { act(() => { result.current.formError.handleFormError(apiError); }); }).not.toThrow(); // No general error should be set (all are field errors) expect(result.current.formError.serverError).toBeNull(); }); }); describe('handleFormError - Non-API Errors', () => { it('handles unexpected error format', () => { const { result } = renderHook(() => useTestForm()); const unexpectedError = new Error('Network error'); act(() => { result.current.formError.handleFormError(unexpectedError); }); expect(result.current.formError.serverError).toBe( 'An unexpected error occurred. Please try again.' ); }); it('handles string errors', () => { const { result } = renderHook(() => useTestForm()); act(() => { result.current.formError.handleFormError('Some error string'); }); expect(result.current.formError.serverError).toBe( 'An unexpected error occurred. Please try again.' ); }); it('handles null errors', () => { const { result } = renderHook(() => useTestForm()); act(() => { result.current.formError.handleFormError(null); }); expect(result.current.formError.serverError).toBe( 'An unexpected error occurred. Please try again.' ); }); it('handles undefined errors', () => { const { result } = renderHook(() => useTestForm()); act(() => { result.current.formError.handleFormError(undefined); }); expect(result.current.formError.serverError).toBe( 'An unexpected error occurred. Please try again.' ); }); }); describe('clearErrors', () => { it('clears server error', () => { const { result } = renderHook(() => useTestForm()); act(() => { result.current.formError.setServerError('Some error'); }); act(() => { result.current.formError.clearErrors(); }); expect(result.current.formError.serverError).toBeNull(); }); it('clears form errors', () => { const { result } = renderHook(() => useTestForm({ email: '', password: '', username: '' })); // Set field errors act(() => { result.current.form.setError('email', { message: 'Email error' }); result.current.form.setError('password', { message: 'Password error' }); }); // Clear all errors act(() => { result.current.formError.clearErrors(); }); expect(result.current.form.formState.errors.email).toBeUndefined(); expect(result.current.form.formState.errors.password).toBeUndefined(); }); it('clears both server and form errors', () => { const { result } = renderHook(() => useTestForm({ email: '', password: '', username: '' })); act(() => { result.current.formError.setServerError('Server error'); result.current.form.setError('email', { message: 'Email error' }); }); act(() => { result.current.formError.clearErrors(); }); expect(result.current.formError.serverError).toBeNull(); expect(result.current.form.formState.errors.email).toBeUndefined(); }); }); describe('Integration Scenarios', () => { it('handles typical login flow with API error', () => { const { result } = renderHook(() => useTestForm({ email: '', password: '', username: '' })); // Simulate API error response const apiError = [{ code: 'AUTH_001', message: 'Invalid email or password' }]; act(() => { result.current.formError.handleFormError(apiError); }); expect(result.current.formError.serverError).toBe('Invalid email or password'); }); it('clears error state on retry', () => { const { result } = renderHook(() => useTestForm()); // First attempt - error act(() => { result.current.formError.setServerError('First error'); }); expect(result.current.formError.serverError).toBe('First error'); // Clear before retry act(() => { result.current.formError.clearErrors(); }); expect(result.current.formError.serverError).toBeNull(); // Second attempt - different error act(() => { result.current.formError.setServerError('Second error'); }); expect(result.current.formError.serverError).toBe('Second error'); }); }); });