import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import DisabilityPersonManagement from '../../src/components/DisabilityPersonManagement'; import { disabilityClientManager } from '../../src/api/disabilityClient'; // 完整的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 = { getAllDisabledPersons: { $get: vi.fn(() => Promise.resolve(createMockResponse(200, { data: [ { id: 1, name: '张三', gender: '男', idCard: '110101199001011234', disabilityId: 'D123456789', disabilityType: '肢体残疾', disabilityLevel: '一级', idAddress: '北京市东城区', phone: '13800138000', province: '北京市', city: '北京市', district: '东城区', detailedAddress: '某街道某号', nation: '汉族', isMarried: 0, canDirectContact: 1, isInBlackList: 0, jobStatus: 1, createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-01T00:00:00Z' } ], total: 1 }))), }, createDisabledPerson: { $post: vi.fn(() => Promise.resolve(createMockResponse(200, { id: 2, name: '李四', gender: '女', idCard: '110101199002021234', disabilityId: 'D123456790', disabilityType: '视力残疾', disabilityLevel: '二级', idAddress: '上海市黄浦区', phone: '13900139000', province: '上海市', city: '上海市', district: '黄浦区', detailedAddress: '某街道某号', nation: '汉族', isMarried: 1, canDirectContact: 1, isInBlackList: 0, jobStatus: 0, createTime: '2024-01-02T00:00:00Z', updateTime: '2024-01-02T00:00:00Z' }))), }, updateDisabledPerson: { $post: vi.fn(() => Promise.resolve(createMockResponse(200, { id: 1, name: '张三(已更新)', gender: '男', idCard: '110101199001011234', disabilityId: 'D123456789', disabilityType: '肢体残疾', disabilityLevel: '一级', idAddress: '北京市东城区', phone: '13800138001', province: '北京市', city: '北京市', district: '东城区', detailedAddress: '更新后的地址', nation: '汉族', isMarried: 1, canDirectContact: 1, isInBlackList: 0, jobStatus: 1, createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-03T00:00:00Z' }))), }, deleteDisabledPerson: { $post: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))), }, searchDisabledPersons: { $get: vi.fn(() => Promise.resolve(createMockResponse(200, { data: [ { id: 1, name: '张三', gender: '男', idCard: '110101199001011234', disabilityId: 'D123456789', disabilityType: '肢体残疾', disabilityLevel: '一级', idAddress: '北京市东城区', phone: '13800138000', province: '北京市', city: '北京市', district: '东城区', detailedAddress: '某街道某号', nation: '汉族', isMarried: 0, canDirectContact: 1, isInBlackList: 0, jobStatus: 1, createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-01T00:00:00Z' } ], total: 1 }))), }, getDisabledPerson: { ':id': { $get: vi.fn(() => Promise.resolve(createMockResponse(200, { id: 1, name: '张三', gender: '男', idCard: '110101199001011234', disabilityId: 'D123456789', disabilityType: '肢体残疾', disabilityLevel: '一级', idAddress: '北京市东城区', phone: '13800138000', province: '北京市', city: '北京市', district: '东城区', detailedAddress: '某街道某号', nation: '汉族', isMarried: 0, canDirectContact: 1, isInBlackList: 0, jobStatus: 1, createTime: '2024-01-01T00:00:00Z', updateTime: '2024-01-01T00:00:00Z' }))), }, }, }; const mockDisabilityClientManager = { get: vi.fn(() => mockDisabilityClient), }; return { disabilityClientManager: mockDisabilityClientManager, disabilityClient: mockDisabilityClient, }; }); // Mock toast vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), }, })); // Mock 枚举包 vi.mock('@d8d/allin-enums', () => ({ DisabilityType: { VISION: 'vision', HEARING: 'hearing', SPEECH: 'speech', PHYSICAL: 'physical', INTELLECTUAL: 'intellectual', MENTAL: 'mental', MULTIPLE: 'multiple', }, DISABILITY_TYPES: ['vision', 'hearing', 'speech', 'physical', 'intellectual', 'mental', 'multiple'], getDisabilityTypeLabel: vi.fn((type) => { const labels: Record = { vision: '视力残疾', hearing: '听力残疾', speech: '言语残疾', physical: '肢体残疾', intellectual: '智力残疾', mental: '精神残疾', multiple: '多重残疾', }; return labels[type] || type; }), DisabilityLevel: { ONE: 1, TWO: 2, THREE: 3, FOUR: 4, }, DISABILITY_LEVELS: [1, 2, 3, 4], getDisabilityLevelLabel: vi.fn((level) => { const labels: Record = { 1: '一级', 2: '二级', 3: '三级', 4: '四级', }; return labels[level] || level.toString(); }), })); // Mock 区域选择器组件 vi.mock('@d8d/area-management-ui/components', () => ({ AreaSelect: vi.fn(({ value, onChange }) => (
)), })); // Mock 文件选择器组件 vi.mock('@d8d/file-management-ui/components', () => ({ FileSelector: vi.fn(({ onChange, placeholder }) => (
)), })); describe('残疾人个人管理集成测试', () => { let queryClient: QueryClient; beforeEach(() => { queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); vi.clearAllMocks(); }); const renderComponent = () => { return render( ); }; it('应该正确渲染残疾人列表', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 验证表格内容 expect(screen.getByText('张三')).toBeInTheDocument(); expect(screen.getByText('男')).toBeInTheDocument(); expect(screen.getByText('110101199001011234')).toBeInTheDocument(); expect(screen.getByText('D123456789')).toBeInTheDocument(); expect(screen.getByText('肢体残疾')).toBeInTheDocument(); expect(screen.getByText('一级')).toBeInTheDocument(); expect(screen.getByText('13800138000')).toBeInTheDocument(); }); it('应该打开创建模态框并填写表单', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 点击新增按钮 - 使用测试ID const addButton = screen.getByTestId('add-disabled-person-button'); fireEvent.click(addButton); // 验证模态框打开 - 使用测试ID await waitFor(() => { expect(screen.getByTestId('create-disabled-person-dialog-title')).toBeInTheDocument(); }); // 填写表单 const nameInput = screen.getByPlaceholderText('请输入姓名'); const idCardInput = screen.getByPlaceholderText('请输入身份证号'); const disabilityIdInput = screen.getByPlaceholderText('请输入残疾证号'); const phoneInput = screen.getByPlaceholderText('请输入联系电话'); const idAddressInput = screen.getByPlaceholderText('请输入身份证地址'); fireEvent.change(nameInput, { target: { value: '李四' } }); fireEvent.change(idCardInput, { target: { value: '110101199002021234' } }); fireEvent.change(disabilityIdInput, { target: { value: 'D123456790' } }); fireEvent.change(phoneInput, { target: { value: '13900139000' } }); fireEvent.change(idAddressInput, { target: { value: '上海市黄浦区' } }); // 选择性别 const genderSelect = screen.getByTestId('gender-select'); fireEvent.change(genderSelect, { target: { value: '女' } }); // 选择残疾类型 const disabilityTypeSelect = screen.getByTestId('disability-type-select'); fireEvent.change(disabilityTypeSelect, { target: { value: '视力残疾' } }); // 选择残疾等级 const disabilityLevelSelect = screen.getByTestId('disability-level-select'); fireEvent.change(disabilityLevelSelect, { target: { value: '二级' } }); // 选择省份和城市 const provinceSelect = screen.getByTestId('province-select'); const citySelect = screen.getByTestId('city-select'); await act(async () => { fireEvent.change(provinceSelect, { target: { value: '1' } }); }); await act(async () => { fireEvent.change(citySelect, { target: { value: '2' } }); }); // 提交表单 const submitButton = screen.getByText('创建'); // 使用act包装状态更新 await act(async () => { fireEvent.click(submitButton); }); // 验证API调用 - 增加等待时间 await waitFor(() => { const mockClient = (disabilityClientManager.get as any)(); expect(mockClient.createDisabledPerson.$post).toHaveBeenCalled(); }, { timeout: 3000 }); // 验证具体的调用参数 const mockClient = (disabilityClientManager.get as any)(); const call = mockClient.createDisabledPerson.$post.mock.calls[0]; expect(call).toBeDefined(); if (call) { expect(call[0].json).toMatchObject({ name: '李四', idCard: '110101199002021234', disabilityId: 'D123456790', phone: '13900139000', idAddress: '上海市黄浦区', }); } }); it('应该打开编辑模态框并更新数据', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 点击编辑按钮 const editButton = screen.getByTestId('edit-person-1'); fireEvent.click(editButton); // 验证模态框打开 await waitFor(() => { expect(screen.getByText('编辑残疾人信息')).toBeInTheDocument(); }); // 修改电话号码 const phoneInput = screen.getByPlaceholderText('请输入联系电话'); fireEvent.change(phoneInput, { target: { value: '13800138001' } }); // 提交表单 const submitButton = screen.getByText('更新'); fireEvent.click(submitButton); // 验证API调用 await waitFor(() => { const mockClient = (disabilityClientManager.get as any)(); expect(mockClient.updateDisabledPerson.$post).toHaveBeenCalledWith({ json: expect.objectContaining({ id: 1, phone: '13800138001', }), }); }); }); it('应该打开查看详情模态框', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 点击查看按钮 const viewButton = screen.getByTestId('view-person-1'); fireEvent.click(viewButton); // 验证模态框打开并显示详情 await waitFor(() => { expect(screen.getByText('残疾人详情')).toBeInTheDocument(); expect(screen.getByText('张三')).toBeInTheDocument(); expect(screen.getByText('110101199001011234')).toBeInTheDocument(); expect(screen.getByText('D123456789')).toBeInTheDocument(); }); }); it('应该打开删除确认对话框并删除数据', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 点击删除按钮 const deleteButton = screen.getByTestId('delete-person-1'); fireEvent.click(deleteButton); // 验证删除对话框打开 - 使用测试ID await waitFor(() => { expect(screen.getByTestId('delete-confirmation-dialog-title')).toBeInTheDocument(); }); // 确认删除 - 使用更精确的选择器 const confirmButtons = screen.getAllByText('确认删除'); const confirmButton = confirmButtons.find(btn => btn.getAttribute('type') === 'button' || btn.getAttribute('data-slot') === 'button') || confirmButtons[0]; fireEvent.click(confirmButton); // 验证API调用 await waitFor(() => { const mockClient = (disabilityClientManager.get as any)(); expect(mockClient.deleteDisabledPerson.$post).toHaveBeenCalledWith({ json: { id: 1 }, }); }); }); it('应该进行搜索操作', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 输入搜索关键词 const searchInput = screen.getByPlaceholderText('搜索姓名或身份证号'); fireEvent.change(searchInput, { target: { value: '张三' } }); // 点击搜索按钮 const searchButton = screen.getByText('搜索'); fireEvent.click(searchButton); // 验证API调用 await waitFor(() => { const mockClient = (disabilityClientManager.get as any)(); expect(mockClient.getAllDisabledPersons.$get).toHaveBeenCalled(); }); }); it('应该测试区域选择器集成', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 打开创建模态框 - 使用测试ID const addButton = screen.getByTestId('add-disabled-person-button'); fireEvent.click(addButton); // 等待模态框打开 - 使用测试ID await waitFor(() => { expect(screen.getByTestId('create-disabled-person-dialog-title')).toBeInTheDocument(); }); // 验证区域选择器存在 expect(screen.getByTestId('area-select')).toBeInTheDocument(); // 选择省份 const provinceSelect = screen.getByTestId('province-select'); fireEvent.change(provinceSelect, { target: { value: '1' } }); // 选择城市 const citySelect = screen.getByTestId('city-select'); fireEvent.change(citySelect, { target: { value: '2' } }); // 选择区县 const districtSelect = screen.getByTestId('district-select'); fireEvent.change(districtSelect, { target: { value: '3' } }); }); it('应该测试文件选择器集成', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 打开创建模态框 - 使用测试ID const addButton = screen.getByTestId('add-disabled-person-button'); fireEvent.click(addButton); // 等待模态框打开 - 使用测试ID await waitFor(() => { expect(screen.getByTestId('create-disabled-person-dialog-title')).toBeInTheDocument(); }); // 验证照片上传组件存在 expect(screen.getByTestId('add-photo-button')).toBeInTheDocument(); // 点击添加照片按钮 const addPhotoButton = screen.getByTestId('add-photo-button'); fireEvent.click(addPhotoButton); }); it('应该测试枚举选择器集成', async () => { renderComponent(); // 等待数据加载 await waitFor(() => { expect(screen.getByText('张三')).toBeInTheDocument(); }); // 打开创建模态框 - 使用测试ID const addButton = screen.getByTestId('add-disabled-person-button'); fireEvent.click(addButton); // 等待模态框打开 - 使用测试ID await waitFor(() => { expect(screen.getByTestId('create-disabled-person-dialog-title')).toBeInTheDocument(); }); // 验证残疾类型选择器 - 使用更稳健的选择器 const disabilityTypeSelects = screen.getAllByRole('combobox'); // 查找包含"残疾类型"标签的选择器 const disabilityTypeSelect = disabilityTypeSelects.find(select => { const label = select.closest('.grid-cols-2')?.querySelector('label'); return label?.textContent?.includes('残疾类型'); }); if (disabilityTypeSelect) { expect(disabilityTypeSelect).toBeInTheDocument(); } // 验证残疾等级选择器 const disabilityLevelSelect = disabilityTypeSelects.find(select => { const label = select.closest('.grid-cols-2')?.querySelector('label'); return label?.textContent?.includes('残疾等级'); }); if (disabilityLevelSelect) { expect(disabilityLevelSelect).toBeInTheDocument(); } }); it('应该显示暂无数据提示', async () => { // 修改mock返回空数据 const mockClient = (disabilityClientManager.get as any)(); mockClient.getAllDisabledPersons.$get.mockResolvedValueOnce( createMockResponse(200, { data: [], total: 0 }) ); renderComponent(); // 等待暂无数据提示出现 await waitFor(() => { expect(screen.getByText('暂无数据')).toBeInTheDocument(); }); // 验证暂无数据提示的样式 const noDataElement = screen.getByText('暂无数据'); expect(noDataElement).toHaveClass('text-muted-foreground'); }); });