import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { MCPServerList } from '../../../src/renderer/components/mcp/MCPServerList'; import { factories } from '../../utils/testHelpers'; /** * Mock the MCPServerCard component to focus on MCPServerList logic */ jest.mock('../../../src/renderer/components/mcp/MCPServerCard', () => ({ MCPServerCard: ({ server, onToggle, onEdit, onDelete, onTest, }: { server: { id: string; name: string }; onToggle: (id: string) => void; onEdit: (id: string) => void; onDelete: (id: string) => void; onTest: (id: string) => void; }) => (
{server.name}
), })); describe('MCPServerList', () => { const mockHandlers = { onToggle: jest.fn(), onEdit: jest.fn(), onDelete: jest.fn(), onTest: jest.fn(), onAdd: jest.fn(), }; beforeEach(() => { jest.clearAllMocks(); }); describe('loading state', () => { it('should display loading spinner when loading is true', () => { render(); expect(screen.getByText('Loading MCP servers...')).toBeInTheDocument(); expect(screen.getByRole('status')).toBeInTheDocument(); }); it('should not display server cards when loading', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Test Server' }), ]; render( ); expect( screen.queryByTestId('server-card-server-1') ).not.toBeInTheDocument(); expect(screen.getByText('Loading MCP servers...')).toBeInTheDocument(); }); }); describe('empty state', () => { it('should display empty state when no servers are configured', () => { render(); expect(screen.getByText('No servers configured')).toBeInTheDocument(); expect( screen.getByText(/Add MCP servers to extend your agent/) ).toBeInTheDocument(); expect(screen.getByText('Add Server')).toBeInTheDocument(); }); it('should call onAdd when "Add Server" button is clicked', () => { render(); const addButton = screen.getByText('Add Server'); fireEvent.click(addButton); expect(mockHandlers.onAdd).toHaveBeenCalledTimes(1); }); }); describe('server list rendering', () => { it('should render all servers when provided', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Server 1' }), factories.mcpServer({ id: 'server-2', name: 'Server 2' }), factories.mcpServer({ id: 'server-3', name: 'Server 3' }), ]; render( ); expect(screen.getByTestId('server-card-server-1')).toBeInTheDocument(); expect(screen.getByTestId('server-card-server-2')).toBeInTheDocument(); expect(screen.getByTestId('server-card-server-3')).toBeInTheDocument(); expect(screen.getByText('Server 1')).toBeInTheDocument(); expect(screen.getByText('Server 2')).toBeInTheDocument(); expect(screen.getByText('Server 3')).toBeInTheDocument(); }); it('should pass all props to MCPServerCard components', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Test Server' }), ]; render( ); const serverCard = screen.getByTestId('server-card-server-1'); expect(serverCard).toBeInTheDocument(); expect(screen.getByTestId('toggle-server-1')).toBeInTheDocument(); expect(screen.getByTestId('edit-server-1')).toBeInTheDocument(); expect(screen.getByTestId('delete-server-1')).toBeInTheDocument(); expect(screen.getByTestId('test-server-1')).toBeInTheDocument(); }); }); describe('event handling', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Test Server' }), ]; it('should handle toggle events', () => { render( ); fireEvent.click(screen.getByTestId('toggle-server-1')); expect(mockHandlers.onToggle).toHaveBeenCalledWith('server-1'); }); it('should handle edit events', () => { render( ); fireEvent.click(screen.getByTestId('edit-server-1')); expect(mockHandlers.onEdit).toHaveBeenCalledWith('server-1'); }); it('should handle delete events', () => { render( ); fireEvent.click(screen.getByTestId('delete-server-1')); expect(mockHandlers.onDelete).toHaveBeenCalledWith('server-1'); }); it('should handle test events', () => { render( ); fireEvent.click(screen.getByTestId('test-server-1')); expect(mockHandlers.onTest).toHaveBeenCalledWith('server-1'); }); }); describe('default props', () => { it('should handle undefined loading prop', () => { render(); expect( screen.queryByText('Loading MCP servers...') ).not.toBeInTheDocument(); expect(screen.getByText('No servers configured')).toBeInTheDocument(); }); it('should handle missing optional handlers gracefully', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Test Server' }), ]; expect(() => { render( ); }).not.toThrow(); }); }); describe('accessibility', () => { it('should have proper ARIA labels for loading state', () => { render(); const spinner = screen.getByRole('status'); expect(spinner).toBeInTheDocument(); }); it('should have proper button roles in empty state', () => { render(); const addButton = screen.getByRole('button', { name: /Add Server/i }); expect(addButton).toBeInTheDocument(); }); }); describe('grid layout', () => { it('should use grid layout for server cards', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Server 1' }), factories.mcpServer({ id: 'server-2', name: 'Server 2' }), ]; const { container } = render( ); const gridContainer = container.querySelector('.grid'); expect(gridContainer).toBeInTheDocument(); expect(gridContainer).toHaveClass('gap-4'); }); }); describe('server statistics', () => { it('should handle servers with tools', () => { const servers = [ factories.mcpServer({ id: 'server-1', name: 'Server 1', status: 'connected', enabled: true, tools: [ { name: 'tool1', description: 'Tool 1' }, { name: 'tool2', description: 'Tool 2' }, ], }), factories.mcpServer({ id: 'server-2', name: 'Server 2', status: 'disconnected', enabled: false, tools: [], }), ]; render( ); expect(screen.getByTestId('server-card-server-1')).toBeInTheDocument(); expect(screen.getByTestId('server-card-server-2')).toBeInTheDocument(); }); }); describe('edge cases', () => { it('should handle servers with missing properties', () => { const servers = [ { id: 'server-1', name: 'Minimal Server', }, ] as { id: string; name: string }[]; expect(() => { render( ); }).not.toThrow(); expect(screen.getByTestId('server-card-server-1')).toBeInTheDocument(); }); it('should handle very long server lists', () => { const servers = Array.from({ length: 50 }, (_, i) => factories.mcpServer({ id: `server-${i}`, name: `Server ${i}`, }) ); const { container } = render( ); expect( container.querySelectorAll('[data-testid^="server-card-"]') ).toHaveLength(50); }); }); });