import request from 'supertest'; import { Role } from '../../../src/generated/prisma/enums.js'; import { closeE2EContext, createE2EContext, type E2EContext, } from '../helpers/e2e-context.helper.js'; import { assertRoleMatrix } from '../helpers/e2e-matrix.helper.js'; import { expectErrorEnvelope, expectSuccessEnvelope, uniqueSeedValue, } from '../helpers/e2e-http.helper.js'; describe('Organization Controllers (e2e)', () => { let ctx: E2EContext; beforeAll(async () => { ctx = await createE2EContext(); }); afterAll(async () => { await closeE2EContext(ctx); }); describe('HospitalsController', () => { describe('POST /b/organization/hospitals', () => { it('成功:SYSTEM_ADMIN 可创建医院', async () => { const response = await request(ctx.app.getHttpServer()) .post('/b/organization/hospitals') .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`) .send({ name: uniqueSeedValue('组织-医院') }); expectSuccessEnvelope(response, 201); expect(response.body.data.name).toContain('组织-医院'); }); it('失败:非系统管理员创建返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .post('/b/organization/hospitals') .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('组织-医院-失败') }); expectErrorEnvelope(response, 403, '无权限执行当前操作'); }); it('角色矩阵:仅 SYSTEM_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'POST /b/organization/hospitals role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 400, [Role.HOSPITAL_ADMIN]: 403, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .post('/b/organization/hospitals') .set('Authorization', `Bearer ${token}`) .send({}), sendWithoutToken: async () => request(ctx.app.getHttpServer()) .post('/b/organization/hospitals') .send({}), }); }); }); describe('GET /b/organization/hospitals', () => { it('成功:SYSTEM_ADMIN 可查询医院列表', async () => { const response = await request(ctx.app.getHttpServer()) .get('/b/organization/hospitals') .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectSuccessEnvelope(response, 200); expect(response.body.data).toHaveProperty('list'); }); it('失败:未登录返回 401', async () => { const response = await request(ctx.app.getHttpServer()).get( '/b/organization/hospitals', ); expectErrorEnvelope(response, 401, '缺少 Bearer Token'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'GET /b/organization/hospitals role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 200, [Role.HOSPITAL_ADMIN]: 200, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .get('/b/organization/hospitals') .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).get('/b/organization/hospitals'), }); }); }); describe('GET /b/organization/hospitals/:id', () => { it('成功:HOSPITAL_ADMIN 可查询本院详情', async () => { const response = await request(ctx.app.getHttpServer()) .get(`/b/organization/hospitals/${ctx.fixtures.hospitalAId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectSuccessEnvelope(response, 200); expect(response.body.data.id).toBe(ctx.fixtures.hospitalAId); }); it('失败:HOSPITAL_ADMIN 查询他院返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .get(`/b/organization/hospitals/${ctx.fixtures.hospitalBId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'GET /b/organization/hospitals/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 200, [Role.HOSPITAL_ADMIN]: 200, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .get(`/b/organization/hospitals/${ctx.fixtures.hospitalAId}`) .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).get( `/b/organization/hospitals/${ctx.fixtures.hospitalAId}`, ), }); }); }); describe('PATCH /b/organization/hospitals/:id', () => { it('成功:HOSPITAL_ADMIN 可更新本院名称', async () => { const originalName = 'Seed Hospital A'; const nextName = uniqueSeedValue('医院更新'); const response = await request(ctx.app.getHttpServer()) .patch(`/b/organization/hospitals/${ctx.fixtures.hospitalAId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: nextName }); expectSuccessEnvelope(response, 200); const rollbackResponse = await request(ctx.app.getHttpServer()) .patch(`/b/organization/hospitals/${ctx.fixtures.hospitalAId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: originalName }); expectSuccessEnvelope(rollbackResponse, 200); }); it('失败:HOSPITAL_ADMIN 更新他院返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .patch(`/b/organization/hospitals/${ctx.fixtures.hospitalBId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('跨院更新失败') }); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'PATCH /b/organization/hospitals/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 404, [Role.HOSPITAL_ADMIN]: 404, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .patch('/b/organization/hospitals/99999999') .set('Authorization', `Bearer ${token}`) .send({ name: 'matrix-hospital-patch' }), sendWithoutToken: async () => request(ctx.app.getHttpServer()) .patch('/b/organization/hospitals/99999999') .send({ name: 'matrix-hospital-patch' }), }); }); }); describe('DELETE /b/organization/hospitals/:id', () => { it('成功:SYSTEM_ADMIN 可删除空医院', async () => { const createResponse = await request(ctx.app.getHttpServer()) .post('/b/organization/hospitals') .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`) .send({ name: uniqueSeedValue('医院待删') }); expectSuccessEnvelope(createResponse, 201); const targetId = createResponse.body.data.id as number; const deleteResponse = await request(ctx.app.getHttpServer()) .delete(`/b/organization/hospitals/${targetId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectSuccessEnvelope(deleteResponse, 200); expect(deleteResponse.body.data.id).toBe(targetId); }); it('失败:HOSPITAL_ADMIN 删除医院返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .delete(`/b/organization/hospitals/${ctx.fixtures.hospitalAId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectErrorEnvelope(response, 403, '无权限执行当前操作'); }); it('角色矩阵:仅 SYSTEM_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'DELETE /b/organization/hospitals/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 404, [Role.HOSPITAL_ADMIN]: 403, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .delete('/b/organization/hospitals/99999999') .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).delete( '/b/organization/hospitals/99999999', ), }); }); }); }); describe('DepartmentsController', () => { describe('POST /b/organization/departments', () => { it('成功:HOSPITAL_ADMIN 可在本院创建科室', async () => { const response = await request(ctx.app.getHttpServer()) .post('/b/organization/departments') .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('组织-科室'), hospitalId: ctx.fixtures.hospitalAId, }); expectSuccessEnvelope(response, 201); }); it('失败:HOSPITAL_ADMIN 跨院创建返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .post('/b/organization/departments') .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('组织-跨院科室失败'), hospitalId: ctx.fixtures.hospitalBId, }); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'POST /b/organization/departments role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 400, [Role.HOSPITAL_ADMIN]: 400, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .post('/b/organization/departments') .set('Authorization', `Bearer ${token}`) .send({}), sendWithoutToken: async () => request(ctx.app.getHttpServer()) .post('/b/organization/departments') .send({}), }); }); }); describe('GET /b/organization/departments', () => { it('成功:HOSPITAL_ADMIN 可查询本院科室列表', async () => { const response = await request(ctx.app.getHttpServer()) .get('/b/organization/departments') .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectSuccessEnvelope(response, 200); expect(response.body.data).toHaveProperty('list'); }); it('失败:未登录返回 401', async () => { const response = await request(ctx.app.getHttpServer()).get( '/b/organization/departments', ); expectErrorEnvelope(response, 401, '缺少 Bearer Token'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'GET /b/organization/departments role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 200, [Role.HOSPITAL_ADMIN]: 200, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .get('/b/organization/departments') .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).get('/b/organization/departments'), }); }); }); describe('GET /b/organization/departments/:id', () => { it('成功:SYSTEM_ADMIN 可查询科室详情', async () => { const response = await request(ctx.app.getHttpServer()) .get(`/b/organization/departments/${ctx.fixtures.departmentA1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectSuccessEnvelope(response, 200); expect(response.body.data.id).toBe(ctx.fixtures.departmentA1Id); }); it('失败:HOSPITAL_ADMIN 查询他院科室返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .get(`/b/organization/departments/${ctx.fixtures.departmentB1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'GET /b/organization/departments/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 200, [Role.HOSPITAL_ADMIN]: 200, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .get(`/b/organization/departments/${ctx.fixtures.departmentA1Id}`) .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).get( `/b/organization/departments/${ctx.fixtures.departmentA1Id}`, ), }); }); }); describe('PATCH /b/organization/departments/:id', () => { it('成功:HOSPITAL_ADMIN 可更新本院科室', async () => { const originalName = 'Cardiology-A2'; const nextName = uniqueSeedValue('科室更新'); const response = await request(ctx.app.getHttpServer()) .patch(`/b/organization/departments/${ctx.fixtures.departmentA2Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: nextName }); expectSuccessEnvelope(response, 200); const rollbackResponse = await request(ctx.app.getHttpServer()) .patch(`/b/organization/departments/${ctx.fixtures.departmentA2Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: originalName }); expectSuccessEnvelope(rollbackResponse, 200); }); it('失败:HOSPITAL_ADMIN 更新他院科室返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .patch(`/b/organization/departments/${ctx.fixtures.departmentB1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('跨院科室更新失败') }); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'PATCH /b/organization/departments/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 404, [Role.HOSPITAL_ADMIN]: 404, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .patch('/b/organization/departments/99999999') .set('Authorization', `Bearer ${token}`) .send({ name: 'matrix-department-patch' }), sendWithoutToken: async () => request(ctx.app.getHttpServer()) .patch('/b/organization/departments/99999999') .send({ name: 'matrix-department-patch' }), }); }); }); describe('DELETE /b/organization/departments/:id', () => { it('成功:SYSTEM_ADMIN 可删除无关联科室', async () => { const createResponse = await request(ctx.app.getHttpServer()) .post('/b/organization/departments') .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`) .send({ name: uniqueSeedValue('科室待删'), hospitalId: ctx.fixtures.hospitalAId, }); expectSuccessEnvelope(createResponse, 201); const targetId = createResponse.body.data.id as number; const deleteResponse = await request(ctx.app.getHttpServer()) .delete(`/b/organization/departments/${targetId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectSuccessEnvelope(deleteResponse, 200); }); it('失败:存在关联数据删除返回 409', async () => { const response = await request(ctx.app.getHttpServer()) .delete(`/b/organization/departments/${ctx.fixtures.departmentA1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectErrorEnvelope(response, 409, '存在关联数据,无法删除'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'DELETE /b/organization/departments/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 404, [Role.HOSPITAL_ADMIN]: 404, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .delete('/b/organization/departments/99999999') .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).delete( '/b/organization/departments/99999999', ), }); }); }); }); describe('GroupsController', () => { describe('POST /b/organization/groups', () => { it('成功:HOSPITAL_ADMIN 可创建小组', async () => { const response = await request(ctx.app.getHttpServer()) .post('/b/organization/groups') .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('组织-小组'), departmentId: ctx.fixtures.departmentA1Id, }); expectSuccessEnvelope(response, 201); }); it('失败:HOSPITAL_ADMIN 跨院创建小组返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .post('/b/organization/groups') .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('组织-跨院小组失败'), departmentId: ctx.fixtures.departmentB1Id, }); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'POST /b/organization/groups role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 400, [Role.HOSPITAL_ADMIN]: 400, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .post('/b/organization/groups') .set('Authorization', `Bearer ${token}`) .send({}), sendWithoutToken: async () => request(ctx.app.getHttpServer()) .post('/b/organization/groups') .send({}), }); }); }); describe('GET /b/organization/groups', () => { it('成功:SYSTEM_ADMIN 可查询小组列表', async () => { const response = await request(ctx.app.getHttpServer()) .get('/b/organization/groups') .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectSuccessEnvelope(response, 200); expect(response.body.data).toHaveProperty('list'); }); it('失败:未登录返回 401', async () => { const response = await request(ctx.app.getHttpServer()).get( '/b/organization/groups', ); expectErrorEnvelope(response, 401, '缺少 Bearer Token'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'GET /b/organization/groups role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 200, [Role.HOSPITAL_ADMIN]: 200, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .get('/b/organization/groups') .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).get('/b/organization/groups'), }); }); }); describe('GET /b/organization/groups/:id', () => { it('成功:HOSPITAL_ADMIN 可查询本院小组详情', async () => { const response = await request(ctx.app.getHttpServer()) .get(`/b/organization/groups/${ctx.fixtures.groupA1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectSuccessEnvelope(response, 200); expect(response.body.data.id).toBe(ctx.fixtures.groupA1Id); }); it('失败:HOSPITAL_ADMIN 查询他院小组返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .get(`/b/organization/groups/${ctx.fixtures.groupB1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'GET /b/organization/groups/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 200, [Role.HOSPITAL_ADMIN]: 200, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .get(`/b/organization/groups/${ctx.fixtures.groupA1Id}`) .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).get( `/b/organization/groups/${ctx.fixtures.groupA1Id}`, ), }); }); }); describe('PATCH /b/organization/groups/:id', () => { it('成功:HOSPITAL_ADMIN 可更新本院小组', async () => { const originalName = 'Shift-A2'; const nextName = uniqueSeedValue('小组更新'); const response = await request(ctx.app.getHttpServer()) .patch(`/b/organization/groups/${ctx.fixtures.groupA2Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: nextName }); expectSuccessEnvelope(response, 200); const rollbackResponse = await request(ctx.app.getHttpServer()) .patch(`/b/organization/groups/${ctx.fixtures.groupA2Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: originalName }); expectSuccessEnvelope(rollbackResponse, 200); }); it('失败:HOSPITAL_ADMIN 更新他院小组返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .patch(`/b/organization/groups/${ctx.fixtures.groupB1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`) .send({ name: uniqueSeedValue('跨院小组更新失败') }); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'PATCH /b/organization/groups/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 404, [Role.HOSPITAL_ADMIN]: 404, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .patch('/b/organization/groups/99999999') .set('Authorization', `Bearer ${token}`) .send({ name: 'matrix-group-patch' }), sendWithoutToken: async () => request(ctx.app.getHttpServer()) .patch('/b/organization/groups/99999999') .send({ name: 'matrix-group-patch' }), }); }); }); describe('DELETE /b/organization/groups/:id', () => { it('成功:SYSTEM_ADMIN 可删除无关联小组', async () => { const createResponse = await request(ctx.app.getHttpServer()) .post('/b/organization/groups') .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`) .send({ name: uniqueSeedValue('小组待删'), departmentId: ctx.fixtures.departmentA1Id, }); expectSuccessEnvelope(createResponse, 201); const targetId = createResponse.body.data.id as number; const deleteResponse = await request(ctx.app.getHttpServer()) .delete(`/b/organization/groups/${targetId}`) .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`); expectSuccessEnvelope(deleteResponse, 200); }); it('失败:HOSPITAL_ADMIN 删除他院小组返回 403', async () => { const response = await request(ctx.app.getHttpServer()) .delete(`/b/organization/groups/${ctx.fixtures.groupB1Id}`) .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`); expectErrorEnvelope(response, 403, '院管仅可操作本院组织数据'); }); it('角色矩阵:SYSTEM_ADMIN/HOSPITAL_ADMIN 可进入业务,其他角色 403,未登录 401', async () => { await assertRoleMatrix({ name: 'DELETE /b/organization/groups/:id role matrix', tokens: ctx.tokens, expectedStatusByRole: { [Role.SYSTEM_ADMIN]: 404, [Role.HOSPITAL_ADMIN]: 404, [Role.DIRECTOR]: 403, [Role.LEADER]: 403, [Role.DOCTOR]: 403, [Role.ENGINEER]: 403, }, sendAsRole: async (_role, token) => request(ctx.app.getHttpServer()) .delete('/b/organization/groups/99999999') .set('Authorization', `Bearer ${token}`), sendWithoutToken: async () => request(ctx.app.getHttpServer()).delete( '/b/organization/groups/99999999', ), }); }); }); }); });