PhotoUploadField.test.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. import { describe, it, expect, vi, beforeEach } from 'vitest';
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react';
  3. import { PhotoUploadField } from '../../src/components/PhotoUploadField';
  4. import { toast } from 'sonner';
  5. // Mock toast
  6. vi.mock('sonner', () => ({
  7. toast: {
  8. warning: vi.fn(),
  9. success: vi.fn(),
  10. error: vi.fn(),
  11. },
  12. }));
  13. // Mock FileSelector
  14. vi.mock('@d8d/file-management-ui/components', () => ({
  15. FileSelector: ({ value, onChange, accept, filterType, placeholder, showPreview, previewSize }: any) => (
  16. <div data-testid="file-selector">
  17. <button
  18. data-testid="file-selector-button"
  19. onClick={() => onChange?.(123)}
  20. >
  21. {placeholder || '选择文件'}
  22. </button>
  23. <div data-testid="file-selector-accept">{accept}</div>
  24. <div data-testid="file-selector-filter-type">{filterType}</div>
  25. <div data-testid="file-selector-preview">{showPreview ? 'show' : 'hide'}</div>
  26. <div data-testid="file-selector-preview-size">{previewSize}</div>
  27. </div>
  28. ),
  29. }));
  30. describe('PhotoUploadField', () => {
  31. beforeEach(() => {
  32. vi.clearAllMocks();
  33. });
  34. const defaultProps = {
  35. value: [],
  36. onChange: vi.fn(),
  37. photoTypes: ['身份证照片', '残疾证照片', '个人照片', '其他照片'],
  38. };
  39. it('应该正确渲染组件', () => {
  40. render(<PhotoUploadField {...defaultProps} />);
  41. expect(screen.getByText('照片上传')).toBeInTheDocument();
  42. expect(screen.getByTestId('add-photo-button')).toBeInTheDocument();
  43. expect(screen.getByText('暂无照片')).toBeInTheDocument();
  44. expect(screen.getByText('点击"添加照片"按钮上传照片')).toBeInTheDocument();
  45. });
  46. it('应该添加照片', () => {
  47. render(<PhotoUploadField {...defaultProps} />);
  48. const addButton = screen.getByTestId('add-photo-button');
  49. fireEvent.click(addButton);
  50. expect(defaultProps.onChange).toHaveBeenCalledWith([
  51. expect.objectContaining({
  52. photoType: '身份证照片',
  53. fileId: null,
  54. canDownload: 0,
  55. })
  56. ]);
  57. });
  58. it('应该添加多张照片(无限制)', () => {
  59. render(<PhotoUploadField {...defaultProps} />);
  60. const addButton = screen.getByTestId('add-photo-button');
  61. // 添加5张照片(原来限制是5张)
  62. for (let i = 0; i < 5; i++) {
  63. fireEvent.click(addButton);
  64. }
  65. // 应该可以添加超过5张照片
  66. fireEvent.click(addButton);
  67. expect(defaultProps.onChange).toHaveBeenCalledTimes(6);
  68. });
  69. it('应该支持自定义最大照片数量', () => {
  70. render(<PhotoUploadField {...defaultProps} maxPhotos={3} />);
  71. const addButton = screen.getByTestId('add-photo-button');
  72. // 添加3张照片
  73. for (let i = 0; i < 3; i++) {
  74. fireEvent.click(addButton);
  75. }
  76. // 尝试添加第4张照片应该显示警告
  77. fireEvent.click(addButton);
  78. expect(toast.warning).toHaveBeenCalledWith('最多只能上传 3 张照片');
  79. });
  80. it('应该移除照片', () => {
  81. const initialValue = [
  82. {
  83. photoType: '身份证照片',
  84. fileId: 123,
  85. canDownload: 1,
  86. tempId: 'temp-1',
  87. },
  88. {
  89. photoType: '残疾证照片',
  90. fileId: 456,
  91. canDownload: 0,
  92. tempId: 'temp-2',
  93. },
  94. ];
  95. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  96. // 找到并点击删除按钮
  97. const deleteButtons = screen.getAllByRole('button', { name: '' });
  98. const firstDeleteButton = deleteButtons.find(button =>
  99. button.innerHTML.includes('Trash2')
  100. );
  101. if (firstDeleteButton) {
  102. fireEvent.click(firstDeleteButton);
  103. }
  104. expect(defaultProps.onChange).toHaveBeenCalledWith([
  105. expect.objectContaining({
  106. photoType: '残疾证照片',
  107. fileId: 456,
  108. canDownload: 0,
  109. })
  110. ]);
  111. });
  112. it('应该更新照片类型', () => {
  113. const initialValue = [
  114. {
  115. photoType: '身份证照片',
  116. fileId: 123,
  117. canDownload: 1,
  118. tempId: 'temp-1',
  119. },
  120. ];
  121. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  122. // 找到选择器并更改值
  123. const selectTrigger = screen.getByText('身份证照片');
  124. fireEvent.click(selectTrigger);
  125. // 选择新类型
  126. const newTypeOption = screen.getByText('残疾证照片');
  127. fireEvent.click(newTypeOption);
  128. expect(defaultProps.onChange).toHaveBeenCalledWith([
  129. expect.objectContaining({
  130. photoType: '残疾证照片',
  131. fileId: 123,
  132. canDownload: 1,
  133. })
  134. ]);
  135. });
  136. it('应该更新文件ID', () => {
  137. const initialValue = [
  138. {
  139. photoType: '身份证照片',
  140. fileId: null,
  141. canDownload: 1,
  142. tempId: 'temp-1',
  143. },
  144. ];
  145. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  146. // 点击文件选择器按钮
  147. const fileSelectorButton = screen.getByTestId('file-selector-button');
  148. fireEvent.click(fileSelectorButton);
  149. expect(defaultProps.onChange).toHaveBeenCalledWith([
  150. expect.objectContaining({
  151. photoType: '身份证照片',
  152. fileId: 123,
  153. canDownload: 1,
  154. })
  155. ]);
  156. });
  157. it('应该更新下载权限', () => {
  158. const initialValue = [
  159. {
  160. photoType: '身份证照片',
  161. fileId: 123,
  162. canDownload: 0,
  163. tempId: 'temp-1',
  164. },
  165. ];
  166. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  167. // 找到开关并切换
  168. const switchElement = screen.getByRole('switch');
  169. fireEvent.click(switchElement);
  170. expect(defaultProps.onChange).toHaveBeenCalledWith([
  171. expect.objectContaining({
  172. photoType: '身份证照片',
  173. fileId: 123,
  174. canDownload: 1,
  175. })
  176. ]);
  177. });
  178. it('应该显示正确的文件格式和大小限制提示', () => {
  179. render(<PhotoUploadField {...defaultProps} />);
  180. expect(screen.getByText('支持的照片格式:JPG、JPEG、PNG、GIF、BMP、WebP等常见图片格式')).toBeInTheDocument();
  181. expect(screen.getByText('文件大小限制:无限制(建议不超过500MB)')).toBeInTheDocument();
  182. });
  183. it('应该使用正确的文件选择器配置', () => {
  184. render(<PhotoUploadField {...defaultProps} />);
  185. // 添加一张照片以显示文件选择器
  186. const addButton = screen.getByTestId('add-photo-button');
  187. fireEvent.click(addButton);
  188. expect(screen.getByTestId('file-selector-accept')).toHaveTextContent('image/*,.jpg,.jpeg,.png,.gif,.bmp,.webp');
  189. expect(screen.getByTestId('file-selector-filter-type')).toHaveTextContent('all');
  190. expect(screen.getByTestId('file-selector-preview')).toHaveTextContent('show');
  191. expect(screen.getByTestId('file-selector-preview-size')).toHaveTextContent('medium');
  192. });
  193. it('应该显示照片类型标签(无星号)', () => {
  194. const initialValue = [
  195. {
  196. photoType: '身份证照片',
  197. fileId: 123,
  198. canDownload: 1,
  199. tempId: 'temp-1',
  200. },
  201. ];
  202. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  203. // 检查照片类型标签没有星号
  204. const photoTypeLabel = screen.getByText('照片类型');
  205. expect(photoTypeLabel).toBeInTheDocument();
  206. expect(photoTypeLabel.innerHTML).not.toContain('*');
  207. });
  208. it('应该显示照片文件标签(无星号)', () => {
  209. const initialValue = [
  210. {
  211. photoType: '身份证照片',
  212. fileId: 123,
  213. canDownload: 1,
  214. tempId: 'temp-1',
  215. },
  216. ];
  217. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  218. // 检查照片文件标签没有星号
  219. const photoFileLabel = screen.getByText('照片文件');
  220. expect(photoFileLabel).toBeInTheDocument();
  221. expect(photoFileLabel.innerHTML).not.toContain('*');
  222. });
  223. it('应该显示添加更多照片按钮(无数量限制时)', () => {
  224. const initialValue = [
  225. {
  226. photoType: '身份证照片',
  227. fileId: 123,
  228. canDownload: 1,
  229. tempId: 'temp-1',
  230. },
  231. ];
  232. render(<PhotoUploadField {...defaultProps} value={initialValue} />);
  233. expect(screen.getByText('添加更多照片')).toBeInTheDocument();
  234. });
  235. it('应该显示添加更多照片按钮(有数量限制时)', () => {
  236. const initialValue = [
  237. {
  238. photoType: '身份证照片',
  239. fileId: 123,
  240. canDownload: 1,
  241. tempId: 'temp-1',
  242. },
  243. ];
  244. render(<PhotoUploadField {...defaultProps} value={initialValue} maxPhotos={5} />);
  245. expect(screen.getByText('添加更多照片(1/5)')).toBeInTheDocument();
  246. });
  247. });