order.integration.test.tsx 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. import { describe, it, expect, vi, beforeEach } from 'vitest';
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react';
  3. import userEvent from '@testing-library/user-event';
  4. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  5. import OrderManagement from '../../src/components/OrderManagement';
  6. import { orderClientManager } from '../../src/api/orderClient';
  7. import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
  8. // Mock 区域选择器组件
  9. vi.mock('@d8d/area-management-ui', () => ({
  10. AreaSelect: vi.fn(({ value, onChange }) => {
  11. return (
  12. <div data-testid="area-select-mock">
  13. <select
  14. data-testid="area-select-province"
  15. value={value?.provinceId || ''}
  16. onChange={(e) => onChange && onChange({ provinceId: e.target.value ? parseInt(e.target.value) : undefined, cityId: undefined, districtId: undefined })}
  17. >
  18. <option value="">选择省份</option>
  19. <option value="1">省份1</option>
  20. <option value="2">省份2</option>
  21. </select>
  22. <select
  23. data-testid="area-select-city"
  24. value={value?.cityId || ''}
  25. onChange={(e) => onChange && onChange({ ...value, cityId: e.target.value ? parseInt(e.target.value) : undefined, districtId: undefined })}
  26. >
  27. <option value="">选择城市</option>
  28. <option value="3">城市1</option>
  29. <option value="4">城市2</option>
  30. </select>
  31. <select
  32. data-testid="area-select-district"
  33. value={value?.districtId || ''}
  34. onChange={(e) => onChange && onChange({ ...value, districtId: e.target.value ? parseInt(e.target.value) : undefined })}
  35. >
  36. <option value="">选择区县</option>
  37. <option value="5">区县1</option>
  38. <option value="6">区县2</option>
  39. </select>
  40. </div>
  41. );
  42. })
  43. }));
  44. // Mock 文件选择器组件
  45. vi.mock('@d8d/file-management-ui', () => ({
  46. FileSelector: vi.fn(({ value, onChange }) => {
  47. return (
  48. <div data-testid="file-selector-mock">
  49. <input
  50. type="file"
  51. data-testid="file-input"
  52. onChange={(e) => {
  53. if (onChange && e.target.files?.[0]) {
  54. onChange('mock-file-id-123');
  55. }
  56. }}
  57. />
  58. {value && <div data-testid="selected-file">已选择文件: {value}</div>}
  59. </div>
  60. );
  61. })
  62. }));
  63. // Mock 残疾人选择器组件
  64. vi.mock('@d8d/allin-disability-person-management-ui', () => ({
  65. DisabledPersonSelector: vi.fn(({ open, onOpenChange, onSelect, mode, disabledIds }) => {
  66. if (!open) return null;
  67. return (
  68. <div data-testid="disabled-person-selector-mock">
  69. <div>残疾人选择器模拟</div>
  70. <button
  71. data-testid="select-person-button"
  72. onClick={() => {
  73. const mockPerson = {
  74. id: 1,
  75. name: '测试残疾人',
  76. gender: '男',
  77. disabilityId: 'D123456',
  78. disabilityType: '肢体残疾',
  79. disabilityLevel: '三级',
  80. phone: '13800138000'
  81. };
  82. onSelect(mode === 'multiple' ? [mockPerson] : mockPerson);
  83. onOpenChange(false);
  84. }}
  85. style={{ pointerEvents: 'auto' }} // 确保按钮可以点击
  86. >
  87. 选择测试人员
  88. </button>
  89. <button
  90. data-testid="close-selector-button"
  91. onClick={() => onOpenChange(false)}
  92. style={{ pointerEvents: 'auto' }} // 确保按钮可以点击
  93. >
  94. 关闭
  95. </button>
  96. </div>
  97. );
  98. })
  99. }));
  100. // 完整的mock响应对象
  101. const createMockResponse = (status: number, data?: any) => ({
  102. status,
  103. ok: status >= 200 && status < 300,
  104. body: null,
  105. bodyUsed: false,
  106. statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
  107. headers: new Headers(),
  108. url: '',
  109. redirected: false,
  110. type: 'basic' as ResponseType,
  111. json: async () => data || {},
  112. text: async () => '',
  113. blob: async () => new Blob(),
  114. arrayBuffer: async () => new ArrayBuffer(0),
  115. formData: async () => new FormData(),
  116. clone: function() { return this; }
  117. });
  118. // Mock API client
  119. vi.mock('../../src/api/orderClient', () => {
  120. const mockOrderClient = {
  121. list: {
  122. $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
  123. data: [
  124. {
  125. id: 1,
  126. orderName: '测试订单1',
  127. platformId: 1,
  128. companyId: 1,
  129. channelId: 1,
  130. expectedStartDate: '2024-01-01T00:00:00Z',
  131. expectedEndDate: '2024-12-31T00:00:00Z',
  132. orderStatus: OrderStatus.DRAFT,
  133. workStatus: WorkStatus.NOT_WORKING,
  134. provinceId: 1,
  135. cityId: 2,
  136. districtId: 3,
  137. address: '测试地址',
  138. contactPerson: '张三',
  139. contactPhone: '13800138001',
  140. remark: '测试备注',
  141. createTime: '2024-01-01T00:00:00Z',
  142. updateTime: '2024-01-01T00:00:00Z'
  143. },
  144. {
  145. id: 2,
  146. orderName: '测试订单2',
  147. platformId: 2,
  148. companyId: 2,
  149. channelId: 2,
  150. expectedStartDate: '2024-02-01T00:00:00Z',
  151. expectedEndDate: '2024-12-31T00:00:00Z',
  152. orderStatus: OrderStatus.CONFIRMED,
  153. workStatus: WorkStatus.PRE_WORKING,
  154. provinceId: 4,
  155. cityId: 5,
  156. districtId: 6,
  157. address: '测试地址2',
  158. contactPerson: '李四',
  159. contactPhone: '13800138002',
  160. remark: '测试备注2',
  161. createTime: '2024-02-01T00:00:00Z',
  162. updateTime: '2024-02-01T00:00:00Z'
  163. }
  164. ],
  165. total: 2
  166. }))),
  167. },
  168. create: {
  169. $post: vi.fn(() => Promise.resolve(createMockResponse(200, {
  170. id: 3,
  171. orderName: '新订单',
  172. platformId: 3,
  173. companyId: 3,
  174. channelId: 3,
  175. expectedStartDate: '2024-03-01T00:00:00Z',
  176. expectedEndDate: '2024-12-31T00:00:00Z',
  177. orderStatus: OrderStatus.DRAFT,
  178. workStatus: WorkStatus.NOT_WORKING,
  179. provinceId: 7,
  180. cityId: 8,
  181. districtId: 9,
  182. address: '新地址',
  183. contactPerson: '王五',
  184. contactPhone: '13800138003',
  185. remark: '新备注',
  186. createTime: '2024-03-01T00:00:00Z',
  187. updateTime: '2024-03-01T00:00:00Z'
  188. }))),
  189. },
  190. update: {
  191. ':id': {
  192. $put: vi.fn(() => Promise.resolve(createMockResponse(200, {
  193. id: 1,
  194. orderName: '更新后的订单',
  195. platformId: 1,
  196. companyId: 1,
  197. channelId: 1,
  198. expectedStartDate: '2024-01-01T00:00:00Z',
  199. expectedEndDate: '2024-12-31T00:00:00Z',
  200. orderStatus: OrderStatus.CONFIRMED,
  201. workStatus: WorkStatus.PRE_WORKING,
  202. provinceId: 1,
  203. cityId: 2,
  204. districtId: 3,
  205. address: '更新后的地址',
  206. contactPerson: '张三',
  207. contactPhone: '13800138001',
  208. remark: '更新后的备注',
  209. createTime: '2024-01-01T00:00:00Z',
  210. updateTime: '2024-03-01T00:00:00Z'
  211. }))),
  212. },
  213. },
  214. delete: {
  215. ':id': {
  216. $delete: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))),
  217. },
  218. },
  219. detail: {
  220. ':id': {
  221. $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
  222. id: 1,
  223. orderName: '测试订单1',
  224. platformId: 1,
  225. companyId: 1,
  226. channelId: 1,
  227. expectedStartDate: '2024-01-01T00:00:00Z',
  228. expectedEndDate: '2024-12-31T00:00:00Z',
  229. orderStatus: OrderStatus.DRAFT,
  230. workStatus: WorkStatus.NOT_WORKING,
  231. provinceId: 1,
  232. cityId: 2,
  233. districtId: 3,
  234. address: '测试地址',
  235. contactPerson: '张三',
  236. contactPhone: '13800138001',
  237. remark: '测试备注',
  238. createTime: '2024-01-01T00:00:00Z',
  239. updateTime: '2024-01-01T00:00:00Z'
  240. }))),
  241. },
  242. },
  243. activate: {
  244. ':orderId': {
  245. $post: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))),
  246. },
  247. },
  248. close: {
  249. ':orderId': {
  250. $post: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))),
  251. },
  252. },
  253. ':orderId': {
  254. persons: {
  255. batch: {
  256. $post: vi.fn(() => Promise.resolve(createMockResponse(200, {
  257. success: true,
  258. message: '批量添加人员成功',
  259. addedCount: 2
  260. }))),
  261. },
  262. },
  263. },
  264. assets: {
  265. create: {
  266. $post: vi.fn(() => Promise.resolve(createMockResponse(200, {
  267. id: 1,
  268. orderId: 1,
  269. personId: 1,
  270. assetType: 'ID_CARD',
  271. assetFileType: 'IMAGE',
  272. fileId: 1,
  273. relatedTime: '2024-01-01T00:00:00Z',
  274. createTime: '2024-01-01T00:00:00Z',
  275. updateTime: '2024-01-01T00:00:00Z'
  276. }))),
  277. },
  278. query: {
  279. $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
  280. data: [],
  281. total: 0
  282. }))),
  283. },
  284. delete: {
  285. ':id': {
  286. $delete: vi.fn(() => Promise.resolve(createMockResponse(200, {
  287. success: true,
  288. message: '删除成功'
  289. }))),
  290. },
  291. },
  292. },
  293. };
  294. const mockOrderClientManager = {
  295. getInstance: vi.fn(() => ({
  296. get: vi.fn(() => mockOrderClient),
  297. reset: vi.fn(),
  298. })),
  299. get: vi.fn(() => mockOrderClient),
  300. reset: vi.fn(),
  301. };
  302. return {
  303. orderClientManager: mockOrderClientManager,
  304. orderClient: mockOrderClient,
  305. };
  306. });
  307. // Mock toast
  308. vi.mock('sonner', () => ({
  309. toast: {
  310. success: vi.fn(),
  311. error: vi.fn(),
  312. },
  313. }));
  314. describe('订单管理集成测试', () => {
  315. let queryClient: QueryClient;
  316. beforeEach(() => {
  317. queryClient = new QueryClient({
  318. defaultOptions: {
  319. queries: {
  320. retry: false,
  321. },
  322. },
  323. });
  324. vi.clearAllMocks();
  325. });
  326. const renderOrderManagement = () => {
  327. return render(
  328. <QueryClientProvider client={queryClient}>
  329. <OrderManagement />
  330. </QueryClientProvider>
  331. );
  332. };
  333. describe('CRUD流程测试', () => {
  334. it('应该成功加载订单列表', async () => {
  335. renderOrderManagement();
  336. // 等待数据加载
  337. await waitFor(() => {
  338. expect(screen.getByText('测试订单1')).toBeInTheDocument();
  339. expect(screen.getByText('测试订单2')).toBeInTheDocument();
  340. });
  341. // 验证表格渲染
  342. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  343. expect(screen.getByTestId('order-row-2')).toBeInTheDocument();
  344. // 验证状态徽章
  345. expect(screen.getByText('草稿')).toBeInTheDocument();
  346. expect(screen.getByText('已确认')).toBeInTheDocument();
  347. expect(screen.getByText('未就业')).toBeInTheDocument();
  348. expect(screen.getByText('待就业')).toBeInTheDocument();
  349. });
  350. it('应该成功创建订单', async () => {
  351. renderOrderManagement();
  352. // 点击创建订单按钮
  353. const createButton = screen.getByTestId('create-order-button');
  354. fireEvent.click(createButton);
  355. // 验证订单表单模态框打开
  356. await waitFor(() => {
  357. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  358. });
  359. // 这里可以添加表单填写和提交的测试
  360. // 由于表单组件比较复杂,这里只验证模态框能正常打开
  361. });
  362. it('应该成功编辑订单', async () => {
  363. renderOrderManagement();
  364. // 等待数据加载
  365. await waitFor(() => {
  366. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  367. });
  368. // 调试:打印所有test ID
  369. const allElements = screen.getAllByTestId(/.*/);
  370. console.debug('所有test ID:', allElements.map(el => el.getAttribute('data-testid')));
  371. // 先点击下拉菜单触发器,然后点击编辑按钮
  372. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  373. expect(menuTrigger).toBeInTheDocument();
  374. // 使用userEvent.click代替fireEvent.click,更好地模拟用户交互
  375. await userEvent.click(menuTrigger);
  376. // 等待下拉菜单打开,然后点击编辑按钮
  377. await waitFor(() => {
  378. // 检查下拉菜单内容是否渲染 - 使用更精确的选择器
  379. // 下拉菜单中的"操作"是DropdownMenuLabel,而表格中的"操作"是表头
  380. // 我们可以检查下拉菜单中的特定元素
  381. const editButton = screen.getByTestId('edit-order-button-1');
  382. expect(editButton).toBeInTheDocument();
  383. });
  384. const editButton = screen.getByTestId('edit-order-button-1');
  385. await userEvent.click(editButton);
  386. // 验证编辑表单模态框打开
  387. await waitFor(() => {
  388. expect(screen.getByText('编辑订单')).toBeInTheDocument();
  389. });
  390. });
  391. it('应该成功删除订单', async () => {
  392. renderOrderManagement();
  393. // 等待数据加载
  394. await waitFor(() => {
  395. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  396. });
  397. // 先点击下拉菜单触发器,然后点击删除按钮
  398. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  399. expect(menuTrigger).toBeInTheDocument();
  400. await userEvent.click(menuTrigger);
  401. // 等待下拉菜单打开,然后点击删除按钮
  402. await waitFor(() => {
  403. const deleteButton = screen.getByTestId('delete-order-button-1');
  404. expect(deleteButton).toBeInTheDocument();
  405. });
  406. const deleteButton = screen.getByTestId('delete-order-button-1');
  407. await userEvent.click(deleteButton);
  408. // 验证删除确认对话框显示
  409. await waitFor(() => {
  410. expect(screen.getByTestId('delete-confirm-dialog')).toBeInTheDocument();
  411. expect(screen.getByTestId('delete-confirm-dialog-title')).toHaveTextContent('删除订单');
  412. expect(screen.getByTestId('delete-confirm-dialog-description')).toHaveTextContent('确定要删除这个订单吗?此操作不可撤销。');
  413. });
  414. // 点击确认按钮
  415. const confirmButton = screen.getByTestId('delete-confirm-dialog-confirm');
  416. await userEvent.click(confirmButton);
  417. // 验证API调用
  418. await waitFor(() => {
  419. expect(orderClientManager.get().delete[':id'].$delete).toHaveBeenCalledWith({
  420. param: { id: 1 },
  421. });
  422. });
  423. });
  424. it('应该成功激活订单', async () => {
  425. renderOrderManagement();
  426. // 等待数据加载
  427. await waitFor(() => {
  428. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  429. });
  430. // 先打开下拉菜单,然后点击激活按钮(只有草稿状态的订单才有激活按钮)
  431. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  432. expect(menuTrigger).toBeInTheDocument();
  433. await userEvent.click(menuTrigger);
  434. // 等待下拉菜单打开,然后点击激活按钮
  435. await waitFor(() => {
  436. const activateButton = screen.getByTestId('activate-order-button-1');
  437. expect(activateButton).toBeInTheDocument();
  438. });
  439. const activateButton = screen.getByTestId('activate-order-button-1');
  440. await userEvent.click(activateButton);
  441. // 验证激活确认对话框显示
  442. await waitFor(() => {
  443. expect(screen.getByTestId('activate-confirm-dialog')).toBeInTheDocument();
  444. expect(screen.getByTestId('activate-confirm-dialog-title')).toHaveTextContent('激活订单');
  445. expect(screen.getByTestId('activate-confirm-dialog-description')).toHaveTextContent('确定要激活这个订单吗?订单激活后将进入进行中状态。');
  446. });
  447. // 点击确认按钮
  448. const confirmButton = screen.getByTestId('activate-confirm-dialog-confirm');
  449. await userEvent.click(confirmButton);
  450. // 验证API调用
  451. await waitFor(() => {
  452. expect(orderClientManager.get().activate[':orderId'].$post).toHaveBeenCalledWith({
  453. param: { orderId: 1 },
  454. });
  455. });
  456. });
  457. it('应该成功关闭订单', async () => {
  458. renderOrderManagement();
  459. // 等待数据加载
  460. await waitFor(() => {
  461. expect(screen.getByTestId('order-row-2')).toBeInTheDocument();
  462. });
  463. // 先打开下拉菜单,然后点击关闭按钮(只有已确认或进行中的订单有关闭按钮)
  464. const menuTrigger = screen.getByTestId('order-menu-trigger-2');
  465. expect(menuTrigger).toBeInTheDocument();
  466. await userEvent.click(menuTrigger);
  467. // 等待下拉菜单打开,然后点击关闭按钮
  468. await waitFor(() => {
  469. const closeButton = screen.getByTestId('close-order-button-2');
  470. expect(closeButton).toBeInTheDocument();
  471. });
  472. const closeButton = screen.getByTestId('close-order-button-2');
  473. await userEvent.click(closeButton);
  474. // 验证关闭确认对话框显示
  475. await waitFor(() => {
  476. expect(screen.getByTestId('close-confirm-dialog')).toBeInTheDocument();
  477. expect(screen.getByTestId('close-confirm-dialog-title')).toHaveTextContent('关闭订单');
  478. expect(screen.getByTestId('close-confirm-dialog-description')).toHaveTextContent('确定要关闭这个订单吗?订单关闭后将无法再添加人员或资产。');
  479. });
  480. // 点击确认按钮
  481. const confirmButton = screen.getByTestId('close-confirm-dialog-confirm');
  482. await userEvent.click(confirmButton);
  483. // 验证API调用
  484. await waitFor(() => {
  485. expect(orderClientManager.get().close[':orderId'].$post).toHaveBeenCalledWith({
  486. param: { orderId: 2 },
  487. });
  488. });
  489. });
  490. it('应该可以取消删除操作', async () => {
  491. renderOrderManagement();
  492. // 等待数据加载
  493. await waitFor(() => {
  494. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  495. });
  496. // 先点击下拉菜单触发器,然后点击删除按钮
  497. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  498. expect(menuTrigger).toBeInTheDocument();
  499. await userEvent.click(menuTrigger);
  500. // 等待下拉菜单打开,然后点击删除按钮
  501. await waitFor(() => {
  502. const deleteButton = screen.getByTestId('delete-order-button-1');
  503. expect(deleteButton).toBeInTheDocument();
  504. });
  505. const deleteButton = screen.getByTestId('delete-order-button-1');
  506. await userEvent.click(deleteButton);
  507. // 验证删除确认对话框显示
  508. await waitFor(() => {
  509. expect(screen.getByTestId('delete-confirm-dialog')).toBeInTheDocument();
  510. });
  511. // 点击取消按钮
  512. const cancelButton = screen.getByTestId('delete-confirm-dialog-cancel');
  513. await userEvent.click(cancelButton);
  514. // 验证对话框关闭
  515. await waitFor(() => {
  516. expect(screen.queryByTestId('delete-confirm-dialog')).not.toBeInTheDocument();
  517. });
  518. // 验证API没有被调用
  519. expect(orderClientManager.get().delete[':id'].$delete).not.toHaveBeenCalled();
  520. });
  521. });
  522. describe('文件上传集成测试', () => {
  523. it('应该成功打开资产关联模态框', async () => {
  524. renderOrderManagement();
  525. // 等待数据加载
  526. await waitFor(() => {
  527. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  528. });
  529. // 先打开下拉菜单,然后点击添加资产按钮
  530. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  531. expect(menuTrigger).toBeInTheDocument();
  532. await userEvent.click(menuTrigger);
  533. // 等待下拉菜单打开,然后点击添加资产按钮
  534. await waitFor(() => {
  535. const addAssetButton = screen.getByTestId('add-asset-button-1');
  536. expect(addAssetButton).toBeInTheDocument();
  537. });
  538. const addAssetButton = screen.getByTestId('add-asset-button-1');
  539. await userEvent.click(addAssetButton);
  540. // 验证资产关联模态框打开
  541. await waitFor(() => {
  542. expect(screen.getByTestId('order-person-asset-dialog-title')).toBeInTheDocument();
  543. });
  544. // 验证文件选择器组件存在 - 可能需要在表单中才会显示
  545. // 先验证模态框基本结构
  546. expect(screen.getByTestId('order-person-asset-dialog-title')).toBeInTheDocument();
  547. // 文件选择器可能在选择了残疾人才显示,这里先跳过具体验证
  548. });
  549. });
  550. describe('区域选择器集成测试', () => {
  551. it('应该成功打开订单表单并显示区域选择器', async () => {
  552. renderOrderManagement();
  553. // 点击创建订单按钮
  554. const createButton = screen.getByTestId('create-order-button');
  555. fireEvent.click(createButton);
  556. // 验证订单表单模态框打开
  557. await waitFor(() => {
  558. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  559. });
  560. // 验证区域选择器组件存在
  561. expect(screen.getByTestId('area-select-mock')).toBeInTheDocument();
  562. });
  563. });
  564. describe('枚举常量集成测试', () => {
  565. it('应该正确显示订单状态枚举', async () => {
  566. renderOrderManagement();
  567. // 等待数据加载 - 验证表格中的订单状态Badge
  568. await waitFor(() => {
  569. // 使用更精确的选择器,避免与Select选项冲突
  570. const orderRow = screen.getByTestId('order-row-1');
  571. expect(orderRow).toBeInTheDocument();
  572. // 验证表格中有订单状态显示
  573. expect(screen.getByText('测试订单1')).toBeInTheDocument();
  574. });
  575. // 验证订单状态筛选器
  576. const statusFilter = screen.getByTestId('filter-order-status-select');
  577. expect(statusFilter).toBeInTheDocument();
  578. // 点击筛选器查看选项
  579. fireEvent.click(statusFilter);
  580. // 验证枚举选项存在
  581. await waitFor(() => {
  582. // 使用test ID验证枚举选项
  583. expect(screen.getByTestId('order-status-option-all')).toBeInTheDocument();
  584. expect(screen.getByTestId('order-status-option-draft')).toBeInTheDocument();
  585. expect(screen.getByTestId('order-status-option-confirmed')).toBeInTheDocument();
  586. expect(screen.getByTestId('order-status-option-in-progress')).toBeInTheDocument();
  587. expect(screen.getByTestId('order-status-option-completed')).toBeInTheDocument();
  588. expect(screen.getByTestId('order-status-option-cancelled')).toBeInTheDocument();
  589. });
  590. });
  591. it('应该正确显示工作状态枚举', async () => {
  592. renderOrderManagement();
  593. // 等待数据加载 - 验证表格中的工作状态Badge
  594. await waitFor(() => {
  595. // 使用更精确的选择器,避免与Select选项冲突
  596. const orderRow = screen.getByTestId('order-row-1');
  597. expect(orderRow).toBeInTheDocument();
  598. // 验证表格中有工作状态显示
  599. expect(screen.getByText('测试订单1')).toBeInTheDocument();
  600. });
  601. // 验证工作状态筛选器
  602. const workStatusFilter = screen.getByTestId('filter-work-status-select');
  603. expect(workStatusFilter).toBeInTheDocument();
  604. // 点击筛选器查看选项
  605. fireEvent.click(workStatusFilter);
  606. // 验证枚举选项存在
  607. await waitFor(() => {
  608. // 使用test ID验证枚举选项
  609. expect(screen.getByTestId('work-status-option-all')).toBeInTheDocument();
  610. expect(screen.getByTestId('work-status-option-not-working')).toBeInTheDocument();
  611. expect(screen.getByTestId('work-status-option-pre-working')).toBeInTheDocument();
  612. expect(screen.getByTestId('work-status-option-working')).toBeInTheDocument();
  613. expect(screen.getByTestId('work-status-option-resigned')).toBeInTheDocument();
  614. });
  615. });
  616. });
  617. describe('人员管理测试', () => {
  618. it('应该成功打开人员选择器', async () => {
  619. renderOrderManagement();
  620. // 等待数据加载
  621. await waitFor(() => {
  622. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  623. });
  624. // 先打开下拉菜单,然后点击添加人员按钮
  625. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  626. expect(menuTrigger).toBeInTheDocument();
  627. await userEvent.click(menuTrigger);
  628. // 等待下拉菜单打开,然后点击添加人员按钮
  629. await waitFor(() => {
  630. const addPersonsButton = screen.getByTestId('add-persons-button-1');
  631. expect(addPersonsButton).toBeInTheDocument();
  632. });
  633. const addPersonsButton = screen.getByTestId('add-persons-button-1');
  634. await userEvent.click(addPersonsButton);
  635. // 验证人员选择器模态框打开
  636. await waitFor(() => {
  637. expect(screen.getByTestId('batch-add-persons-dialog-title')).toBeInTheDocument();
  638. });
  639. });
  640. });
  641. describe('搜索和筛选测试', () => {
  642. it('应该支持按订单名称搜索', async () => {
  643. renderOrderManagement();
  644. // 等待数据加载
  645. await waitFor(() => {
  646. expect(screen.getByTestId('search-order-name-input')).toBeInTheDocument();
  647. });
  648. // 输入搜索关键词
  649. const searchInput = screen.getByTestId('search-order-name-input');
  650. fireEvent.change(searchInput, { target: { value: '测试订单1' } });
  651. // 点击搜索按钮
  652. const searchButton = screen.getByTestId('search-button');
  653. fireEvent.click(searchButton);
  654. // 验证API调用
  655. // 实际测试中应该验证API调用参数
  656. });
  657. it('应该支持按订单状态筛选', async () => {
  658. renderOrderManagement();
  659. // 等待数据加载
  660. await waitFor(() => {
  661. expect(screen.getByTestId('filter-order-status-select')).toBeInTheDocument();
  662. });
  663. // 选择订单状态
  664. const statusFilter = screen.getByTestId('filter-order-status-select');
  665. fireEvent.click(statusFilter);
  666. // 选择"草稿"状态
  667. await waitFor(() => {
  668. const draftOption = screen.getByText('草稿');
  669. fireEvent.click(draftOption);
  670. });
  671. // 点击搜索按钮
  672. const searchButton = screen.getByTestId('search-button');
  673. fireEvent.click(searchButton);
  674. // 验证API调用
  675. // 实际测试中应该验证API调用参数
  676. });
  677. it('应该支持按工作状态筛选', async () => {
  678. renderOrderManagement();
  679. // 等待数据加载
  680. await waitFor(() => {
  681. expect(screen.getByTestId('filter-work-status-select')).toBeInTheDocument();
  682. });
  683. // 选择工作状态
  684. const workStatusFilter = screen.getByTestId('filter-work-status-select');
  685. fireEvent.click(workStatusFilter);
  686. // 选择"未就业"状态
  687. await waitFor(() => {
  688. const notWorkingOption = screen.getByText('未就业');
  689. fireEvent.click(notWorkingOption);
  690. });
  691. // 点击搜索按钮
  692. const searchButton = screen.getByTestId('search-button');
  693. fireEvent.click(searchButton);
  694. // 验证API调用
  695. // 实际测试中应该验证API调用参数
  696. });
  697. });
  698. describe('创建订单人员绑定测试', () => {
  699. it('应该成功创建订单并绑定人员', async () => {
  700. renderOrderManagement();
  701. // 点击创建订单按钮
  702. const createButton = screen.getByTestId('create-order-button');
  703. fireEvent.click(createButton);
  704. // 验证订单表单模态框打开
  705. await waitFor(() => {
  706. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  707. });
  708. // 验证人员选择区域显示
  709. // 使用更精确的选择器,避免与CardTitle中的文本冲突
  710. await waitFor(() => {
  711. expect(screen.getByTestId('select-persons-button')).toBeInTheDocument();
  712. });
  713. // 验证描述文本
  714. expect(screen.getByText('创建订单时必须至少选择一名残疾人')).toBeInTheDocument();
  715. // 点击选择残疾人按钮
  716. const selectPersonsButton = screen.getByTestId('select-persons-button');
  717. await userEvent.click(selectPersonsButton);
  718. // 验证残疾人选择器打开
  719. await waitFor(() => {
  720. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  721. });
  722. // 选择测试人员
  723. const selectPersonButton = screen.getByTestId('select-person-button');
  724. await userEvent.click(selectPersonButton);
  725. // 验证人员被添加到列表
  726. await waitFor(() => {
  727. expect(screen.getByText('测试残疾人')).toBeInTheDocument();
  728. expect(screen.getByText('肢体残疾')).toBeInTheDocument();
  729. expect(screen.getByText('三级')).toBeInTheDocument();
  730. });
  731. // 填写订单基本信息
  732. const orderNameInput = screen.getByPlaceholderText('请输入订单名称');
  733. fireEvent.change(orderNameInput, { target: { value: '测试订单带人员' } });
  734. // 选择平台
  735. const platformSelect = screen.getAllByRole('combobox')[0];
  736. fireEvent.click(platformSelect);
  737. const platformOption = screen.getByText('平台1');
  738. fireEvent.click(platformOption);
  739. // 选择公司
  740. const companySelect = screen.getAllByRole('combobox')[1];
  741. fireEvent.click(companySelect);
  742. const companyOption = screen.getByText('公司1');
  743. fireEvent.click(companyOption);
  744. // 选择渠道
  745. const channelSelect = screen.getAllByRole('combobox')[2];
  746. fireEvent.click(channelSelect);
  747. const channelOption = screen.getByText('渠道1');
  748. fireEvent.click(channelOption);
  749. // 填写人员详情
  750. const salaryInput = screen.getByTestId('salary-detail-input-1');
  751. fireEvent.change(salaryInput, { target: { value: '5000元/月' } });
  752. // 提交表单
  753. const submitButton = screen.getByRole('button', { name: /创建/ });
  754. fireEvent.click(submitButton);
  755. // 验证API调用
  756. await waitFor(() => {
  757. // 验证创建订单API被调用
  758. const mockOrderClient = orderClientManager.get();
  759. expect(mockOrderClient.create.$post).toHaveBeenCalledWith({
  760. json: expect.objectContaining({
  761. orderName: '测试订单带人员',
  762. platformId: 1,
  763. companyId: 1,
  764. channelId: 1,
  765. })
  766. });
  767. // 验证批量添加人员API被调用
  768. expect(mockOrderClient[':orderId'].persons.batch.$post).toHaveBeenCalledWith({
  769. param: { orderId: expect.any(Number) },
  770. json: {
  771. persons: expect.arrayContaining([
  772. expect.objectContaining({
  773. personId: 1,
  774. salaryDetail: '5000元/月'
  775. })
  776. ])
  777. }
  778. });
  779. });
  780. });
  781. it('应该验证至少选择一名人员', async () => {
  782. renderOrderManagement();
  783. // 点击创建订单按钮
  784. const createButton = screen.getByTestId('create-order-button');
  785. fireEvent.click(createButton);
  786. // 验证订单表单模态框打开
  787. await waitFor(() => {
  788. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  789. });
  790. // 填写订单基本信息但不选择人员
  791. const orderNameInput = screen.getByPlaceholderText('请输入订单名称');
  792. fireEvent.change(orderNameInput, { target: { value: '测试订单无人员' } });
  793. // 尝试提交表单
  794. const submitButton = screen.getByRole('button', { name: /创建/ });
  795. fireEvent.click(submitButton);
  796. // 验证表单验证错误
  797. await waitFor(() => {
  798. expect(screen.getByText('至少选择一名人员')).toBeInTheDocument();
  799. });
  800. // 验证创建订单API没有被调用
  801. const mockOrderClient = orderClientManager.get();
  802. expect(mockOrderClient.create.$post).not.toHaveBeenCalled();
  803. });
  804. });
  805. describe('错误处理测试', () => {
  806. it('应该处理API错误', async () => {
  807. // Mock API错误
  808. const mockOrderClient = orderClientManager.get();
  809. mockOrderClient.list.$get.mockImplementationOnce(() =>
  810. Promise.resolve(createMockResponse(500, {
  811. code: 500,
  812. message: '服务器错误'
  813. }))
  814. );
  815. renderOrderManagement();
  816. // 验证错误处理
  817. await waitFor(() => {
  818. expect(screen.getByText(/加载失败/)).toBeInTheDocument();
  819. });
  820. });
  821. });
  822. });