order.integration.test.tsx 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  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/allin-salary-management-ui', () => ({
  10. salaryClientManager: {
  11. get: vi.fn(() => ({
  12. byProvinceCity: {
  13. $get: vi.fn(({ query }) => {
  14. // 模拟API响应
  15. const { provinceId } = query;
  16. // 根据省份ID返回不同的薪资
  17. let salary = 5000; // 默认
  18. if (provinceId === 1 || provinceId === 2 || provinceId === 3 || provinceId === 4) {
  19. salary = 8000; // 一线城市
  20. } else if (provinceId === 5 || provinceId === 6 || provinceId === 7) {
  21. salary = 6000; // 二线城市
  22. }
  23. return Promise.resolve({
  24. ok: true,
  25. json: () => Promise.resolve({ salary })
  26. });
  27. })
  28. }
  29. }))
  30. }
  31. }));
  32. // Mock 区域选择器组件
  33. vi.mock('@d8d/area-management-ui', () => ({
  34. AreaSelect: vi.fn(({ value, onChange }) => {
  35. return (
  36. <div data-testid="area-select-mock">
  37. <select
  38. data-testid="area-select-province"
  39. value={value?.provinceId || ''}
  40. onChange={(e) => onChange && onChange({ provinceId: e.target.value ? parseInt(e.target.value) : undefined, cityId: undefined, districtId: undefined })}
  41. >
  42. <option value="">选择省份</option>
  43. <option value="1">省份1</option>
  44. <option value="2">省份2</option>
  45. </select>
  46. <select
  47. data-testid="area-select-city"
  48. value={value?.cityId || ''}
  49. onChange={(e) => onChange && onChange({ ...value, cityId: e.target.value ? parseInt(e.target.value) : undefined, districtId: undefined })}
  50. >
  51. <option value="">选择城市</option>
  52. <option value="3">城市1</option>
  53. <option value="4">城市2</option>
  54. </select>
  55. <select
  56. data-testid="area-select-district"
  57. value={value?.districtId || ''}
  58. onChange={(e) => onChange && onChange({ ...value, districtId: e.target.value ? parseInt(e.target.value) : undefined })}
  59. >
  60. <option value="">选择区县</option>
  61. <option value="5">区县1</option>
  62. <option value="6">区县2</option>
  63. </select>
  64. </div>
  65. );
  66. })
  67. }));
  68. // Mock 文件选择器组件
  69. vi.mock('@d8d/file-management-ui', () => ({
  70. FileSelector: vi.fn(({ value, onChange }) => {
  71. return (
  72. <div data-testid="file-selector-mock">
  73. <input
  74. type="file"
  75. data-testid="file-input"
  76. onChange={(e) => {
  77. if (onChange && e.target.files?.[0]) {
  78. onChange('mock-file-id-123');
  79. }
  80. }}
  81. />
  82. {value && <div data-testid="selected-file">已选择文件: {value}</div>}
  83. </div>
  84. );
  85. })
  86. }));
  87. // Mock 残疾人选择器组件
  88. vi.mock('@d8d/allin-disability-person-management-ui', () => ({
  89. DisabledPersonSelector: vi.fn(({ open, onOpenChange, onSelect, mode }) => {
  90. if (!open) return null;
  91. return (
  92. <div data-testid="disabled-person-selector-mock">
  93. <div>残疾人选择器模拟</div>
  94. <button
  95. data-testid="select-person-button"
  96. onClick={() => {
  97. const mockPerson = {
  98. id: 1,
  99. name: '测试残疾人',
  100. gender: '男',
  101. disabilityId: 'D123456',
  102. disabilityType: '肢体残疾',
  103. disabilityLevel: '三级',
  104. phone: '13800138000',
  105. province: '北京',
  106. city: '北京市',
  107. // 注意:原系统使用字符串存储省市,而不是ID
  108. // 薪资查询函数现在需要省市ID,但这里保持原样
  109. // 实际应该从API获取省市ID
  110. };
  111. console.log('测试:调用onSelect,人员数据:', mockPerson);
  112. onSelect(mode === 'multiple' ? [mockPerson] : mockPerson);
  113. // 选择人员后自动关闭残疾人选择器,模拟真实行为
  114. onOpenChange(false);
  115. }}
  116. style={{ pointerEvents: 'auto' }} // 确保按钮可以点击
  117. >
  118. 选择测试人员
  119. </button>
  120. <button
  121. data-testid="close-selector-button"
  122. onClick={() => onOpenChange(false)}
  123. style={{ pointerEvents: 'auto' }} // 确保按钮可以点击
  124. >
  125. 关闭
  126. </button>
  127. </div>
  128. );
  129. })
  130. }));
  131. // Mock 平台选择器组件
  132. vi.mock('@d8d/allin-platform-management-ui', () => ({
  133. PlatformSelector: vi.fn(({ value, onChange, placeholder, 'data-testid': testId }) => {
  134. return (
  135. <select
  136. data-testid={testId || 'platform-selector-mock'}
  137. value={value || ''}
  138. onChange={(e) => onChange && onChange(e.target.value ? parseInt(e.target.value) : 0)}
  139. >
  140. <option value="">{placeholder || '选择平台'}</option>
  141. <option value="1">平台1</option>
  142. <option value="2">平台2</option>
  143. <option value="3">平台3</option>
  144. </select>
  145. );
  146. })
  147. }));
  148. // Mock 公司选择器组件
  149. vi.mock('@d8d/allin-company-management-ui', () => ({
  150. CompanySelector: vi.fn(({ value, onChange, placeholder, 'data-testid': testId }) => {
  151. return (
  152. <select
  153. data-testid={testId || 'company-selector-mock'}
  154. value={value || ''}
  155. onChange={(e) => onChange && onChange(e.target.value ? parseInt(e.target.value) : 0)}
  156. >
  157. <option value="">{placeholder || '选择公司'}</option>
  158. <option value="1">公司1</option>
  159. <option value="2">公司2</option>
  160. <option value="3">公司3</option>
  161. </select>
  162. );
  163. })
  164. }));
  165. // Mock 渠道选择器组件
  166. vi.mock('@d8d/allin-channel-management-ui', () => ({
  167. ChannelSelector: vi.fn(({ value, onChange, placeholder, 'data-testid': testId }) => {
  168. return (
  169. <select
  170. data-testid={testId || 'channel-selector-mock'}
  171. value={value || ''}
  172. onChange={(e) => onChange && onChange(e.target.value ? parseInt(e.target.value) : 0)}
  173. >
  174. <option value="">{placeholder || '选择渠道'}</option>
  175. <option value="1">渠道1</option>
  176. <option value="2">渠道2</option>
  177. <option value="3">渠道3</option>
  178. </select>
  179. );
  180. })
  181. }));
  182. // 完整的mock响应对象
  183. const createMockResponse = (status: number, data?: any) => ({
  184. status,
  185. ok: status >= 200 && status < 300,
  186. body: null,
  187. bodyUsed: false,
  188. statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
  189. headers: new Headers(),
  190. url: '',
  191. redirected: false,
  192. type: 'basic' as ResponseType,
  193. json: async () => data || {},
  194. text: async () => '',
  195. blob: async () => new Blob(),
  196. arrayBuffer: async () => new ArrayBuffer(0),
  197. formData: async () => new FormData(),
  198. clone: function() { return this; }
  199. });
  200. // Mock API client
  201. vi.mock('../../src/api/orderClient', () => {
  202. const mockOrderClient = {
  203. list: {
  204. $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
  205. data: [
  206. {
  207. id: 1,
  208. orderName: '测试订单1',
  209. platformId: 1,
  210. companyId: 1,
  211. channelId: 1,
  212. expectedStartDate: '2024-01-01T00:00:00Z',
  213. expectedEndDate: '2024-12-31T00:00:00Z',
  214. orderStatus: OrderStatus.DRAFT,
  215. workStatus: WorkStatus.NOT_WORKING,
  216. provinceId: 1,
  217. cityId: 2,
  218. districtId: 3,
  219. address: '测试地址',
  220. contactPerson: '张三',
  221. contactPhone: '13800138001',
  222. remark: '测试备注',
  223. createTime: '2024-01-01T00:00:00Z',
  224. updateTime: '2024-01-01T00:00:00Z'
  225. },
  226. {
  227. id: 2,
  228. orderName: '测试订单2',
  229. platformId: 2,
  230. companyId: 2,
  231. channelId: 2,
  232. expectedStartDate: '2024-02-01T00:00:00Z',
  233. expectedEndDate: '2024-12-31T00:00:00Z',
  234. orderStatus: OrderStatus.CONFIRMED,
  235. workStatus: WorkStatus.PRE_WORKING,
  236. provinceId: 4,
  237. cityId: 5,
  238. districtId: 6,
  239. address: '测试地址2',
  240. contactPerson: '李四',
  241. contactPhone: '13800138002',
  242. remark: '测试备注2',
  243. createTime: '2024-02-01T00:00:00Z',
  244. updateTime: '2024-02-01T00:00:00Z'
  245. }
  246. ],
  247. total: 2
  248. }))),
  249. },
  250. create: {
  251. $post: vi.fn(() => Promise.resolve(createMockResponse(200, {
  252. id: 3,
  253. orderName: '新订单',
  254. platformId: 3,
  255. companyId: 3,
  256. channelId: 3,
  257. expectedStartDate: '2024-03-01T00:00:00Z',
  258. expectedEndDate: '2024-12-31T00:00:00Z',
  259. orderStatus: OrderStatus.DRAFT,
  260. workStatus: WorkStatus.NOT_WORKING,
  261. provinceId: 7,
  262. cityId: 8,
  263. districtId: 9,
  264. address: '新地址',
  265. contactPerson: '王五',
  266. contactPhone: '13800138003',
  267. remark: '新备注',
  268. createTime: '2024-03-01T00:00:00Z',
  269. updateTime: '2024-03-01T00:00:00Z'
  270. }))),
  271. },
  272. update: {
  273. ':id': {
  274. $put: vi.fn(() => Promise.resolve(createMockResponse(200, {
  275. id: 1,
  276. orderName: '更新后的订单',
  277. platformId: 1,
  278. companyId: 1,
  279. channelId: 1,
  280. expectedStartDate: '2024-01-01T00:00:00Z',
  281. expectedEndDate: '2024-12-31T00:00:00Z',
  282. orderStatus: OrderStatus.CONFIRMED,
  283. workStatus: WorkStatus.PRE_WORKING,
  284. provinceId: 1,
  285. cityId: 2,
  286. districtId: 3,
  287. address: '更新后的地址',
  288. contactPerson: '张三',
  289. contactPhone: '13800138001',
  290. remark: '更新后的备注',
  291. createTime: '2024-01-01T00:00:00Z',
  292. updateTime: '2024-03-01T00:00:00Z'
  293. }))),
  294. },
  295. },
  296. delete: {
  297. ':id': {
  298. $delete: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))),
  299. },
  300. },
  301. detail: {
  302. ':id': {
  303. $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
  304. id: 1,
  305. orderName: '测试订单1',
  306. platformId: 1,
  307. companyId: 1,
  308. channelId: 1,
  309. expectedStartDate: '2024-01-01T00:00:00Z',
  310. actualStartDate: null,
  311. actualEndDate: null,
  312. orderStatus: OrderStatus.DRAFT,
  313. workStatus: WorkStatus.NOT_WORKING,
  314. provinceId: 1,
  315. cityId: 2,
  316. districtId: 3,
  317. address: '测试地址',
  318. contactPerson: '张三',
  319. contactPhone: '13800138001',
  320. remark: '测试备注',
  321. createTime: '2024-01-01T00:00:00Z',
  322. updateTime: '2024-01-01T00:00:00Z',
  323. orderPersons: [
  324. {
  325. id: 1,
  326. orderId: 1,
  327. personId: 100, // 改为不同的ID,避免与测试选择的人员冲突
  328. joinDate: '2024-01-01',
  329. workStatus: 1,
  330. salaryDetail: 5000,
  331. person: {
  332. id: 100,
  333. name: '测试人员100',
  334. gender: '男',
  335. disabilityType: '视力残疾',
  336. phone: '13800138000'
  337. }
  338. }
  339. ]
  340. }))),
  341. },
  342. },
  343. activate: {
  344. ':orderId': {
  345. $post: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))),
  346. },
  347. },
  348. close: {
  349. ':orderId': {
  350. $post: vi.fn(() => Promise.resolve(createMockResponse(200, { success: true }))),
  351. },
  352. },
  353. ':orderId': {
  354. persons: {
  355. batch: {
  356. $post: vi.fn(() => Promise.resolve(createMockResponse(200, {
  357. success: true,
  358. message: '批量添加人员成功',
  359. addedCount: 2
  360. }))),
  361. },
  362. },
  363. },
  364. assets: {
  365. create: {
  366. $post: vi.fn(() => Promise.resolve(createMockResponse(200, {
  367. id: 1,
  368. orderId: 1,
  369. personId: 1,
  370. assetType: 'ID_CARD',
  371. assetFileType: 'IMAGE',
  372. fileId: 1,
  373. relatedTime: '2024-01-01T00:00:00Z',
  374. createTime: '2024-01-01T00:00:00Z',
  375. updateTime: '2024-01-01T00:00:00Z'
  376. }))),
  377. },
  378. query: {
  379. $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
  380. data: [],
  381. total: 0
  382. }))),
  383. },
  384. delete: {
  385. ':id': {
  386. $delete: vi.fn(() => Promise.resolve(createMockResponse(200, {
  387. success: true,
  388. message: '删除成功'
  389. }))),
  390. },
  391. },
  392. },
  393. };
  394. const mockOrderClientManager = {
  395. getInstance: vi.fn(() => ({
  396. get: vi.fn(() => mockOrderClient),
  397. reset: vi.fn(),
  398. })),
  399. get: vi.fn(() => mockOrderClient),
  400. reset: vi.fn(),
  401. };
  402. return {
  403. orderClientManager: mockOrderClientManager,
  404. orderClient: mockOrderClient,
  405. };
  406. });
  407. // Mock toast
  408. vi.mock('sonner', () => ({
  409. toast: {
  410. success: vi.fn(),
  411. error: vi.fn(),
  412. },
  413. }));
  414. describe('订单管理集成测试', () => {
  415. let queryClient: QueryClient;
  416. beforeEach(() => {
  417. queryClient = new QueryClient({
  418. defaultOptions: {
  419. queries: {
  420. retry: false,
  421. },
  422. },
  423. });
  424. vi.clearAllMocks();
  425. });
  426. const renderOrderManagement = () => {
  427. return render(
  428. <QueryClientProvider client={queryClient}>
  429. <OrderManagement />
  430. </QueryClientProvider>
  431. );
  432. };
  433. describe('CRUD流程测试', () => {
  434. it('应该成功加载订单列表', async () => {
  435. renderOrderManagement();
  436. // 等待数据加载
  437. await waitFor(() => {
  438. expect(screen.getByText('测试订单1')).toBeInTheDocument();
  439. expect(screen.getByText('测试订单2')).toBeInTheDocument();
  440. });
  441. // 验证表格渲染
  442. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  443. expect(screen.getByTestId('order-row-2')).toBeInTheDocument();
  444. // 验证状态徽章
  445. expect(screen.getByText('草稿')).toBeInTheDocument();
  446. expect(screen.getByText('已确认')).toBeInTheDocument();
  447. expect(screen.getByText('未就业')).toBeInTheDocument();
  448. expect(screen.getByText('待就业')).toBeInTheDocument();
  449. });
  450. it('应该成功创建订单', async () => {
  451. renderOrderManagement();
  452. // 点击创建订单按钮
  453. const createButton = screen.getByTestId('create-order-button');
  454. fireEvent.click(createButton);
  455. // 验证订单表单模态框打开
  456. await waitFor(() => {
  457. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  458. });
  459. // 这里可以添加表单填写和提交的测试
  460. // 由于表单组件比较复杂,这里只验证模态框能正常打开
  461. });
  462. it('应该成功编辑订单', async () => {
  463. renderOrderManagement();
  464. // 等待数据加载
  465. await waitFor(() => {
  466. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  467. });
  468. // 调试:打印所有test ID
  469. const allElements = screen.getAllByTestId(/.*/);
  470. console.debug('所有test ID:', allElements.map(el => el.getAttribute('data-testid')));
  471. // 先点击下拉菜单触发器,然后点击编辑按钮
  472. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  473. expect(menuTrigger).toBeInTheDocument();
  474. // 使用userEvent.click代替fireEvent.click,更好地模拟用户交互
  475. await userEvent.click(menuTrigger);
  476. // 等待下拉菜单打开,然后点击编辑按钮
  477. await waitFor(() => {
  478. // 检查下拉菜单内容是否渲染 - 使用更精确的选择器
  479. // 下拉菜单中的"操作"是DropdownMenuLabel,而表格中的"操作"是表头
  480. // 我们可以检查下拉菜单中的特定元素
  481. const editButton = screen.getByTestId('edit-order-button-1');
  482. expect(editButton).toBeInTheDocument();
  483. });
  484. const editButton = screen.getByTestId('edit-order-button-1');
  485. await userEvent.click(editButton);
  486. // 验证编辑表单模态框打开
  487. await waitFor(() => {
  488. expect(screen.getByText('编辑订单')).toBeInTheDocument();
  489. });
  490. });
  491. it('应该成功删除订单', async () => {
  492. renderOrderManagement();
  493. // 等待数据加载
  494. await waitFor(() => {
  495. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  496. });
  497. // 先点击下拉菜单触发器,然后点击删除按钮
  498. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  499. expect(menuTrigger).toBeInTheDocument();
  500. await userEvent.click(menuTrigger);
  501. // 等待下拉菜单打开,然后点击删除按钮
  502. await waitFor(() => {
  503. const deleteButton = screen.getByTestId('delete-order-button-1');
  504. expect(deleteButton).toBeInTheDocument();
  505. });
  506. const deleteButton = screen.getByTestId('delete-order-button-1');
  507. await userEvent.click(deleteButton);
  508. // 验证删除确认对话框显示
  509. await waitFor(() => {
  510. expect(screen.getByTestId('delete-confirm-dialog')).toBeInTheDocument();
  511. expect(screen.getByTestId('delete-confirm-dialog-title')).toHaveTextContent('删除订单');
  512. expect(screen.getByTestId('delete-confirm-dialog-description')).toHaveTextContent('确定要删除这个订单吗?此操作不可撤销。');
  513. });
  514. // 点击确认按钮
  515. const confirmButton = screen.getByTestId('delete-confirm-dialog-confirm');
  516. await userEvent.click(confirmButton);
  517. // 验证API调用
  518. await waitFor(() => {
  519. expect(orderClientManager.get().delete[':id'].$delete).toHaveBeenCalledWith({
  520. param: { id: 1 },
  521. });
  522. });
  523. });
  524. it('应该成功激活订单', async () => {
  525. renderOrderManagement();
  526. // 等待数据加载
  527. await waitFor(() => {
  528. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  529. });
  530. // 先打开下拉菜单,然后点击激活按钮(只有草稿状态的订单才有激活按钮)
  531. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  532. expect(menuTrigger).toBeInTheDocument();
  533. await userEvent.click(menuTrigger);
  534. // 等待下拉菜单打开,然后点击激活按钮
  535. await waitFor(() => {
  536. const activateButton = screen.getByTestId('activate-order-button-1');
  537. expect(activateButton).toBeInTheDocument();
  538. });
  539. const activateButton = screen.getByTestId('activate-order-button-1');
  540. await userEvent.click(activateButton);
  541. // 验证激活确认对话框显示
  542. await waitFor(() => {
  543. expect(screen.getByTestId('activate-confirm-dialog')).toBeInTheDocument();
  544. expect(screen.getByTestId('activate-confirm-dialog-title')).toHaveTextContent('激活订单');
  545. expect(screen.getByTestId('activate-confirm-dialog-description')).toHaveTextContent('确定要激活这个订单吗?订单激活后将进入进行中状态。');
  546. });
  547. // 点击确认按钮
  548. const confirmButton = screen.getByTestId('activate-confirm-dialog-confirm');
  549. await userEvent.click(confirmButton);
  550. // 验证API调用
  551. await waitFor(() => {
  552. expect(orderClientManager.get().activate[':orderId'].$post).toHaveBeenCalledWith({
  553. param: { orderId: 1 },
  554. });
  555. });
  556. });
  557. it('应该成功关闭订单', async () => {
  558. renderOrderManagement();
  559. // 等待数据加载
  560. await waitFor(() => {
  561. expect(screen.getByTestId('order-row-2')).toBeInTheDocument();
  562. });
  563. // 先打开下拉菜单,然后点击关闭按钮(只有已确认或进行中的订单有关闭按钮)
  564. const menuTrigger = screen.getByTestId('order-menu-trigger-2');
  565. expect(menuTrigger).toBeInTheDocument();
  566. await userEvent.click(menuTrigger);
  567. // 等待下拉菜单打开,然后点击关闭按钮
  568. await waitFor(() => {
  569. const closeButton = screen.getByTestId('close-order-button-2');
  570. expect(closeButton).toBeInTheDocument();
  571. });
  572. const closeButton = screen.getByTestId('close-order-button-2');
  573. await userEvent.click(closeButton);
  574. // 验证关闭确认对话框显示
  575. await waitFor(() => {
  576. expect(screen.getByTestId('close-confirm-dialog')).toBeInTheDocument();
  577. expect(screen.getByTestId('close-confirm-dialog-title')).toHaveTextContent('关闭订单');
  578. expect(screen.getByTestId('close-confirm-dialog-description')).toHaveTextContent('确定要关闭这个订单吗?订单关闭后将无法再添加人员或资产。');
  579. });
  580. // 点击确认按钮
  581. const confirmButton = screen.getByTestId('close-confirm-dialog-confirm');
  582. await userEvent.click(confirmButton);
  583. // 验证API调用
  584. await waitFor(() => {
  585. expect(orderClientManager.get().close[':orderId'].$post).toHaveBeenCalledWith({
  586. param: { orderId: 2 },
  587. });
  588. });
  589. });
  590. it('应该可以取消删除操作', async () => {
  591. renderOrderManagement();
  592. // 等待数据加载
  593. await waitFor(() => {
  594. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  595. });
  596. // 先点击下拉菜单触发器,然后点击删除按钮
  597. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  598. expect(menuTrigger).toBeInTheDocument();
  599. await userEvent.click(menuTrigger);
  600. // 等待下拉菜单打开,然后点击删除按钮
  601. await waitFor(() => {
  602. const deleteButton = screen.getByTestId('delete-order-button-1');
  603. expect(deleteButton).toBeInTheDocument();
  604. });
  605. const deleteButton = screen.getByTestId('delete-order-button-1');
  606. await userEvent.click(deleteButton);
  607. // 验证删除确认对话框显示
  608. await waitFor(() => {
  609. expect(screen.getByTestId('delete-confirm-dialog')).toBeInTheDocument();
  610. });
  611. // 点击取消按钮
  612. const cancelButton = screen.getByTestId('delete-confirm-dialog-cancel');
  613. await userEvent.click(cancelButton);
  614. // 验证对话框关闭
  615. await waitFor(() => {
  616. expect(screen.queryByTestId('delete-confirm-dialog')).not.toBeInTheDocument();
  617. });
  618. // 验证API没有被调用
  619. expect(orderClientManager.get().delete[':id'].$delete).not.toHaveBeenCalled();
  620. });
  621. });
  622. describe('文件上传集成测试', () => {
  623. it('应该成功打开资产关联模态框', async () => {
  624. renderOrderManagement();
  625. // 等待数据加载
  626. await waitFor(() => {
  627. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  628. });
  629. // 先打开下拉菜单,然后点击添加资产按钮
  630. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  631. expect(menuTrigger).toBeInTheDocument();
  632. await userEvent.click(menuTrigger);
  633. // 等待下拉菜单打开,然后点击添加资产按钮
  634. await waitFor(() => {
  635. const addAssetButton = screen.getByTestId('add-asset-button-1');
  636. expect(addAssetButton).toBeInTheDocument();
  637. });
  638. const addAssetButton = screen.getByTestId('add-asset-button-1');
  639. await userEvent.click(addAssetButton);
  640. // 验证资产关联模态框打开
  641. await waitFor(() => {
  642. expect(screen.getByTestId('order-asset-modal-title')).toBeInTheDocument();
  643. });
  644. // 验证文件选择器组件存在 - 可能需要在表单中才会显示
  645. // 先验证模态框基本结构
  646. expect(screen.getByTestId('order-asset-modal-title')).toBeInTheDocument();
  647. // 文件选择器可能在选择了残疾人才显示,这里先跳过具体验证
  648. });
  649. });
  650. describe('区域选择器集成测试', () => {
  651. it('应该成功打开订单表单并显示区域选择器', async () => {
  652. renderOrderManagement();
  653. // 点击创建订单按钮
  654. const createButton = screen.getByTestId('create-order-button');
  655. fireEvent.click(createButton);
  656. // 验证订单表单模态框打开
  657. await waitFor(() => {
  658. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  659. });
  660. // 验证区域选择器组件存在 - 暂时跳过,因为OrderForm中未集成区域选择器
  661. // expect(screen.getByTestId('area-select-mock')).toBeInTheDocument();
  662. });
  663. });
  664. describe('枚举常量集成测试', () => {
  665. it('应该正确显示订单状态枚举', async () => {
  666. renderOrderManagement();
  667. // 等待数据加载 - 验证表格中的订单状态Badge
  668. await waitFor(() => {
  669. // 使用更精确的选择器,避免与Select选项冲突
  670. const orderRow = screen.getByTestId('order-row-1');
  671. expect(orderRow).toBeInTheDocument();
  672. // 验证表格中有订单状态显示
  673. expect(screen.getByText('测试订单1')).toBeInTheDocument();
  674. });
  675. // 验证订单状态筛选器
  676. const statusFilter = screen.getByTestId('filter-order-status-select');
  677. expect(statusFilter).toBeInTheDocument();
  678. // 点击筛选器查看选项
  679. fireEvent.click(statusFilter);
  680. // 验证枚举选项存在
  681. await waitFor(() => {
  682. // 使用test ID验证枚举选项
  683. expect(screen.getByTestId('order-status-option-all')).toBeInTheDocument();
  684. expect(screen.getByTestId('order-status-option-draft')).toBeInTheDocument();
  685. expect(screen.getByTestId('order-status-option-confirmed')).toBeInTheDocument();
  686. expect(screen.getByTestId('order-status-option-in-progress')).toBeInTheDocument();
  687. expect(screen.getByTestId('order-status-option-completed')).toBeInTheDocument();
  688. expect(screen.getByTestId('order-status-option-cancelled')).toBeInTheDocument();
  689. });
  690. });
  691. it('应该正确显示工作状态枚举', async () => {
  692. renderOrderManagement();
  693. // 等待数据加载 - 验证表格中的工作状态Badge
  694. await waitFor(() => {
  695. // 使用更精确的选择器,避免与Select选项冲突
  696. const orderRow = screen.getByTestId('order-row-1');
  697. expect(orderRow).toBeInTheDocument();
  698. // 验证表格中有工作状态显示
  699. expect(screen.getByText('测试订单1')).toBeInTheDocument();
  700. });
  701. // 验证工作状态筛选器
  702. const workStatusFilter = screen.getByTestId('filter-work-status-select');
  703. expect(workStatusFilter).toBeInTheDocument();
  704. // 点击筛选器查看选项
  705. fireEvent.click(workStatusFilter);
  706. // 验证枚举选项存在
  707. await waitFor(() => {
  708. // 使用test ID验证枚举选项
  709. expect(screen.getByTestId('work-status-option-all')).toBeInTheDocument();
  710. expect(screen.getByTestId('work-status-option-not-working')).toBeInTheDocument();
  711. expect(screen.getByTestId('work-status-option-pre-working')).toBeInTheDocument();
  712. expect(screen.getByTestId('work-status-option-working')).toBeInTheDocument();
  713. expect(screen.getByTestId('work-status-option-resigned')).toBeInTheDocument();
  714. });
  715. });
  716. });
  717. describe('人员管理测试', () => {
  718. it('应该成功打开人员选择器', async () => {
  719. renderOrderManagement();
  720. // 等待数据加载
  721. await waitFor(() => {
  722. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  723. });
  724. // 打开订单详情弹窗
  725. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  726. expect(menuTrigger).toBeInTheDocument();
  727. await userEvent.click(menuTrigger);
  728. // 点击查看详情
  729. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  730. await userEvent.click(viewDetailButton);
  731. // 等待订单详情弹窗打开
  732. await waitFor(() => {
  733. expect(screen.getByTestId('order-detail-dialog')).toBeInTheDocument();
  734. });
  735. // 在订单详情弹窗中点击添加人员按钮
  736. await waitFor(() => {
  737. expect(screen.getByTestId('order-detail-card-add-persons-button')).toBeInTheDocument();
  738. });
  739. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  740. await userEvent.click(addPersonsButton);
  741. // 验证残疾人选择器打开
  742. await waitFor(() => {
  743. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  744. });
  745. });
  746. it.skip('应该成功批量添加人员到已存在订单', async () => {
  747. renderOrderManagement();
  748. // 等待数据加载
  749. await waitFor(() => {
  750. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  751. });
  752. // 打开订单详情弹窗
  753. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  754. expect(menuTrigger).toBeInTheDocument();
  755. await userEvent.click(menuTrigger);
  756. // 点击查看详情
  757. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  758. await userEvent.click(viewDetailButton);
  759. // 等待订单详情弹窗打开
  760. await waitFor(() => {
  761. expect(screen.getByTestId('order-detail-dialog')).toBeInTheDocument();
  762. });
  763. // 在订单详情弹窗中点击添加人员按钮
  764. await waitFor(() => {
  765. expect(screen.getByTestId('order-detail-card-add-persons-button')).toBeInTheDocument();
  766. });
  767. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  768. await userEvent.click(addPersonsButton);
  769. // 验证残疾人选择器打开
  770. await waitFor(() => {
  771. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  772. });
  773. // 选择人员
  774. const selectPersonButton = screen.getByTestId('select-person-button');
  775. await userEvent.click(selectPersonButton);
  776. // 等待残疾人选择器关闭(选择人员后会自动关闭)
  777. await waitFor(() => {
  778. expect(screen.queryByTestId('disabled-person-selector-mock')).not.toBeInTheDocument();
  779. });
  780. // 立即检查PersonSelector模态框是否还在
  781. console.debug('选择人员后立即检查PersonSelector模态框...');
  782. const dialogTitle = screen.queryByTestId('batch-add-persons-dialog-title');
  783. console.debug('找到的dialogTitle:', dialogTitle ? '是' : '否');
  784. // 调试:查看当前所有文本
  785. console.debug('选择人员后所有文本:', Array.from(screen.getAllByText(/.*/)).map(el => el.textContent).filter(t => t && t.trim()));
  786. // 调试:查看当前所有test ID
  787. const allTestIds = screen.getAllByTestId(/.*/);
  788. console.debug('选择人员后所有test ID:', allTestIds.map(el => el.getAttribute('data-testid')));
  789. // 首先验证PersonSelector模态框仍然打开
  790. await waitFor(() => {
  791. expect(screen.getByTestId('batch-add-persons-dialog-title')).toBeInTheDocument();
  792. });
  793. // 验证人员被添加到列表
  794. await waitFor(() => {
  795. const personElements = screen.getAllByText('测试残疾人');
  796. console.debug('找到的测试残疾人元素数量:', personElements.length);
  797. expect(personElements.length).toBeGreaterThan(0);
  798. });
  799. // 填写人员详情
  800. const joinDateInput = screen.getByTestId('join-date-input-1');
  801. fireEvent.change(joinDateInput, { target: { value: '2024-01-01' } });
  802. const salaryInput = screen.getByTestId('salary-detail-input-1');
  803. fireEvent.change(salaryInput, { target: { value: '5000元/月' } });
  804. const workStatusInput = screen.getByTestId('work-status-input-1');
  805. fireEvent.change(workStatusInput, { target: { value: '在职' } });
  806. // 提交表单
  807. const submitButton = screen.getByRole('button', { name: /添加/ });
  808. fireEvent.click(submitButton);
  809. // 验证API调用
  810. await waitFor(() => {
  811. const mockOrderClient = orderClientManager.get();
  812. // 验证批量添加人员API被调用
  813. expect(mockOrderClient[':orderId'].persons.batch.$post).toHaveBeenCalledWith({
  814. param: { orderId: 1 },
  815. json: {
  816. persons: expect.arrayContaining([
  817. expect.objectContaining({
  818. personId: 1,
  819. joinDate: '2024-01-01',
  820. salaryDetail: '5000元/月',
  821. workStatus: 'working'
  822. })
  823. ])
  824. }
  825. });
  826. });
  827. });
  828. });
  829. describe('搜索和筛选测试', () => {
  830. it('应该支持按订单名称搜索', async () => {
  831. renderOrderManagement();
  832. // 等待数据加载
  833. await waitFor(() => {
  834. expect(screen.getByTestId('search-order-name-input')).toBeInTheDocument();
  835. });
  836. // 输入搜索关键词
  837. const searchInput = screen.getByTestId('search-order-name-input');
  838. fireEvent.change(searchInput, { target: { value: '测试订单1' } });
  839. // 点击搜索按钮
  840. const searchButton = screen.getByTestId('search-button');
  841. fireEvent.click(searchButton);
  842. // 验证API调用
  843. // 实际测试中应该验证API调用参数
  844. });
  845. it('应该支持按订单状态筛选', async () => {
  846. renderOrderManagement();
  847. // 等待数据加载
  848. await waitFor(() => {
  849. expect(screen.getByTestId('filter-order-status-select')).toBeInTheDocument();
  850. });
  851. // 选择订单状态
  852. const statusFilter = screen.getByTestId('filter-order-status-select');
  853. fireEvent.click(statusFilter);
  854. // 选择"草稿"状态
  855. await waitFor(() => {
  856. const draftOption = screen.getByText('草稿');
  857. fireEvent.click(draftOption);
  858. });
  859. // 点击搜索按钮
  860. const searchButton = screen.getByTestId('search-button');
  861. fireEvent.click(searchButton);
  862. // 验证API调用
  863. // 实际测试中应该验证API调用参数
  864. });
  865. it('应该支持按工作状态筛选', async () => {
  866. renderOrderManagement();
  867. // 等待数据加载
  868. await waitFor(() => {
  869. expect(screen.getByTestId('filter-work-status-select')).toBeInTheDocument();
  870. });
  871. // 选择工作状态
  872. const workStatusFilter = screen.getByTestId('filter-work-status-select');
  873. fireEvent.click(workStatusFilter);
  874. // 选择"未就业"状态
  875. await waitFor(() => {
  876. const notWorkingOption = screen.getByText('未就业');
  877. fireEvent.click(notWorkingOption);
  878. });
  879. // 点击搜索按钮
  880. const searchButton = screen.getByTestId('search-button');
  881. fireEvent.click(searchButton);
  882. // 验证API调用
  883. // 实际测试中应该验证API调用参数
  884. });
  885. });
  886. describe('创建订单人员绑定测试', () => {
  887. it('应该成功创建订单并绑定人员', async () => {
  888. renderOrderManagement();
  889. // 点击创建订单按钮
  890. const createButton = screen.getByTestId('create-order-button');
  891. await userEvent.click(createButton);
  892. // 验证订单表单模态框打开
  893. await waitFor(() => {
  894. // 调试:打印所有test ID
  895. const allElements = screen.getAllByTestId(/.*/);
  896. console.debug('所有test ID:', allElements.map(el => el.getAttribute('data-testid')));
  897. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  898. });
  899. // 验证人员选择区域显示
  900. // 使用更精确的选择器,避免与CardTitle中的文本冲突
  901. await waitFor(() => {
  902. expect(screen.getByTestId('select-persons-button')).toBeInTheDocument();
  903. });
  904. // 验证描述文本
  905. expect(screen.getByText('创建订单时必须至少选择一名残疾人')).toBeInTheDocument();
  906. // 点击选择残疾人按钮
  907. const selectPersonsButton = screen.getByTestId('select-persons-button');
  908. await userEvent.click(selectPersonsButton);
  909. // 验证残疾人选择器打开
  910. await waitFor(() => {
  911. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  912. });
  913. // 选择测试人员
  914. const selectPersonButton = screen.getByTestId('select-person-button');
  915. await userEvent.click(selectPersonButton);
  916. // 等待残疾人选择器关闭(选择人员后会自动关闭)
  917. await waitFor(() => {
  918. expect(screen.queryByTestId('disabled-person-selector-mock')).not.toBeInTheDocument();
  919. });
  920. // 调试:查看当前渲染的所有元素
  921. console.debug('选择人员后,所有可见文本:', Array.from(screen.getAllByText(/.*/)).map(el => el.textContent).filter(t => t && t.trim()));
  922. // 首先验证订单表单仍然打开
  923. await waitFor(() => {
  924. // 调试:打印所有test ID
  925. const allElements = screen.getAllByTestId(/.*/);
  926. console.debug('选择人员后所有test ID:', allElements.map(el => el.getAttribute('data-testid')));
  927. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  928. });
  929. // 验证人员被添加到列表
  930. await waitFor(() => {
  931. // 使用getAllByText因为可能有多个元素包含相同文本
  932. const personElements = screen.getAllByText('测试残疾人');
  933. expect(personElements.length).toBeGreaterThan(0);
  934. const disabilityTypeElements = screen.getAllByText('肢体残疾');
  935. expect(disabilityTypeElements.length).toBeGreaterThan(0);
  936. const levelElements = screen.getAllByText('三级');
  937. expect(levelElements.length).toBeGreaterThan(0);
  938. });
  939. // 填写订单基本信息
  940. const orderNameInput = screen.getByPlaceholderText('请输入订单名称');
  941. fireEvent.change(orderNameInput, { target: { value: '测试订单带人员' } });
  942. // 选择平台 - 使用select元素直接选择
  943. const platformSelect = screen.getByTestId('platform-selector');
  944. await userEvent.selectOptions(platformSelect, '1');
  945. // 选择公司
  946. const companySelect = screen.getByTestId('company-selector');
  947. await userEvent.selectOptions(companySelect, '1');
  948. // 选择渠道
  949. const channelSelect = screen.getByTestId('channel-selector');
  950. await userEvent.selectOptions(channelSelect, '1');
  951. // 填写开始日期
  952. const startDateInputs = screen.getAllByLabelText('预计开始日期');
  953. const startDateInput = startDateInputs[0]; // 第一个是date输入框
  954. fireEvent.change(startDateInput, { target: { value: '2024-01-01' } });
  955. // 注意:OrderForm中已移除"预计结束日期"和"联系人手机号"字段
  956. // 这些字段在实际实体中不存在,已根据故事要求清理
  957. // 填写人员详情
  958. const salaryInput = screen.getByTestId('salary-detail-input-1');
  959. fireEvent.change(salaryInput, { target: { value: '5000' } });
  960. // 提交表单
  961. const submitButton = screen.getByRole('button', { name: /创建/ });
  962. fireEvent.click(submitButton);
  963. // 验证API调用
  964. await waitFor(() => {
  965. // 验证创建订单API被调用
  966. const mockOrderClient = orderClientManager.get();
  967. expect(mockOrderClient.create.$post).toHaveBeenCalledWith({
  968. json: expect.objectContaining({
  969. orderName: '测试订单带人员',
  970. platformId: 1,
  971. companyId: 1,
  972. channelId: 1,
  973. })
  974. });
  975. // 验证批量添加人员API被调用
  976. expect(mockOrderClient[':orderId'].persons.batch.$post).toHaveBeenCalledWith({
  977. param: { orderId: expect.any(Number) },
  978. json: {
  979. persons: expect.arrayContaining([
  980. expect.objectContaining({
  981. personId: 1,
  982. salaryDetail: 5000
  983. })
  984. ])
  985. }
  986. });
  987. });
  988. });
  989. it('应该验证至少选择一名人员', async () => {
  990. renderOrderManagement();
  991. // 点击创建订单按钮
  992. const createButton = screen.getByTestId('create-order-button');
  993. fireEvent.click(createButton);
  994. // 验证订单表单模态框打开
  995. await waitFor(() => {
  996. expect(screen.getByTestId('create-order-dialog-title')).toBeInTheDocument();
  997. });
  998. // 填写订单基本信息但不选择人员
  999. const orderNameInput = screen.getByPlaceholderText('请输入订单名称');
  1000. fireEvent.change(orderNameInput, { target: { value: '测试订单无人员' } });
  1001. // 尝试提交表单
  1002. const submitButton = screen.getByRole('button', { name: /创建/ });
  1003. fireEvent.click(submitButton);
  1004. // 验证表单验证错误
  1005. await waitFor(() => {
  1006. expect(screen.getByText('至少选择一名人员')).toBeInTheDocument();
  1007. });
  1008. // 验证创建订单API没有被调用
  1009. const mockOrderClient = orderClientManager.get();
  1010. expect(mockOrderClient.create.$post).not.toHaveBeenCalled();
  1011. });
  1012. });
  1013. describe('错误处理测试', () => {
  1014. it('应该处理API错误', async () => {
  1015. // Mock API错误
  1016. const mockOrderClient = vi.mocked(orderClientManager.get());
  1017. mockOrderClient.list.$get.mockImplementationOnce(() =>
  1018. Promise.resolve(createMockResponse(500, {
  1019. code: 500,
  1020. message: '服务器错误'
  1021. }))
  1022. );
  1023. renderOrderManagement();
  1024. // 验证错误处理
  1025. await waitFor(() => {
  1026. expect(screen.getByText(/加载失败/)).toBeInTheDocument();
  1027. });
  1028. });
  1029. });
  1030. describe('订单详情弹窗测试', () => {
  1031. let mockBatchAddPersons: any;
  1032. beforeEach(() => {
  1033. // 获取批量添加人员的mock函数
  1034. mockBatchAddPersons = vi.mocked(orderClientManager.get())[':orderId']?.persons?.batch?.$post;
  1035. });
  1036. it('应该打开订单详情弹窗', async () => {
  1037. renderOrderManagement();
  1038. // 等待订单列表加载
  1039. await waitFor(() => {
  1040. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1041. });
  1042. // 打开操作菜单
  1043. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1044. await userEvent.click(menuTrigger);
  1045. // 点击查看详情
  1046. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1047. await userEvent.click(viewDetailButton);
  1048. // 验证订单详情弹窗打开
  1049. await waitFor(() => {
  1050. expect(screen.getByTestId('order-detail-dialog')).toBeInTheDocument();
  1051. expect(screen.getByTestId('order-detail-dialog-title')).toHaveTextContent('订单详情');
  1052. });
  1053. });
  1054. it('应该显示订单详情信息', async () => {
  1055. renderOrderManagement();
  1056. // 等待订单列表加载
  1057. await waitFor(() => {
  1058. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1059. });
  1060. // 打开操作菜单并点击查看详情
  1061. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1062. await userEvent.click(menuTrigger);
  1063. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1064. await userEvent.click(viewDetailButton);
  1065. // 验证订单详情信息显示
  1066. await waitFor(() => {
  1067. expect(screen.getByTestId('order-detail-id')).toHaveTextContent('1');
  1068. expect(screen.getByTestId('order-detail-name')).toHaveTextContent('测试订单1');
  1069. expect(screen.getByTestId('order-detail-platform')).toHaveTextContent('平台1');
  1070. expect(screen.getByTestId('order-detail-company')).toHaveTextContent('公司1');
  1071. expect(screen.getByTestId('order-detail-status')).toBeInTheDocument();
  1072. });
  1073. });
  1074. it('应该显示绑定人员列表', async () => {
  1075. renderOrderManagement();
  1076. // 等待订单列表加载
  1077. await waitFor(() => {
  1078. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1079. });
  1080. // 打开操作菜单并点击查看详情
  1081. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1082. await userEvent.click(menuTrigger);
  1083. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1084. await userEvent.click(viewDetailButton);
  1085. // 验证人员列表显示
  1086. await waitFor(() => {
  1087. // 检查是否有人员列表或"暂无绑定人员"提示
  1088. // 使用更具体的选择器,只查找订单详情弹窗内的元素
  1089. const dialog = screen.getByTestId('order-detail-dialog');
  1090. const personList = dialog.querySelector('[data-testid="order-detail-person-100"]');
  1091. const noDataMessage = dialog.querySelector('.text-center.py-8.text-muted-foreground');
  1092. expect(personList || noDataMessage).toBeInTheDocument();
  1093. });
  1094. });
  1095. it('应该支持添加人员功能', async () => {
  1096. renderOrderManagement();
  1097. // 等待订单列表加载
  1098. await waitFor(() => {
  1099. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1100. });
  1101. // 打开操作菜单并点击查看详情
  1102. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1103. await userEvent.click(menuTrigger);
  1104. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1105. await userEvent.click(viewDetailButton);
  1106. // 点击添加人员按钮
  1107. await waitFor(() => {
  1108. expect(screen.getByTestId('order-detail-card-add-persons-button')).toBeInTheDocument();
  1109. });
  1110. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  1111. await userEvent.click(addPersonsButton);
  1112. // 验证残疾人选择器打开
  1113. await waitFor(() => {
  1114. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1115. });
  1116. });
  1117. it('应该支持资源上传功能', async () => {
  1118. renderOrderManagement();
  1119. // 等待订单列表加载
  1120. await waitFor(() => {
  1121. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1122. });
  1123. // 打开操作菜单并点击查看详情
  1124. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1125. await userEvent.click(menuTrigger);
  1126. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1127. await userEvent.click(viewDetailButton);
  1128. // 点击资源上传按钮
  1129. await waitFor(() => {
  1130. expect(screen.getByTestId('order-detail-bottom-add-asset-button')).toBeInTheDocument();
  1131. });
  1132. const addAssetButton = screen.getByTestId('order-detail-bottom-add-asset-button');
  1133. await userEvent.click(addAssetButton);
  1134. // 验证资产关联模态框打开
  1135. await waitFor(() => {
  1136. expect(screen.getByTestId('order-asset-modal-title')).toBeInTheDocument();
  1137. });
  1138. });
  1139. it('应该根据订单状态显示激活/关闭按钮', async () => {
  1140. renderOrderManagement();
  1141. // 等待订单列表加载
  1142. await waitFor(() => {
  1143. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1144. });
  1145. // 打开操作菜单并点击查看详情
  1146. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1147. await userEvent.click(menuTrigger);
  1148. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1149. await userEvent.click(viewDetailButton);
  1150. // 根据订单状态验证按钮显示
  1151. await waitFor(() => {
  1152. // 订单1的状态是DRAFT,应该显示激活按钮
  1153. const activateButton = screen.queryByTestId('order-detail-activate-button');
  1154. const closeButton = screen.queryByTestId('order-detail-close-order-button');
  1155. // 根据mock数据,订单1的状态是DRAFT
  1156. expect(activateButton).toBeInTheDocument();
  1157. expect(closeButton).not.toBeInTheDocument();
  1158. });
  1159. });
  1160. it('应该关闭订单详情弹窗', async () => {
  1161. renderOrderManagement();
  1162. // 等待订单列表加载
  1163. await waitFor(() => {
  1164. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1165. });
  1166. // 打开操作菜单并点击查看详情
  1167. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1168. await userEvent.click(menuTrigger);
  1169. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1170. await userEvent.click(viewDetailButton);
  1171. // 验证弹窗打开
  1172. await waitFor(() => {
  1173. expect(screen.getByTestId('order-detail-dialog')).toBeInTheDocument();
  1174. });
  1175. // 点击关闭按钮
  1176. const closeButton = screen.getByTestId('order-detail-close-button');
  1177. await userEvent.click(closeButton);
  1178. // 验证弹窗关闭
  1179. await waitFor(() => {
  1180. expect(screen.queryByTestId('order-detail-dialog')).not.toBeInTheDocument();
  1181. });
  1182. });
  1183. it.skip('应该将选择的人员添加到待添加列表而不是立即调用API', async () => {
  1184. renderOrderManagement();
  1185. // 等待订单列表加载
  1186. await waitFor(() => {
  1187. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1188. });
  1189. // 打开操作菜单并点击查看详情
  1190. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1191. await userEvent.click(menuTrigger);
  1192. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1193. await userEvent.click(viewDetailButton);
  1194. // 点击添加人员按钮
  1195. await waitFor(() => {
  1196. expect(screen.getByTestId('order-detail-card-add-persons-button')).toBeInTheDocument();
  1197. });
  1198. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  1199. await userEvent.click(addPersonsButton);
  1200. // 验证残疾人选择器打开
  1201. await waitFor(() => {
  1202. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1203. });
  1204. // 选择人员
  1205. const selectPersonButton = screen.getByTestId('select-person-button');
  1206. await userEvent.click(selectPersonButton);
  1207. // 等待残疾人选择器自动关闭(选择人员后自动关闭)
  1208. await waitFor(() => {
  1209. expect(screen.queryByTestId('disabled-person-selector-mock')).not.toBeInTheDocument();
  1210. });
  1211. // 等待handlePersonSelect完成
  1212. await waitFor(() => {
  1213. // 检查toast是否显示
  1214. const toastElement = screen.queryByText(/已添加.*名人员到待添加列表/);
  1215. if (toastElement) {
  1216. console.log('测试:找到toast消息');
  1217. }
  1218. }, { timeout: 3000 });
  1219. // 验证待添加人员列表显示 - 添加更多调试信息
  1220. console.log('测试:开始验证待添加人员列表显示...');
  1221. await waitFor(() => {
  1222. // 先检查是否显示"没有待添加人员",如果是,说明状态还没更新
  1223. const noPendingElement = screen.queryByTestId('no-pending-persons');
  1224. if (noPendingElement) {
  1225. console.log('测试:仍然显示"没有待添加人员"');
  1226. }
  1227. // 检查pending-persons-card
  1228. const pendingCard = screen.queryByTestId('pending-persons-card');
  1229. console.log('测试:pending-persons-card找到:', pendingCard ? '是' : '否');
  1230. // 检查pending-person-1
  1231. const pendingPerson = screen.queryByTestId('pending-person-1');
  1232. console.log('测试:pending-person-1找到:', pendingPerson ? '是' : '否');
  1233. // 打印当前所有test ID用于调试
  1234. const allTestIds = screen.getAllByTestId(/.*/);
  1235. console.log('测试:当前所有test ID:', allTestIds.map(el => el.getAttribute('data-testid')));
  1236. expect(screen.getByTestId('pending-persons-card')).toBeInTheDocument();
  1237. expect(screen.getByTestId('pending-person-1')).toBeInTheDocument();
  1238. }, { timeout: 5000 });
  1239. // 验证确认添加按钮显示正确数量
  1240. const confirmButton = screen.getByTestId('confirm-add-persons-button');
  1241. expect(confirmButton).toHaveTextContent('确认添加 (1)');
  1242. // 验证没有立即调用批量添加API
  1243. expect(mockBatchAddPersons).not.toHaveBeenCalled();
  1244. });
  1245. it.skip('应该支持编辑待添加人员的薪资', async () => {
  1246. renderOrderManagement();
  1247. // 等待订单列表加载
  1248. await waitFor(() => {
  1249. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1250. });
  1251. // 打开操作菜单并点击查看详情
  1252. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1253. await userEvent.click(menuTrigger);
  1254. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1255. await userEvent.click(viewDetailButton);
  1256. // 点击添加人员按钮并选择人员
  1257. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  1258. await userEvent.click(addPersonsButton);
  1259. await waitFor(() => {
  1260. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1261. });
  1262. const selectPersonButton = screen.getByTestId('select-person-button');
  1263. await userEvent.click(selectPersonButton);
  1264. // 关闭残疾人选择器
  1265. const closeSelectorButton = screen.getByTestId('close-selector-button');
  1266. await userEvent.click(closeSelectorButton);
  1267. // 等待待添加人员列表显示
  1268. await waitFor(() => {
  1269. expect(screen.getByTestId('pending-persons-card')).toBeInTheDocument();
  1270. });
  1271. // 编辑薪资
  1272. const salaryInput = screen.getByTestId('pending-person-salary-input-1');
  1273. await userEvent.clear(salaryInput);
  1274. await userEvent.type(salaryInput, '8000');
  1275. // 验证薪资已更新
  1276. expect(salaryInput).toHaveValue(8000);
  1277. });
  1278. it.skip('应该支持从待添加列表中移除人员', async () => {
  1279. renderOrderManagement();
  1280. // 等待订单列表加载
  1281. await waitFor(() => {
  1282. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1283. });
  1284. // 打开操作菜单并点击查看详情
  1285. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1286. await userEvent.click(menuTrigger);
  1287. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1288. await userEvent.click(viewDetailButton);
  1289. // 点击添加人员按钮并选择人员
  1290. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  1291. await userEvent.click(addPersonsButton);
  1292. await waitFor(() => {
  1293. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1294. });
  1295. const selectPersonButton = screen.getByTestId('select-person-button');
  1296. await userEvent.click(selectPersonButton);
  1297. // 关闭残疾人选择器
  1298. const closeSelectorButton = screen.getByTestId('close-selector-button');
  1299. await userEvent.click(closeSelectorButton);
  1300. // 等待待添加人员列表显示
  1301. await waitFor(() => {
  1302. expect(screen.getByTestId('pending-persons-card')).toBeInTheDocument();
  1303. });
  1304. // 移除人员
  1305. const removeButton = screen.getByTestId('remove-pending-person-button-1');
  1306. await userEvent.click(removeButton);
  1307. // 验证人员已从列表中移除
  1308. await waitFor(() => {
  1309. expect(screen.queryByTestId('pending-person-1')).not.toBeInTheDocument();
  1310. });
  1311. });
  1312. it.skip('应该点击确认添加按钮后调用批量添加API', async () => {
  1313. renderOrderManagement();
  1314. // 等待订单列表加载
  1315. await waitFor(() => {
  1316. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1317. });
  1318. // 打开操作菜单并点击查看详情
  1319. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1320. await userEvent.click(menuTrigger);
  1321. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1322. await userEvent.click(viewDetailButton);
  1323. // 点击添加人员按钮并选择人员
  1324. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  1325. await userEvent.click(addPersonsButton);
  1326. await waitFor(() => {
  1327. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1328. });
  1329. const selectPersonButton = screen.getByTestId('select-person-button');
  1330. await userEvent.click(selectPersonButton);
  1331. // 关闭残疾人选择器
  1332. const closeSelectorButton = screen.getByTestId('close-selector-button');
  1333. await userEvent.click(closeSelectorButton);
  1334. // 等待待添加人员列表显示
  1335. await waitFor(() => {
  1336. expect(screen.getByTestId('pending-persons-card')).toBeInTheDocument();
  1337. });
  1338. // 点击确认添加按钮
  1339. const confirmButton = screen.getByTestId('confirm-add-persons-button');
  1340. await userEvent.click(confirmButton);
  1341. // 验证批量添加API被调用
  1342. await waitFor(() => {
  1343. expect(mockBatchAddPersons).toHaveBeenCalledTimes(1);
  1344. });
  1345. // 验证API调用参数正确
  1346. expect(mockBatchAddPersons).toHaveBeenCalledWith(
  1347. expect.objectContaining({
  1348. param: { orderId: 1 },
  1349. json: expect.objectContaining({
  1350. persons: expect.arrayContaining([
  1351. expect.objectContaining({
  1352. personId: 1,
  1353. salaryDetail: expect.any(Number),
  1354. joinDate: expect.stringMatching(/^\d{4}-\d{2}-\d{2}$/), // YYYY-MM-DD格式
  1355. workStatus: WorkStatus.NOT_WORKING
  1356. })
  1357. ])
  1358. })
  1359. })
  1360. );
  1361. });
  1362. it.skip('应该避免重复添加已在订单中或已在待添加列表中的人员', async () => {
  1363. renderOrderManagement();
  1364. // 等待订单列表加载
  1365. await waitFor(() => {
  1366. expect(screen.getByTestId('order-row-1')).toBeInTheDocument();
  1367. });
  1368. // 打开操作菜单并点击查看详情
  1369. const menuTrigger = screen.getByTestId('order-menu-trigger-1');
  1370. await userEvent.click(menuTrigger);
  1371. const viewDetailButton = screen.getByTestId('view-order-detail-button-1');
  1372. await userEvent.click(viewDetailButton);
  1373. // 等待订单详情弹窗打开
  1374. await waitFor(() => {
  1375. expect(screen.getByTestId('order-detail-dialog')).toBeInTheDocument();
  1376. });
  1377. // 点击添加人员按钮
  1378. const addPersonsButton = screen.getByTestId('order-detail-card-add-persons-button');
  1379. await userEvent.click(addPersonsButton);
  1380. await waitFor(() => {
  1381. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1382. });
  1383. // 第一次选择人员
  1384. const selectPersonButton = screen.getByTestId('select-person-button');
  1385. await userEvent.click(selectPersonButton);
  1386. // 关闭残疾人选择器
  1387. const closeSelectorButton = screen.getByTestId('close-selector-button');
  1388. await userEvent.click(closeSelectorButton);
  1389. // 等待待添加人员列表显示
  1390. await waitFor(() => {
  1391. expect(screen.getByTestId('pending-persons-card')).toBeInTheDocument();
  1392. });
  1393. // 再次打开选择器并选择相同人员
  1394. await userEvent.click(addPersonsButton);
  1395. await waitFor(() => {
  1396. expect(screen.getByTestId('disabled-person-selector-mock')).toBeInTheDocument();
  1397. });
  1398. await userEvent.click(selectPersonButton);
  1399. // 验证待添加人员列表仍然只有1人(没有重复添加)
  1400. await waitFor(() => {
  1401. const pendingPersonRows = screen.getAllByTestId(/^pending-person-/);
  1402. expect(pendingPersonRows).toHaveLength(1);
  1403. });
  1404. });
  1405. });
  1406. });