Kaynağa Gözat

✅ test(areas): 完善区域API集成测试

- 添加TestQueryFactory工具类统一管理测试查询参数
- 为地区创建测试添加tenantId字段
- 为树形结构查询测试添加tenantId查询参数
- 重构省份、城市、区县列表查询测试,使用工厂方法生成查询参数
- 优化租户数据隔离测试的响应类型处理和断言逻辑

♻️ refactor(tests): 优化测试代码结构

- 定义SuccessResponse和ErrorResponse接口规范响应类型
- 统一使用TestQueryFactory创建各类测试查询参数
- 改进分页测试参数传递方式
- 增强测试代码的可维护性和一致性
yourname 1 ay önce
ebeveyn
işleme
575015aa4e

+ 13 - 5
packages/geo-areas-mt/tests/integration/admin-areas.integration.test.ts

@@ -115,6 +115,7 @@ describe('管理地区API集成测试 (使用hono/testing)', () => {
   describe('地区CRUD操作测试', () => {
     it('应该成功创建地区(使用有效认证令牌)', async () => {
       const areaData = {
+        tenantId: 1,
         name: '测试省份',
         code: 'test_province_001',
         level: AreaLevel.PROVINCE,
@@ -286,7 +287,9 @@ describe('管理地区API集成测试 (使用hono/testing)', () => {
 
   describe('树形结构查询测试', () => {
     it('应该成功获取完整树形结构', async () => {
-      const response = await client.tree.$get({}, {
+      const response = await client.tree.$get({
+        query: { tenantId: 1 }
+      }, {
         headers: {
           'Authorization': `Bearer ${testToken}`
         }
@@ -308,7 +311,8 @@ describe('管理地区API集成测试 (使用hono/testing)', () => {
 
     it('应该根据层级获取树形结构', async () => {
       const response = await client.tree.level[':level'].$get({
-        param: { level: AreaLevel.PROVINCE }
+        param: { level: AreaLevel.PROVINCE },
+        query: { tenantId: 1 }
       }, {
         headers: {
           'Authorization': `Bearer ${testToken}`
@@ -335,7 +339,8 @@ describe('管理地区API集成测试 (使用hono/testing)', () => {
       expect(province).toBeDefined();
 
       const response = await client.tree[':id'].$get({
-        param: { id: province!.id }
+        param: { id: province!.id },
+        query: { tenantId: 1 }
       }, {
         headers: {
           'Authorization': `Bearer ${testToken}`
@@ -365,7 +370,8 @@ describe('管理地区API集成测试 (使用hono/testing)', () => {
       expect(district).toBeDefined();
 
       const response = await client.path[':id'].$get({
-        param: { id: district!.id }
+        param: { id: district!.id },
+        query: { tenantId: 1 }
       }, {
         headers: {
           'Authorization': `Bearer ${testToken}`
@@ -411,7 +417,9 @@ describe('管理地区API集成测试 (使用hono/testing)', () => {
 
     it('树形结构查询响应时间应小于300ms', async () => {
       const startTime = Date.now();
-      const response = await client.tree.$get({}, {
+      const response = await client.tree.$get({
+        query: { tenantId: 1 }
+      }, {
         headers: {
           'Authorization': `Bearer ${testToken}`
         }

+ 84 - 32
packages/geo-areas-mt/tests/integration/areas.integration.test.ts

@@ -9,6 +9,37 @@ import { areasRoutesMt } from '../../src/api/areas/index.mt';
 import { AreaEntityMt, AreaLevel } from '../../src/modules/areas/area.entity.mt';
 import { DisabledStatus } from '@d8d/shared-types';
 import { TestDataFactory } from '../utils/test-data-factory';
+import { TestQueryFactory } from '../utils/test-query-factory';
+
+// 定义响应类型
+interface SuccessResponse {
+  success: boolean;
+  data: {
+    provinces: Array<{
+      id: number;
+      name: string;
+      code: string;
+      level: number;
+      parentId: number | null;
+    }>;
+    pagination: {
+      page: number;
+      pageSize: number;
+      total: number;
+      totalPages: number;
+    };
+  };
+  message: string;
+}
+
+interface ErrorResponse {
+  code: number;
+  message: string;
+  errors?: Array<{
+    path: string[];
+    message: string;
+  }>;
+}
 
 // 设置集成测试钩子
 setupIntegrationDatabaseHooksWithEntities([AreaEntityMt])
@@ -132,7 +163,7 @@ describe('区域API集成测试', () => {
   describe('GET /areas/provinces', () => {
     it('应该成功获取启用状态的省份列表', async () => {
       const response = await client.provinces.$get({
-        query: { page: 1, pageSize: 50 }
+        query: TestQueryFactory.createProvincesQuery()
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -166,7 +197,7 @@ describe('区域API集成测试', () => {
 
     it('应该正确处理分页参数', async () => {
       const response = await client.provinces.$get({
-        query: { page: 1, pageSize: 2 }
+        query: TestQueryFactory.createPaginationQuery(1, 2)
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -189,7 +220,7 @@ describe('区域API集成测试', () => {
   describe('GET /areas/cities', () => {
     it('应该成功获取指定省份下启用状态的城市列表', async () => {
       const response = await client.cities.$get({
-        query: { provinceId: testAreas[0].id, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createCitiesQuery(testAreas[0].id)
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -220,7 +251,7 @@ describe('区域API集成测试', () => {
 
     it('应该处理不存在的省份ID', async () => {
       const response = await client.cities.$get({
-        query: { provinceId: 999, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createCitiesQuery(999)
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -235,7 +266,7 @@ describe('区域API集成测试', () => {
 
     it('应该验证省份ID参数', async () => {
       const response = await client.cities.$get({
-        query: { provinceId: 0, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createCitiesQuery(0)
       });
 
       // 参数验证应该返回400错误
@@ -250,7 +281,7 @@ describe('区域API集成测试', () => {
       expect(chaoyangCity).toBeDefined();
 
       const response = await client.districts.$get({
-        query: { cityId: chaoyangCity!.id, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createDistrictsQuery(chaoyangCity!.id)
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -280,7 +311,7 @@ describe('区域API集成测试', () => {
 
     it('应该处理不存在的城市ID', async () => {
       const response = await client.districts.$get({
-        query: { cityId: 999, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createDistrictsQuery(999)
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -295,7 +326,7 @@ describe('区域API集成测试', () => {
 
     it('应该验证城市ID参数', async () => {
       const response = await client.districts.$get({
-        query: { cityId: 0, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createDistrictsQuery(0)
       });
 
       // 参数验证应该返回400错误
@@ -307,7 +338,7 @@ describe('区域API集成测试', () => {
     it('应该确保所有API只返回启用状态的区域', async () => {
       // 测试省份API
       const provincesResponse = await client.provinces.$get({
-        query: { page: 1, pageSize: 50 }
+        query: TestQueryFactory.createProvincesQuery()
       });
       IntegrationTestAssertions.expectStatus(provincesResponse, 200);
       const provincesData = await provincesResponse.json();
@@ -321,7 +352,7 @@ describe('区域API集成测试', () => {
 
       // 测试城市API
       const citiesResponse = await client.cities.$get({
-        query: { provinceId: testAreas[0].id, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createCitiesQuery(testAreas[0].id)
       });
       IntegrationTestAssertions.expectStatus(citiesResponse, 200);
       const citiesData = await citiesResponse.json();
@@ -336,7 +367,7 @@ describe('区域API集成测试', () => {
       // 测试区县API
       const chaoyangCity = testAreas.find(area => area.name === '朝阳区' && area.level === AreaLevel.CITY);
       const districtsResponse = await client.districts.$get({
-        query: { cityId: chaoyangCity!.id, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createDistrictsQuery(chaoyangCity!.id)
       });
       IntegrationTestAssertions.expectStatus(districtsResponse, 200);
       const districtsData = await districtsResponse.json();
@@ -375,17 +406,22 @@ describe('区域API集成测试', () => {
     it('应该只返回指定租户的数据', async () => {
       // 测试租户1的数据
       const response1 = await client.provinces.$get({
-        query: { tenantId: 1, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createProvincesQuery()
       });
 
       IntegrationTestAssertions.expectStatus(response1, 200);
       const data1 = await response1.json();
 
       // 验证租户1只看到租户1的数据
-      const tenant1Provinces = data1.data.provinces;
-      expect(tenant1Provinces).toHaveLength(3); // 租户1有3个省份
-      const hasTenant2Data = tenant1Provinces.some((p: any) => p.name.includes('租户2'));
-      expect(hasTenant2Data).toBe(false);
+      const successData1 = data1 as SuccessResponse;
+      if (successData1.success) {
+        const tenant1Provinces = successData1.data.provinces;
+        expect(tenant1Provinces).toHaveLength(3); // 租户1有3个省份
+        const hasTenant2Data = tenant1Provinces.some((p: any) => p.name.includes('租户2'));
+        expect(hasTenant2Data).toBe(false);
+      } else {
+        throw new Error('租户1数据获取失败');
+      }
 
       // 测试租户2的数据
       const response2 = await client.provinces.$get({
@@ -396,16 +432,21 @@ describe('区域API集成测试', () => {
       const data2 = await response2.json();
 
       // 验证租户2只看到租户2的数据
-      const tenant2Provinces = data2.data.provinces;
-      expect(tenant2Provinces).toHaveLength(2); // 租户2有2个省份
-      const hasTenant1Data = tenant2Provinces.some((p: any) => p.name.includes('北京市') && !p.name.includes('租户2'));
-      expect(hasTenant1Data).toBe(false);
+      const successData2 = data2 as SuccessResponse;
+      if (successData2.success) {
+        const tenant2Provinces = successData2.data.provinces;
+        expect(tenant2Provinces).toHaveLength(2); // 租户2有2个省份
+        const hasTenant1Data = tenant2Provinces.some((p: any) => p.name.includes('北京市') && !p.name.includes('租户2'));
+        expect(hasTenant1Data).toBe(false);
+      } else {
+        throw new Error('租户2数据获取失败');
+      }
     });
 
     it('不同租户的数据应该完全隔离', async () => {
       // 租户1查询省份
       const response1 = await client.provinces.$get({
-        query: { tenantId: 1, page: 1, pageSize: 50 }
+        query: TestQueryFactory.createProvincesQuery()
       });
 
       IntegrationTestAssertions.expectStatus(response1, 200);
@@ -420,21 +461,27 @@ describe('区域API集成测试', () => {
       const data2 = await response2.json();
 
       // 验证两个租户的数据完全不同
-      const tenant1Names = data1.data.provinces.map((p: any) => p.name);
-      const tenant2Names = data2.data.provinces.map((p: any) => p.name);
-
-      expect(tenant1Names).not.toEqual(tenant2Names);
-      expect(tenant1Names).toContain('北京市');
-      expect(tenant1Names).toContain('上海市');
-      expect(tenant1Names).toContain('广东省');
-      expect(tenant2Names).toContain('租户2-北京市');
-      expect(tenant2Names).toContain('租户2-上海市');
+      const successData1 = data1 as SuccessResponse;
+      const successData2 = data2 as SuccessResponse;
+      if (successData1.success && successData2.success) {
+        const tenant1Names = successData1.data.provinces.map((p: any) => p.name);
+        const tenant2Names = successData2.data.provinces.map((p: any) => p.name);
+
+        expect(tenant1Names).not.toEqual(tenant2Names);
+        expect(tenant1Names).toContain('北京市');
+        expect(tenant1Names).toContain('上海市');
+        expect(tenant1Names).toContain('广东省');
+        expect(tenant2Names).toContain('租户2-北京市');
+        expect(tenant2Names).toContain('租户2-上海市');
+      } else {
+        throw new Error('租户数据获取失败');
+      }
     });
 
     it('应该验证tenantId参数', async () => {
       // 测试缺少tenantId参数
       const response = await client.provinces.$get({
-        query: { page: 1, pageSize: 50 }
+        query: TestQueryFactory.createProvincesQuery()
       });
 
       // 应该返回400错误,因为缺少必需的tenantId参数
@@ -450,7 +497,12 @@ describe('区域API集成测试', () => {
       const data = await response.json();
 
       // 不存在的租户应该返回空数组
-      expect(data.data.provinces).toHaveLength(0);
+      const successData = data as SuccessResponse;
+      if (successData.success) {
+        expect(successData.data.provinces).toHaveLength(0);
+      } else {
+        throw new Error('不存在的租户数据获取失败');
+      }
     });
   });
 });

+ 94 - 0
packages/geo-areas-mt/tests/utils/test-query-factory.ts

@@ -0,0 +1,94 @@
+/**
+ * 测试查询工厂类 - 专门用于生成测试查询参数
+ */
+export class TestQueryFactory {
+  /**
+   * 创建省份查询参数
+   */
+  static createProvincesQuery(overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      page: 1,
+      pageSize: 50,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建城市查询参数
+   */
+  static createCitiesQuery(provinceId: number, overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      provinceId,
+      page: 1,
+      pageSize: 50,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建区县查询参数
+   */
+  static createDistrictsQuery(cityId: number, overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      cityId,
+      page: 1,
+      pageSize: 50,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建树形结构查询参数
+   */
+  static createTreeQuery(overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建层级树形结构查询参数
+   */
+  static createTreeByLevelQuery(level: number, overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建子树查询参数
+   */
+  static createSubTreeQuery(id: number, overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建区域路径查询参数
+   */
+  static createAreaPathQuery(id: number, overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建分页查询参数
+   */
+  static createPaginationQuery(page: number = 1, pageSize: number = 50, overrides: any = {}): any {
+    return {
+      tenantId: 1,
+      page,
+      pageSize,
+      ...overrides
+    };
+  }
+}