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 { UserManagement } from '../../src/components/UserManagement'; import { userClient } from '../../src/api/userClient'; // 完整的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/userClient', () => { const mockUserClient = { index: { $get: vi.fn(() => Promise.resolve({ status: 200, body: null })), $post: vi.fn(() => Promise.resolve({ status: 201, body: null })), }, ':id': { $put: vi.fn(() => Promise.resolve({ status: 200, body: null })), $delete: vi.fn(() => Promise.resolve({ status: 204, body: null })), }, }; return { userClient: mockUserClient, }; }); // Mock toast vi.mock('sonner', () => ({ toast: { success: vi.fn(() => {}), error: vi.fn(() => {}), }, })); const createTestQueryClient = () => new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); const renderWithProviders = (component: React.ReactElement) => { const queryClient = createTestQueryClient(); return render( {component as any} ); }; describe('用户管理集成测试', () => { beforeEach(() => { vi.clearAllMocks(); }); it('应该完成完整的用户CRUD流程', async () => { const mockUsers = { data: [ { id: 1, username: 'existinguser', nickname: 'Existing User', email: 'existing@example.com', phone: '1234567890', name: 'Existing Name', isDisabled: 0, createdAt: '2024-01-01T00:00:00Z', roles: [{ id: 1, name: 'admin' }], avatarFile: null, }, ], pagination: { total: 1, page: 1, pageSize: 10, }, }; const { toast } = await import('sonner'); // Mock initial user list (userClient.index.$get as any).mockResolvedValue(createMockResponse(200, mockUsers)); renderWithProviders(); // Wait for initial data to load await waitFor(() => { expect(screen.getByText('existinguser')).toBeInTheDocument(); }); // Test create user const createButton = screen.getByTestId('create-user-button'); fireEvent.click(createButton); // Fill create form const usernameInput = screen.getByPlaceholderText('请输入用户名'); const passwordInput = screen.getByPlaceholderText('请输入密码'); const emailInput = screen.getByPlaceholderText('请输入邮箱'); fireEvent.change(usernameInput, { target: { value: 'newuser' } }); fireEvent.change(passwordInput, { target: { value: 'password123' } }); fireEvent.change(emailInput, { target: { value: 'new@example.com' } }); // Mock successful creation (userClient.index.$post as any).mockResolvedValue(createMockResponse(201, { id: 2, username: 'newuser' })); const submitButton = screen.getByTestId('create-user-submit-button'); fireEvent.click(submitButton); await waitFor(() => { expect(userClient.index.$post).toHaveBeenCalledWith({ json: { username: 'newuser', password: 'password123', email: 'new@example.com', nickname: null, phone: null, name: null, isDisabled: 0, }, }); expect(toast.success).toHaveBeenCalledWith('用户创建成功'); }); // Test edit user const editButtons = screen.getAllByRole('button', { name: '编辑用户' }); fireEvent.click(editButtons[0]); // Verify edit form is populated await waitFor(() => { expect(screen.getByDisplayValue('existinguser')).toBeInTheDocument(); }); // Update user const updateUsernameInput = screen.getByDisplayValue('existinguser'); fireEvent.change(updateUsernameInput, { target: { value: 'updateduser' } }); // Mock successful update (userClient[':id']['$put'] as any).mockResolvedValue(createMockResponse(200)); const updateButton = screen.getByText('更新用户'); fireEvent.click(updateButton); await waitFor(() => { expect(userClient[':id']['$put']).toHaveBeenCalledWith({ param: { id: 1 }, json: { username: 'updateduser', nickname: 'Existing User', email: 'existing@example.com', phone: '1234567890', name: 'Existing Name', password: undefined, avatarFileId: undefined, isDisabled: 0, }, }); expect(toast.success).toHaveBeenCalledWith('用户更新成功'); }); // Test delete user const deleteButtons = screen.getAllByRole('button', { name: '删除用户' }); fireEvent.click(deleteButtons[0]); // Confirm deletion expect(screen.getByText('确认删除')).toBeInTheDocument(); // Mock successful deletion (userClient[':id']['$delete'] as any).mockResolvedValue({ status: 204, }); const confirmDeleteButton = screen.getByText('删除'); fireEvent.click(confirmDeleteButton); await waitFor(() => { expect(userClient[':id']['$delete']).toHaveBeenCalledWith({ param: { id: 1 }, }); expect(toast.success).toHaveBeenCalledWith('用户删除成功'); }); }); it('应该优雅处理API错误', async () => { const { userClient } = await import('../../src/api/userClient'); const { toast } = await import('sonner'); // Mock API error (userClient.index.$get as any).mockRejectedValue(new Error('API Error')); renderWithProviders(); // Should handle error without crashing await waitFor(() => { expect(screen.getByText('用户管理')).toBeInTheDocument(); }); // Test create user error const createButton = screen.getByText('创建用户'); fireEvent.click(createButton); const usernameInput = screen.getByPlaceholderText('请输入用户名'); const passwordInput = screen.getByPlaceholderText('请输入密码'); fireEvent.change(usernameInput, { target: { value: 'testuser' } }); fireEvent.change(passwordInput, { target: { value: 'password' } }); // Mock creation error (userClient.index.$post as any).mockRejectedValue(new Error('Creation failed')); const submitButton = screen.getByTestId('create-user-submit-button'); fireEvent.click(submitButton); await waitFor(() => { expect(toast.error).toHaveBeenCalledWith('创建失败,请重试'); }); }); it('应该处理搜索和过滤器集成', async () => { const { userClient } = await import('../../src/api/userClient'); const mockUsers = { data: [], pagination: { total: 0, page: 1, pageSize: 10 }, }; (userClient.index.$get as any).mockResolvedValue(createMockResponse(200, mockUsers)); renderWithProviders(); // Test search const searchInput = screen.getByPlaceholderText('搜索用户名、昵称或邮箱...'); fireEvent.change(searchInput, { target: { value: 'searchterm' } }); await waitFor(() => { expect(userClient.index.$get).toHaveBeenCalledWith({ query: { page: 1, pageSize: 10, keyword: 'searchterm', filters: undefined, }, }); }); // Test filter const filterButton = screen.getByTestId('advanced-filter-button'); fireEvent.click(filterButton); // Wait for filter panel to appear await waitFor(() => { expect(screen.getByTestId('status-filter-trigger')).toBeInTheDocument(); }, { timeout: 2000 }); // Apply status filter const statusSelect = screen.getByTestId('status-filter-trigger'); fireEvent.click(statusSelect); const enabledOption = screen.getByTestId('status-enabled-option'); fireEvent.click(enabledOption); await waitFor(() => { expect(userClient.index.$get).toHaveBeenCalledWith({ query: { page: 1, pageSize: 10, keyword: 'searchterm', filters: expect.stringContaining('isDisabled'), }, }); }); }); });