import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { vi } from 'vitest';
import AttendanceModal from '../../src/components/AttendanceModal';
// Mock xlsx
vi.mock('xlsx', () => ({
__esModule: true,
default: {
utils: {
book_new: vi.fn(() => ({})),
aoa_to_sheet: vi.fn(() => ({})),
book_append_sheet: vi.fn(),
},
writeFile: vi.fn(),
},
utils: {
book_new: vi.fn(() => ({})),
aoa_to_sheet: vi.fn(() => ({})),
book_append_sheet: vi.fn(),
},
writeFile: vi.fn(),
}));
// Mock sonner toast
vi.mock('sonner', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
warning: vi.fn(),
},
}));
describe('AttendanceModal', () => {
const mockOrderPersons = [
{
personId: 1,
personName: '张三',
disabilityId: 'D001',
disabilityType: '肢体残疾',
},
{
personId: 2,
personName: '李四',
disabilityId: 'D002',
disabilityType: '视力残疾',
},
];
const defaultProps = {
open: true,
onOpenChange: vi.fn(),
orderId: 123,
orderName: '测试订单',
orderPersons: mockOrderPersons,
};
beforeEach(() => {
vi.clearAllMocks();
});
it('应该正确渲染AttendanceModal组件', () => {
render();
expect(screen.getByTestId('attendance-modal')).toBeInTheDocument();
expect(screen.getByTestId('attendance-modal-title')).toHaveTextContent('出勤表导出');
expect(screen.getByText(/为订单"测试订单"生成月度出勤Excel表/)).toBeInTheDocument();
expect(screen.getByTestId('attendance-month-select')).toBeInTheDocument();
expect(screen.getByTestId('attendance-days-select')).toBeInTheDocument();
expect(screen.getByTestId('attendance-generate-button')).toBeInTheDocument();
expect(screen.getByTestId('attendance-cancel-button')).toBeInTheDocument();
});
it('应该显示订单信息', () => {
render();
expect(screen.getByText('订单名称:')).toBeInTheDocument();
expect(screen.getByText('测试订单')).toBeInTheDocument();
expect(screen.getByText('订单ID:')).toBeInTheDocument();
expect(screen.getByText('123')).toBeInTheDocument();
expect(screen.getByText('人员数量:')).toBeInTheDocument();
expect(screen.getByText('2人')).toBeInTheDocument();
});
it('应该显示月份选择器', () => {
render();
const monthSelect = screen.getByTestId('attendance-month-select');
expect(monthSelect).toBeInTheDocument();
expect(screen.getByText('选择月份')).toBeInTheDocument();
});
it('应该显示出勤天数选择器', () => {
render();
const daysSelect = screen.getByTestId('attendance-days-select');
expect(daysSelect).toBeInTheDocument();
expect(screen.getByText('出勤天数')).toBeInTheDocument();
});
it('应该显示出勤表预览信息', () => {
render();
expect(screen.getByText('表格结构:')).toBeInTheDocument();
expect(screen.getByText(/列: 姓名、残疾证号、残疾类型、1-20日、出勤天数、缺勤天数、备注/)).toBeInTheDocument();
expect(screen.getByText(/行: 2名人员/)).toBeInTheDocument();
expect(screen.getByText(/出勤标记: √ \(出勤\), 空白 \(缺勤\)/)).toBeInTheDocument();
expect(screen.getByText(/文件格式: Excel \(\.xlsx\)/)).toBeInTheDocument();
});
it('应该在没有人员时禁用生成按钮', () => {
const propsWithoutPersons = {
...defaultProps,
orderPersons: [],
};
render();
const generateButton = screen.getByTestId('attendance-generate-button');
expect(generateButton).toBeDisabled();
});
it('应该在有人员时启用生成按钮', () => {
render();
const generateButton = screen.getByTestId('attendance-generate-button');
expect(generateButton).toBeEnabled();
});
it('应该点击取消按钮关闭模态框', async () => {
const user = userEvent.setup();
const onOpenChange = vi.fn();
render();
const cancelButton = screen.getByTestId('attendance-cancel-button');
await user.click(cancelButton);
expect(onOpenChange).toHaveBeenCalledWith(false);
});
it('应该在没有人员时显示警告并阻止生成', async () => {
const user = userEvent.setup();
const propsWithoutPersons = {
...defaultProps,
orderPersons: [],
};
const { toast } = await import('sonner');
render();
const form = screen.getByRole('form');
fireEvent.submit(form);
await waitFor(() => {
expect(toast.warning).toHaveBeenCalledWith('订单中没有人员,无法生成出勤表');
});
});
it('应该显示生成按钮', () => {
render();
const generateButton = screen.getByTestId('attendance-generate-button');
expect(generateButton).toBeInTheDocument();
expect(generateButton).toHaveTextContent('生成出勤表');
});
it('应该显示取消按钮', () => {
render();
const cancelButton = screen.getByTestId('attendance-cancel-button');
expect(cancelButton).toBeInTheDocument();
expect(cancelButton).toHaveTextContent('取消');
});
});