文件
OmniCard/backend/test/modules/team/data-scope.test.ts

125 行
3.9 KiB
TypeScript

import {
TeamDataScopeService,
UserDataContext,
buildLeadDataScopeFilter,
assertLeadAccessPermission,
} from '../../../src/modules/team/service/data-scope';
describe('Point 52: 多租户团队成员细粒度数据隔离与销售管辖范围保护', () => {
let service: TeamDataScopeService;
beforeEach(() => {
service = new TeamDataScopeService();
});
describe('1. buildLeadDataScopeFilter (数据权限范围查询条件构建)', () => {
it('租户拥有者 (owner) 与管理员 (admin) 应具备租户级全量权限', () => {
const ownerCtx: UserDataContext = {
userId: 1,
tenantId: 'tenant-100',
role: 'owner',
};
const adminCtx: UserDataContext = {
userId: 2,
tenantId: 'tenant-100',
role: 'admin',
};
const ownerFilter = buildLeadDataScopeFilter(ownerCtx);
expect(ownerFilter.tenantId).toBe('tenant-100');
expect(ownerFilter.assignedUserId).toBeUndefined(); // 全员无限制
expect(ownerFilter.departmentId).toBeUndefined();
const adminFilter = buildLeadDataScopeFilter(adminCtx);
expect(adminFilter.tenantId).toBe('tenant-100');
expect(adminFilter.assignedUserId).toBeUndefined();
});
it('部门区域销售总监 (sales_manager) 应锁定为本部门管辖范围', () => {
const managerCtx: UserDataContext = {
userId: 10,
tenantId: 'tenant-100',
role: 'sales_manager',
departmentId: 'dept-middle-east',
};
const filter = buildLeadDataScopeFilter(managerCtx);
expect(filter.tenantId).toBe('tenant-100');
expect(filter.departmentId).toBe('dept-middle-east');
expect(filter.assignedUserId).toBeUndefined();
});
it('一线销售 (sales_rep/member) 必须严格隔离只能查看本人线索', () => {
const repCtx: UserDataContext = {
userId: 88,
tenantId: 'tenant-100',
role: 'sales_rep',
departmentId: 'dept-middle-east',
};
const filter = buildLeadDataScopeFilter(repCtx);
expect(filter.tenantId).toBe('tenant-100');
expect(filter.assignedUserId).toBe(88);
});
});
describe('2. assertLeadAccessPermission (单条线索详情读取防越权校验)', () => {
const mockLead = {
id: 999,
tenantId: 'tenant-100',
assignedUserId: 88,
departmentId: 'dept-middle-east',
};
it('允许线索归属人本人 (userId=88) 访问', () => {
const repCtx: UserDataContext = {
userId: 88,
tenantId: 'tenant-100',
role: 'sales_rep',
};
expect(() => assertLeadAccessPermission(repCtx, mockLead)).not.toThrow();
});
it('允许所属部门主管 (dept-middle-east) 与企业 Owner 跨权限访问', () => {
const managerCtx: UserDataContext = {
userId: 10,
tenantId: 'tenant-100',
role: 'sales_manager',
departmentId: 'dept-middle-east',
};
const ownerCtx: UserDataContext = {
userId: 1,
tenantId: 'tenant-100',
role: 'owner',
};
expect(() => assertLeadAccessPermission(managerCtx, mockLead)).not.toThrow();
expect(() => assertLeadAccessPermission(ownerCtx, mockLead)).not.toThrow();
});
it('同租户其他销售 (userId=89) 越权访问时应抛出 403 明确拒绝', () => {
const otherRepCtx: UserDataContext = {
userId: 89,
tenantId: 'tenant-100',
role: 'sales_rep',
};
expect(() => assertLeadAccessPermission(otherRepCtx, mockLead)).toThrow(
/无权访问该客户线索|Forbidden|权限不足/i
);
});
it('跨租户访问应坚决阻断', () => {
const crossTenantCtx: UserDataContext = {
userId: 1,
tenantId: 'tenant-200', // 跨租户
role: 'owner',
};
expect(() => assertLeadAccessPermission(crossTenantCtx, mockLead)).toThrow(
/无权访问该客户线索|Forbidden|权限不足/i
);
});
});
});