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 { UserSelector } from '../../src/components/UserSelector';
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 = {
$get: vi.fn(() => Promise.resolve({
status: 200,
body: null,
json: async () => ({ data: [], pagination: { total: 0, page: 1, pageSize: 100 } })
})),
};
const mockUserClientManager = {
get: vi.fn(() => mockUserClient),
};
return {
userClientManager: mockUserClientManager,
userClient: mockUserClient,
};
});
const createTestQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
enabled: true,
},
},
});
const renderWithProviders = (component: React.ReactElement) => {
const queryClient = createTestQueryClient();
return render(
{component as any}
);
};
describe('用户选择器集成测试', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('应该加载并显示用户列表', async () => {
const mockUsers = {
data: [
{
id: 1,
username: 'user1',
name: 'User One',
email: 'user1@example.com',
phone: '1234567890',
},
{
id: 2,
username: 'user2',
name: 'User Two',
email: 'user2@example.com',
phone: '0987654321',
},
],
pagination: {
total: 2,
page: 1,
pageSize: 100,
},
};
// Mock user list API
(userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
renderWithProviders();
// Open select dropdown to trigger API call
const selectTrigger = screen.getByTestId('user-selector');
fireEvent.click(selectTrigger);
// Wait for API call and loading to complete
await waitFor(() => {
expect(userClient.$get).toHaveBeenCalledWith({
query: {
page: 1,
pageSize: 100,
},
});
});
// Verify select trigger is rendered
expect(selectTrigger).toBeInTheDocument();
});
it('应该处理用户选择', async () => {
const mockUsers = {
data: [
{
id: 1,
username: 'user1',
name: 'User One',
email: 'user1@example.com',
phone: '1234567890',
},
],
pagination: {
total: 1,
page: 1,
pageSize: 100,
},
};
const mockOnChange = vi.fn();
// Mock user list API
(userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
renderWithProviders(
);
// Wait for API call
await waitFor(() => {
expect(userClient.$get).toHaveBeenCalledWith({
query: {
page: 1,
pageSize: 100,
},
});
});
// Verify select trigger is rendered
const selectTrigger = screen.getByTestId('user-selector');
expect(selectTrigger).toBeInTheDocument();
// Verify onChange callback is properly passed
expect(mockOnChange).not.toHaveBeenCalled();
});
it('应该显示自定义占位符', async () => {
const mockUsers = {
data: [],
pagination: {
total: 0,
page: 1,
pageSize: 100,
},
};
// Mock empty user list
(userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
renderWithProviders(
);
// Open select dropdown to trigger API call
const selectTrigger = screen.getByTestId('user-selector');
fireEvent.click(selectTrigger);
// Wait for API call
await waitFor(() => {
expect(userClient.$get).toHaveBeenCalled();
});
// Verify custom placeholder is shown
expect(selectTrigger).toHaveTextContent('请选择用户');
});
it('应该处理禁用状态', async () => {
const mockUsers = {
data: [
{
id: 1,
username: 'user1',
name: 'User One',
email: 'user1@example.com',
phone: '1234567890',
},
],
pagination: {
total: 1,
page: 1,
pageSize: 100,
},
};
// Mock user list API
(userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
renderWithProviders(
);
// Verify select is disabled immediately (no need to wait for API call)
const selectTrigger = screen.getByTestId('user-selector');
expect(selectTrigger).toBeDisabled();
});
it('应该处理API错误', async () => {
// Mock API error
(userClient.$get as any).mockRejectedValue(new Error('API Error'));
renderWithProviders();
// Should handle error without crashing
await waitFor(() => {
expect(screen.getByTestId('user-selector')).toBeInTheDocument();
});
});
it('应该显示预选值', async () => {
const mockUsers = {
data: [
{
id: 1,
username: 'user1',
name: 'User One',
email: 'user1@example.com',
phone: '1234567890',
},
{
id: 2,
username: 'user2',
name: 'User Two',
email: 'user2@example.com',
phone: '0987654321',
},
],
pagination: {
total: 2,
page: 1,
pageSize: 100,
},
};
// Mock user list API
(userClient.$get as any).mockResolvedValue(createMockResponse(200, mockUsers));
renderWithProviders(
);
// Wait for data to load
await waitFor(() => {
expect(userClient.$get).toHaveBeenCalled();
});
// Verify the select has the correct value
const selectTrigger = screen.getByTestId('user-selector');
expect(selectTrigger).toHaveAttribute('data-state', 'closed');
});
});