admin-order-items.integration.test.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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 { Goods, GoodsCategory } from '@d8d/goods-module';
  8. import { Supplier } from '@d8d/supplier-module';
  9. import { Merchant } from '@d8d/merchant-module';
  10. import { DeliveryAddress } from '@d8d/delivery-address-module';
  11. import { AreaEntity } from '@d8d/geo-areas';
  12. import { adminOrderItemsRoutes } from '../../src/routes/admin/order-items';
  13. import { Order, OrderGoods } from '../../src/entities';
  14. // 设置集成测试钩子
  15. setupIntegrationDatabaseHooksWithEntities([
  16. UserEntity, Role, Order, OrderGoods, Goods, GoodsCategory, File, Supplier, Merchant, DeliveryAddress, AreaEntity
  17. ])
  18. describe('管理员订单商品管理API集成测试', () => {
  19. let client: ReturnType<typeof testClient<typeof adminOrderItemsRoutes>>;
  20. let adminToken: string;
  21. let testUser: UserEntity;
  22. let testAdmin: UserEntity;
  23. let testOrder: Order;
  24. let otherUserOrder: Order;
  25. let testGoods: Goods;
  26. let testSupplier: Supplier;
  27. let testFile: File;
  28. beforeEach(async () => {
  29. // 创建测试客户端
  30. client = testClient(adminOrderItemsRoutes);
  31. // 获取数据源
  32. const dataSource = await IntegrationTestDatabase.getDataSource();
  33. // 创建测试用户
  34. const userRepository = dataSource.getRepository(UserEntity);
  35. testUser = userRepository.create({
  36. username: `test_user_${Math.floor(Math.random() * 100000)}`,
  37. password: 'test_password',
  38. nickname: '测试用户',
  39. registrationSource: 'web'
  40. });
  41. await userRepository.save(testUser);
  42. // 创建测试管理员用户
  43. testAdmin = userRepository.create({
  44. username: `test_admin_${Math.floor(Math.random() * 100000)}`,
  45. password: 'admin_password',
  46. nickname: '测试管理员',
  47. registrationSource: 'web'
  48. });
  49. await userRepository.save(testAdmin);
  50. // 生成测试管理员的token
  51. adminToken = JWTUtil.generateToken({
  52. id: testAdmin.id,
  53. username: testAdmin.username,
  54. roles: [{name:'admin'}]
  55. });
  56. // 创建测试商品
  57. const goodsRepository = dataSource.getRepository(Goods);
  58. testGoods = goodsRepository.create({
  59. name: '测试商品',
  60. price: 100.00,
  61. costPrice: 80.00,
  62. categoryId1: 1,
  63. categoryId2: 1,
  64. categoryId3: 1,
  65. goodsType: 1,
  66. supplierId: 1,
  67. state: 1,
  68. stock: 100,
  69. lowestBuy: 1,
  70. createdBy: testUser.id
  71. });
  72. await goodsRepository.save(testGoods);
  73. // 创建测试供应商
  74. const supplierRepository = dataSource.getRepository(Supplier);
  75. testSupplier = supplierRepository.create({
  76. name: '测试供应商',
  77. username: `test_supplier_${Math.floor(Math.random() * 100000)}`,
  78. password: 'password123',
  79. phone: '13800138000',
  80. realname: '测试供应商',
  81. state: 1,
  82. createdBy: testUser.id
  83. });
  84. await supplierRepository.save(testSupplier);
  85. // 创建测试文件
  86. const fileRepository = dataSource.getRepository(File);
  87. testFile = fileRepository.create({
  88. name: 'test_image.jpg',
  89. type: 'image/jpeg',
  90. size: 102400,
  91. path: 'images/test_image.jpg',
  92. uploadUserId: testUser.id,
  93. uploadTime: new Date(),
  94. createdAt: new Date(),
  95. updatedAt: new Date()
  96. });
  97. await fileRepository.save(testFile);
  98. // 创建测试用户的订单
  99. const orderRepository = dataSource.getRepository(Order);
  100. testOrder = orderRepository.create({
  101. orderNo: `ORDER_${Math.floor(Math.random() * 100000)}`,
  102. userId: testUser.id,
  103. amount: 100.00,
  104. costAmount: 80.00,
  105. payAmount: 100.00,
  106. orderType: 1,
  107. payType: 1,
  108. payState: 2,
  109. state: 0,
  110. createdBy: testUser.id
  111. });
  112. await orderRepository.save(testOrder);
  113. // 创建其他用户的订单
  114. otherUserOrder = 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: 0,
  124. createdBy: testAdmin.id
  125. });
  126. await orderRepository.save(otherUserOrder);
  127. });
  128. describe('GET /order-items', () => {
  129. it('应该返回所有订单的商品列表', async () => {
  130. // 为不同用户的订单创建商品
  131. const dataSource = await IntegrationTestDatabase.getDataSource();
  132. const orderGoodsRepository = dataSource.getRepository(OrderGoods);
  133. const userOrderGoods = orderGoodsRepository.create({
  134. orderId: testOrder.id,
  135. goodsId: testGoods.id,
  136. goodsName: '测试用户商品',
  137. price: 50.00,
  138. num: 2,
  139. state: 0,
  140. supplierId: testSupplier.id,
  141. imageFileId: testFile.id,
  142. createdBy: testUser.id
  143. });
  144. await orderGoodsRepository.save(userOrderGoods);
  145. const adminOrderGoods = orderGoodsRepository.create({
  146. orderId: otherUserOrder.id,
  147. goodsId: testGoods.id,
  148. goodsName: '管理员用户商品',
  149. price: 100.00,
  150. num: 1,
  151. state: 0,
  152. supplierId: testSupplier.id,
  153. imageFileId: testFile.id,
  154. createdBy: testAdmin.id
  155. });
  156. await orderGoodsRepository.save(adminOrderGoods);
  157. const response = await client.index.$get({
  158. query: {}
  159. }, {
  160. headers: {
  161. 'Authorization': `Bearer ${adminToken}`
  162. }
  163. });
  164. console.debug('管理员订单商品列表响应状态:', response.status);
  165. expect(response.status).toBe(200);
  166. if (response.status === 200) {
  167. const data = await response.json();
  168. expect(data).toHaveProperty('data');
  169. expect(Array.isArray(data.data)).toBe(true);
  170. // 验证返回所有用户的订单商品(管理员可以访问所有数据)
  171. const userOrderGoodsCount = data.data.filter((orderGoods: any) =>
  172. orderGoods.order && orderGoods.order.userId === testUser.id
  173. ).length;
  174. const adminOrderGoodsCount = data.data.filter((orderGoods: any) =>
  175. orderGoods.order && orderGoods.order.userId === testAdmin.id
  176. ).length;
  177. expect(userOrderGoodsCount).toBeGreaterThan(0);
  178. expect(adminOrderGoodsCount).toBeGreaterThan(0);
  179. }
  180. });
  181. it('应该拒绝未认证用户的访问', async () => {
  182. const response = await client.index.$get({
  183. query: {}
  184. });
  185. expect(response.status).toBe(401);
  186. });
  187. });
  188. describe('POST /order-items', () => {
  189. it('应该成功创建订单商品并可以指定权限', async () => {
  190. const createData = {
  191. orderId: testOrder.id,
  192. goodsId: testGoods.id,
  193. goodsName: '管理员创建商品',
  194. price: 75.00,
  195. num: 3,
  196. state: 0,
  197. supplierId: testSupplier.id,
  198. imageFileId: testFile.id,
  199. createdBy: testAdmin.id // 管理员可以指定创建人
  200. };
  201. const response = await client.index.$post({
  202. json: createData
  203. }, {
  204. headers: {
  205. 'Authorization': `Bearer ${adminToken}`
  206. }
  207. });
  208. console.debug('管理员创建订单商品响应状态:', response.status);
  209. if (response.status !== 201) {
  210. const errorData = await response.json();
  211. console.debug('管理员创建订单商品错误响应:', errorData);
  212. }
  213. expect(response.status).toBe(201);
  214. if (response.status === 201) {
  215. const data = await response.json();
  216. expect(data).toHaveProperty('id');
  217. expect(data.goodsName).toBe(createData.goodsName);
  218. expect(parseFloat(data.price)).toBe(createData.price);
  219. expect(data.num).toBe(createData.num);
  220. expect(data.createdBy).toBe(testAdmin.id); // 验证可以指定创建人
  221. }
  222. });
  223. it('应该验证创建订单商品的必填字段', async () => {
  224. const invalidData = {
  225. // 缺少必填字段
  226. price: -1,
  227. num: -1
  228. };
  229. const response = await client.index.$post({
  230. json: invalidData
  231. }, {
  232. headers: {
  233. 'Authorization': `Bearer ${adminToken}`
  234. }
  235. });
  236. expect(response.status).toBe(400);
  237. });
  238. });
  239. describe('GET /order-items/:id', () => {
  240. it('应该返回指定订单商品的详情', async () => {
  241. // 先为测试用户的订单创建一个商品
  242. const dataSource = await IntegrationTestDatabase.getDataSource();
  243. const orderGoodsRepository = dataSource.getRepository(OrderGoods);
  244. const testOrderGoods = orderGoodsRepository.create({
  245. orderId: testOrder.id,
  246. goodsId: testGoods.id,
  247. goodsName: '测试订单商品详情',
  248. price: 50.00,
  249. num: 2,
  250. state: 0,
  251. supplierId: testSupplier.id,
  252. imageFileId: testFile.id,
  253. createdBy: testUser.id
  254. });
  255. await orderGoodsRepository.save(testOrderGoods);
  256. const response = await client[':id'].$get({
  257. param: { id: testOrderGoods.id }
  258. }, {
  259. headers: {
  260. 'Authorization': `Bearer ${adminToken}`
  261. }
  262. });
  263. console.debug('管理员订单商品详情响应状态:', response.status);
  264. expect(response.status).toBe(200);
  265. if (response.status === 200) {
  266. const data = await response.json();
  267. expect(data.id).toBe(testOrderGoods.id);
  268. expect(data.goodsName).toBe(testOrderGoods.goodsName);
  269. expect(data.order.userId).toBe(testUser.id); // 验证可以访问其他用户的订单商品
  270. }
  271. });
  272. it('应该处理不存在的订单商品', async () => {
  273. const response = await client[':id'].$get({
  274. param: { id: 999999 }
  275. }, {
  276. headers: {
  277. 'Authorization': `Bearer ${adminToken}`
  278. }
  279. });
  280. expect(response.status).toBe(404);
  281. });
  282. });
  283. describe('PUT /order-items/:id', () => {
  284. it('应该成功更新任何订单商品', async () => {
  285. // 先为测试用户的订单创建一个商品
  286. const dataSource = await IntegrationTestDatabase.getDataSource();
  287. const orderGoodsRepository = dataSource.getRepository(OrderGoods);
  288. const testOrderGoods = orderGoodsRepository.create({
  289. orderId: testOrder.id,
  290. goodsId: testGoods.id,
  291. goodsName: '测试更新订单商品',
  292. price: 50.00,
  293. num: 2,
  294. state: 0,
  295. supplierId: testSupplier.id,
  296. imageFileId: testFile.id,
  297. createdBy: testUser.id
  298. });
  299. await orderGoodsRepository.save(testOrderGoods);
  300. const updateData = {
  301. num: 5,
  302. state: 1,
  303. updatedBy: testAdmin.id // 管理员可以指定更新人
  304. };
  305. const response = await client[':id'].$put({
  306. param: { id: testOrderGoods.id },
  307. json: updateData
  308. }, {
  309. headers: {
  310. 'Authorization': `Bearer ${adminToken}`
  311. }
  312. });
  313. console.debug('管理员更新订单商品响应状态:', response.status);
  314. expect(response.status).toBe(200);
  315. if (response.status === 200) {
  316. const data = await response.json();
  317. expect(data.num).toBe(updateData.num);
  318. expect(data.state).toBe(updateData.state);
  319. expect(data.updatedBy).toBe(testAdmin.id); // 验证可以指定更新人
  320. }
  321. });
  322. });
  323. describe('DELETE /order-items/:id', () => {
  324. it('应该成功删除任何订单商品', async () => {
  325. // 先为测试用户的订单创建一个商品
  326. const dataSource = await IntegrationTestDatabase.getDataSource();
  327. const orderGoodsRepository = dataSource.getRepository(OrderGoods);
  328. const testOrderGoods = orderGoodsRepository.create({
  329. orderId: testOrder.id,
  330. goodsId: testGoods.id,
  331. goodsName: '测试删除订单商品',
  332. price: 50.00,
  333. num: 2,
  334. state: 0,
  335. supplierId: testSupplier.id,
  336. imageFileId: testFile.id,
  337. createdBy: testUser.id
  338. });
  339. await orderGoodsRepository.save(testOrderGoods);
  340. const response = await client[':id'].$delete({
  341. param: { id: testOrderGoods.id }
  342. }, {
  343. headers: {
  344. 'Authorization': `Bearer ${adminToken}`
  345. }
  346. });
  347. console.debug('管理员删除订单商品响应状态:', response.status);
  348. expect(response.status).toBe(204);
  349. });
  350. });
  351. describe('管理员权限验证测试', () => {
  352. it('应该验证管理员可以访问所有数据', async () => {
  353. const dataSource = await IntegrationTestDatabase.getDataSource();
  354. const orderGoodsRepository = dataSource.getRepository(OrderGoods);
  355. // 创建不同用户的订单商品
  356. const userOrderGoods = orderGoodsRepository.create({
  357. orderId: testOrder.id,
  358. goodsId: testGoods.id,
  359. goodsName: '用户订单商品',
  360. price: 50.00,
  361. num: 2,
  362. state: 0,
  363. supplierId: testSupplier.id,
  364. imageFileId: testFile.id,
  365. createdBy: testUser.id
  366. });
  367. await orderGoodsRepository.save(userOrderGoods);
  368. const adminOrderGoods = orderGoodsRepository.create({
  369. orderId: otherUserOrder.id,
  370. goodsId: testGoods.id,
  371. goodsName: '管理员订单商品',
  372. price: 100.00,
  373. num: 1,
  374. state: 0,
  375. supplierId: testSupplier.id,
  376. imageFileId: testFile.id,
  377. createdBy: testAdmin.id
  378. });
  379. await orderGoodsRepository.save(adminOrderGoods);
  380. // 使用管理员token获取列表
  381. const response = await client.index.$get({
  382. query: {}
  383. }, {
  384. headers: {
  385. 'Authorization': `Bearer ${adminToken}`
  386. }
  387. });
  388. expect(response.status).toBe(200);
  389. const data = await response.json();
  390. // 类型检查确保data属性存在
  391. if ('data' in data && Array.isArray(data.data)) {
  392. // 验证返回所有用户的订单商品
  393. const userOrderGoodsInResponse = data.data.filter((orderGoods: any) =>
  394. orderGoods.order && orderGoods.order.userId === testUser.id
  395. );
  396. const adminOrderGoodsInResponse = data.data.filter((orderGoods: any) =>
  397. orderGoods.order && orderGoods.order.userId === testAdmin.id
  398. );
  399. expect(userOrderGoodsInResponse.length).toBeGreaterThan(0);
  400. expect(adminOrderGoodsInResponse.length).toBeGreaterThan(0);
  401. } else {
  402. // 如果响应是错误格式,应该失败
  403. expect(data).toHaveProperty('data');
  404. }
  405. });
  406. });
  407. });