2
0

admin-orders.integration.test.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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 { DeliveryAddress } from '@d8d/delivery-address-module';
  7. import { AreaEntity } from '@d8d/geo-areas';
  8. import { Merchant } from '@d8d/merchant-module';
  9. import { Supplier } from '@d8d/supplier-module';
  10. import { File } from '@d8d/file-module';
  11. import { adminOrderRoutes } from '../../src/routes/admin/orders';
  12. import { Order } from '../../src/entities';
  13. // 设置集成测试钩子
  14. setupIntegrationDatabaseHooksWithEntities([
  15. UserEntity, Role, Order, DeliveryAddress, Merchant, Supplier, File, AreaEntity
  16. ])
  17. describe('管理员订单管理API集成测试', () => {
  18. let client: ReturnType<typeof testClient<typeof adminOrderRoutes>>;
  19. let adminToken: string;
  20. let testUser: UserEntity;
  21. let testAdmin: UserEntity;
  22. let testDeliveryAddress: DeliveryAddress;
  23. let testMerchant: Merchant;
  24. let testSupplier: Supplier;
  25. beforeEach(async () => {
  26. // 创建测试客户端
  27. client = testClient(adminOrderRoutes);
  28. // 获取数据源
  29. const dataSource = await IntegrationTestDatabase.getDataSource();
  30. // 创建测试用户
  31. const userRepository = dataSource.getRepository(UserEntity);
  32. testUser = userRepository.create({
  33. username: `test_user_${Math.floor(Math.random() * 100000)}`,
  34. password: 'test_password',
  35. nickname: '测试用户',
  36. registrationSource: 'web'
  37. });
  38. await userRepository.save(testUser);
  39. // 创建测试管理员用户
  40. testAdmin = userRepository.create({
  41. username: `test_admin_${Math.floor(Math.random() * 100000)}`,
  42. password: 'admin_password',
  43. nickname: '测试管理员',
  44. registrationSource: 'web'
  45. });
  46. await userRepository.save(testAdmin);
  47. // 生成测试管理员的token
  48. adminToken = JWTUtil.generateToken({
  49. id: testAdmin.id,
  50. username: testAdmin.username,
  51. roles: [{name:'admin'}]
  52. });
  53. // 创建测试配送地址
  54. const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
  55. testDeliveryAddress = deliveryAddressRepository.create({
  56. userId: testUser.id,
  57. name: '收货人姓名',
  58. phone: '13800138000',
  59. province: '广东省',
  60. city: '深圳市',
  61. district: '南山区',
  62. address: '测试地址',
  63. isDefault: 1,
  64. state: 1,
  65. createdBy: testUser.id
  66. });
  67. await deliveryAddressRepository.save(testDeliveryAddress);
  68. // 创建测试商户
  69. const merchantRepository = dataSource.getRepository(Merchant);
  70. testMerchant = merchantRepository.create({
  71. name: '测试商户',
  72. username: `test_merchant_${Math.floor(Math.random() * 100000)}`,
  73. password: 'password123',
  74. phone: '13800138001',
  75. realname: '测试商户',
  76. state: 1,
  77. createdBy: testUser.id
  78. });
  79. await merchantRepository.save(testMerchant);
  80. // 创建测试供应商
  81. const supplierRepository = dataSource.getRepository(Supplier);
  82. testSupplier = supplierRepository.create({
  83. name: '测试供应商',
  84. username: `test_supplier_${Math.floor(Math.random() * 100000)}`,
  85. password: 'password123',
  86. phone: '13800138002',
  87. realname: '测试供应商',
  88. state: 1,
  89. createdBy: testUser.id
  90. });
  91. await supplierRepository.save(testSupplier);
  92. });
  93. describe('GET /orders', () => {
  94. it('应该返回所有订单列表', async () => {
  95. // 创建多个用户的订单
  96. const dataSource = await IntegrationTestDatabase.getDataSource();
  97. const orderRepository = dataSource.getRepository(Order);
  98. const userOrder1 = orderRepository.create({
  99. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  100. userId: testUser.id,
  101. amount: 100.00,
  102. costAmount: 80.00,
  103. payAmount: 100.00,
  104. orderType: 1,
  105. payType: 1,
  106. payState: 2,
  107. state: 0,
  108. deliveryAddressId: testDeliveryAddress.id,
  109. merchantId: testMerchant.id,
  110. supplierId: testSupplier.id,
  111. createdBy: testUser.id
  112. });
  113. await orderRepository.save(userOrder1);
  114. const userOrder2 = orderRepository.create({
  115. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  116. userId: testAdmin.id,
  117. amount: 200.00,
  118. costAmount: 160.00,
  119. payAmount: 200.00,
  120. orderType: 1,
  121. payType: 1,
  122. payState: 2,
  123. state: 1,
  124. deliveryAddressId: testDeliveryAddress.id,
  125. merchantId: testMerchant.id,
  126. supplierId: testSupplier.id,
  127. createdBy: testAdmin.id
  128. });
  129. await orderRepository.save(userOrder2);
  130. const response = await client.index.$get({
  131. query: {}
  132. }, {
  133. headers: {
  134. 'Authorization': `Bearer ${adminToken}`
  135. }
  136. });
  137. console.debug('管理员订单列表响应状态:', response.status);
  138. expect(response.status).toBe(200);
  139. if (response.status === 200) {
  140. const data = await response.json();
  141. expect(data).toHaveProperty('data');
  142. expect(Array.isArray(data.data)).toBe(true);
  143. // 验证返回所有用户的订单(管理员可以访问所有数据)
  144. const userOrderCount = data.data.filter((order: any) => order.userId === testUser.id).length;
  145. const adminOrderCount = data.data.filter((order: any) => order.userId === testAdmin.id).length;
  146. expect(userOrderCount).toBeGreaterThan(0);
  147. expect(adminOrderCount).toBeGreaterThan(0);
  148. }
  149. });
  150. it('应该拒绝未认证用户的访问', async () => {
  151. const response = await client.index.$get({
  152. query: {}
  153. });
  154. expect(response.status).toBe(401);
  155. });
  156. });
  157. describe('POST /orders', () => {
  158. it('应该成功创建订单并可以指定权限', async () => {
  159. const createData = {
  160. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  161. userId: testUser.id,
  162. amount: 150.00,
  163. costAmount: 120.00,
  164. payAmount: 150.00,
  165. orderType: 1,
  166. payType: 1,
  167. payState: 0,
  168. state: 0,
  169. deliveryAddressId: testDeliveryAddress.id,
  170. merchantId: testMerchant.id,
  171. supplierId: testSupplier.id,
  172. createdBy: testUser.id // 管理员可以指定创建人
  173. };
  174. const response = await client.index.$post({
  175. json: createData
  176. }, {
  177. headers: {
  178. 'Authorization': `Bearer ${adminToken}`
  179. }
  180. });
  181. console.debug('管理员创建订单响应状态:', response.status);
  182. if (response.status !== 201) {
  183. const errorData = await response.json();
  184. console.debug('管理员创建订单错误响应:', errorData);
  185. }
  186. expect(response.status).toBe(201);
  187. if (response.status === 201) {
  188. const data = await response.json();
  189. expect(data).toHaveProperty('id');
  190. expect(data.orderNo).toBe(createData.orderNo);
  191. expect(parseFloat(data.amount)).toBe(createData.amount);
  192. expect(data.userId).toBe(createData.userId); // 验证可以指定用户
  193. expect(data.createdBy).toBe(testUser.id); // 验证可以指定创建人
  194. }
  195. });
  196. it('应该验证创建订单的必填字段', async () => {
  197. const invalidData = {
  198. // 缺少必填字段
  199. amount: -1,
  200. orderType: -1
  201. };
  202. const response = await client.index.$post({
  203. json: invalidData
  204. }, {
  205. headers: {
  206. 'Authorization': `Bearer ${adminToken}`
  207. }
  208. });
  209. expect(response.status).toBe(400);
  210. });
  211. });
  212. describe('GET /orders/:id', () => {
  213. it('应该返回指定订单的详情', async () => {
  214. // 先创建一个订单
  215. const dataSource = await IntegrationTestDatabase.getDataSource();
  216. const orderRepository = dataSource.getRepository(Order);
  217. const testOrder = orderRepository.create({
  218. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  219. userId: testUser.id,
  220. amount: 100.00,
  221. costAmount: 80.00,
  222. payAmount: 100.00,
  223. orderType: 1,
  224. payType: 1,
  225. payState: 2,
  226. state: 0,
  227. deliveryAddressId: testDeliveryAddress.id,
  228. merchantId: testMerchant.id,
  229. supplierId: testSupplier.id,
  230. createdBy: testUser.id
  231. });
  232. await orderRepository.save(testOrder);
  233. const response = await client[':id'].$get({
  234. param: { id: testOrder.id }
  235. }, {
  236. headers: {
  237. 'Authorization': `Bearer ${adminToken}`
  238. }
  239. });
  240. console.debug('管理员订单详情响应状态:', response.status);
  241. expect(response.status).toBe(200);
  242. if (response.status === 200) {
  243. const data = await response.json();
  244. expect(data.id).toBe(testOrder.id);
  245. expect(data.orderNo).toBe(testOrder.orderNo);
  246. expect(data.userId).toBe(testUser.id);
  247. }
  248. });
  249. it('应该处理不存在的订单', async () => {
  250. const response = await client[':id'].$get({
  251. param: { id: 999999 }
  252. }, {
  253. headers: {
  254. 'Authorization': `Bearer ${adminToken}`
  255. }
  256. });
  257. expect(response.status).toBe(404);
  258. });
  259. });
  260. describe('PUT /orders/:id', () => {
  261. it('应该成功更新任何订单', async () => {
  262. // 先创建一个订单
  263. const dataSource = await IntegrationTestDatabase.getDataSource();
  264. const orderRepository = dataSource.getRepository(Order);
  265. const testOrder = orderRepository.create({
  266. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  267. userId: testUser.id,
  268. amount: 100.00,
  269. costAmount: 80.00,
  270. payAmount: 100.00,
  271. orderType: 1,
  272. payType: 1,
  273. payState: 2,
  274. state: 0,
  275. deliveryAddressId: testDeliveryAddress.id,
  276. merchantId: testMerchant.id,
  277. supplierId: testSupplier.id,
  278. createdBy: testUser.id
  279. });
  280. await orderRepository.save(testOrder);
  281. const updateData = {
  282. state: 1,
  283. payState: 1,
  284. updatedBy: testAdmin.id // 管理员可以指定更新人
  285. };
  286. const response = await client[':id'].$put({
  287. param: { id: testOrder.id },
  288. json: updateData
  289. }, {
  290. headers: {
  291. 'Authorization': `Bearer ${adminToken}`
  292. }
  293. });
  294. console.debug('管理员更新订单响应状态:', response.status);
  295. expect(response.status).toBe(200);
  296. if (response.status === 200) {
  297. const data = await response.json();
  298. expect(data.state).toBe(updateData.state);
  299. expect(data.payState).toBe(updateData.payState);
  300. expect(data.updatedBy).toBe(testAdmin.id); // 验证可以指定更新人
  301. }
  302. });
  303. });
  304. describe('DELETE /orders/:id', () => {
  305. it('应该成功删除任何订单', async () => {
  306. // 先创建一个订单
  307. const dataSource = await IntegrationTestDatabase.getDataSource();
  308. const orderRepository = dataSource.getRepository(Order);
  309. const testOrder = orderRepository.create({
  310. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  311. userId: testUser.id,
  312. amount: 100.00,
  313. costAmount: 80.00,
  314. payAmount: 100.00,
  315. orderType: 1,
  316. payType: 1,
  317. payState: 2,
  318. state: 0,
  319. deliveryAddressId: testDeliveryAddress.id,
  320. merchantId: testMerchant.id,
  321. supplierId: testSupplier.id,
  322. createdBy: testUser.id
  323. });
  324. await orderRepository.save(testOrder);
  325. const response = await client[':id'].$delete({
  326. param: { id: testOrder.id }
  327. }, {
  328. headers: {
  329. 'Authorization': `Bearer ${adminToken}`
  330. }
  331. });
  332. console.debug('管理员删除订单响应状态:', response.status);
  333. expect(response.status).toBe(204);
  334. });
  335. });
  336. describe('订单状态管理测试', () => {
  337. it('应该正确处理订单状态变更', async () => {
  338. const dataSource = await IntegrationTestDatabase.getDataSource();
  339. const orderRepository = dataSource.getRepository(Order);
  340. // 创建不同状态的订单
  341. const pendingOrder = orderRepository.create({
  342. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  343. userId: testUser.id,
  344. amount: 100.00,
  345. costAmount: 80.00,
  346. payAmount: 100.00,
  347. orderType: 1,
  348. payType: 1,
  349. payState: 2,
  350. state: 0, // 未发货
  351. deliveryAddressId: testDeliveryAddress.id,
  352. merchantId: testMerchant.id,
  353. supplierId: testSupplier.id,
  354. createdBy: testUser.id
  355. });
  356. await orderRepository.save(pendingOrder);
  357. const shippedOrder = orderRepository.create({
  358. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  359. userId: testUser.id,
  360. amount: 200.00,
  361. costAmount: 160.00,
  362. payAmount: 200.00,
  363. orderType: 1,
  364. payType: 1,
  365. payState: 2,
  366. state: 1, // 已发货
  367. deliveryAddressId: testDeliveryAddress.id,
  368. merchantId: testMerchant.id,
  369. supplierId: testSupplier.id,
  370. createdBy: testUser.id
  371. });
  372. await orderRepository.save(shippedOrder);
  373. const completedOrder = orderRepository.create({
  374. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  375. userId: testUser.id,
  376. amount: 300.00,
  377. costAmount: 240.00,
  378. payAmount: 300.00,
  379. orderType: 1,
  380. payType: 1,
  381. payState: 2,
  382. state: 2, // 收货成功
  383. deliveryAddressId: testDeliveryAddress.id,
  384. merchantId: testMerchant.id,
  385. supplierId: testSupplier.id,
  386. createdBy: testUser.id
  387. });
  388. await orderRepository.save(completedOrder);
  389. // 验证状态过滤
  390. const response = await client.index.$get({
  391. query: { filters: JSON.stringify({ state: 1 }) }
  392. }, {
  393. headers: {
  394. 'Authorization': `Bearer ${adminToken}`
  395. }
  396. });
  397. expect(response.status).toBe(200);
  398. const data = await response.json();
  399. // 类型检查确保data属性存在
  400. if ('data' in data && Array.isArray(data.data)) {
  401. // 应该只返回已发货状态的订单
  402. const pendingOrdersInResponse = data.data.filter((order: any) => order.state === 0);
  403. const shippedOrdersInResponse = data.data.filter((order: any) => order.state === 1);
  404. const completedOrdersInResponse = data.data.filter((order: any) => order.state === 2);
  405. expect(pendingOrdersInResponse.length).toBe(0);
  406. expect(shippedOrdersInResponse.length).toBeGreaterThan(0);
  407. expect(completedOrdersInResponse.length).toBe(0);
  408. } else {
  409. // 如果响应是错误格式,应该失败
  410. expect(data).toHaveProperty('data');
  411. }
  412. });
  413. });
  414. describe('支付状态管理测试', () => {
  415. it('应该正确处理支付状态变更', async () => {
  416. const dataSource = await IntegrationTestDatabase.getDataSource();
  417. const orderRepository = dataSource.getRepository(Order);
  418. // 创建不同支付状态的订单
  419. const unpaidOrder = orderRepository.create({
  420. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  421. userId: testUser.id,
  422. amount: 100.00,
  423. costAmount: 80.00,
  424. payAmount: 100.00,
  425. orderType: 1,
  426. payType: 1,
  427. payState: 0, // 未支付
  428. state: 0,
  429. deliveryAddressId: testDeliveryAddress.id,
  430. merchantId: testMerchant.id,
  431. supplierId: testSupplier.id,
  432. createdBy: testUser.id
  433. });
  434. await orderRepository.save(unpaidOrder);
  435. const payingOrder = orderRepository.create({
  436. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  437. userId: testUser.id,
  438. amount: 200.00,
  439. costAmount: 160.00,
  440. payAmount: 200.00,
  441. orderType: 1,
  442. payType: 1,
  443. payState: 1, // 支付中
  444. state: 0,
  445. deliveryAddressId: testDeliveryAddress.id,
  446. merchantId: testMerchant.id,
  447. supplierId: testSupplier.id,
  448. createdBy: testUser.id
  449. });
  450. await orderRepository.save(payingOrder);
  451. const paidOrder = orderRepository.create({
  452. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  453. userId: testUser.id,
  454. amount: 300.00,
  455. costAmount: 240.00,
  456. payAmount: 300.00,
  457. orderType: 1,
  458. payType: 1,
  459. payState: 2, // 支付成功
  460. state: 0,
  461. deliveryAddressId: testDeliveryAddress.id,
  462. merchantId: testMerchant.id,
  463. supplierId: testSupplier.id,
  464. createdBy: testUser.id
  465. });
  466. await orderRepository.save(paidOrder);
  467. // 验证支付状态过滤
  468. const response = await client.index.$get({
  469. query: { filters: JSON.stringify({ payState: 2 }) }
  470. }, {
  471. headers: {
  472. 'Authorization': `Bearer ${adminToken}`
  473. }
  474. });
  475. expect(response.status).toBe(200);
  476. const data = await response.json();
  477. // 类型检查确保data属性存在
  478. if ('data' in data && Array.isArray(data.data)) {
  479. // 应该只返回支付成功状态的订单
  480. const unpaidOrdersInResponse = data.data.filter((order: any) => order.payState === 0);
  481. const payingOrdersInResponse = data.data.filter((order: any) => order.payState === 1);
  482. const paidOrdersInResponse = data.data.filter((order: any) => order.payState === 2);
  483. expect(unpaidOrdersInResponse.length).toBe(0);
  484. expect(payingOrdersInResponse.length).toBe(0);
  485. expect(paidOrdersInResponse.length).toBeGreaterThan(0);
  486. } else {
  487. // 如果响应是错误格式,应该失败
  488. expect(data).toHaveProperty('data');
  489. }
  490. });
  491. });
  492. describe('管理员权限验证测试', () => {
  493. it('应该验证管理员可以访问所有数据', async () => {
  494. const dataSource = await IntegrationTestDatabase.getDataSource();
  495. const orderRepository = dataSource.getRepository(Order);
  496. // 创建多个用户的订单
  497. const userOrder = orderRepository.create({
  498. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  499. userId: testUser.id,
  500. amount: 100.00,
  501. costAmount: 80.00,
  502. payAmount: 100.00,
  503. orderType: 1,
  504. payType: 1,
  505. payState: 2,
  506. state: 0,
  507. deliveryAddressId: testDeliveryAddress.id,
  508. merchantId: testMerchant.id,
  509. supplierId: testSupplier.id,
  510. createdBy: testUser.id
  511. });
  512. await orderRepository.save(userOrder);
  513. const adminOrder = orderRepository.create({
  514. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  515. userId: testAdmin.id,
  516. amount: 200.00,
  517. costAmount: 160.00,
  518. payAmount: 200.00,
  519. orderType: 1,
  520. payType: 1,
  521. payState: 2,
  522. state: 0,
  523. deliveryAddressId: testDeliveryAddress.id,
  524. merchantId: testMerchant.id,
  525. supplierId: testSupplier.id,
  526. createdBy: testAdmin.id
  527. });
  528. await orderRepository.save(adminOrder);
  529. // 使用管理员token获取列表
  530. const response = await client.index.$get({
  531. query: {}
  532. }, {
  533. headers: {
  534. 'Authorization': `Bearer ${adminToken}`
  535. }
  536. });
  537. expect(response.status).toBe(200);
  538. const data = await response.json();
  539. // 类型检查确保data属性存在
  540. if ('data' in data && Array.isArray(data.data)) {
  541. // 验证返回所有用户的订单
  542. const userOrdersInResponse = data.data.filter((order: any) => order.userId === testUser.id);
  543. const adminOrdersInResponse = data.data.filter((order: any) => order.userId === testAdmin.id);
  544. expect(userOrdersInResponse.length).toBeGreaterThan(0);
  545. expect(adminOrdersInResponse.length).toBeGreaterThan(0);
  546. } else {
  547. // 如果响应是错误格式,应该失败
  548. expect(data).toHaveProperty('data');
  549. }
  550. });
  551. });
  552. });