import { describe, it, expect, beforeEach } 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 { File } from '@d8d/file-module'; import { AreaEntity } from '@d8d/geo-areas'; import salaryRoutes from '../../src/routes/salary.routes'; import { SalaryLevel } from '../../src/entities/salary-level.entity'; // 设置集成测试钩子 setupIntegrationDatabaseHooksWithEntities([UserEntity, File, Role, AreaEntity, SalaryLevel]) describe('薪资管理API集成测试', () => { let client: ReturnType>; let testToken: string; let testUser: UserEntity; let testProvince: AreaEntity; let testCity: AreaEntity; let testDistrict: AreaEntity; let testProvince2: AreaEntity; let testCity2: AreaEntity; beforeEach(async () => { // 创建测试客户端 client = testClient(salaryRoutes); // 获取数据源 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); // 生成测试用户的token testToken = JWTUtil.generateToken({ id: testUser.id, username: testUser.username, roles: [{name:'user'}] }); // 创建测试区域数据 const areaRepository = dataSource.getRepository(AreaEntity); // 创建省份 testProvince = areaRepository.create({ code: '110000', name: '北京市', level: 1, parentId: null }); await areaRepository.save(testProvince); // 创建城市 testCity = areaRepository.create({ code: '110100', name: '北京市', level: 2, parentId: testProvince.id }); await areaRepository.save(testCity); // 创建区县 testDistrict = areaRepository.create({ code: '110101', name: '东城区', level: 3, parentId: testCity.id }); await areaRepository.save(testDistrict); // 创建第二个省份 testProvince2 = areaRepository.create({ code: '120000', name: '天津市', level: 1, parentId: null }); await areaRepository.save(testProvince2); // 创建第二个城市 testCity2 = areaRepository.create({ code: '120100', name: '天津市', level: 2, parentId: testProvince2.id }); await areaRepository.save(testCity2); }); describe('POST /salary/create', () => { it('应该成功创建薪资水平', async () => { const createData = { provinceId: testProvince.id, cityId: testCity.id, districtId: testDistrict.id, basicSalary: 5000.00 }; console.debug('发送的创建数据:', JSON.stringify(createData, null, 2)); const response = await client.create.$post({ json: createData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); if (response.status !== 200) { const error = await response.json(); console.debug('创建薪资失败:', JSON.stringify(error, null, 2)); } expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data.id).toBeDefined(); expect(data.provinceId).toBe(testProvince.id); expect(data.cityId).toBe(testCity.id); expect(data.districtId).toBe(testDistrict.id); expect(data.basicSalary).toBe(5000.00); expect(data.totalSalary).toBe(5000.00); // 只有基本工资 } }); it('应该验证区域层级关系', async () => { const createData = { provinceId: testProvince.id, cityId: testDistrict.id, // 错误的层级:城市ID使用了区县ID districtId: testCity.id, // 错误的层级:区县ID使用了城市ID basicSalary: 5000.00 }; const response = await client.create.$post({ json: createData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(400); }); it('应该验证区域唯一性约束', async () => { // 第一次创建 const createData = { provinceId: testProvince.id, cityId: testCity.id, basicSalary: 5000.00 }; const firstResponse = await client.create.$post({ json: createData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(firstResponse.status).toBe(200); // 第二次创建相同区域 const secondResponse = await client.create.$post({ json: createData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(secondResponse.status).toBe(400); }); }); describe('GET /salary/list', () => { beforeEach(async () => { // 创建测试数据 const dataSource = await IntegrationTestDatabase.getDataSource(); const salaryRepository = dataSource.getRepository(SalaryLevel); const salary1 = salaryRepository.create({ provinceId: testProvince.id, cityId: testCity.id, districtId: testDistrict.id, basicSalary: 5000.00, allowance: 1000.00, insurance: 500.00, housingFund: 800.00, totalSalary: 7300.00 }); await salaryRepository.save(salary1); const salary2 = salaryRepository.create({ provinceId: testProvince2.id, // 使用不同的省份 cityId: testCity2.id, // 使用不同的城市 basicSalary: 6000.00, allowance: 1200.00, insurance: 600.00, housingFund: 900.00, totalSalary: 8700.00 }); await salaryRepository.save(salary2); }); it('应该返回所有薪资水平列表', async () => { const response = await client.list.$get({ query: {} }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data).toHaveProperty('data'); expect(data).toHaveProperty('total'); expect(data.data).toHaveLength(2); expect(data.total).toBe(2); } }); it('应该支持按区域ID过滤', async () => { const response = await client.list.$get({ query: { provinceId: testProvince.id.toString(), cityId: testCity.id.toString() } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data.data).toHaveLength(1); } }); it('应该支持分页查询', async () => { const response = await client.list.$get({ query: { skip: '0', take: '1' } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data.data).toHaveLength(1); expect(data.total).toBe(2); } }); }); describe('GET /salary/detail/:id', () => { let testSalary: SalaryLevel; beforeEach(async () => { // 创建测试薪资数据 const dataSource = await IntegrationTestDatabase.getDataSource(); const salaryRepository = dataSource.getRepository(SalaryLevel); testSalary = salaryRepository.create({ provinceId: testProvince.id, cityId: testCity.id, districtId: testDistrict.id, basicSalary: 5000.00, allowance: 1000.00, insurance: 500.00, housingFund: 800.00, totalSalary: 7300.00, }); await salaryRepository.save(testSalary); }); it('应该返回指定ID的薪资详情', async () => { const response = await client.detail[':id'].$get({ param: { id: testSalary.id.toString() } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data?.id).toBe(testSalary.id); expect(data?.provinceId).toBe(testProvince.id); expect(data?.cityId).toBe(testCity.id); } }); it('应该处理不存在的薪资ID', async () => { const response = await client.detail[':id'].$get({ param: { id: '999999' } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(404); }); }); describe('GET /salary/byProvinceCity', () => { let testSalary: SalaryLevel; beforeEach(async () => { // 创建测试薪资数据 const dataSource = await IntegrationTestDatabase.getDataSource(); const salaryRepository = dataSource.getRepository(SalaryLevel); testSalary = salaryRepository.create({ provinceId: testProvince.id, cityId: testCity.id, basicSalary: 5000.00, allowance: 1000.00, insurance: 500.00, housingFund: 800.00, totalSalary: 7300.00, }); await salaryRepository.save(testSalary); }); it('应该按省份城市查询薪资', async () => { const response = await client.byProvinceCity.$get({ query: { provinceId: testProvince.id.toString(), cityId: testCity.id.toString() } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data?.id).toBe(testSalary.id); expect(data?.provinceId).toBe(testProvince.id); expect(data?.cityId).toBe(testCity.id); } }); it('应该处理不存在的区域组合', async () => { const response = await client.byProvinceCity.$get({ query: { provinceId: '999999', cityId: '999999' } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(404); }); }); describe('PUT /salary/update/:id', () => { let testSalary: SalaryLevel; beforeEach(async () => { // 创建测试薪资数据 const dataSource = await IntegrationTestDatabase.getDataSource(); const salaryRepository = dataSource.getRepository(SalaryLevel); testSalary = salaryRepository.create({ provinceId: testProvince.id, cityId: testCity.id, basicSalary: 5000.00, allowance: 1000.00, insurance: 500.00, housingFund: 800.00, totalSalary: 7300.00, }); await salaryRepository.save(testSalary); }); it('应该成功更新薪资水平', async () => { const updateData = { basicSalary: 5500.00, allowance: 1200.00 }; const response = await client.update[':id'].$put({ param: { id: testSalary.id.toString() }, json: updateData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data.id).toBe(testSalary.id); expect(data.basicSalary).toBe(5500.00); expect(data.allowance).toBe(1200.00); expect(data.totalSalary).toBe(8000.00); // 5500 + 1200 + 500 + 800 } }); it('应该验证更新后的区域数据', async () => { const updateData = { provinceId: 999999 // 不存在的区域ID }; const response = await client.update[':id'].$put({ param: { id: testSalary.id.toString() }, json: updateData }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(400); }); }); describe('DELETE /salary/delete/:id', () => { let testSalary: SalaryLevel; beforeEach(async () => { // 创建测试薪资数据 const dataSource = await IntegrationTestDatabase.getDataSource(); const salaryRepository = dataSource.getRepository(SalaryLevel); testSalary = salaryRepository.create({ provinceId: testProvince.id, cityId: testCity.id, basicSalary: 5000.00, allowance: 1000.00, insurance: 500.00, housingFund: 800.00, totalSalary: 7300.00, }); await salaryRepository.save(testSalary); }); it('应该成功删除薪资水平', async () => { const response = await client.delete[':id'].$delete({ param: { id: testSalary.id.toString() } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(200); if (response.status === 200) { const data = await response.json(); expect(data).toEqual({ success: true }); // 验证数据已删除 const dataSource = await IntegrationTestDatabase.getDataSource(); const salaryRepository = dataSource.getRepository(SalaryLevel); const deletedSalary = await salaryRepository.findOne({ where: { id: testSalary.id } }); expect(deletedSalary).toBeNull(); } }); it('应该处理不存在的薪资ID', async () => { const response = await client.delete[':id'].$delete({ param: { id: '999999' } }, { headers: { 'Authorization': `Bearer ${testToken}` } }); expect(response.status).toBe(404); }); }); describe('认证测试', () => { it('应该要求认证', async () => { const response = await client.list.$get({ query: {} // 不提供Authorization header }); expect(response.status).toBe(401); }); it('应该验证无效token', async () => { const response = await client.list.$get({ query: {} }, { headers: { 'Authorization': 'Bearer invalid_token' } }); expect(response.status).toBe(401); }); }); });