import { describe, it, expect, beforeEach } from 'vitest'; import { testClient } from 'hono/testing'; import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util'; import { IntegrationTestAssertions } from '../utils/integration-test-utils'; import adminAreaRoutes from '../../src/api/admin/areas'; import { AreaEntity, AreaLevel } from '../../src/modules/areas/area.entity'; import { Role, UserEntity } from '@d8d/user-module'; import { File } from '@d8d/file-module'; import { DisabledStatus } from '@d8d/shared-types'; import { TestDataFactory } from '../utils/test-data-factory'; import { AuthService } from '@d8d/auth-module'; import { UserService } from '@d8d/user-module'; // 设置集成测试钩子 setupIntegrationDatabaseHooksWithEntities([AreaEntity, UserEntity, File, Role]) describe('管理地区API集成测试 (使用hono/testing)', () => { let client: ReturnType>; let authService: AuthService; let userService: UserService; let testToken: string; let testUser: any; let testAreas: AreaEntity[]; beforeEach(async () => { // 创建测试客户端 client = testClient(adminAreaRoutes); // 获取数据源 const dataSource = await IntegrationTestDatabase.getDataSource(); if (!dataSource) throw new Error('Database not initialized'); // 初始化服务 userService = new UserService(dataSource); authService = new AuthService(userService); // 创建测试用户并生成token testUser = await TestDataFactory.createTestUser(dataSource, { username: 'testuser_admin_areas', password: 'TestPassword123!', email: 'testuser_admin_areas@example.com' }); // 生成测试用户的token testToken = authService.generateToken(testUser); // 创建测试地区数据 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 city1 = await TestDataFactory.createTestArea(dataSource, { name: '朝阳区', level: AreaLevel.CITY, parentId: province1.id, isDisabled: DisabledStatus.ENABLED }); const city2 = await TestDataFactory.createTestArea(dataSource, { name: '海淀区', level: AreaLevel.CITY, parentId: province1.id, isDisabled: DisabledStatus.ENABLED }); const district1 = await TestDataFactory.createTestArea(dataSource, { name: '朝阳区', level: AreaLevel.DISTRICT, parentId: city1.id, isDisabled: DisabledStatus.ENABLED }); testAreas = [province1, province2, city1, city2, district1]; }); describe('认证测试', () => { it('应该拒绝无认证令牌的请求', async () => { const response = await client.index.$get({ query: {} }); // 应该返回401状态码,因为缺少认证 expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('Authorization header missing'); } }); it('应该拒绝无效认证令牌的请求', async () => { const response = await client.index.$get({ query: {} }, { headers: { 'Authorization': 'Bearer invalid.token.here' } }); // 应该返回401状态码,因为令牌无效 expect(response.status).toBe(401); if (response.status === 401) { const responseData = await response.json(); expect(responseData.message).toContain('Invalid token'); } }); }); describe('地区CRUD操作测试', () => { it('应该成功创建地区(使用有效认证令牌)', async () => { const areaData = { name: '测试省份', code: 'test_province_001', level: AreaLevel.PROVINCE, parentId: null, isDisabled: DisabledStatus.ENABLED }; const response = await client.index.$post({ json: areaData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); // 断言响应 expect(response.status).toBe(201); if (response.status === 201) { const responseData = await response.json(); expect(responseData).toHaveProperty('id'); expect(responseData.name).toBe(areaData.name); expect(responseData.code).toBe(areaData.code); expect(responseData.level).toBe(areaData.level); // 断言数据库中存在地区 await IntegrationTestAssertions.expectAreaToExist(areaData.name); } }); it('应该成功获取地区列表', async () => { const response = await client.index.$get({ query: {} }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const responseData = await response.json(); expect(Array.isArray(responseData.data)).toBe(true); expect(responseData.data.length).toBeGreaterThanOrEqual(5); // 至少有5个测试地区 } }); it('应该成功获取单个地区详情', async () => { const testArea = testAreas[0]; const response = await client[':id'].$get({ param: { id: testArea.id } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const responseData = await response.json(); expect(responseData.id).toBe(testArea.id); expect(responseData.name).toBe(testArea.name); expect(responseData.level).toBe(testArea.level); } }); it('应该返回404当地区不存在时', async () => { const response = await client[':id'].$get({ param: { id: 999999 } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(404); if (response.status === 404) { const responseData = await response.json(); expect(responseData.message).toContain('资源不存在'); } }); it('应该成功更新地区信息', async () => { const testArea = testAreas[0]; const updateData = { name: '更新后的北京市', code: 'updated_beijing' }; const response = await client[':id'].$put({ param: { id: testArea.id }, json: updateData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const responseData = await response.json(); expect(responseData.name).toBe(updateData.name); expect(responseData.code).toBe(updateData.code); } }); it('应该成功删除地区', async () => { const dataSource = await IntegrationTestDatabase.getDataSource(); if (!dataSource) throw new Error('Database not initialized'); const testArea = await TestDataFactory.createTestArea(dataSource, { name: '待删除地区', level: AreaLevel.PROVINCE }); const response = await client[':id'].$delete({ param: { id: testArea.id } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 204); // 验证地区已从数据库中删除 await IntegrationTestAssertions.expectAreaNotToExist('待删除地区'); }); }); describe('地区搜索测试', () => { it('应该能够按名称搜索地区', async () => { const response = await client.index.$get({ query: { keyword: '北京' } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const responseData = await response.json(); expect(Array.isArray(responseData.data)).toBe(true); expect(responseData.data.length).toBeGreaterThan(0); // 验证搜索结果包含正确的地区 const names = responseData.data.map((area: any) => area.name); expect(names).toContain('北京市'); } }); it('应该能够按代码搜索地区', async () => { const response = await client.index.$get({ query: { keyword: 'area_' } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const responseData = await response.json(); expect(responseData.data.length).toBeGreaterThan(0); } }); }); describe('树形结构查询测试', () => { it('应该成功获取完整树形结构', async () => { const response = await client.tree.$get({}, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const responseData = await response.json(); expect(responseData).toHaveProperty('success', true); expect(responseData).toHaveProperty('data'); expect(Array.isArray(responseData.data)).toBe(true); // 验证树形结构包含省份 const provinceNames = responseData.data.map((area: any) => area.name); expect(provinceNames).toContain('北京市'); expect(provinceNames).toContain('上海市'); } }); it('应该根据层级获取树形结构', async () => { const response = await client.tree.level[':level'].$get({ param: { level: AreaLevel.PROVINCE } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const responseData = await response.json(); expect(responseData).toHaveProperty('success', true); expect(responseData).toHaveProperty('data'); // 验证只返回省级地区 const provinces = responseData.data; expect(provinces.length).toBeGreaterThan(0); provinces.forEach((province: any) => { expect(province.level).toBe(AreaLevel.PROVINCE); }); } }); it('应该获取指定节点的子树', async () => { const province = testAreas.find(area => area.name === '北京市'); expect(province).toBeDefined(); const response = await client.tree[':id'].$get({ param: { id: province!.id } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const responseData = await response.json(); expect(responseData).toHaveProperty('success', true); expect(responseData).toHaveProperty('data'); // 验证子树包含城市 const subTree = responseData.data; expect(subTree).toBeDefined(); expect(subTree).toHaveProperty('children'); if (subTree && subTree.children) { const cityNames = subTree.children.map((city: any) => city.name); expect(cityNames).toContain('朝阳区'); expect(cityNames).toContain('海淀区'); } } }); it('应该获取区域路径', async () => { const district = testAreas.find(area => area.level === AreaLevel.DISTRICT); expect(district).toBeDefined(); const response = await client.path[':id'].$get({ param: { id: district!.id } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); IntegrationTestAssertions.expectStatus(response, 200); if (response.status === 200) { const responseData = await response.json(); expect(responseData).toHaveProperty('success', true); expect(responseData).toHaveProperty('data'); // 验证路径包含正确的层级 const path = responseData.data; expect(Array.isArray(path)).toBe(true); expect(path.length).toBeGreaterThan(0); // 路径应该包含从省份到区县的完整路径 const levels = path.map((area: any) => area.level); expect(levels).toContain(AreaLevel.PROVINCE); expect(levels).toContain(AreaLevel.CITY); expect(levels).toContain(AreaLevel.DISTRICT); } }); }); describe('性能测试', () => { it('地区列表查询响应时间应小于200ms', async () => { const startTime = Date.now(); const response = await client.index.$get({ query: {} }, { headers: { 'Authorization': `Bearer ${testToken}` } }); const endTime = Date.now(); const responseTime = endTime - startTime; IntegrationTestAssertions.expectStatus(response, 200); expect(responseTime).toBeLessThan(200); // 响应时间应小于200ms }); it('树形结构查询响应时间应小于300ms', async () => { const startTime = Date.now(); const response = await client.tree.$get({}, { headers: { 'Authorization': `Bearer ${testToken}` } }); const endTime = Date.now(); const responseTime = endTime - startTime; IntegrationTestAssertions.expectStatus(response, 200); expect(responseTime).toBeLessThan(300); // 树形结构查询响应时间应小于300ms }); }); });