| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- 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) => (
- <div data-testid="area-select">
- <select
- value={value?.provinceId || ''}
- onChange={(e) => onChange({ provinceId: e.target.value ? Number(e.target.value) : undefined })}
- data-testid="area-select-input"
- >
- <option value="">{placeholder || '选择地区'}</option>
- <option value="1">北京市</option>
- <option value="2">上海市</option>
- </select>
- </div>
- )
- }));
- // Mock shared-ui-components
- vi.mock('@d8d/shared-ui-components/components/ui/dialog', () => ({
- Dialog: ({ children, open, onOpenChange }: any) => open ? (
- <div data-testid="dialog">{children}</div>
- ) : null,
- DialogContent: ({ children, className }: any) => (
- <div data-testid="dialog-content" className={className}>{children}</div>
- ),
- DialogHeader: ({ children }: any) => (
- <div data-testid="dialog-header">{children}</div>
- ),
- DialogTitle: ({ children }: any) => (
- <h2 data-testid="dialog-title">{children}</h2>
- ),
- DialogFooter: ({ children, className }: any) => (
- <div data-testid="dialog-footer" className={className}>{children}</div>
- )
- }));
- vi.mock('@d8d/shared-ui-components/components/ui/button', () => ({
- Button: ({ children, onClick, disabled, variant, ...props }: any) => (
- <button
- onClick={onClick}
- disabled={disabled}
- data-testid={props['data-testid'] || 'button'}
- data-variant={variant}
- {...props}
- >
- {children}
- </button>
- )
- }));
- vi.mock('@d8d/shared-ui-components/components/ui/input', () => ({
- Input: ({ value, onChange, placeholder, ...props }: any) => (
- <input
- type="text"
- value={value}
- onChange={onChange}
- placeholder={placeholder}
- data-testid={props['data-testid'] || 'input'}
- {...props}
- />
- )
- }));
- vi.mock('@d8d/shared-ui-components/components/ui/select', () => ({
- Select: ({ children }: any) => (
- <div data-testid="select">
- {children}
- </div>
- ),
- SelectTrigger: ({ children }: any) => (
- <div data-testid="select-trigger">{children}</div>
- ),
- SelectValue: ({ placeholder }: any) => (
- <span data-testid="select-value">{placeholder}</span>
- ),
- SelectContent: ({ children }: any) => (
- <div data-testid="select-content">{children}</div>
- ),
- SelectItem: ({ children, value }: any) => (
- <option value={value} data-testid={`select-item-${value}`}>{children}</option>
- )
- }));
- vi.mock('@d8d/shared-ui-components/components/ui/label', () => ({
- Label: ({ children, htmlFor }: any) => (
- <label htmlFor={htmlFor} data-testid="label">{children}</label>
- )
- }));
- vi.mock('@d8d/shared-ui-components/components/ui/table', () => ({
- Table: ({ children, ...props }: any) => (
- <table data-testid={props['data-testid'] || 'table'}>{children}</table>
- ),
- TableHeader: ({ children }: any) => <thead data-testid="table-header">{children}</thead>,
- TableBody: ({ children }: any) => <tbody data-testid="table-body">{children}</tbody>,
- TableRow: ({ children, onClick, className, ...props }: any) => (
- <tr onClick={onClick} className={className} data-testid={props['data-testid'] || 'table-row'}>{children}</tr>
- ),
- TableHead: ({ children, className }: any) => <th className={className}>{children}</th>,
- TableCell: ({ children }: any) => <td>{children}</td>,
- }));
- vi.mock('@d8d/shared-ui-components/components/admin/DataTablePagination', () => ({
- DataTablePagination: ({ currentPage, pageSize, totalCount, onPageChange, ...props }: any) => (
- <div data-testid={props['data-testid'] || 'pagination'}>
- <button onClick={() => onPageChange(currentPage - 1, pageSize)} data-testid="prev-page">上一页</button>
- <span>第{currentPage}页,共{Math.ceil(totalCount / pageSize)}页</span>
- <button onClick={() => onPageChange(currentPage + 1, pageSize)} data-testid="next-page">下一页</button>
- </div>
- )
- }));
- vi.mock('@d8d/shared-ui-components/components/ui/checkbox', () => ({
- Checkbox: ({ checked, onCheckedChange, disabled, ...props }: any) => (
- <input
- type="checkbox"
- checked={checked}
- onChange={(e) => 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) => (
- <div data-testid="alert" data-variant={variant}>{children}</div>
- ),
- AlertDescription: ({ children }: any) => (
- <div data-testid="alert-description">{children}</div>
- )
- }));
- vi.mock('lucide-react', () => ({
- AlertCircle: () => <div data-testid="alert-circle">⚠️</div>
- }));
- describe('DisabledPersonSelector', () => {
- let queryClient: QueryClient;
- let onOpenChange: ReturnType<typeof vi.fn>;
- let onSelect: ReturnType<typeof vi.fn>;
- beforeEach(() => {
- queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: false,
- },
- },
- });
- onOpenChange = vi.fn();
- onSelect = vi.fn();
- vi.clearAllMocks();
- });
- const renderComponent = (props = {}) => {
- return render(
- <QueryClientProvider client={queryClient}>
- <DisabledPersonSelector
- open={true}
- onOpenChange={onOpenChange}
- onSelect={onSelect}
- {...props}
- />
- </QueryClientProvider>
- );
- };
- 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);
- });
- });
|