import { render, screen, waitFor, act } from '@testing-library/react'; import { describe, it, expect, vi } from 'vitest'; import { ToastComponent, Toast } from './Toast'; import { ToastProvider, useToastContext } from './ToastProvider'; import { useToast } from '@/hooks/useToast'; describe('Toast Components', () => { describe('ToastComponent', () => { const mockToast: Toast = { id: '1', message: 'Test message', type: 'success', }; it('renders toast with message', async () => { const onDismiss = vi.fn(); render(); await waitFor(() => { expect(screen.getByText('Test message')).toBeInTheDocument(); }); }); it('renders with correct type styling', async () => { const onDismiss = vi.fn(); const { container } = render( , ); await waitFor(() => { const toast = container.querySelector( '.bg-red-50, .dark\\:bg-red-900\\/20', ); expect(toast).toBeInTheDocument(); }); }); it('auto-dismisses after duration', async () => { vi.useFakeTimers(); const onDismiss = vi.fn(); render( , ); await waitFor(() => { expect(screen.getByText('Test message')).toBeInTheDocument(); }); act(() => { vi.advanceTimersByTime(1100); }); await waitFor(() => { expect(onDismiss).toHaveBeenCalledWith('1'); }); vi.useRealTimers(); }); it('does not auto-dismiss when duration is 0', async () => { vi.useFakeTimers(); const onDismiss = vi.fn(); render( , ); await waitFor(() => { expect(screen.getByText('Test message')).toBeInTheDocument(); }); act(() => { vi.advanceTimersByTime(6000); }); await waitFor(() => { expect(onDismiss).not.toHaveBeenCalled(); }); vi.useRealTimers(); }); it('calls onDismiss when close button is clicked', async () => { const onDismiss = vi.fn(); render(); await waitFor(() => { expect(screen.getByText('Test message')).toBeInTheDocument(); }); const closeButton = screen.getByLabelText('Fermer'); closeButton.click(); await waitFor( () => { expect(onDismiss).toHaveBeenCalledWith('1'); }, { timeout: 500 }, ); }); it('renders correct icon for each type', async () => { const onDismiss = vi.fn(); const { container, rerender } = render( , ); await waitFor(() => { const icon = container.querySelector('svg'); expect(icon).toBeInTheDocument(); }); rerender( , ); rerender( , ); rerender( , ); }); it('renders with default type when type is not provided', async () => { const onDismiss = vi.fn(); const { container } = render( , ); await waitFor(() => { expect(screen.getByText('Test')).toBeInTheDocument(); const toast = container.querySelector( '.bg-blue-50, .dark\\:bg-blue-900\\/20', ); expect(toast).toBeInTheDocument(); }); }); }); describe('ToastProvider', () => { it('provides toast context', () => { const TestComponent = () => { const context = useToastContext(); expect(context).toBeDefined(); expect(context.toasts).toEqual([]); expect(typeof context.addToast).toBe('function'); expect(typeof context.removeToast).toBe('function'); return
Test
; }; render( , ); }); it('throws error when used outside provider', () => { const TestComponent = () => { try { useToastContext(); return
Should not render
; } catch (error: any) { expect(error.message).toContain( 'useToastContext must be used within ToastProvider', ); return
Error caught
; } }; render(); }); it('adds toast to queue', async () => { const TestComponent = () => { const { addToast, toasts } = useToastContext(); return (
{toasts.length}
); }; render( , ); const button = screen.getByText('Add Toast'); button.click(); await waitFor(() => { expect(screen.getByTestId('toast-count')).toHaveTextContent('1'); }); }); it('removes toast from queue', async () => { const TestComponent = () => { const { addToast, removeToast, toasts } = useToastContext(); return (
{toasts.length}
); }; render( , ); const addButton = screen.getByText('Add Toast'); addButton.click(); await waitFor(() => { expect(screen.getByTestId('toast-count')).toHaveTextContent('1'); }); const removeButton = screen.getByText('Remove Toast'); removeButton.click(); await waitFor(() => { expect(screen.getByTestId('toast-count')).toHaveTextContent('0'); }); }); it('renders toasts in container', async () => { const TestComponent = () => { const { addToast } = useToastContext(); return ( ); }; render( , ); const button = screen.getByText('Add Toast'); await act(async () => { button.click(); }); await waitFor( () => { expect(screen.getByText('Test message')).toBeInTheDocument(); }, { timeout: 1000 }, ); }); it('applies correct position classes', () => { const { container, rerender } = render(
Test
, ); let positionDiv = container.querySelector('.top-4.right-4'); expect(positionDiv).toBeInTheDocument(); rerender(
Test
, ); positionDiv = container.querySelector('.bottom-4.left-4'); expect(positionDiv).toBeInTheDocument(); }); }); describe('useToast hook', () => { it('provides toast methods', () => { const TestComponent = () => { const toast = useToast(); expect(typeof toast.success).toBe('function'); expect(typeof toast.error).toBe('function'); expect(typeof toast.warning).toBe('function'); expect(typeof toast.info).toBe('function'); expect(typeof toast.toast).toBe('function'); return
Test
; }; render( , ); }); it('displays success toast', async () => { const TestComponent = () => { const toast = useToast(); return ( ); }; render( , ); const button = screen.getByText('Show Success'); await act(async () => { button.click(); }); // Wait for toast to appear (with animation delay) await waitFor( () => { const toast = screen.queryByText('Success message'); expect(toast).toBeInTheDocument(); }, { timeout: 1000 }, ); }); it('displays error toast', async () => { const TestComponent = () => { const toast = useToast(); return ( ); }; render( , ); const button = screen.getByText('Show Error'); await act(async () => { button.click(); }); await waitFor( () => { expect(screen.getByText('Error message')).toBeInTheDocument(); }, { timeout: 1000 }, ); }); it('displays warning toast', async () => { const TestComponent = () => { const toast = useToast(); return ( ); }; render( , ); const button = screen.getByText('Show Warning'); await act(async () => { button.click(); }); await waitFor( () => { expect(screen.getByText('Warning message')).toBeInTheDocument(); }, { timeout: 1000 }, ); }); it('displays info toast', async () => { const TestComponent = () => { const toast = useToast(); return ( ); }; render( , ); const button = screen.getByText('Show Info'); await act(async () => { button.click(); }); await waitFor( () => { expect(screen.getByText('Info message')).toBeInTheDocument(); }, { timeout: 1000 }, ); }); it('allows custom toast with toast method', async () => { const TestComponent = () => { const toast = useToast(); return ( ); }; render( , ); const button = screen.getByText('Show Custom'); await act(async () => { button.click(); }); await waitFor( () => { expect(screen.getByText('Custom message')).toBeInTheDocument(); }, { timeout: 1000 }, ); }); }); });