import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import DisabledPersonSelector from '../../src/components/DisabledPersonSelector'; import { disabilityClientManager } from '../../src/api/disabilityClient'; import type { DisabledPersonData } from '../../src/api/types'; // 完整的mock响应对象 const createMockResponse = (status: number, data?: any) => ({ status, ok: status >= 200 && status < 300, body: null, bodyUsed: false, statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error', headers: new Headers(), url: '', redirected: false, type: 'basic' as ResponseType, json: async () => data || {}, text: async () => '', blob: async () => new Blob(), arrayBuffer: async () => new ArrayBuffer(0), formData: async () => new FormData(), clone: function() { return this; } }); // Mock API client vi.mock('../../src/api/disabilityClient', () => { const mockDisabilityClient = { searchDisabledPersons: { $get: vi.fn(() => Promise.resolve(createMockResponse(200, { data: [ { id: 1, name: '张三', gender: '男', idCard: '110101199001011234', disabilityId: 'CJZ20240001', disabilityType: '视力残疾', disabilityLevel: '一级', idAddress: '北京市东城区', phone: '13800138000', province: '北京市', city: '北京市', district: '东城区', isInBlackList: 0, createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-01T00:00:00Z' }, { id: 2, name: '李四', gender: '女', idCard: '110101199001011235', disabilityId: 'CJZ20240002', disabilityType: '听力残疾', disabilityLevel: '二级', idAddress: '上海市黄浦区', phone: '13800138001', province: '上海市', city: '上海市', district: '黄浦区', isInBlackList: 1, // 黑名单人员 createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-01T00:00:00Z' } ], total: 2 }))) }, getAllDisabledPersons: { $get: vi.fn(() => Promise.resolve(createMockResponse(200, { data: [ { id: 3, name: '王五', gender: '男', idCard: '110101199001011236', disabilityId: 'CJZ20240003', disabilityType: '肢体残疾', disabilityLevel: '三级', idAddress: '广州市天河区', phone: '13800138002', province: '广东省', city: '广州市', district: '天河区', isInBlackList: 0, createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-01T00:00:00Z' } ], total: 1 }))) } }; const mockClientManager = { get: vi.fn(() => mockDisabilityClient), init: vi.fn(() => mockDisabilityClient), reset: vi.fn(), getInstance: vi.fn(() => mockClientManager) }; return { disabilityClientManager: mockClientManager, disabilityClient: mockDisabilityClient }; }); // Mock AreaSelect组件 vi.mock('@d8d/area-management-ui', () => ({ AreaSelect: ({ value, onChange, placeholder }: any) => (
) })); // Mock shared-ui-components vi.mock('@d8d/shared-ui-components/components/ui/dialog', () => ({ Dialog: ({ children, open, onOpenChange }: any) => open ? (
{children}
) : null, DialogContent: ({ children, className }: any) => (
{children}
), DialogHeader: ({ children }: any) => (
{children}
), DialogTitle: ({ children }: any) => (

{children}

), DialogFooter: ({ children, className }: any) => (
{children}
) })); vi.mock('@d8d/shared-ui-components/components/ui/button', () => ({ Button: ({ children, onClick, disabled, variant, ...props }: any) => ( ) })); vi.mock('@d8d/shared-ui-components/components/ui/input', () => ({ Input: ({ value, onChange, placeholder, ...props }: any) => ( ) })); vi.mock('@d8d/shared-ui-components/components/ui/select', () => ({ Select: ({ children }: any) => (
{children}
), SelectTrigger: ({ children }: any) => (
{children}
), SelectValue: ({ placeholder }: any) => ( {placeholder} ), SelectContent: ({ children }: any) => (
{children}
), SelectItem: ({ children, value }: any) => ( ) })); vi.mock('@d8d/shared-ui-components/components/ui/label', () => ({ Label: ({ children, htmlFor }: any) => ( ) })); vi.mock('@d8d/shared-ui-components/components/ui/table', () => ({ Table: ({ children, ...props }: any) => ( {children}
), TableHeader: ({ children }: any) => {children}, TableBody: ({ children }: any) => {children}, TableRow: ({ children, onClick, className, ...props }: any) => ( {children} ), TableHead: ({ children, className }: any) => {children}, TableCell: ({ children }: any) => {children}, })); vi.mock('@d8d/shared-ui-components/components/admin/DataTablePagination', () => ({ DataTablePagination: ({ currentPage, pageSize, totalCount, onPageChange, ...props }: any) => (
第{currentPage}页,共{Math.ceil(totalCount / pageSize)}页
) })); vi.mock('@d8d/shared-ui-components/components/ui/checkbox', () => ({ Checkbox: ({ checked, onCheckedChange, disabled, ...props }: any) => ( onCheckedChange && onCheckedChange(e.target.checked)} disabled={disabled} data-testid={props['data-testid'] || 'checkbox'} {...props} /> ) })); vi.mock('@d8d/shared-ui-components/components/ui/alert', () => ({ Alert: ({ children, variant }: any) => (
{children}
), AlertDescription: ({ children }: any) => (
{children}
) })); vi.mock('lucide-react', () => ({ AlertCircle: () =>
⚠️
})); describe('DisabledPersonSelector', () => { let queryClient: QueryClient; let onOpenChange: ReturnType; let onSelect: ReturnType; beforeEach(() => { queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); onOpenChange = vi.fn(); onSelect = vi.fn(); vi.clearAllMocks(); }); const renderComponent = (props = {}) => { return render( ); }; it('应该渲染对话框和搜索区域', () => { renderComponent(); expect(screen.getByTestId('dialog')).toBeInTheDocument(); expect(screen.getByTestId('dialog-title')).toHaveTextContent('选择残疾人'); // 检查搜索字段 expect(screen.getByTestId('search-name-input')).toBeInTheDocument(); expect(screen.getByTestId('area-select')).toBeInTheDocument(); expect(screen.getByTestId('search-button')).toBeInTheDocument(); expect(screen.getByTestId('reset-button')).toBeInTheDocument(); }); it('应该显示残疾人列表', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByTestId('data-table')).toBeInTheDocument(); }); // 检查表格数据 expect(screen.getByText('张三')).toBeInTheDocument(); expect(screen.getByText('男')).toBeInTheDocument(); expect(screen.getByText('110101199001011234')).toBeInTheDocument(); }); it('应该处理搜索功能', async () => { renderComponent(); // 输入搜索关键词 const searchInput = screen.getByTestId('search-name-input'); fireEvent.change(searchInput, { target: { value: '张三' } }); // 点击搜索按钮 const searchButton = screen.getByTestId('search-button'); fireEvent.click(searchButton); // 验证搜索API被调用 await waitFor(() => { expect(disabilityClientManager.get().searchDisabledPersons.$get).toHaveBeenCalledWith({ query: { keyword: '张三', skip: 0, take: 10 } }); }); }); it('应该处理重置搜索', () => { renderComponent(); // 输入搜索关键词 const searchInput = screen.getByTestId('search-name-input'); fireEvent.change(searchInput, { target: { value: '张三' } }); // 点击重置按钮 const resetButton = screen.getByTestId('reset-button'); fireEvent.click(resetButton); // 验证搜索输入被清空 expect(searchInput).toHaveValue(''); }); it('应该处理单选模式', async () => { renderComponent({ mode: 'single' }); await waitFor(() => { expect(screen.getByTestId('data-table')).toBeInTheDocument(); }); // 点击表格行选择人员 const firstRow = screen.getByTestId('table-row-0'); fireEvent.click(firstRow); // 验证选择回调被调用 expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ id: 1, name: '张三' })); expect(onOpenChange).toHaveBeenCalledWith(false); }); it('应该处理多选模式', async () => { renderComponent({ mode: 'multiple' }); await waitFor(() => { expect(screen.getByTestId('data-table')).toBeInTheDocument(); }); // 应该显示多选相关的UI expect(screen.getAllByTestId('checkbox')).toHaveLength(3); // 全选复选框 + 每行复选框 // 点击确认批量选择按钮(初始时禁用) const confirmButton = screen.getByTestId('confirm-batch-button'); expect(confirmButton).toBeDisabled(); }); it('应该处理黑名单人员确认', async () => { renderComponent({ mode: 'single' }); await waitFor(() => { expect(screen.getByTestId('data-table')).toBeInTheDocument(); }); // 点击黑名单人员(李四) const blacklistRow = screen.getByTestId('table-row-1'); fireEvent.click(blacklistRow); // 应该显示黑名单确认对话框 await waitFor(() => { expect(screen.getByTestId('alert')).toBeInTheDocument(); expect(screen.getByTestId('alert-description')).toHaveTextContent('您选择的人员在黑名单中,是否确认选择?'); }); // 点击确认选择 const confirmButton = screen.getByTestId('confirm-blacklist-button'); fireEvent.click(confirmButton); // 验证选择回调被调用 expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ id: 2, name: '李四', isInBlackList: 1 })); expect(onOpenChange).toHaveBeenCalledWith(false); }); it('应该处理禁用的人员', async () => { renderComponent({ mode: 'single', disabledIds: [1] // 禁用张三 }); await waitFor(() => { expect(screen.getByTestId('data-table')).toBeInTheDocument(); }); // 点击禁用的人员应该没有反应 const disabledRow = screen.getByTestId('table-row-0'); fireEvent.click(disabledRow); expect(onSelect).not.toHaveBeenCalled(); }); it('应该处理分页', async () => { renderComponent(); await waitFor(() => { expect(screen.getByTestId('pagination')).toBeInTheDocument(); }); // 点击下一页 const nextPageButton = screen.getByTestId('next-page'); fireEvent.click(nextPageButton); // 验证API被调用(第2页) await waitFor(() => { expect(disabilityClientManager.get().getAllDisabledPersons.$get).toHaveBeenCalledWith({ query: { skip: 10, take: 10 } }); }); }); it('应该处理对话框关闭', () => { renderComponent(); // 点击取消按钮 const cancelButton = screen.getByTestId('cancel-button'); fireEvent.click(cancelButton); expect(onOpenChange).toHaveBeenCalledWith(false); }); });