AttendanceModal.test.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import React from 'react';
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react';
  3. import userEvent from '@testing-library/user-event';
  4. import { vi } from 'vitest';
  5. import AttendanceModal from '../../src/components/AttendanceModal';
  6. // Mock xlsx
  7. vi.mock('xlsx', () => ({
  8. __esModule: true,
  9. default: {
  10. utils: {
  11. book_new: vi.fn(() => ({})),
  12. aoa_to_sheet: vi.fn(() => ({})),
  13. book_append_sheet: vi.fn(),
  14. },
  15. writeFile: vi.fn(),
  16. },
  17. utils: {
  18. book_new: vi.fn(() => ({})),
  19. aoa_to_sheet: vi.fn(() => ({})),
  20. book_append_sheet: vi.fn(),
  21. },
  22. writeFile: vi.fn(),
  23. }));
  24. // Mock sonner toast
  25. vi.mock('sonner', () => ({
  26. toast: {
  27. success: vi.fn(),
  28. error: vi.fn(),
  29. warning: vi.fn(),
  30. },
  31. }));
  32. describe('AttendanceModal', () => {
  33. const mockOrderPersons = [
  34. {
  35. personId: 1,
  36. personName: '张三',
  37. disabilityId: 'D001',
  38. disabilityType: '肢体残疾',
  39. },
  40. {
  41. personId: 2,
  42. personName: '李四',
  43. disabilityId: 'D002',
  44. disabilityType: '视力残疾',
  45. },
  46. ];
  47. const defaultProps = {
  48. open: true,
  49. onOpenChange: vi.fn(),
  50. orderId: 123,
  51. orderName: '测试订单',
  52. orderPersons: mockOrderPersons,
  53. };
  54. beforeEach(() => {
  55. vi.clearAllMocks();
  56. });
  57. it('应该正确渲染AttendanceModal组件', () => {
  58. render(<AttendanceModal {...defaultProps} />);
  59. expect(screen.getByTestId('attendance-modal')).toBeInTheDocument();
  60. expect(screen.getByTestId('attendance-modal-title')).toHaveTextContent('出勤表导出');
  61. expect(screen.getByText(/为订单"测试订单"生成月度出勤Excel表/)).toBeInTheDocument();
  62. expect(screen.getByTestId('attendance-month-select')).toBeInTheDocument();
  63. expect(screen.getByTestId('attendance-days-select')).toBeInTheDocument();
  64. expect(screen.getByTestId('attendance-generate-button')).toBeInTheDocument();
  65. expect(screen.getByTestId('attendance-cancel-button')).toBeInTheDocument();
  66. });
  67. it('应该显示订单信息', () => {
  68. render(<AttendanceModal {...defaultProps} />);
  69. expect(screen.getByText('订单名称:')).toBeInTheDocument();
  70. expect(screen.getByText('测试订单')).toBeInTheDocument();
  71. expect(screen.getByText('订单ID:')).toBeInTheDocument();
  72. expect(screen.getByText('123')).toBeInTheDocument();
  73. expect(screen.getByText('人员数量:')).toBeInTheDocument();
  74. expect(screen.getByText('2人')).toBeInTheDocument();
  75. });
  76. it('应该显示月份选择器', () => {
  77. render(<AttendanceModal {...defaultProps} />);
  78. const monthSelect = screen.getByTestId('attendance-month-select');
  79. expect(monthSelect).toBeInTheDocument();
  80. expect(screen.getByText('选择月份')).toBeInTheDocument();
  81. });
  82. it('应该显示出勤天数选择器', () => {
  83. render(<AttendanceModal {...defaultProps} />);
  84. const daysSelect = screen.getByTestId('attendance-days-select');
  85. expect(daysSelect).toBeInTheDocument();
  86. expect(screen.getByText('出勤天数')).toBeInTheDocument();
  87. });
  88. it('应该显示出勤表预览信息', () => {
  89. render(<AttendanceModal {...defaultProps} />);
  90. expect(screen.getByText('表格结构:')).toBeInTheDocument();
  91. expect(screen.getByText(/列: 姓名、残疾证号、残疾类型、1-20日、出勤天数、缺勤天数、备注/)).toBeInTheDocument();
  92. expect(screen.getByText(/行: 2名人员/)).toBeInTheDocument();
  93. expect(screen.getByText(/出勤标记: √ \(出勤\), 空白 \(缺勤\)/)).toBeInTheDocument();
  94. expect(screen.getByText(/文件格式: Excel \(\.xlsx\)/)).toBeInTheDocument();
  95. });
  96. it('应该在没有人员时禁用生成按钮', () => {
  97. const propsWithoutPersons = {
  98. ...defaultProps,
  99. orderPersons: [],
  100. };
  101. render(<AttendanceModal {...propsWithoutPersons} />);
  102. const generateButton = screen.getByTestId('attendance-generate-button');
  103. expect(generateButton).toBeDisabled();
  104. });
  105. it('应该在有人员时启用生成按钮', () => {
  106. render(<AttendanceModal {...defaultProps} />);
  107. const generateButton = screen.getByTestId('attendance-generate-button');
  108. expect(generateButton).toBeEnabled();
  109. });
  110. it('应该点击取消按钮关闭模态框', async () => {
  111. const user = userEvent.setup();
  112. const onOpenChange = vi.fn();
  113. render(<AttendanceModal {...defaultProps} onOpenChange={onOpenChange} />);
  114. const cancelButton = screen.getByTestId('attendance-cancel-button');
  115. await user.click(cancelButton);
  116. expect(onOpenChange).toHaveBeenCalledWith(false);
  117. });
  118. it('应该在没有人员时显示警告并阻止生成', async () => {
  119. const user = userEvent.setup();
  120. const propsWithoutPersons = {
  121. ...defaultProps,
  122. orderPersons: [],
  123. };
  124. const { toast } = await import('sonner');
  125. render(<AttendanceModal {...propsWithoutPersons} />);
  126. const form = screen.getByRole('form');
  127. fireEvent.submit(form);
  128. await waitFor(() => {
  129. expect(toast.warning).toHaveBeenCalledWith('订单中没有人员,无法生成出勤表');
  130. });
  131. });
  132. it('应该显示生成按钮', () => {
  133. render(<AttendanceModal {...defaultProps} />);
  134. const generateButton = screen.getByTestId('attendance-generate-button');
  135. expect(generateButton).toBeInTheDocument();
  136. expect(generateButton).toHaveTextContent('生成出勤表');
  137. });
  138. it('应该显示取消按钮', () => {
  139. render(<AttendanceModal {...defaultProps} />);
  140. const cancelButton = screen.getByTestId('attendance-cancel-button');
  141. expect(cancelButton).toBeInTheDocument();
  142. expect(cancelButton).toHaveTextContent('取消');
  143. });
  144. });