/** * SubAgentSelector Component Tests * Rewritten for database-driven agents with numeric row_ids */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent } from '@testing-library/react'; import { SubAgentSelector, type AvailableAgent } from '../SubAgentSelector'; // Mock useLanguage vi.mock('@/shared/i18n/LanguageContext', () => ({ useLanguage: () => ({ language: 'en', setLanguage: vi.fn(), t: (key: string) => { const map: Record = { 'chat.subAgents': 'Sub-agents', 'chat.noAgentsAvailable': 'No agents available', }; return map[key] ?? key; }, }), })); const mockAgents: AvailableAgent[] = [ { row_id: 1, name: 'Translator', icon: '\uD83C\uDF10', description: 'Translates messages automatically' }, { row_id: 2, name: 'Summarizer', icon: '\uD83D\uDCC4', description: 'Creates summaries of long discussions' }, { row_id: 3, name: 'Vector Search', icon: '\uD83D\uDD0D', description: 'Semantic search in knowledge base' }, ]; describe('SubAgentSelector', () => { const mockOnChange = vi.fn(); beforeEach(() => { vi.clearAllMocks(); }); it('renders all available agents', () => { render( ); expect(screen.getByText('Translator')).toBeInTheDocument(); expect(screen.getByText('Summarizer')).toBeInTheDocument(); expect(screen.getByText('Vector Search')).toBeInTheDocument(); }); it('shows header label', () => { render( ); expect(screen.getByText('Sub-agents')).toBeInTheDocument(); }); it('shows descriptions for each agent', () => { render( ); expect(screen.getByText('Translates messages automatically')).toBeInTheDocument(); expect(screen.getByText('Creates summaries of long discussions')).toBeInTheDocument(); expect(screen.getByText('Semantic search in knowledge base')).toBeInTheDocument(); }); it('shows agent icon emoji', () => { render( ); expect(screen.getByText('\uD83C\uDF10')).toBeInTheDocument(); expect(screen.getByText('\uD83D\uDCC4')).toBeInTheDocument(); expect(screen.getByText('\uD83D\uDD0D')).toBeInTheDocument(); }); it('adds agent row_id when toggled on', () => { render( ); fireEvent.click(screen.getByText('Translator').closest('button')!); expect(mockOnChange).toHaveBeenCalledWith([1]); }); it('removes agent row_id when toggled off', () => { render( ); fireEvent.click(screen.getByText('Translator').closest('button')!); expect(mockOnChange).toHaveBeenCalledWith([2]); }); it('preserves other selected agents when toggling', () => { render( ); fireEvent.click(screen.getByText('Vector Search').closest('button')!); expect(mockOnChange).toHaveBeenCalledWith([1, 3]); }); it('reflects selected state visually', () => { render( ); const summaryButton = screen.getByText('Summarizer').closest('button'); expect(summaryButton).toHaveClass('bg-[var(--color-primary-500)]/10'); }); it('does not call onChange when disabled', () => { render( ); fireEvent.click(screen.getByText('Translator').closest('button')!); expect(mockOnChange).not.toHaveBeenCalled(); }); it('shows loading state', () => { render( ); expect(screen.getByTestId('sub-agent-loading')).toBeInTheDocument(); expect(screen.queryByTestId('sub-agent-empty')).not.toBeInTheDocument(); }); it('shows empty state when no agents available', () => { render( ); expect(screen.getByTestId('sub-agent-empty')).toBeInTheDocument(); expect(screen.getByText('No agents available')).toBeInTheDocument(); }); it('does not show empty state while loading', () => { render( ); expect(screen.queryByTestId('sub-agent-empty')).not.toBeInTheDocument(); }); it('renders agent without description', () => { const agentNoDesc: AvailableAgent[] = [ { row_id: 10, name: 'Simple Agent' }, ]; render( ); expect(screen.getByText('Simple Agent')).toBeInTheDocument(); }); it('renders agent without icon using fallback Bot icon', () => { const agentNoIcon: AvailableAgent[] = [ { row_id: 10, name: 'No Icon Agent', icon: null }, ]; render( ); expect(screen.getByText('No Icon Agent')).toBeInTheDocument(); // The button should exist and be clickable const button = screen.getByText('No Icon Agent').closest('button'); expect(button).toBeInTheDocument(); }); it('has data-testid on each agent item', () => { render( ); expect(screen.getByTestId('sub-agent-item-1')).toBeInTheDocument(); expect(screen.getByTestId('sub-agent-item-2')).toBeInTheDocument(); expect(screen.getByTestId('sub-agent-item-3')).toBeInTheDocument(); }); });