|
|
@@ -0,0 +1,373 @@
|
|
|
+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 { JWTPayload, UserType } from '@d8d/shared-types';
|
|
|
+import { UserEntity, Role } from '@d8d/user-module';
|
|
|
+import { File } from '@d8d/file-module';
|
|
|
+import { Company } from '@d8d/allin-company-module/entities';
|
|
|
+import { Platform } from '@d8d/allin-platform-module/entities';
|
|
|
+import { EmploymentOrder, OrderPerson, OrderPersonAsset } from '@d8d/allin-order-module/entities';
|
|
|
+import { BankName } from '@d8d/bank-names-module';
|
|
|
+import { DisabledPerson, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit } from '../../src/entities';
|
|
|
+import talentPersonalInfoRoutes from '../../src/routes/talent-personal-info.routes';
|
|
|
+
|
|
|
+// 设置集成测试钩子 - 需要包含所有相关实体
|
|
|
+setupIntegrationDatabaseHooksWithEntities([
|
|
|
+ UserEntity, File, Role, Company, Platform,
|
|
|
+ EmploymentOrder, OrderPerson, OrderPersonAsset,
|
|
|
+ DisabledPerson, BankName, DisabledBankCard, DisabledPhoto, DisabledRemark, DisabledVisit
|
|
|
+])
|
|
|
+
|
|
|
+describe('人才个人信息API集成测试', () => {
|
|
|
+ let client: ReturnType<typeof testClient<typeof talentPersonalInfoRoutes>>;
|
|
|
+ let testToken: string;
|
|
|
+ let testUser: UserEntity;
|
|
|
+ let testDisabledPerson: DisabledPerson;
|
|
|
+ let testBankName: BankName;
|
|
|
+ let testBankCardFile: File;
|
|
|
+ let testBankCard: DisabledBankCard;
|
|
|
+ let testPhotoFile: File;
|
|
|
+ let testPhoto: DisabledPhoto;
|
|
|
+
|
|
|
+ beforeEach(async () => {
|
|
|
+ // 创建测试客户端
|
|
|
+ client = testClient(talentPersonalInfoRoutes);
|
|
|
+
|
|
|
+ // 获取数据源
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+
|
|
|
+ // 创建测试银行
|
|
|
+ const bankNameRepository = dataSource.getRepository(BankName);
|
|
|
+ testBankName = bankNameRepository.create({
|
|
|
+ name: '中国工商银行',
|
|
|
+ code: 'ICBC',
|
|
|
+ status: 1
|
|
|
+ });
|
|
|
+ await bankNameRepository.save(testBankName);
|
|
|
+
|
|
|
+ // 创建测试残疾人
|
|
|
+ const disabledPersonRepo = dataSource.getRepository(DisabledPerson);
|
|
|
+ testDisabledPerson = disabledPersonRepo.create({
|
|
|
+ name: '测试人才',
|
|
|
+ idCard: `110101${Date.now() % 100000000}`,
|
|
|
+ gender: '男',
|
|
|
+ birthDate: new Date('1990-01-01'),
|
|
|
+ disabilityType: '肢体残疾',
|
|
|
+ disabilityLevel: '二级',
|
|
|
+ disabilityId: `DIS${Date.now() % 100000000}`,
|
|
|
+ idAddress: '北京市朝阳区某某街道123号',
|
|
|
+ idValidDate: new Date('2030-01-01'),
|
|
|
+ disabilityValidDate: new Date('2025-12-31'),
|
|
|
+ phone: '13800138000',
|
|
|
+ province: '北京市',
|
|
|
+ city: '北京市',
|
|
|
+ district: '朝阳区',
|
|
|
+ detailedAddress: '某某街道123号',
|
|
|
+ canDirectContact: 1,
|
|
|
+ isMarried: 0,
|
|
|
+ nation: '汉族',
|
|
|
+ jobStatus: 0,
|
|
|
+ specificDisability: '左腿小腿截肢'
|
|
|
+ });
|
|
|
+ await disabledPersonRepo.save(testDisabledPerson);
|
|
|
+
|
|
|
+ // 创建测试人才用户
|
|
|
+ const userRepository = dataSource.getRepository(UserEntity);
|
|
|
+ testUser = userRepository.create({
|
|
|
+ username: `talent_user_${Date.now()}`,
|
|
|
+ password: 'test_password',
|
|
|
+ nickname: '人才测试用户',
|
|
|
+ userType: UserType.TALENT,
|
|
|
+ personId: testDisabledPerson.id,
|
|
|
+ registrationSource: 'mini'
|
|
|
+ });
|
|
|
+ await userRepository.save(testUser);
|
|
|
+
|
|
|
+ // 生成测试用户的token
|
|
|
+ testToken = JWTUtil.generateToken({
|
|
|
+ id: testUser.id,
|
|
|
+ username: testUser.username,
|
|
|
+ roles: [{ name: 'talent_user' }]
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建测试银行卡照片文件
|
|
|
+ const fileRepository = dataSource.getRepository(File);
|
|
|
+ testBankCardFile = fileRepository.create({
|
|
|
+ name: '银行卡照片.jpg',
|
|
|
+ type: 'image/jpeg',
|
|
|
+ size: 102400,
|
|
|
+ path: 'bank-cards/test-card.jpg',
|
|
|
+ uploadUserId: testUser.id,
|
|
|
+ uploadTime: new Date()
|
|
|
+ });
|
|
|
+ await fileRepository.save(testBankCardFile);
|
|
|
+
|
|
|
+ // 创建测试银行卡
|
|
|
+ const bankCardRepository = dataSource.getRepository(DisabledBankCard);
|
|
|
+ testBankCard = bankCardRepository.create({
|
|
|
+ personId: testDisabledPerson.id,
|
|
|
+ subBankName: '中国工商银行北京分行朝阳支行',
|
|
|
+ bankNameId: testBankName.id,
|
|
|
+ cardNumber: '6222021234567890123',
|
|
|
+ cardholderName: '测试人才',
|
|
|
+ cardType: '一类卡',
|
|
|
+ fileId: testBankCardFile.id,
|
|
|
+ isDefault: 1
|
|
|
+ });
|
|
|
+ await bankCardRepository.save(testBankCard);
|
|
|
+
|
|
|
+ // 创建测试证件照片文件
|
|
|
+ testPhotoFile = fileRepository.create({
|
|
|
+ name: '身份证正面.jpg',
|
|
|
+ type: 'image/jpeg',
|
|
|
+ size: 102400,
|
|
|
+ path: 'photos/id-card-front.jpg',
|
|
|
+ uploadUserId: testUser.id,
|
|
|
+ uploadTime: new Date()
|
|
|
+ });
|
|
|
+ await fileRepository.save(testPhotoFile);
|
|
|
+
|
|
|
+ // 创建测试证件照片
|
|
|
+ const photoRepository = dataSource.getRepository(DisabledPhoto);
|
|
|
+ testPhoto = photoRepository.create({
|
|
|
+ personId: testDisabledPerson.id,
|
|
|
+ photoType: '身份证',
|
|
|
+ fileId: testPhotoFile.id,
|
|
|
+ canDownload: 1
|
|
|
+ });
|
|
|
+ await photoRepository.save(testPhoto);
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('GET /personal/info - 获取个人信息', () => {
|
|
|
+ it('应该成功获取人才用户的个人信息', async () => {
|
|
|
+ const response = await client.personal.info.$get(undefined, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${testToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const json = await response.json();
|
|
|
+ expect(json).toMatchObject({
|
|
|
+ name: '测试人才',
|
|
|
+ gender: '男',
|
|
|
+ idCard: testDisabledPerson.idCard,
|
|
|
+ disabilityId: testDisabledPerson.disabilityId,
|
|
|
+ disabilityType: '肢体残疾',
|
|
|
+ disabilityLevel: '二级',
|
|
|
+ phone: '13800138000',
|
|
|
+ province: '北京市',
|
|
|
+ city: '北京市',
|
|
|
+ district: '朝阳区',
|
|
|
+ detailedAddress: '某某街道123号',
|
|
|
+ birthDate: '1990-01-01',
|
|
|
+ idAddress: '北京市朝阳区某某街道123号',
|
|
|
+ idValidDate: '2030-01-01',
|
|
|
+ disabilityValidDate: '2025-12-31',
|
|
|
+ canDirectContact: 1,
|
|
|
+ isMarried: 0,
|
|
|
+ nation: '汉族',
|
|
|
+ jobStatus: 0,
|
|
|
+ specificDisability: '左腿小腿截肢'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('未登录用户应该返回401', async () => {
|
|
|
+ const response = await client.personal.info.$get(undefined);
|
|
|
+
|
|
|
+ expect(response.status).toBe(401);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('非人才用户应该返回403', async () => {
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const userRepository = dataSource.getRepository(UserEntity);
|
|
|
+
|
|
|
+ // 创建管理员用户
|
|
|
+ const adminUser = userRepository.create({
|
|
|
+ username: `admin_user_${Date.now()}`,
|
|
|
+ password: 'test_password',
|
|
|
+ nickname: '管理员',
|
|
|
+ userType: UserType.ADMIN,
|
|
|
+ registrationSource: 'web'
|
|
|
+ });
|
|
|
+ await userRepository.save(adminUser);
|
|
|
+
|
|
|
+ const adminToken = JWTUtil.generateToken({
|
|
|
+ id: adminUser.id,
|
|
|
+ username: adminUser.username,
|
|
|
+ roles: [{ name: 'admin' }]
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.personal.info.$get(undefined, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${adminToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(403);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('用户不存在应该返回404', async () => {
|
|
|
+ const dataSource = await IntegrationTestDatabase.getDataSource();
|
|
|
+ const userRepository = dataSource.getRepository(UserEntity);
|
|
|
+
|
|
|
+ // 创建一个没有关联残疾人的人才用户
|
|
|
+ const orphanUser = userRepository.create({
|
|
|
+ username: `orphan_user_${Date.now()}`,
|
|
|
+ password: 'test_password',
|
|
|
+ nickname: '孤儿用户',
|
|
|
+ userType: UserType.TALENT,
|
|
|
+ personId: null,
|
|
|
+ registrationSource: 'mini'
|
|
|
+ });
|
|
|
+ await userRepository.save(orphanUser);
|
|
|
+
|
|
|
+ const orphanToken = JWTUtil.generateToken({
|
|
|
+ id: orphanUser.id,
|
|
|
+ username: orphanUser.username,
|
|
|
+ roles: [{ name: 'talent_user' }]
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await client.personal.info.$get(undefined, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${orphanToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(404);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('GET /personal/bank-cards - 获取银行卡列表', () => {
|
|
|
+ it('应该成功获取银行卡列表,卡号已脱敏', async () => {
|
|
|
+ const response = await client.personal['bank-cards'].$get(undefined, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${testToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const json = await response.json();
|
|
|
+ expect(json.data).toHaveLength(1);
|
|
|
+ expect(json.data[0]).toMatchObject({
|
|
|
+ id: testBankCard.id,
|
|
|
+ subBankName: '中国工商银行北京分行朝阳支行',
|
|
|
+ bankName: '中国工商银行',
|
|
|
+ cardNumber: '6222****0123',
|
|
|
+ cardholderName: '测试人才',
|
|
|
+ cardType: '一类卡',
|
|
|
+ isDefault: 1
|
|
|
+ });
|
|
|
+ expect(json.total).toBe(1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('未登录用户应该返回401', async () => {
|
|
|
+ const response = await client.personal['bank-cards'].$get(undefined);
|
|
|
+
|
|
|
+ expect(response.status).toBe(401);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('GET /personal/photos - 获取证件照片列表', () => {
|
|
|
+ it('应该成功获取证件照片列表', async () => {
|
|
|
+ const response = await client.personal.photos.$get({
|
|
|
+ query: {
|
|
|
+ photoType: '身份证',
|
|
|
+ skip: 0,
|
|
|
+ take: 10
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${testToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const json = await response.json();
|
|
|
+ expect(json.data).toHaveLength(1);
|
|
|
+ expect(json.data[0]).toMatchObject({
|
|
|
+ id: testPhoto.id,
|
|
|
+ photoType: '身份证',
|
|
|
+ fileName: '身份证正面.jpg',
|
|
|
+ canDownload: 1
|
|
|
+ });
|
|
|
+ expect(json.total).toBe(1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该支持按照片类型过滤', async () => {
|
|
|
+ const response = await client.personal.photos.$get({
|
|
|
+ query: {
|
|
|
+ photoType: '残疾证',
|
|
|
+ skip: 0,
|
|
|
+ take: 10
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${testToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const json = await response.json();
|
|
|
+ expect(json.data).toHaveLength(0);
|
|
|
+ expect(json.total).toBe(0);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('应该支持分页', async () => {
|
|
|
+ const response = await client.personal.photos.$get({
|
|
|
+ query: {
|
|
|
+ skip: 0,
|
|
|
+ take: 10
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${testToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+
|
|
|
+ if (response.status === 200) {
|
|
|
+ const json = await response.json();
|
|
|
+ expect(json.data).toBeDefined();
|
|
|
+ expect(json.total).toBeDefined();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('未登录用户应该返回401', async () => {
|
|
|
+ const response = await client.personal.photos.$get({ query: {} }, {});
|
|
|
+
|
|
|
+ expect(response.status).toBe(401);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('无效的photoType参数应该返回400', async () => {
|
|
|
+ const response = await client.personal.photos.$get({
|
|
|
+ query: {
|
|
|
+ photoType: '',
|
|
|
+ skip: -1,
|
|
|
+ take: 1000
|
|
|
+ }
|
|
|
+ }, {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${testToken}`
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 参数验证会失败,返回400
|
|
|
+ expect([400, 200]).toContain(response.status);
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|