import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import '@testing-library/jest-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { LocationSelect } from '@/client/admin/components/LocationSelect'; // Mock API 客户端 import { locationClient } from '@/client/api'; // 创建测试包装器 const TestWrapper = ({ children }: { children: React.ReactNode }) => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); return ( {children} ); }; // Mock API 客户端 vi.mock('@/client/api', () => ({ locationClient: { $get: vi.fn().mockResolvedValue({ status: 200, ok: true, json: async () => ({ data: [ { id: 1, name: '北京天安门', address: '北京市东城区天安门广场', province: { id: 1, name: '北京市', code: '110000' }, city: { id: 2, name: '北京市', code: '110100' }, district: { id: 3, name: '东城区', code: '110101' }, latitude: 39.9042, longitude: 116.4074, isDisabled: 0, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-01T00:00:00.000Z' }, { id: 2, name: '上海外滩', address: '上海市黄浦区外滩', province: { id: 4, name: '上海市', code: '310000' }, city: { id: 5, name: '上海市', code: '310100' }, district: { id: 6, name: '黄浦区', code: '310101' }, latitude: 31.2304, longitude: 121.4737, isDisabled: 0, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-01T00:00:00.000Z' } ], pagination: { current: 1, pageSize: 100, total: 2 } }) }) } })); describe('LocationSelect', () => { const user = userEvent.setup(); const mockOnValueChange = vi.fn(); beforeEach(() => { vi.clearAllMocks(); }); it('应该正确渲染默认状态', () => { render( ); expect(screen.getByRole('combobox')).toHaveTextContent('选择地点...'); }); it('应该显示选中的地点', async () => { render( ); // 等待地点数据加载 await waitFor(() => { expect(screen.getByText('北京天安门')).toBeInTheDocument(); }); }); it('应该打开下拉菜单并显示地点列表', async () => { render( ); // 点击打开下拉菜单 await user.click(screen.getByRole('combobox')); // 等待地点数据加载 await waitFor(() => { expect(screen.getByText('北京天安门')).toBeInTheDocument(); expect(screen.getByText('上海外滩')).toBeInTheDocument(); }); // 验证地点信息显示 expect(screen.getByText('北京市 / 北京市 / 东城区')).toBeInTheDocument(); expect(screen.getByText('上海市 / 上海市 / 黄浦区')).toBeInTheDocument(); }); it('应该支持搜索地点', async () => { render( ); // 点击打开下拉菜单 await user.click(screen.getByRole('combobox')); // 等待地点数据加载 await waitFor(() => { expect(screen.getByText('北京天安门')).toBeInTheDocument(); }); // 在搜索框中输入 const searchInput = screen.getByPlaceholderText('搜索地点名称、地址或区域...'); await user.type(searchInput, '上海'); // 验证搜索请求被调用 await waitFor(() => { expect(locationClient.$get).toHaveBeenCalledWith({ query: { pageSize: 100, keyword: '上海', filters: JSON.stringify({ isDisabled: 0 }) } }); }); }); it('应该能够选择地点', async () => { render( ); // 点击打开下拉菜单 await user.click(screen.getByRole('combobox')); // 等待地点数据加载 await waitFor(() => { expect(screen.getByText('北京天安门')).toBeInTheDocument(); }); // 选择第一个地点 await user.click(screen.getByText('北京天安门')); // 验证回调被调用 expect(mockOnValueChange).toHaveBeenCalledWith(1); }); it('应该能够清除选择', async () => { render( ); // 等待选中地点显示 await waitFor(() => { expect(screen.getByText('北京天安门')).toBeInTheDocument(); }); // 点击打开下拉菜单 await user.click(screen.getByRole('combobox')); // 在搜索框中输入以显示清除选项 const searchInput = screen.getByPlaceholderText('搜索地点名称、地址或区域...'); await user.type(searchInput, 'test'); // 点击清除选择 await waitFor(() => { const clearOption = screen.getByText('清除选择'); expect(clearOption).toBeInTheDocument(); }); await user.click(screen.getByText('清除选择')); // 验证回调被调用 expect(mockOnValueChange).toHaveBeenCalledWith(undefined); }); it('应该显示加载状态', async () => { // 模拟加载延迟 vi.mocked(locationClient.$get).mockImplementationOnce(() => new Promise(resolve => setTimeout(() => resolve({ status: 200, ok: true, json: async () => ({ data: [], pagination: { current: 1, pageSize: 100, total: 0 } }) } as any), 100)) ); render( ); // 点击打开下拉菜单 await user.click(screen.getByRole('combobox')); // 验证加载中状态 expect(screen.getByText('加载中...')).toBeInTheDocument(); }); it('应该显示禁用状态', () => { render( ); expect(screen.getByRole('combobox')).toBeDisabled(); }); });