/** * Tests for ConnectionStatus Component */ import { render, screen, fireEvent } from '@testing-library/react'; import { ConnectionStatus } from '@/components/events/ConnectionStatus'; import type { SSEError } from '@/lib/types/events'; describe('ConnectionStatus', () => { const mockOnReconnect = jest.fn(); beforeEach(() => { jest.clearAllMocks(); }); describe('connected state', () => { it('renders connected status', () => { render(); expect(screen.getByText('Connected')).toBeInTheDocument(); expect(screen.getByText('Receiving real-time updates')).toBeInTheDocument(); }); it('does not show reconnect button when connected', () => { render(); expect(screen.queryByRole('button', { name: /reconnect/i })).not.toBeInTheDocument(); }); it('applies connected styling', () => { const { container } = render(); expect(container.querySelector('.border-green-200')).toBeInTheDocument(); }); }); describe('connecting state', () => { it('renders connecting status', () => { render(); expect(screen.getByText('Connecting')).toBeInTheDocument(); expect(screen.getByText('Establishing connection...')).toBeInTheDocument(); }); it('shows retry count when retrying', () => { render(); expect(screen.getByText('Retry 3')).toBeInTheDocument(); }); }); describe('disconnected state', () => { it('renders disconnected status', () => { render(); expect(screen.getByText('Disconnected')).toBeInTheDocument(); expect(screen.getByText('Not connected to server')).toBeInTheDocument(); }); it('shows reconnect button when disconnected', () => { render(); const button = screen.getByRole('button', { name: /reconnect/i }); expect(button).toBeInTheDocument(); }); it('calls onReconnect when button is clicked', () => { render(); const button = screen.getByRole('button', { name: /reconnect/i }); fireEvent.click(button); expect(mockOnReconnect).toHaveBeenCalledTimes(1); }); }); describe('error state', () => { it('renders error status', () => { render(); expect(screen.getByText('Connection Error')).toBeInTheDocument(); expect(screen.getByText('Failed to connect')).toBeInTheDocument(); }); it('shows reconnect button when in error state', () => { render(); const button = screen.getByRole('button', { name: /reconnect/i }); expect(button).toBeInTheDocument(); }); it('applies error styling', () => { const { container } = render(); expect(container.querySelector('.border-destructive')).toBeInTheDocument(); }); }); describe('error details', () => { const mockError: SSEError = { message: 'Connection timeout', code: 'TIMEOUT', timestamp: '2024-01-15T10:30:00Z', retryAttempt: 2, }; it('shows error message when error is provided', () => { render(); expect(screen.getByText(/Error: Connection timeout/)).toBeInTheDocument(); }); it('shows error code when provided', () => { render(); expect(screen.getByText(/Code: TIMEOUT/)).toBeInTheDocument(); }); it('hides error details when showErrorDetails is false', () => { render(); expect(screen.queryByText(/Error: Connection timeout/)).not.toBeInTheDocument(); }); }); describe('compact mode', () => { it('renders compact version', () => { const { container } = render(); // Compact mode should not have the full description expect(screen.queryByText('Receiving real-time updates')).not.toBeInTheDocument(); // Should still show the label expect(screen.getByText('Connected')).toBeInTheDocument(); // Should use smaller container expect(container.querySelector('.rounded-lg')).not.toBeInTheDocument(); }); it('shows compact reconnect button when disconnected', () => { render(); // Should have a small reconnect button const button = screen.getByRole('button', { name: /reconnect/i }); expect(button).toBeInTheDocument(); expect(button.className).toContain('h-6'); }); it('shows retry count in compact mode', () => { render(); expect(screen.getByText(/retry 5/i)).toBeInTheDocument(); }); }); describe('showReconnectButton prop', () => { it('hides reconnect button when showReconnectButton is false', () => { render( ); expect(screen.queryByRole('button', { name: /reconnect/i })).not.toBeInTheDocument(); }); }); describe('accessibility', () => { it('has role="status" for screen readers', () => { render(); expect(screen.getByRole('status')).toBeInTheDocument(); }); it('has aria-live="polite" for status updates', () => { render(); const status = screen.getByRole('status'); expect(status).toHaveAttribute('aria-live', 'polite'); }); }); describe('className prop', () => { it('applies custom className', () => { const { container } = render(); expect(container.querySelector('.custom-class')).toBeInTheDocument(); }); }); });