Просмотр исходного кода

✅ test(activities,routes): 改进集成测试以使用动态生成的地点ID

- 活动测试中使用TestDataFactory创建真实地点,替换硬编码的venueLocationId=1
- 路线测试中使用动态生成的起点和终点地点ID,替代固定数值
- 在测试数据工厂中添加区域和地点的创建方法,支持完整的位置关系链
- 优化路线测试数据生成,自动创建必要的关联地点
- 移除所有测试中硬编码的位置ID,提高测试稳定性和独立性
yourname 4 месяцев назад
Родитель
Сommit
8a6a11b558

+ 12 - 3
tests/integration/server/admin/activities.integration.test.ts

@@ -37,13 +37,16 @@ describe('活动管理API集成测试', () => {
 
   describe('活动创建测试', () => {
     it('应该成功创建去程活动', async () => {
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const testLocation = await TestDataFactory.createTestLocation(dataSource);
+
       const activityData = {
         name: '测试去程活动',
         description: '这是一个测试去程活动',
         type: ActivityType.DEPARTURE,
         startDate: '2025-10-17T08:00:00.000Z',
         endDate: '2025-10-17T18:00:00.000Z',
-        venueLocationId: 1
+        venueLocationId: testLocation.id
       };
 
       const response = await client.activities.$post({
@@ -70,13 +73,16 @@ describe('活动管理API集成测试', () => {
     });
 
     it('应该成功创建返程活动', async () => {
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const testLocation = await TestDataFactory.createTestLocation(dataSource);
+
       const activityData = {
         name: '测试返程活动',
         description: '这是一个测试返程活动',
         type: ActivityType.RETURN,
         startDate: '2025-10-17T16:00:00.000Z',
         endDate: '2025-10-17T20:00:00.000Z',
-        venueLocationId: 1
+        venueLocationId: testLocation.id
       };
 
       const response = await client.activities.$post({
@@ -96,13 +102,16 @@ describe('活动管理API集成测试', () => {
     });
 
     it('应该拒绝创建无效活动类型的活动', async () => {
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const testLocation = await TestDataFactory.createTestLocation(dataSource);
+
       const activityData = {
         name: '测试无效活动',
         description: '这是一个测试活动',
         type: 'invalid_type' as any, // 无效类型
         startDate: '2025-10-17T08:00:00.000Z',
         endDate: '2025-10-17T18:00:00.000Z',
-        venueLocationId: 1
+        venueLocationId: testLocation.id
       };
 
       const response = await client.activities.$post({

+ 12 - 11
tests/integration/server/admin/routes.integration.test.ts

@@ -40,13 +40,16 @@ describe('路线管理API集成测试', () => {
       const dataSource = await IntegrationTestDatabase.getDataSource();
       if (!dataSource) throw new Error('Database not initialized');
 
-      // 先创建一个活动
+      // 先创建活动
       const testActivity = await TestDataFactory.createTestActivity(dataSource);
+      // 创建起点和终点地点
+      const startLocation = await TestDataFactory.createTestLocation(dataSource);
+      const endLocation = await TestDataFactory.createTestLocation(dataSource);
 
       const routeData = {
         name: '测试路线',
-        startLocationId: 1,
-        endLocationId: 2,
+        startLocationId: startLocation.id,
+        endLocationId: endLocation.id,
         pickupPoint: '北京西站',
         dropoffPoint: '上海南站',
         departureTime: '2025-10-17T08:00:00.000Z',
@@ -396,9 +399,9 @@ describe('路线管理API集成测试', () => {
       const dataSource = await IntegrationTestDatabase.getDataSource();
       if (!dataSource) throw new Error('Database not initialized');
 
-      await TestDataFactory.createTestRoute(dataSource, { name: '搜索路线1', startLocationId: 1 });
-      await TestDataFactory.createTestRoute(dataSource, { name: '搜索路线2', startLocationId: 2 });
-      await TestDataFactory.createTestRoute(dataSource, { name: '其他路线', startLocationId: 3 });
+      await TestDataFactory.createTestRoute(dataSource, { name: '搜索路线1' });
+      await TestDataFactory.createTestRoute(dataSource, { name: '搜索路线2' });
+      await TestDataFactory.createTestRoute(dataSource, { name: '其他路线' });
 
       const response = await client.routes.$get({
         query: { keyword: '搜索路线' }
@@ -427,8 +430,8 @@ describe('路线管理API集成测试', () => {
       const dataSource = await IntegrationTestDatabase.getDataSource();
       if (!dataSource) throw new Error('Database not initialized');
 
-      await TestDataFactory.createTestRoute(dataSource, { name: '路线1', startLocationId: 1 });
-      await TestDataFactory.createTestRoute(dataSource, { name: '路线2', startLocationId: 1 });
+      await TestDataFactory.createTestRoute(dataSource, { name: '路线1' });
+      await TestDataFactory.createTestRoute(dataSource, { name: '路线2' });
 
       const response = await client.routes.$get({
         query: { keyword: '北京' }
@@ -486,9 +489,7 @@ describe('路线管理API集成测试', () => {
       // 创建一些测试数据
       for (let i = 0; i < 10; i++) {
         await TestDataFactory.createTestRoute(dataSource, {
-          name: `性能测试路线_${i}`,
-          startLocationId: i + 1,
-          endLocationId: i + 2
+          name: `性能测试路线_${i}`
         });
       }
 

+ 109 - 3
tests/utils/server/integration-test-db.ts

@@ -4,6 +4,8 @@ import { UserEntity } from '@/server/modules/users/user.entity';
 import { Role } from '@/server/modules/users/role.entity';
 import { ActivityEntity, ActivityType } from '@/server/modules/activities/activity.entity';
 import { RouteEntity } from '@/server/modules/routes/route.entity';
+import { LocationEntity } from '@/server/modules/locations/location.entity';
+import { AreaEntity } from '@/server/modules/areas/area.entity';
 import { VehicleType } from '@/server/modules/routes/route.schema';
 import { AppDataSource } from '@/server/data-source';
 
@@ -65,6 +67,41 @@ export class TestDataFactory {
     };
   }
 
+  /**
+   * 创建测试区域数据
+   */
+  static createAreaData(overrides: Partial<AreaEntity> = {}): Partial<AreaEntity> {
+    const timestamp = Date.now();
+    return {
+      name: `测试区域_${timestamp}`,
+      code: `area_${timestamp}`,
+      level: 1,
+      parentId: null,
+      isDisabled: 0,
+      isDeleted: 0,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建测试地点数据
+   */
+  static createLocationData(overrides: Partial<LocationEntity> = {}): Partial<LocationEntity> {
+    const timestamp = Date.now();
+    return {
+      name: `测试地点_${timestamp}`,
+      address: `测试地址_${timestamp}`,
+      provinceId: 0, // 将在创建时自动设置
+      cityId: 0,     // 将在创建时自动设置
+      districtId: 0, // 将在创建时自动设置
+      latitude: 39.9042,
+      longitude: 116.4074,
+      isDisabled: 0,
+      isDeleted: 0,
+      ...overrides
+    };
+  }
+
   /**
    * 在数据库中创建测试用户
    */
@@ -87,6 +124,57 @@ export class TestDataFactory {
     return await roleRepository.save(role);
   }
 
+  /**
+   * 在数据库中创建测试区域
+   */
+  static async createTestArea(dataSource: DataSource, overrides: Partial<AreaEntity> = {}): Promise<AreaEntity> {
+    const areaData = this.createAreaData(overrides);
+    const areaRepository = dataSource.getRepository(AreaEntity);
+
+    // 对于顶级区域(省/直辖市),parentId应该为null
+    if (areaData.level === 1) {
+      areaData.parentId = null;
+    }
+    // 对于市级区域,确保有对应的省级区域
+    else if (areaData.level === 2 && !areaData.parentId) {
+      const province = await this.createTestArea(dataSource, { level: 1 });
+      areaData.parentId = province.id;
+    }
+    // 对于区县级区域,确保有对应的市级区域
+    else if (areaData.level === 3 && !areaData.parentId) {
+      const city = await this.createTestArea(dataSource, { level: 2 });
+      areaData.parentId = city.id;
+    }
+
+    const area = areaRepository.create(areaData);
+    return await areaRepository.save(area);
+  }
+
+  /**
+   * 在数据库中创建测试地点
+   */
+  static async createTestLocation(dataSource: DataSource, overrides: Partial<LocationEntity> = {}): Promise<LocationEntity> {
+    const locationData = this.createLocationData(overrides);
+    const locationRepository = dataSource.getRepository(LocationEntity);
+
+    // 确保关联的区域存在 - 按层级顺序创建
+    if (!locationData.provinceId) {
+      const province = await this.createTestArea(dataSource, { level: 1 });
+      locationData.provinceId = province.id;
+    }
+    if (!locationData.cityId) {
+      const city = await this.createTestArea(dataSource, { level: 2, parentId: locationData.provinceId });
+      locationData.cityId = city.id;
+    }
+    if (!locationData.districtId) {
+      const district = await this.createTestArea(dataSource, { level: 3, parentId: locationData.cityId });
+      locationData.districtId = district.id;
+    }
+
+    const location = locationRepository.create(locationData);
+    return await locationRepository.save(location);
+  }
+
   /**
    * 创建测试活动数据
    */
@@ -101,7 +189,7 @@ export class TestDataFactory {
       type: ActivityType.DEPARTURE,
       startDate: now,
       endDate: tomorrow,
-      venueLocationId: 1, // 默认举办地点ID
+      venueLocationId: 0, // 将在创建时自动设置
       isDisabled: 0,
       isDeleted: 0,
       ...overrides
@@ -118,8 +206,8 @@ export class TestDataFactory {
 
     return {
       name: `测试路线_${timestamp}`,
-      startLocationId: 1,
-      endLocationId: 2,
+      startLocationId: 0, // 将在创建时自动设置
+      endLocationId: 0,   // 将在创建时自动设置
       pickupPoint: `上车点_${timestamp}`,
       dropoffPoint: `下车点_${timestamp}`,
       departureTime: departureTime,
@@ -140,6 +228,12 @@ export class TestDataFactory {
     const activityData = this.createActivityData(overrides);
     const activityRepository = dataSource.getRepository(ActivityEntity);
 
+    // 如果没有提供venueLocationId,自动创建一个测试地点
+    if (!activityData.venueLocationId || activityData.venueLocationId === 0) {
+      const testLocation = await this.createTestLocation(dataSource);
+      activityData.venueLocationId = testLocation.id;
+    }
+
     const activity = activityRepository.create(activityData);
     return await activityRepository.save(activity);
   }
@@ -151,6 +245,18 @@ export class TestDataFactory {
     const routeData = this.createRouteData(overrides);
     const routeRepository = dataSource.getRepository(RouteEntity);
 
+    // 如果没有提供startLocationId,自动创建一个测试地点
+    if (!routeData.startLocationId || routeData.startLocationId === 0) {
+      const startLocation = await this.createTestLocation(dataSource);
+      routeData.startLocationId = startLocation.id;
+    }
+
+    // 如果没有提供endLocationId,自动创建一个测试地点
+    if (!routeData.endLocationId || routeData.endLocationId === 0) {
+      const endLocation = await this.createTestLocation(dataSource);
+      routeData.endLocationId = endLocation.id;
+    }
+
     // 如果没有提供activityId,自动创建一个测试活动
     if (!routeData.activityId) {
       const testActivity = await this.createTestActivity(dataSource);