Selaa lähdekoodia

✅ test(delivery-address): 添加用户配送地址管理API集成测试

- 测试用户配送地址列表获取接口
- 测试配送地址创建接口及必填字段验证
- 测试配送地址详情获取接口
- 测试配送地址更新接口
- 测试配送地址删除接口
- 验证用户数据访问权限控制
- 模拟测试数据环境及用户认证场景
yourname 1 kuukausi sitten
vanhempi
sitoutus
cc3ba3fc44

+ 565 - 0
packages/delivery-address-module/tests/integration/user-routes.integration.test.ts

@@ -0,0 +1,565 @@
+import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
+import { testClient } from 'hono/testing';
+import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
+import { JWTUtil } from '@d8d/shared-utils';
+import { UserEntity, Role } from '@d8d/user-module';
+import { AreaEntity, AreaLevel } from '@d8d/geo-areas';
+import { userDeliveryAddressRoutes } from '../../src/routes';
+import { DeliveryAddress } from '../../src/entities';
+
+// 设置集成测试钩子
+setupIntegrationDatabaseHooksWithEntities([UserEntity, Role, AreaEntity, DeliveryAddress])
+
+describe('用户配送地址管理API集成测试', () => {
+  let client: ReturnType<typeof testClient<typeof userDeliveryAddressRoutes>>;
+  let userToken: string;
+  let otherUserToken: string;
+  let testUser: UserEntity;
+  let otherUser: UserEntity;
+  let testProvince: AreaEntity;
+  let testCity: AreaEntity;
+  let testDistrict: AreaEntity;
+
+  beforeEach(async () => {
+    // 创建测试客户端
+    client = testClient(userDeliveryAddressRoutes);
+
+    // 获取数据源
+    const dataSource = await IntegrationTestDatabase.getDataSource();
+
+    // 创建测试用户
+    const userRepository = dataSource.getRepository(UserEntity);
+    testUser = userRepository.create({
+      username: `test_user_${Date.now()}`,
+      password: 'test_password',
+      nickname: '测试用户',
+      registrationSource: 'web'
+    });
+    await userRepository.save(testUser);
+
+    // 创建其他用户
+    otherUser = userRepository.create({
+      username: `other_user_${Date.now()}`,
+      password: 'other_password',
+      nickname: '其他用户',
+      registrationSource: 'web'
+    });
+    await userRepository.save(otherUser);
+
+    // 创建测试地区数据 - 省
+    const areaRepository = dataSource.getRepository(AreaEntity);
+    testProvince = areaRepository.create({
+      name: '北京市',
+      code: '110000',
+      level: AreaLevel.PROVINCE,
+      parentId: null
+    });
+    await areaRepository.save(testProvince);
+
+    // 创建测试地区数据 - 市
+    testCity = areaRepository.create({
+      name: '北京市',
+      code: '110100',
+      level: AreaLevel.CITY,
+      parentId: testProvince.id
+    });
+    await areaRepository.save(testCity);
+
+    // 创建测试地区数据 - 区
+    testDistrict = areaRepository.create({
+      name: '朝阳区',
+      code: '110105',
+      level: AreaLevel.DISTRICT,
+      parentId: testCity.id
+    });
+    await areaRepository.save(testDistrict);
+
+    // 生成测试用户的token
+    userToken = JWTUtil.generateToken({
+      id: testUser.id,
+      username: testUser.username,
+      roles: [{name:'user'}]
+    });
+
+    // 生成其他用户的token
+    otherUserToken = JWTUtil.generateToken({
+      id: otherUser.id,
+      username: otherUser.username,
+      roles: [{name:'user'}]
+    });
+  });
+
+  describe('GET /delivery-address', () => {
+    it('应该返回当前用户的配送地址列表', async () => {
+      // 为测试用户创建一些地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+
+      const userAddress1 = deliveryAddressRepository.create({
+        userId: testUser.id,
+        name: '用户地址1',
+        phone: '13800138001',
+        address: '用户地址1',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: testUser.id
+      });
+      await deliveryAddressRepository.save(userAddress1);
+
+      const userAddress2 = deliveryAddressRepository.create({
+        userId: testUser.id,
+        name: '用户地址2',
+        phone: '13800138002',
+        address: '用户地址2',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: testUser.id
+      });
+      await deliveryAddressRepository.save(userAddress2);
+
+      // 为其他用户创建一个地址,确保不会返回
+      const otherUserAddress = deliveryAddressRepository.create({
+        userId: otherUser.id,
+        name: '其他用户地址',
+        phone: '13800138003',
+        address: '其他用户地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: otherUser.id
+      });
+      await deliveryAddressRepository.save(otherUserAddress);
+
+      const response = await client.index.$get({
+        query: {}
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户配送地址列表响应状态:', response.status);
+      expect(response.status).toBe(200);
+
+      if (response.status === 200) {
+        const data = await response.json();
+        if (data && 'data' in data) {
+          expect(Array.isArray(data.data)).toBe(true);
+          // 应该只返回当前用户的地址
+          data.data.forEach((address: any) => {
+            expect(address.userId).toBe(testUser.id);
+          });
+        }
+      }
+    });
+
+    it('应该拒绝未认证用户的访问', async () => {
+      const response = await client.index.$get({
+        query: {}
+      });
+      expect(response.status).toBe(401);
+    });
+  });
+
+  describe('POST /delivery-address', () => {
+    it('应该成功创建配送地址并自动使用当前用户ID', async () => {
+      const createData = {
+        name: '张三',
+        phone: '13800138000',
+        address: '朝阳区建国路88号',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 1
+      };
+
+      const response = await client.index.$post({
+        json: createData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户创建配送地址响应状态:', response.status);
+      expect(response.status).toBe(201);
+
+      if (response.status === 201) {
+        const data = await response.json();
+        expect(data).toHaveProperty('id');
+        expect(data.userId).toBe(testUser.id); // 自动使用当前用户ID
+        expect(data.name).toBe(createData.name);
+        expect(data.phone).toBe(createData.phone);
+        expect(data.address).toBe(createData.address);
+      }
+    });
+
+    it('应该验证创建配送地址的必填字段', async () => {
+      const invalidData = {
+        // 缺少必填字段
+        name: '',
+        phone: '',
+        address: '',
+        receiverProvince: 0,
+        receiverCity: 0,
+        receiverDistrict: 0
+      };
+
+      const response = await client.index.$post({
+        json: invalidData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      expect(response.status).toBe(400);
+    });
+  });
+
+  describe('GET /delivery-address/:id', () => {
+    it('应该返回当前用户的配送地址详情', async () => {
+      // 先为当前用户创建一个配送地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+      const testDeliveryAddress = deliveryAddressRepository.create({
+        userId: testUser.id,
+        name: '王五',
+        phone: '13600136000',
+        address: '海淀区中关村大街1号',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: testUser.id
+      });
+      await deliveryAddressRepository.save(testDeliveryAddress);
+
+      const response = await client[':id'].$get({
+        param: { id: testDeliveryAddress.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户配送地址详情响应状态:', response.status);
+      expect(response.status).toBe(200);
+
+      if (response.status === 200) {
+        const data = await response.json();
+        expect(data.id).toBe(testDeliveryAddress.id);
+        expect(data.userId).toBe(testUser.id);
+        expect(data.name).toBe(testDeliveryAddress.name);
+        expect(data.phone).toBe(testDeliveryAddress.phone);
+        expect(data.address).toBe(testDeliveryAddress.address);
+      }
+    });
+
+    it('应该拒绝访问其他用户的配送地址', async () => {
+      // 为其他用户创建一个配送地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+      const otherUserAddress = deliveryAddressRepository.create({
+        userId: otherUser.id,
+        name: '其他用户地址',
+        phone: '13600136001',
+        address: '其他用户地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: otherUser.id
+      });
+      await deliveryAddressRepository.save(otherUserAddress);
+
+      // 当前用户尝试访问其他用户的地址
+      const response = await client[':id'].$get({
+        param: { id: otherUserAddress.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户访问其他用户地址响应状态:', response.status);
+      expect(response.status).toBe(404); // 应该返回404,而不是403
+    });
+
+    it('应该处理不存在的配送地址', async () => {
+      const response = await client[':id'].$get({
+        param: { id: 999999 }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      expect(response.status).toBe(404);
+    });
+  });
+
+  describe('PUT /delivery-address/:id', () => {
+    it('应该成功更新当前用户的配送地址', async () => {
+      // 先为当前用户创建一个配送地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+      const testDeliveryAddress = deliveryAddressRepository.create({
+        userId: testUser.id,
+        name: '原始姓名',
+        phone: '13500135000',
+        address: '原始地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: testUser.id
+      });
+      await deliveryAddressRepository.save(testDeliveryAddress);
+
+      const updateData = {
+        name: '更新后的姓名',
+        phone: '13700137000',
+        address: '更新后的地址',
+        isDefault: 1
+      };
+
+      const response = await client[':id'].$put({
+        param: { id: testDeliveryAddress.id },
+        json: updateData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户更新配送地址响应状态:', response.status);
+      expect(response.status).toBe(200);
+
+      if (response.status === 200) {
+        const data = await response.json();
+        expect(data.name).toBe(updateData.name);
+        expect(data.phone).toBe(updateData.phone);
+        expect(data.address).toBe(updateData.address);
+        expect(data.isDefault).toBe(updateData.isDefault);
+      }
+    });
+
+    it('应该拒绝更新其他用户的配送地址', async () => {
+      // 为其他用户创建一个配送地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+      const otherUserAddress = deliveryAddressRepository.create({
+        userId: otherUser.id,
+        name: '其他用户地址',
+        phone: '13500135001',
+        address: '其他用户地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: otherUser.id
+      });
+      await deliveryAddressRepository.save(otherUserAddress);
+
+      const updateData = {
+        name: '尝试更新的姓名',
+        phone: '13700137001',
+        address: '尝试更新的地址'
+      };
+
+      // 当前用户尝试更新其他用户的地址
+      const response = await client[':id'].$put({
+        param: { id: otherUserAddress.id },
+        json: updateData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户更新其他用户地址响应状态:', response.status);
+      expect(response.status).toBe(404); // 应该返回404,而不是403
+    });
+  });
+
+  describe('DELETE /delivery-address/:id', () => {
+    it('应该成功删除当前用户的配送地址', async () => {
+      // 先为当前用户创建一个配送地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+      const testDeliveryAddress = deliveryAddressRepository.create({
+        userId: testUser.id,
+        name: '待删除地址',
+        phone: '13400134000',
+        address: '待删除地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: testUser.id
+      });
+      await deliveryAddressRepository.save(testDeliveryAddress);
+
+      const response = await client[':id'].$delete({
+        param: { id: testDeliveryAddress.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户删除配送地址响应状态:', response.status);
+      expect(response.status).toBe(204);
+
+      // 验证配送地址确实被删除
+      const deletedDeliveryAddress = await deliveryAddressRepository.findOne({
+        where: { id: testDeliveryAddress.id }
+      });
+      expect(deletedDeliveryAddress).toBeNull();
+    });
+
+    it('应该拒绝删除其他用户的配送地址', async () => {
+      // 为其他用户创建一个配送地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+      const otherUserAddress = deliveryAddressRepository.create({
+        userId: otherUser.id,
+        name: '其他用户地址',
+        phone: '13400134001',
+        address: '其他用户地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: otherUser.id
+      });
+      await deliveryAddressRepository.save(otherUserAddress);
+
+      // 当前用户尝试删除其他用户的地址
+      const response = await client[':id'].$delete({
+        param: { id: otherUserAddress.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      console.debug('用户删除其他用户地址响应状态:', response.status);
+      expect(response.status).toBe(404); // 应该返回404,而不是403
+    });
+  });
+
+  describe('数据权限验证', () => {
+    it('用户应该只能访问和操作自己的数据', async () => {
+      // 为两个用户都创建地址
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const deliveryAddressRepository = dataSource.getRepository(DeliveryAddress);
+
+      const userAddress = deliveryAddressRepository.create({
+        userId: testUser.id,
+        name: '用户地址',
+        phone: '13800138004',
+        address: '用户地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: testUser.id
+      });
+      await deliveryAddressRepository.save(userAddress);
+
+      const otherUserAddress = deliveryAddressRepository.create({
+        userId: otherUser.id,
+        name: '其他用户地址',
+        phone: '13800138005',
+        address: '其他用户地址',
+        receiverProvince: testProvince.id,
+        receiverCity: testCity.id,
+        receiverDistrict: testDistrict.id,
+        receiverTown: 0,
+        state: 1,
+        isDefault: 0,
+        createdBy: otherUser.id
+      });
+      await deliveryAddressRepository.save(otherUserAddress);
+
+      // 当前用户应该只能看到自己的地址
+      const listResponse = await client.index.$get({
+        query: {}
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+
+      expect(listResponse.status).toBe(200);
+      const listData = await listResponse.json();
+      if (listData && 'data' in listData) {
+        expect(Array.isArray(listData.data)).toBe(true);
+        // 应该只包含当前用户的地址
+        listData.data.forEach((address: any) => {
+          expect(address.userId).toBe(testUser.id);
+        });
+      }
+
+      // 当前用户应该无法访问其他用户的地址详情
+      const getResponse = await client[':id'].$get({
+        param: { id: otherUserAddress.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+      expect(getResponse.status).toBe(404);
+
+      // 当前用户应该无法更新其他用户的地址
+      const updateResponse = await client[':id'].$put({
+        param: { id: otherUserAddress.id },
+        json: { name: '尝试更新' }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+      expect(updateResponse.status).toBe(404);
+
+      // 当前用户应该无法删除其他用户的地址
+      const deleteResponse = await client[':id'].$delete({
+        param: { id: otherUserAddress.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${userToken}`
+        }
+      });
+      expect(deleteResponse.status).toBe(404);
+    });
+  });
+});