disability.integration.test.ts 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. import { describe, it, expect, beforeEach } from 'vitest';
  2. import { testClient } from 'hono/testing';
  3. import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
  4. import { JWTUtil } from '@d8d/shared-utils';
  5. import { UserEntity, Role } from '@d8d/user-module';
  6. import { File } from '@d8d/file-module';
  7. import { BankName } from '@d8d/bank-names-module';
  8. import disabledPersonRoutes from '../../src/routes/disabled-person.routes';
  9. import { DisabledPerson } from '../../src/entities/disabled-person.entity';
  10. import { DisabledBankCard } from '../../src/entities/disabled-bank-card.entity';
  11. import { DisabledPhoto } from '../../src/entities/disabled-photo.entity';
  12. import { DisabledRemark } from '../../src/entities/disabled-remark.entity';
  13. import { DisabledVisit } from '../../src/entities/disabled-visit.entity';
  14. // 设置集成测试钩子 - 包含所有相关实体
  15. setupIntegrationDatabaseHooksWithEntities([
  16. UserEntity,
  17. Role,
  18. File,
  19. BankName,
  20. DisabledPerson,
  21. DisabledBankCard,
  22. DisabledPhoto,
  23. DisabledRemark,
  24. DisabledVisit
  25. ])
  26. describe('残疾人管理API集成测试', () => {
  27. let client: ReturnType<typeof testClient<typeof disabledPersonRoutes>>;
  28. let testToken: string;
  29. let testUser: UserEntity;
  30. let testFile: File;
  31. beforeEach(async () => {
  32. // 创建测试客户端
  33. client = testClient(disabledPersonRoutes);
  34. // 获取数据源
  35. const dataSource = await IntegrationTestDatabase.getDataSource();
  36. // 创建测试用户
  37. const userRepository = dataSource.getRepository(UserEntity);
  38. testUser = userRepository.create({
  39. username: `test_user_${Date.now()}`,
  40. password: 'test_password',
  41. nickname: '测试用户',
  42. registrationSource: 'web'
  43. });
  44. await userRepository.save(testUser);
  45. // 创建测试文件(用于照片集成测试)
  46. const fileRepository = dataSource.getRepository(File);
  47. testFile = fileRepository.create({
  48. name: 'test_photo.jpg',
  49. path: 'test_photo.jpg',
  50. type: 'image/jpeg',
  51. size: 1024,
  52. uploadUserId: testUser.id,
  53. uploadTime: new Date()
  54. });
  55. await fileRepository.save(testFile);
  56. // 生成测试用户的token
  57. testToken = JWTUtil.generateToken({
  58. id: testUser.id,
  59. username: testUser.username,
  60. roles: [{name:'user'}]
  61. });
  62. });
  63. describe('POST /createDisabledPerson', () => {
  64. it('应该成功创建残疾人基本信息', async () => {
  65. const createData = {
  66. name: '张三',
  67. gender: '男',
  68. idCard: '110101199001011234',
  69. disabilityId: 'D123456789',
  70. disabilityType: '肢体残疾',
  71. disabilityLevel: '一级',
  72. idAddress: '北京市东城区',
  73. phone: '13800138000',
  74. province: '北京市',
  75. city: '北京市',
  76. // 新增字段
  77. canDirectContact: 1,
  78. isInBlackList: 0,
  79. jobStatus: 1,
  80. specificDisability: '左眼视力0.1,右眼视力0.2,需要助听器',
  81. // 日期字段
  82. idValidDate: new Date('2030-12-31'),
  83. disabilityValidDate: new Date('2030-12-31')
  84. };
  85. const response = await client.createDisabledPerson.$post({
  86. json: createData
  87. }, {
  88. headers: {
  89. 'Authorization': `Bearer ${testToken}`
  90. }
  91. });
  92. expect(response.status).toBe(200);
  93. if (response.status === 200) {
  94. const data = await response.json();
  95. expect(data.name).toBe(createData.name);
  96. expect(data.idCard).toBe(createData.idCard);
  97. expect(data.disabilityId).toBe(createData.disabilityId);
  98. // 验证新增字段
  99. expect(data.canDirectContact).toBe(createData.canDirectContact);
  100. expect(data.isInBlackList).toBe(createData.isInBlackList);
  101. expect(data.jobStatus).toBe(createData.jobStatus);
  102. expect(data.specificDisability).toBe(createData.specificDisability);
  103. // 验证日期字段
  104. expect(data.idValidDate).toBeDefined();
  105. expect(data.disabilityValidDate).toBeDefined();
  106. if (data.idValidDate) {
  107. expect(new Date(data.idValidDate).toISOString().split('T')[0]).toBe('2030-12-31');
  108. }
  109. if (data.disabilityValidDate) {
  110. expect(new Date(data.disabilityValidDate).toISOString().split('T')[0]).toBe('2030-12-31');
  111. }
  112. }
  113. });
  114. it('应该验证身份证号唯一性', async () => {
  115. // 先创建一个残疾人
  116. const dataSource = await IntegrationTestDatabase.getDataSource();
  117. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  118. const existingPerson = disabledPersonRepository.create({
  119. name: '李四',
  120. gender: '女',
  121. idCard: '110101199001011235',
  122. disabilityId: 'D123456788',
  123. disabilityType: '视力残疾',
  124. disabilityLevel: '二级',
  125. idAddress: '北京市西城区',
  126. phone: '13900139000',
  127. province: '北京市',
  128. city: '北京市',
  129. // 新增字段
  130. canDirectContact: 0,
  131. isInBlackList: 0,
  132. jobStatus: 2,
  133. // 日期字段
  134. idValidDate: new Date('2035-05-15'),
  135. disabilityValidDate: new Date('2035-05-15')
  136. });
  137. await disabledPersonRepository.save(existingPerson);
  138. // 尝试创建相同身份证号的残疾人
  139. const createData = {
  140. name: '王五',
  141. gender: '男',
  142. idCard: '110101199001011235', // 重复的身份证号
  143. disabilityId: 'D123456777',
  144. disabilityType: '听力残疾',
  145. disabilityLevel: '三级',
  146. idAddress: '北京市朝阳区',
  147. phone: '13700137000',
  148. province: '北京市',
  149. city: '北京市',
  150. // 新增字段
  151. canDirectContact: 1,
  152. isInBlackList: 1,
  153. jobStatus: 3,
  154. // 日期字段
  155. idValidDate: new Date('2043-08-20'),
  156. disabilityValidDate: new Date('2043-08-20')
  157. };
  158. const response = await client.createDisabledPerson.$post({
  159. json: createData
  160. }, {
  161. headers: {
  162. 'Authorization': `Bearer ${testToken}`
  163. }
  164. });
  165. expect(response.status).toBe(400);
  166. });
  167. it('应该验证必填字段', async () => {
  168. const createData = {
  169. name: '', // 空字符串,应该验证失败
  170. gender: '男',
  171. idCard: '110101199001011236',
  172. disabilityId: 'D123456776',
  173. disabilityType: '肢体残疾',
  174. disabilityLevel: '一级',
  175. idAddress: '北京市海淀区',
  176. phone: '13600136000',
  177. province: '北京市',
  178. city: '北京市',
  179. // 新增字段(可选字段,不影响必填验证)
  180. canDirectContact: 1,
  181. isInBlackList: 0,
  182. jobStatus: 1,
  183. // 日期字段(可选字段,不影响必填验证)
  184. idValidDate: new Date('2028-03-10'),
  185. disabilityValidDate: new Date('2028-03-10')
  186. };
  187. const response = await client.createDisabledPerson.$post({
  188. json: createData
  189. }, {
  190. headers: {
  191. 'Authorization': `Bearer ${testToken}`
  192. }
  193. });
  194. expect(response.status).toBe(400);
  195. });
  196. it('应该验证具体残疾部位和情况字段为空值', async () => {
  197. const createData = {
  198. name: '空值测试',
  199. gender: '男',
  200. idCard: '110101199001011236',
  201. disabilityId: 'D123456776',
  202. disabilityType: '肢体残疾',
  203. disabilityLevel: '一级',
  204. idAddress: '北京市海淀区',
  205. phone: '13600136000',
  206. province: '北京市',
  207. city: '北京市',
  208. canDirectContact: 1,
  209. isInBlackList: 0,
  210. jobStatus: 1,
  211. // specificDisability 字段不提供,测试空值
  212. idValidDate: new Date('2028-03-10'),
  213. disabilityValidDate: new Date('2028-03-10')
  214. };
  215. const response = await client.createDisabledPerson.$post({
  216. json: createData
  217. }, {
  218. headers: {
  219. 'Authorization': `Bearer ${testToken}`
  220. }
  221. });
  222. expect(response.status).toBe(200);
  223. if (response.status === 200) {
  224. const data = await response.json();
  225. expect(data.name).toBe(createData.name);
  226. expect(data.specificDisability).toBeNull(); // 应该为null,因为数据库字段nullable: true
  227. }
  228. });
  229. it('应该验证具体残疾部位和情况字段为有效值', async () => {
  230. const createData = {
  231. name: '有效值测试',
  232. gender: '女',
  233. idCard: '110101199001011237',
  234. disabilityId: 'D123456775',
  235. disabilityType: '视力残疾',
  236. disabilityLevel: '二级',
  237. idAddress: '北京市朝阳区',
  238. phone: '13700137000',
  239. province: '北京市',
  240. city: '北京市',
  241. canDirectContact: 0,
  242. isInBlackList: 0,
  243. jobStatus: 0,
  244. specificDisability: '双眼视力均为0.05,需要导盲犬辅助',
  245. idValidDate: new Date('2030-06-15'),
  246. disabilityValidDate: new Date('2030-06-15')
  247. };
  248. const response = await client.createDisabledPerson.$post({
  249. json: createData
  250. }, {
  251. headers: {
  252. 'Authorization': `Bearer ${testToken}`
  253. }
  254. });
  255. expect(response.status).toBe(200);
  256. if (response.status === 200) {
  257. const data = await response.json();
  258. expect(data.name).toBe(createData.name);
  259. expect(data.specificDisability).toBe(createData.specificDisability);
  260. }
  261. });
  262. it('应该验证具体残疾部位和情况字段边界值(500字符)', async () => {
  263. // 生成500字符的字符串
  264. const maxLengthText = 'A'.repeat(500);
  265. const createData = {
  266. name: '边界值测试',
  267. gender: '男',
  268. idCard: '110101199001011238',
  269. disabilityId: 'D123456774',
  270. disabilityType: '听力残疾',
  271. disabilityLevel: '三级',
  272. idAddress: '北京市丰台区',
  273. phone: '13800138001',
  274. province: '北京市',
  275. city: '北京市',
  276. canDirectContact: 1,
  277. isInBlackList: 0,
  278. jobStatus: 1,
  279. specificDisability: maxLengthText,
  280. idValidDate: new Date('2032-08-20'),
  281. disabilityValidDate: new Date('2032-08-20')
  282. };
  283. const response = await client.createDisabledPerson.$post({
  284. json: createData
  285. }, {
  286. headers: {
  287. 'Authorization': `Bearer ${testToken}`
  288. }
  289. });
  290. expect(response.status).toBe(200);
  291. if (response.status === 200) {
  292. const data = await response.json();
  293. expect(data.name).toBe(createData.name);
  294. expect(data.specificDisability).toBe(createData.specificDisability);
  295. expect(data.specificDisability.length).toBe(500);
  296. }
  297. });
  298. it('应该验证具体残疾部位和情况字段超过500字符限制', async () => {
  299. // 生成501字符的字符串
  300. const tooLongText = 'A'.repeat(501);
  301. const createData = {
  302. name: '超长测试',
  303. gender: '女',
  304. idCard: '110101199001011239',
  305. disabilityId: 'D123456773',
  306. disabilityType: '言语残疾',
  307. disabilityLevel: '四级',
  308. idAddress: '北京市石景山区',
  309. phone: '13900139001',
  310. province: '北京市',
  311. city: '北京市',
  312. canDirectContact: 0,
  313. isInBlackList: 0,
  314. jobStatus: 0,
  315. specificDisability: tooLongText,
  316. idValidDate: new Date('2034-12-31'),
  317. disabilityValidDate: new Date('2034-12-31')
  318. };
  319. const response = await client.createDisabledPerson.$post({
  320. json: createData
  321. }, {
  322. headers: {
  323. 'Authorization': `Bearer ${testToken}`
  324. }
  325. });
  326. expect(response.status).toBe(400); // 应该返回400,因为超过长度限制
  327. });
  328. });
  329. describe('POST /deleteDisabledPerson', () => {
  330. it('应该成功删除残疾人', async () => {
  331. // 先创建一个残疾人
  332. const dataSource = await IntegrationTestDatabase.getDataSource();
  333. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  334. const person = disabledPersonRepository.create({
  335. name: '测试删除人员',
  336. gender: '男',
  337. idCard: '110101199001011237',
  338. disabilityId: 'D123456775',
  339. disabilityType: '肢体残疾',
  340. disabilityLevel: '一级',
  341. idAddress: '北京市石景山区',
  342. phone: '13500135000',
  343. province: '北京市',
  344. city: '北京市'
  345. });
  346. await disabledPersonRepository.save(person);
  347. const deleteData = {
  348. id: person.id
  349. };
  350. const response = await client.deleteDisabledPerson.$post({
  351. json: deleteData
  352. }, {
  353. headers: {
  354. 'Authorization': `Bearer ${testToken}`
  355. }
  356. });
  357. expect(response.status).toBe(200);
  358. if (response.status === 200) {
  359. const data = await response.json();
  360. expect(data.success).toBe(true);
  361. // 验证残疾人已被删除
  362. const deletedPerson = await disabledPersonRepository.findOne({ where: { id: person.id } });
  363. expect(deletedPerson).toBeNull();
  364. }
  365. });
  366. it('应该处理不存在的残疾人ID', async () => {
  367. const deleteData = {
  368. id: 99999 // 不存在的ID
  369. };
  370. const response = await client.deleteDisabledPerson.$post({
  371. json: deleteData
  372. }, {
  373. headers: {
  374. 'Authorization': `Bearer ${testToken}`
  375. }
  376. });
  377. expect(response.status).toBe(404);
  378. });
  379. });
  380. describe('POST /updateDisabledPerson', () => {
  381. it('应该成功更新残疾人信息', async () => {
  382. // 先创建一个残疾人
  383. const dataSource = await IntegrationTestDatabase.getDataSource();
  384. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  385. const person = disabledPersonRepository.create({
  386. name: '原始姓名',
  387. gender: '男',
  388. idCard: '110101199001011238',
  389. disabilityId: 'D123456774',
  390. disabilityType: '肢体残疾',
  391. disabilityLevel: '一级',
  392. idAddress: '北京市通州区',
  393. phone: '13400134000',
  394. province: '北京市',
  395. city: '北京市',
  396. // 新增字段初始值
  397. canDirectContact: 1,
  398. isInBlackList: 0,
  399. jobStatus: 1,
  400. // 日期字段初始值
  401. idValidDate: new Date('2023-01-01'),
  402. disabilityValidDate: new Date('2023-01-01')
  403. });
  404. await disabledPersonRepository.save(person);
  405. const updateData = {
  406. id: person.id,
  407. name: '更新后的姓名',
  408. gender: '女',
  409. phone: '13300133000',
  410. // 更新新增字段
  411. canDirectContact: 0,
  412. isInBlackList: 1,
  413. jobStatus: 1,
  414. // 更新日期字段
  415. idValidDate: new Date('2033-01-01'), // 更新有效期
  416. disabilityValidDate: new Date('2033-01-01') // 更新有效期
  417. };
  418. const response = await client.updateDisabledPerson.$post({
  419. json: updateData
  420. }, {
  421. headers: {
  422. 'Authorization': `Bearer ${testToken}`
  423. }
  424. });
  425. expect(response.status).toBe(200);
  426. if (response.status === 200) {
  427. const data = await response.json();
  428. expect(data.name).toBe(updateData.name);
  429. expect(data.gender).toBe(updateData.gender);
  430. expect(data.phone).toBe(updateData.phone);
  431. // 验证新增字段已更新
  432. expect(data.canDirectContact).toBe(updateData.canDirectContact);
  433. expect(data.isInBlackList).toBe(updateData.isInBlackList);
  434. expect(data.jobStatus).toBe(updateData.jobStatus);
  435. // 验证日期字段
  436. expect(data.idValidDate).toBeDefined();
  437. expect(data.disabilityValidDate).toBeDefined();
  438. if (data.idValidDate) {
  439. expect(new Date(data.idValidDate).toISOString().split('T')[0]).toBe('2033-01-01');
  440. }
  441. if (data.disabilityValidDate) {
  442. expect(new Date(data.disabilityValidDate).toISOString().split('T')[0]).toBe('2033-01-01');
  443. }
  444. }
  445. });
  446. it('应该验证身份证号唯一性(更新时)', async () => {
  447. // 创建两个残疾人
  448. const dataSource = await IntegrationTestDatabase.getDataSource();
  449. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  450. const person1 = disabledPersonRepository.create({
  451. name: '人员A',
  452. gender: '男',
  453. idCard: '110101199001011239',
  454. disabilityId: 'D123456773',
  455. disabilityType: '肢体残疾',
  456. disabilityLevel: '一级',
  457. idAddress: '北京市顺义区',
  458. phone: '13200132000',
  459. province: '北京市',
  460. city: '北京市',
  461. // 新增字段
  462. canDirectContact: 1,
  463. isInBlackList: 0,
  464. jobStatus: 1,
  465. // 日期字段
  466. idValidDate: new Date('2028-06-15'),
  467. disabilityValidDate: new Date('2028-06-15')
  468. });
  469. await disabledPersonRepository.save(person1);
  470. const person2 = disabledPersonRepository.create({
  471. name: '人员B',
  472. gender: '女',
  473. idCard: '110101199001011240',
  474. disabilityId: 'D123456772',
  475. disabilityType: '视力残疾',
  476. disabilityLevel: '二级',
  477. idAddress: '北京市大兴区',
  478. phone: '13100131000',
  479. province: '北京市',
  480. city: '北京市',
  481. // 新增字段
  482. canDirectContact: 0,
  483. isInBlackList: 1,
  484. jobStatus: 2,
  485. // 日期字段
  486. idValidDate: new Date('2034-09-20'),
  487. disabilityValidDate: new Date('2034-09-20')
  488. });
  489. await disabledPersonRepository.save(person2);
  490. // 尝试将人员2的身份证号改为人员1的身份证号
  491. const updateData = {
  492. id: person2.id,
  493. idCard: '110101199001011239' // 重复的身份证号
  494. };
  495. const response = await client.updateDisabledPerson.$post({
  496. json: updateData
  497. }, {
  498. headers: {
  499. 'Authorization': `Bearer ${testToken}`
  500. }
  501. });
  502. expect(response.status).toBe(400);
  503. });
  504. it('应该处理不存在的残疾人', async () => {
  505. const updateData = {
  506. id: 99999, // 不存在的ID
  507. name: '新姓名'
  508. };
  509. const response = await client.updateDisabledPerson.$post({
  510. json: updateData
  511. }, {
  512. headers: {
  513. 'Authorization': `Bearer ${testToken}`
  514. }
  515. });
  516. expect(response.status).toBe(404);
  517. });
  518. });
  519. describe('GET /getAllDisabledPersons', () => {
  520. it('应该成功获取残疾人列表(分页)', async () => {
  521. // 创建一些测试数据
  522. const dataSource = await IntegrationTestDatabase.getDataSource();
  523. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  524. for (let i = 1; i <= 5; i++) {
  525. const person = disabledPersonRepository.create({
  526. name: `残疾人${i}`,
  527. gender: i % 2 === 0 ? '女' : '男',
  528. idCard: `1101011990010112${40 + i}`,
  529. disabilityId: `D1234567${70 + i}`,
  530. disabilityType: '肢体残疾',
  531. disabilityLevel: '一级',
  532. idAddress: `北京市测试区${i}`,
  533. phone: `138001380${i}`,
  534. province: '北京市',
  535. city: '北京市'
  536. });
  537. await disabledPersonRepository.save(person);
  538. }
  539. const response = await client.getAllDisabledPersons.$get({
  540. query: {
  541. skip: 0,
  542. take: 10
  543. }
  544. }, {
  545. headers: {
  546. 'Authorization': `Bearer ${testToken}`
  547. }
  548. });
  549. expect(response.status).toBe(200);
  550. if (response.status === 200) {
  551. const data = await response.json();
  552. expect(data.data).toHaveLength(5);
  553. expect(data.total).toBe(5);
  554. expect(data.data[0].name).toBe('残疾人5'); // 按ID降序排列
  555. }
  556. });
  557. it('应该处理分页参数', async () => {
  558. // 创建更多测试数据
  559. const dataSource = await IntegrationTestDatabase.getDataSource();
  560. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  561. for (let i = 1; i <= 15; i++) {
  562. const person = disabledPersonRepository.create({
  563. name: `分页人员${i}`,
  564. gender: i % 2 === 0 ? '女' : '男',
  565. idCard: `1101011990010113${i}`,
  566. disabilityId: `D1234568${i}`,
  567. disabilityType: '肢体残疾',
  568. disabilityLevel: '一级',
  569. idAddress: `北京市分页区${i}`,
  570. phone: `138001381${i}`,
  571. province: '北京市',
  572. city: '北京市'
  573. });
  574. await disabledPersonRepository.save(person);
  575. }
  576. const response = await client.getAllDisabledPersons.$get({
  577. query: {
  578. skip: 5,
  579. take: 5
  580. }
  581. }, {
  582. headers: {
  583. 'Authorization': `Bearer ${testToken}`
  584. }
  585. });
  586. expect(response.status).toBe(200);
  587. if (response.status === 200) {
  588. const data = await response.json();
  589. expect(data.data).toHaveLength(5);
  590. expect(data.total).toBe(15);
  591. }
  592. });
  593. it('应该支持残疾类型筛选', async () => {
  594. // 创建测试数据
  595. const dataSource = await IntegrationTestDatabase.getDataSource();
  596. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  597. // 创建不同残疾类型的人员
  598. const person1 = disabledPersonRepository.create({
  599. name: '视力残疾人',
  600. gender: '男',
  601. idCard: '110101199001011351',
  602. disabilityId: 'D123456851',
  603. disabilityType: '视力残疾',
  604. disabilityLevel: '一级',
  605. idAddress: '北京市测试区',
  606. phone: '1380013851',
  607. province: '北京市',
  608. city: '北京市'
  609. });
  610. await disabledPersonRepository.save(person1);
  611. const person2 = disabledPersonRepository.create({
  612. name: '肢体残疾人',
  613. gender: '女',
  614. idCard: '110101199001011352',
  615. disabilityId: 'D123456852',
  616. disabilityType: '肢体残疾',
  617. disabilityLevel: '二级',
  618. idAddress: '北京市测试区',
  619. phone: '1380013852',
  620. province: '北京市',
  621. city: '北京市'
  622. });
  623. await disabledPersonRepository.save(person2);
  624. // 测试视力残疾筛选
  625. const response = await client.getAllDisabledPersons.$get({
  626. query: {
  627. disabilityType: '视力残疾',
  628. skip: 0,
  629. take: 10
  630. }
  631. }, {
  632. headers: {
  633. 'Authorization': `Bearer ${testToken}`
  634. }
  635. });
  636. expect(response.status).toBe(200);
  637. if (response.status === 200) {
  638. const data = await response.json();
  639. expect(data.data).toHaveLength(1);
  640. expect(data.data[0].disabilityType).toBe('视力残疾');
  641. }
  642. });
  643. it('应该支持残疾级别筛选', async () => {
  644. // 创建测试数据
  645. const dataSource = await IntegrationTestDatabase.getDataSource();
  646. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  647. // 创建不同残疾级别的人员
  648. const person1 = disabledPersonRepository.create({
  649. name: '一级残疾人',
  650. gender: '男',
  651. idCard: '110101199001011361',
  652. disabilityId: 'D123456861',
  653. disabilityType: '肢体残疾',
  654. disabilityLevel: '一级',
  655. idAddress: '北京市测试区',
  656. phone: '1380013861',
  657. province: '北京市',
  658. city: '北京市'
  659. });
  660. await disabledPersonRepository.save(person1);
  661. const person2 = disabledPersonRepository.create({
  662. name: '二级残疾人',
  663. gender: '女',
  664. idCard: '110101199001011362',
  665. disabilityId: 'D123456862',
  666. disabilityType: '肢体残疾',
  667. disabilityLevel: '二级',
  668. idAddress: '北京市测试区',
  669. phone: '1380013862',
  670. province: '北京市',
  671. city: '北京市'
  672. });
  673. await disabledPersonRepository.save(person2);
  674. // 测试一级残疾筛选
  675. const response = await client.getAllDisabledPersons.$get({
  676. query: {
  677. disabilityLevel: '一级',
  678. skip: 0,
  679. take: 10
  680. }
  681. }, {
  682. headers: {
  683. 'Authorization': `Bearer ${testToken}`
  684. }
  685. });
  686. expect(response.status).toBe(200);
  687. if (response.status === 200) {
  688. const data = await response.json();
  689. expect(data.data).toHaveLength(1);
  690. expect(data.data[0].disabilityLevel).toBe('一级');
  691. }
  692. });
  693. it('应该支持省份筛选', async () => {
  694. // 创建测试数据
  695. const dataSource = await IntegrationTestDatabase.getDataSource();
  696. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  697. // 创建不同省份的人员
  698. const person1 = disabledPersonRepository.create({
  699. name: '北京人员',
  700. gender: '男',
  701. idCard: '110101199001011371',
  702. disabilityId: 'D123456871',
  703. disabilityType: '肢体残疾',
  704. disabilityLevel: '一级',
  705. idAddress: '北京市测试区',
  706. phone: '1380013871',
  707. province: '北京市',
  708. city: '北京市'
  709. });
  710. await disabledPersonRepository.save(person1);
  711. const person2 = disabledPersonRepository.create({
  712. name: '上海人员',
  713. gender: '女',
  714. idCard: '310101199001011372',
  715. disabilityId: 'D123456872',
  716. disabilityType: '肢体残疾',
  717. disabilityLevel: '二级',
  718. idAddress: '上海市测试区',
  719. phone: '1380013872',
  720. province: '上海市',
  721. city: '上海市'
  722. });
  723. await disabledPersonRepository.save(person2);
  724. // 测试北京筛选
  725. const response = await client.getAllDisabledPersons.$get({
  726. query: {
  727. province: '北京市',
  728. skip: 0,
  729. take: 10
  730. }
  731. }, {
  732. headers: {
  733. 'Authorization': `Bearer ${testToken}`
  734. }
  735. });
  736. expect(response.status).toBe(200);
  737. if (response.status === 200) {
  738. const data = await response.json();
  739. expect(data.data).toHaveLength(1);
  740. expect(data.data[0].province).toBe('北京市');
  741. }
  742. });
  743. it('应该支持多条件组合筛选', async () => {
  744. // 创建测试数据
  745. const dataSource = await IntegrationTestDatabase.getDataSource();
  746. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  747. // 创建符合多个条件的人员
  748. const person1 = disabledPersonRepository.create({
  749. name: '北京一级视力残疾人',
  750. gender: '男',
  751. idCard: '110101199001011381',
  752. disabilityId: 'D123456881',
  753. disabilityType: '视力残疾',
  754. disabilityLevel: '一级',
  755. idAddress: '北京市测试区',
  756. phone: '1380013881',
  757. province: '北京市',
  758. city: '北京市'
  759. });
  760. await disabledPersonRepository.save(person1);
  761. // 创建不符合全部条件的人员
  762. const person2 = disabledPersonRepository.create({
  763. name: '北京二级肢体残疾人',
  764. gender: '女',
  765. idCard: '110101199001011382',
  766. disabilityId: 'D123456882',
  767. disabilityType: '肢体残疾',
  768. disabilityLevel: '二级',
  769. idAddress: '北京市测试区',
  770. phone: '1380013882',
  771. province: '北京市',
  772. city: '北京市'
  773. });
  774. await disabledPersonRepository.save(person2);
  775. // 测试多条件组合筛选:北京 + 一级 + 视力残疾
  776. const response = await client.getAllDisabledPersons.$get({
  777. query: {
  778. province: '北京市',
  779. disabilityType: '视力残疾',
  780. disabilityLevel: '一级',
  781. skip: 0,
  782. take: 10
  783. }
  784. }, {
  785. headers: {
  786. 'Authorization': `Bearer ${testToken}`
  787. }
  788. });
  789. expect(response.status).toBe(200);
  790. if (response.status === 200) {
  791. const data = await response.json();
  792. expect(data.data).toHaveLength(1);
  793. expect(data.data[0].name).toBe('北京一级视力残疾人');
  794. }
  795. });
  796. });
  797. describe('GET /searchDisabledPersons', () => {
  798. it('应该成功按姓名搜索残疾人', async () => {
  799. // 创建测试数据
  800. const dataSource = await IntegrationTestDatabase.getDataSource();
  801. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  802. const person1 = disabledPersonRepository.create({
  803. name: '张三',
  804. gender: '男',
  805. idCard: '110101199001011241',
  806. disabilityId: 'D123456771',
  807. disabilityType: '肢体残疾',
  808. disabilityLevel: '一级',
  809. idAddress: '北京市昌平区',
  810. phone: '13000130001',
  811. province: '北京市',
  812. city: '北京市'
  813. });
  814. await disabledPersonRepository.save(person1);
  815. const person2 = disabledPersonRepository.create({
  816. name: '李四',
  817. gender: '女',
  818. idCard: '110101199001011242',
  819. disabilityId: 'D123456770',
  820. disabilityType: '视力残疾',
  821. disabilityLevel: '二级',
  822. idAddress: '北京市平谷区',
  823. phone: '13000130002',
  824. province: '北京市',
  825. city: '北京市'
  826. });
  827. await disabledPersonRepository.save(person2);
  828. const response = await client.searchDisabledPersons.$get({
  829. query: {
  830. keyword: '张三',
  831. skip: 0,
  832. take: 10
  833. }
  834. }, {
  835. headers: {
  836. 'Authorization': `Bearer ${testToken}`
  837. }
  838. });
  839. expect(response.status).toBe(200);
  840. if (response.status === 200) {
  841. const data = await response.json();
  842. expect(data.data).toHaveLength(1);
  843. expect(data.data[0].name).toBe('张三');
  844. }
  845. });
  846. it('应该验证搜索关键词不能为空', async () => {
  847. const response = await client.searchDisabledPersons.$get({
  848. query: {
  849. keyword: '', // 空关键词
  850. skip: 0,
  851. take: 10
  852. }
  853. }, {
  854. headers: {
  855. 'Authorization': `Bearer ${testToken}`
  856. }
  857. });
  858. expect(response.status).toBe(400);
  859. });
  860. });
  861. describe('GET /getDisabledPerson/{id}', () => {
  862. it('应该成功获取单个残疾人详情', async () => {
  863. // 先创建一个残疾人
  864. const dataSource = await IntegrationTestDatabase.getDataSource();
  865. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  866. const person = disabledPersonRepository.create({
  867. name: '测试人员详情',
  868. gender: '男',
  869. idCard: '110101199001011243',
  870. disabilityId: 'D123456769',
  871. disabilityType: '肢体残疾',
  872. disabilityLevel: '一级',
  873. idAddress: '北京市怀柔区',
  874. phone: '13000130003',
  875. province: '北京市',
  876. city: '北京市',
  877. canDirectContact: 1,
  878. isMarried: 1
  879. });
  880. await disabledPersonRepository.save(person);
  881. const response = await client.getDisabledPerson[':id'].$get({
  882. param: {
  883. id: person.id
  884. }
  885. }, {
  886. headers: {
  887. 'Authorization': `Bearer ${testToken}`
  888. }
  889. });
  890. expect(response.status).toBe(200);
  891. if (response.status === 200) {
  892. const data = await response.json();
  893. expect(data?.name).toBe('测试人员详情');
  894. expect(data?.canDirectContact).toBe(1);
  895. }
  896. });
  897. it('应该处理不存在的残疾人ID', async () => {
  898. const response = await client.getDisabledPerson[':id'].$get({
  899. param: {
  900. id: 99999 // 不存在的ID
  901. }
  902. }, {
  903. headers: {
  904. 'Authorization': `Bearer ${testToken}`
  905. }
  906. });
  907. expect(response.status).toBe(200); // 返回200,但数据为null
  908. if (response.status === 200) {
  909. const data = await response.json();
  910. expect(data).toBeNull();
  911. }
  912. });
  913. });
  914. describe('GET /getDisabledPersonByIdCard', () => {
  915. it('应该成功根据身份证号查询残疾人', async () => {
  916. // 先创建一个残疾人
  917. const dataSource = await IntegrationTestDatabase.getDataSource();
  918. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  919. const person = disabledPersonRepository.create({
  920. name: '身份证查询测试',
  921. gender: '女',
  922. idCard: '110101199001011244',
  923. disabilityId: 'D123456768',
  924. disabilityType: '听力残疾',
  925. disabilityLevel: '三级',
  926. idAddress: '北京市密云区',
  927. phone: '13000130004',
  928. province: '北京市',
  929. city: '北京市'
  930. });
  931. await disabledPersonRepository.save(person);
  932. const response = await client.findByIdCard[':idCard'].$get({
  933. param: {
  934. idCard: '110101199001011244'
  935. }
  936. }, {
  937. headers: {
  938. 'Authorization': `Bearer ${testToken}`
  939. }
  940. });
  941. expect(response.status).toBe(200);
  942. if (response.status === 200) {
  943. const data = await response.json();
  944. expect(data?.name).toBe('身份证查询测试');
  945. expect(data?.idCard).toBe('110101199001011244');
  946. }
  947. });
  948. it('应该处理不存在的身份证号', async () => {
  949. const response = await client.findByIdCard[':idCard'].$get({
  950. param: {
  951. idCard: '999999999999999999' // 不存在的身份证号
  952. }
  953. }, {
  954. headers: {
  955. 'Authorization': `Bearer ${testToken}`
  956. }
  957. });
  958. expect(response.status).toBe(200); // 返回200,但数据为null
  959. if (response.status === 200) {
  960. const data = await response.json();
  961. expect(data).toBeNull();
  962. }
  963. });
  964. });
  965. describe('POST /createAggregatedDisabledPerson', () => {
  966. it('应该成功创建聚合残疾人信息(包含所有关联数据)', async () => {
  967. const createData = {
  968. personInfo: {
  969. name: '聚合创建测试',
  970. gender: '男',
  971. idCard: '110101199001011245',
  972. disabilityId: 'D123456767',
  973. disabilityType: '肢体残疾',
  974. disabilityLevel: '一级',
  975. idAddress: '北京市延庆区',
  976. phone: '13000130005',
  977. province: '北京市',
  978. city: '北京市',
  979. // 新增字段
  980. canDirectContact: 1,
  981. isInBlackList: 0,
  982. jobStatus: 1,
  983. specificDisability: '左腿截肢,右腿行动不便,需要轮椅',
  984. // 日期字段
  985. idValidDate: new Date('2045-11-30'),
  986. disabilityValidDate: new Date('2045-11-30')
  987. },
  988. bankCards: [
  989. {
  990. subBankName: '北京分行',
  991. bankName: '中国工商银行',
  992. cardNumber: '6222021234567890123',
  993. cardholderName: '聚合创建测试',
  994. fileId: testFile.id,
  995. isDefault: 0
  996. }
  997. ],
  998. photos: [
  999. {
  1000. photoType: '身份证照片',
  1001. fileId: testFile.id // 使用测试文件ID
  1002. }
  1003. ],
  1004. remarks: [
  1005. {
  1006. remarkContent: '家庭经济困难,需要帮助',
  1007. operatorId: 1
  1008. }
  1009. ],
  1010. visits: [
  1011. {
  1012. visitDate: '2025-12-02T10:00:00Z',
  1013. visitType: '电话回访',
  1014. visitContent: '初次回访,了解基本情况',
  1015. visitorId: 1
  1016. }
  1017. ]
  1018. };
  1019. const response = await client.createAggregatedDisabledPerson.$post({
  1020. json: createData
  1021. }, {
  1022. headers: {
  1023. 'Authorization': `Bearer ${testToken}`
  1024. }
  1025. });
  1026. expect(response.status).toBe(200);
  1027. if (response.status === 200) {
  1028. const data = await response.json();
  1029. expect(data.personInfo.name).toBe('聚合创建测试');
  1030. // 验证新增字段
  1031. expect(data.personInfo.canDirectContact).toBe(1);
  1032. expect(data.personInfo.isInBlackList).toBe(0);
  1033. expect(data.personInfo.jobStatus).toBe(1);
  1034. expect(data.personInfo.specificDisability).toBe('左腿截肢,右腿行动不便,需要轮椅');
  1035. // 验证日期字段
  1036. expect(data.personInfo.idValidDate).toBeDefined();
  1037. expect(data.personInfo.disabilityValidDate).toBeDefined();
  1038. if (data.personInfo.idValidDate) {
  1039. expect(new Date(data.personInfo.idValidDate).toISOString().split('T')[0]).toBe('2045-11-30');
  1040. }
  1041. if (data.personInfo.disabilityValidDate) {
  1042. expect(new Date(data.personInfo.disabilityValidDate).toISOString().split('T')[0]).toBe('2045-11-30');
  1043. }
  1044. expect(data.bankCards).toHaveLength(1);
  1045. expect(data.photos).toHaveLength(1);
  1046. expect(data.remarks).toHaveLength(1);
  1047. expect(data.visits).toHaveLength(1);
  1048. // 验证文件集成
  1049. expect(data.photos[0].fileId).toBe(testFile.id);
  1050. }
  1051. });
  1052. it('应该验证文件ID的有效性', async () => {
  1053. const createData = {
  1054. personInfo: {
  1055. name: '文件验证测试',
  1056. gender: '女',
  1057. idCard: '110101199001011246',
  1058. disabilityId: 'D123456766',
  1059. disabilityType: '视力残疾',
  1060. disabilityLevel: '二级',
  1061. idAddress: '北京市房山区',
  1062. phone: '13000130006',
  1063. province: '北京市',
  1064. city: '北京市',
  1065. // 新增字段
  1066. canDirectContact: 0,
  1067. isInBlackList: 1,
  1068. jobStatus: 2,
  1069. // 日期字段
  1070. idValidDate: new Date('2036-07-25'),
  1071. disabilityValidDate: new Date('2036-07-25')
  1072. },
  1073. photos: [
  1074. {
  1075. photoType: '身份证照片',
  1076. fileId: 99999 // 不存在的文件ID
  1077. }
  1078. ]
  1079. };
  1080. const response = await client.createAggregatedDisabledPerson.$post({
  1081. json: createData
  1082. }, {
  1083. headers: {
  1084. 'Authorization': `Bearer ${testToken}`
  1085. }
  1086. });
  1087. expect(response.status).toBe(400); // 应该返回400,因为文件ID无效
  1088. });
  1089. });
  1090. describe('GET /getAggregatedDisabledPerson/{personId}', () => {
  1091. it('应该成功获取聚合残疾人信息', async () => {
  1092. // 先创建一个完整的残疾人数据(包含所有关联数据)
  1093. const dataSource = await IntegrationTestDatabase.getDataSource();
  1094. // 创建残疾人
  1095. const disabledPersonRepository = dataSource.getRepository(DisabledPerson);
  1096. const person = disabledPersonRepository.create({
  1097. name: '聚合查询测试',
  1098. gender: '男',
  1099. idCard: '110101199001011247',
  1100. disabilityId: 'D123456765',
  1101. disabilityType: '肢体残疾',
  1102. disabilityLevel: '一级',
  1103. idAddress: '北京市门头沟区',
  1104. phone: '13000130007',
  1105. province: '北京市',
  1106. city: '北京市'
  1107. });
  1108. await disabledPersonRepository.save(person);
  1109. // 创建银行卡
  1110. const bankCardRepository = dataSource.getRepository(DisabledBankCard);
  1111. const bankCard = bankCardRepository.create({
  1112. personId: person.id,
  1113. subBankName: '北京分行',
  1114. bankName: '中国建设银行',
  1115. cardNumber: '6227001234567890123',
  1116. cardholderName: '聚合查询测试',
  1117. fileId: testFile.id,
  1118. isDefault: 0
  1119. });
  1120. await bankCardRepository.save(bankCard);
  1121. // 创建照片(使用测试文件)
  1122. const photoRepository = dataSource.getRepository(DisabledPhoto);
  1123. const photo = photoRepository.create({
  1124. personId: person.id,
  1125. photoType: '身份证照片',
  1126. fileId: testFile.id
  1127. });
  1128. await photoRepository.save(photo);
  1129. // 创建备注
  1130. const remarkRepository = dataSource.getRepository(DisabledRemark);
  1131. const remark = remarkRepository.create({
  1132. personId: person.id,
  1133. remarkContent: '目前无工作,需要就业帮助',
  1134. operatorId: 1
  1135. });
  1136. await remarkRepository.save(remark);
  1137. // 创建回访记录
  1138. const visitRepository = dataSource.getRepository(DisabledVisit);
  1139. const visit = visitRepository.create({
  1140. personId: person.id,
  1141. visitDate: new Date('2025-12-01T14:30:00Z'),
  1142. visitType: '上门回访',
  1143. visitContent: '了解就业需求',
  1144. visitorId: 2
  1145. });
  1146. await visitRepository.save(visit);
  1147. const response = await client.getAggregatedDisabledPerson[':id'].$get({
  1148. param: {
  1149. id: person.id
  1150. }
  1151. }, {
  1152. headers: {
  1153. 'Authorization': `Bearer ${testToken}`
  1154. }
  1155. });
  1156. // 调试:打印响应状态和错误信息
  1157. console.debug('响应状态:', response.status);
  1158. if (response.status !== 200) {
  1159. const errorText = await response.text();
  1160. console.debug('错误响应:', errorText);
  1161. }
  1162. expect(response.status).toBe(200);
  1163. if (response.status === 200) {
  1164. const data = await response.json();
  1165. expect(data).not.toBeNull();
  1166. expect(data!.personInfo.name).toBe('聚合查询测试');
  1167. expect(data!.bankCards).toHaveLength(1);
  1168. expect(data!.photos).toHaveLength(1);
  1169. expect(data!.remarks).toHaveLength(1);
  1170. expect(data!.visits).toHaveLength(1);
  1171. // 验证文件数据完整性
  1172. expect(data!.photos[0].fileId).toBe(testFile.id);
  1173. }
  1174. });
  1175. it('应该处理不存在的残疾人ID', async () => {
  1176. const response = await client.getAggregatedDisabledPerson[':id'].$get({
  1177. param: {
  1178. id: 99999 // 不存在的ID
  1179. }
  1180. }, {
  1181. headers: {
  1182. 'Authorization': `Bearer ${testToken}`
  1183. }
  1184. });
  1185. expect(response.status).toBe(404);
  1186. });
  1187. });
  1188. describe('认证测试', () => {
  1189. it('应该验证所有端点需要认证', async () => {
  1190. // 测试没有token的情况
  1191. const response = await client.createDisabledPerson.$post({
  1192. json: {
  1193. name: '测试人员',
  1194. gender: '男',
  1195. idCard: '110101199001011235',
  1196. disabilityId: 'D123456789',
  1197. disabilityType: '视力残疾',
  1198. disabilityLevel: '一级',
  1199. idAddress: '北京市东城区',
  1200. phone: '13800138000',
  1201. province: '北京市',
  1202. city: '北京市'
  1203. }
  1204. });
  1205. expect(response.status).toBe(401);
  1206. });
  1207. it('应该验证无效token', async () => {
  1208. const response = await client.createDisabledPerson.$post({
  1209. json: {
  1210. name: '测试人员',
  1211. gender: '男',
  1212. idCard: '110101199001011236',
  1213. disabilityId: 'D123456790',
  1214. disabilityType: '视力残疾',
  1215. disabilityLevel: '一级',
  1216. idAddress: '北京市东城区',
  1217. phone: '13800138001',
  1218. province: '北京市',
  1219. city: '北京市'
  1220. }
  1221. }, {
  1222. headers: {
  1223. 'Authorization': 'Bearer invalid_token'
  1224. }
  1225. });
  1226. expect(response.status).toBe(401);
  1227. });
  1228. });
  1229. });