import { describe, it, expect, beforeEach } from 'vitest'; import { testClient } from 'hono/testing'; import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities, IntegrationTestAssertions } from '@d8d/shared-test-util'; import { areaRoutes } from '../../src/api/areas'; import { AreaEntity, AreaLevel } from '../../src/modules/areas/area.entity'; import { DisabledStatus } from '@d8d/shared-types'; import { TestDataFactory } from '../utils/test-data-factory'; // 设置集成测试钩子 setupIntegrationDatabaseHooksWithEntities([AreaEntity]) describe('区域API集成测试', () => { let client: ReturnType>; let testAreas: AreaEntity[]; beforeEach(async () => { // 创建测试客户端 client = testClient(areaRoutes); // 创建测试数据 const dataSource = await IntegrationTestDatabase.getDataSource(); // 创建启用状态的省份 const province1 = await TestDataFactory.createTestArea(dataSource, { name: '北京市', level: AreaLevel.PROVINCE, isDisabled: DisabledStatus.ENABLED }); const province2 = await TestDataFactory.createTestArea(dataSource, { name: '上海市', level: AreaLevel.PROVINCE, isDisabled: DisabledStatus.ENABLED }); const province3 = await TestDataFactory.createTestArea(dataSource, { name: '广东省', level: AreaLevel.PROVINCE, isDisabled: DisabledStatus.ENABLED }); // 创建启用状态的城市 const city11 = await TestDataFactory.createTestArea(dataSource, { name: '北京市', level: AreaLevel.CITY, parentId: province1.id, isDisabled: DisabledStatus.ENABLED }); const city12 = await TestDataFactory.createTestArea(dataSource, { name: '朝阳区', level: AreaLevel.CITY, parentId: province1.id, isDisabled: DisabledStatus.ENABLED }); const city13 = await TestDataFactory.createTestArea(dataSource, { name: '海淀区', level: AreaLevel.CITY, parentId: province1.id, isDisabled: DisabledStatus.ENABLED }); const city21 = await TestDataFactory.createTestArea(dataSource, { name: '上海市', level: AreaLevel.CITY, parentId: province2.id, isDisabled: DisabledStatus.ENABLED }); const city22 = await TestDataFactory.createTestArea(dataSource, { name: '浦东新区', level: AreaLevel.CITY, parentId: province2.id, isDisabled: DisabledStatus.ENABLED }); // 创建启用状态的区县 const district101 = await TestDataFactory.createTestArea(dataSource, { name: '朝阳区', level: AreaLevel.DISTRICT, parentId: city12.id, isDisabled: DisabledStatus.ENABLED }); const district102 = await TestDataFactory.createTestArea(dataSource, { name: '海淀区', level: AreaLevel.DISTRICT, parentId: city13.id, isDisabled: DisabledStatus.ENABLED }); const district103 = await TestDataFactory.createTestArea(dataSource, { name: '西城区', level: AreaLevel.DISTRICT, parentId: city12.id, isDisabled: DisabledStatus.ENABLED }); const district201 = await TestDataFactory.createTestArea(dataSource, { name: '浦东新区', level: AreaLevel.DISTRICT, parentId: city22.id, isDisabled: DisabledStatus.ENABLED }); // 创建禁用状态的区域用于测试过滤 const disabledProvince = await TestDataFactory.createTestArea(dataSource, { name: '禁用省份', level: AreaLevel.PROVINCE, isDisabled: DisabledStatus.DISABLED }); const disabledCity = await TestDataFactory.createTestArea(dataSource, { name: '禁用城市', level: AreaLevel.CITY, parentId: province3.id, isDisabled: DisabledStatus.DISABLED }); const disabledDistrict = await TestDataFactory.createTestArea(dataSource, { name: '禁用区县', level: AreaLevel.DISTRICT, parentId: city12.id, isDisabled: DisabledStatus.DISABLED }); testAreas = [ province1, province2, province3, city11, city12, city13, city21, city22, district101, district102, district103, district201, disabledProvince, disabledCity, disabledDistrict ]; }); describe('GET /areas/provinces', () => { it('应该成功获取启用状态的省份列表', async () => { const response = await client.provinces.$get({ query: { page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const data = await response.json(); // 验证响应数据格式 expect(data).toHaveProperty('success', true); expect(data).toHaveProperty('data'); expect(data.data).toHaveProperty('provinces'); expect(data.data).toHaveProperty('pagination'); // 验证只返回启用状态的省份 const provinces = data.data.provinces; expect(provinces).toHaveLength(3); // 只返回3个启用状态的省份 // 验证不包含禁用状态的省份 const disabledProvince = provinces.find((p: any) => p.isDisabled === DisabledStatus.DISABLED); expect(disabledProvince).toBeUndefined(); // 验证分页信息 expect(data.data.pagination).toEqual({ page: 1, pageSize: 50, total: 3, totalPages: 1 }); } }); it('应该正确处理分页参数', async () => { const response = await client.provinces.$get({ query: { page: 1, pageSize: 2 } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const data = await response.json(); // 验证分页结果 expect(data.data.provinces).toHaveLength(2); expect(data.data.pagination).toEqual({ page: 1, pageSize: 2, total: 3, totalPages: 2 }); } }); }); describe('GET /areas/cities', () => { it('应该成功获取指定省份下启用状态的城市列表', async () => { const response = await client.cities.$get({ query: { provinceId: testAreas[0].id, page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const data = await response.json(); // 验证响应数据格式 expect(data).toHaveProperty('success', true); expect(data).toHaveProperty('data'); expect(data.data).toHaveProperty('cities'); // 验证只返回启用状态的城市 const cities = data.data.cities; expect(cities).toHaveLength(3); // 北京市下有3个启用状态的城市 // 验证城市数据正确 const cityNames = cities.map((c: any) => c.name); expect(cityNames).toContain('北京市'); expect(cityNames).toContain('朝阳区'); expect(cityNames).toContain('海淀区'); // 验证不包含禁用状态的城市 const disabledCity = cities.find((c: any) => c.name === '禁用城市'); expect(disabledCity).toBeUndefined(); } }); it('应该处理不存在的省份ID', async () => { const response = await client.cities.$get({ query: { provinceId: 999, page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const data = await response.json(); // 不存在的省份应该返回空数组 expect(data.data.cities).toHaveLength(0); } }); it('应该验证省份ID参数', async () => { const response = await client.cities.$get({ query: { provinceId: 0, page: 1, pageSize: 50 } }); // 参数验证应该返回400错误 IntegrationTestAssertions.expectStatus(response, 400); }); }); describe('GET /areas/districts', () => { it('应该成功获取指定城市下启用状态的区县列表', async () => { // 找到朝阳区城市对象 const chaoyangCity = testAreas.find(area => area.name === '朝阳区' && area.level === AreaLevel.CITY); expect(chaoyangCity).toBeDefined(); const response = await client.districts.$get({ query: { cityId: chaoyangCity!.id, page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const data = await response.json(); // 验证响应数据格式 expect(data).toHaveProperty('success', true); expect(data).toHaveProperty('data'); expect(data.data).toHaveProperty('districts'); // 验证只返回启用状态的区县 const districts = data.data.districts; expect(districts).toHaveLength(2); // 朝阳区下有2个启用状态的区县 // 验证区县数据正确 const districtNames = districts.map((d: any) => d.name); expect(districtNames).toContain('朝阳区'); expect(districtNames).toContain('西城区'); // 验证不包含禁用状态的区县 const disabledDistrict = districts.find((d: any) => d.name === '禁用区县'); expect(disabledDistrict).toBeUndefined(); } }); it('应该处理不存在的城市ID', async () => { const response = await client.districts.$get({ query: { cityId: 999, page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const data = await response.json(); // 不存在的城市应该返回空数组 expect(data.data.districts).toHaveLength(0); } }); it('应该验证城市ID参数', async () => { const response = await client.districts.$get({ query: { cityId: 0, page: 1, pageSize: 50 } }); // 参数验证应该返回400错误 IntegrationTestAssertions.expectStatus(response, 400); }); }); describe('过滤禁用状态验证', () => { it('应该确保所有API只返回启用状态的区域', async () => { // 测试省份API const provincesResponse = await client.provinces.$get({ query: { page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(provincesResponse, 200); const provincesData = await provincesResponse.json(); // 验证省份不包含禁用状态 if ('data' in provincesData) { const provinces = provincesData.data.provinces; const hasDisabledProvince = provinces.some((p: any) => p.isDisabled === DisabledStatus.DISABLED); expect(hasDisabledProvince).toBe(false); } // 测试城市API const citiesResponse = await client.cities.$get({ query: { provinceId: testAreas[0].id, page: 1, pageSize: 50 } }); IntegrationTestAssertions.expectStatus(citiesResponse, 200); const citiesData = await citiesResponse.json(); // 验证城市不包含禁用状态 if ('data' in citiesData) { const cities = citiesData.data.cities; const hasDisabledCity = cities.some((c: any) => c.isDisabled === DisabledStatus.DISABLED); expect(hasDisabledCity).toBe(false); } // 测试区县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 } }); IntegrationTestAssertions.expectStatus(districtsResponse, 200); const districtsData = await districtsResponse.json(); // 验证区县不包含禁用状态 if ('data' in districtsData) { const districts = districtsData.data.districts; const hasDisabledDistrict = districts.some((d: any) => d.isDisabled === DisabledStatus.DISABLED); expect(hasDisabledDistrict).toBe(false); } }); }); });