import { render, screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, it, expect, vi } from 'vitest'; import { ProviderTable } from '@/pages/Providers/ProviderTable'; import type { Provider } from '@/types'; const mockModelsData = [ { id: 'model-1', providerId: 'openai', modelName: 'gpt-4o', enabled: true }, { id: 'model-2', providerId: 'openai', modelName: 'gpt-3.5-turbo', enabled: false }, ]; vi.mock('@/hooks/useModels', () => ({ useModels: vi.fn(() => ({ data: mockModelsData, isLoading: false })), useDeleteModel: vi.fn(() => ({ mutate: vi.fn() })), })); const mockProviders: Provider[] = [ { id: 'openai', name: 'OpenAI', apiKey: 'sk-abcdefgh12345678', baseUrl: 'https://api.openai.com/v1', enabled: true, createdAt: '2024-01-01T00:00:00Z', updatedAt: '2024-01-01T00:00:00Z', }, { id: 'anthropic', name: 'Anthropic', apiKey: 'sk-ant-test', baseUrl: 'https://api.anthropic.com', enabled: false, createdAt: '2024-01-02T00:00:00Z', updatedAt: '2024-01-02T00:00:00Z', }, ]; const defaultProps = { providers: mockProviders, loading: false, onAdd: vi.fn(), onEdit: vi.fn(), onDelete: vi.fn(), onAddModel: vi.fn(), onEditModel: vi.fn(), }; describe('ProviderTable', () => { it('renders provider list with name, baseUrl, masked apiKey, and status tags', () => { render(); expect(screen.getByText('供应商列表')).toBeInTheDocument(); expect(screen.getByText('OpenAI')).toBeInTheDocument(); expect(screen.getByText('https://api.openai.com/v1')).toBeInTheDocument(); expect(screen.getByText('****5678')).toBeInTheDocument(); expect(screen.getByText('Anthropic')).toBeInTheDocument(); expect(screen.getByText('https://api.anthropic.com')).toBeInTheDocument(); expect(screen.getByText('****test')).toBeInTheDocument(); const enabledTags = screen.getAllByText('启用'); const disabledTags = screen.getAllByText('禁用'); expect(enabledTags.length).toBeGreaterThanOrEqual(1); expect(disabledTags.length).toBeGreaterThanOrEqual(1); }); it('renders within a Card component', () => { const { container } = render(); expect(container.querySelector('.ant-card')).toBeInTheDocument(); expect(container.querySelector('.ant-card-head')).toBeInTheDocument(); expect(container.querySelector('.ant-card-body')).toBeInTheDocument(); }); it('renders short api keys fully masked', () => { const shortKeyProvider: Provider[] = [ { ...mockProviders[0], id: 'short', name: 'ShortKey', apiKey: 'ab', }, ]; render(); expect(screen.getByText('****')).toBeInTheDocument(); }); it('calls onAdd when clicking "添加供应商" button', async () => { const user = userEvent.setup(); const onAdd = vi.fn(); render(); await user.click(screen.getByRole('button', { name: '添加供应商' })); expect(onAdd).toHaveBeenCalledTimes(1); }); it('calls onEdit with correct provider when clicking "编辑"', async () => { const user = userEvent.setup(); const onEdit = vi.fn(); render(); const editButtons = screen.getAllByRole('button', { name: '编辑' }); await user.click(editButtons[0]); expect(onEdit).toHaveBeenCalledTimes(1); expect(onEdit).toHaveBeenCalledWith(mockProviders[0]); }); it('calls onDelete with correct provider ID when delete is confirmed', async () => { const user = userEvent.setup(); const onDelete = vi.fn(); render(); // Find and click the delete button for the first row const deleteButtons = screen.getAllByRole('button', { name: '删除' }); await user.click(deleteButtons[0]); // Find and click the "确 定" confirm button in the Popconfirm popup // antd renders the text with spaces between Chinese characters const confirmButtons = await screen.findAllByText('确 定'); await user.click(confirmButtons[0]); // Assert that onDelete was called with the correct provider ID expect(onDelete).toHaveBeenCalledTimes(1); expect(onDelete).toHaveBeenCalledWith('openai'); }, 10000); it('shows loading state', () => { render(); expect(document.querySelector('.ant-spin')).toBeInTheDocument(); }); it('renders expandable ModelTable when row is expanded', async () => { const user = userEvent.setup(); render(); // Find and click the expand button for the first row const expandButtons = screen.getAllByRole('button', { name: /expand/i }); expect(expandButtons.length).toBeGreaterThanOrEqual(1); await user.click(expandButtons[0]); // Verify that ModelTable content is rendered with data from mocked useModels expect(await screen.findByText('gpt-4o')).toBeInTheDocument(); expect(screen.getByText('gpt-3.5-turbo')).toBeInTheDocument(); }); });