- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8 - Actualizaciones de configuracion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
308 lines
14 KiB
JavaScript
308 lines
14 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const testing_1 = require("@nestjs/testing");
|
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
const common_1 = require("@nestjs/common");
|
|
const rbac_service_1 = require("../services/rbac.service");
|
|
const entities_1 = require("../entities");
|
|
describe('RbacService', () => {
|
|
let service;
|
|
let roleRepository;
|
|
let permissionRepository;
|
|
let userRoleRepository;
|
|
let rolePermissionRepository;
|
|
const mockRole = {
|
|
id: 'role-123',
|
|
tenant_id: 'tenant-123',
|
|
name: 'Admin',
|
|
code: 'admin',
|
|
description: 'Administrator role',
|
|
is_system: false,
|
|
is_active: true,
|
|
metadata: null,
|
|
created_at: new Date('2026-01-01'),
|
|
updated_at: new Date('2026-01-01'),
|
|
};
|
|
const mockSystemRole = {
|
|
...mockRole,
|
|
id: 'role-system',
|
|
code: 'owner',
|
|
name: 'Owner',
|
|
is_system: true,
|
|
};
|
|
const mockPermission = {
|
|
id: 'perm-123',
|
|
code: 'users:read',
|
|
name: 'Read Users',
|
|
description: 'Can read user data',
|
|
category: 'users',
|
|
is_sensitive: false,
|
|
requires_owner: false,
|
|
created_at: new Date('2026-01-01'),
|
|
};
|
|
const mockUserRole = {
|
|
id: 'ur-123',
|
|
user_id: 'user-123',
|
|
role_id: 'role-123',
|
|
tenant_id: 'tenant-123',
|
|
assigned_by: 'admin-123',
|
|
created_at: new Date('2026-01-01'),
|
|
};
|
|
const mockRolePermission = {
|
|
id: 'rp-123',
|
|
role_id: 'role-123',
|
|
permission_id: 'perm-123',
|
|
created_at: new Date('2026-01-01'),
|
|
};
|
|
beforeEach(async () => {
|
|
const module = await testing_1.Test.createTestingModule({
|
|
providers: [
|
|
rbac_service_1.RbacService,
|
|
{
|
|
provide: (0, typeorm_1.getRepositoryToken)(entities_1.Role),
|
|
useValue: {
|
|
findOne: jest.fn(),
|
|
find: jest.fn(),
|
|
save: jest.fn(),
|
|
create: jest.fn(),
|
|
delete: jest.fn(),
|
|
count: jest.fn(),
|
|
},
|
|
},
|
|
{
|
|
provide: (0, typeorm_1.getRepositoryToken)(entities_1.Permission),
|
|
useValue: {
|
|
findOne: jest.fn(),
|
|
find: jest.fn(),
|
|
save: jest.fn(),
|
|
},
|
|
},
|
|
{
|
|
provide: (0, typeorm_1.getRepositoryToken)(entities_1.UserRole),
|
|
useValue: {
|
|
findOne: jest.fn(),
|
|
find: jest.fn(),
|
|
save: jest.fn(),
|
|
create: jest.fn(),
|
|
delete: jest.fn(),
|
|
count: jest.fn(),
|
|
},
|
|
},
|
|
{
|
|
provide: (0, typeorm_1.getRepositoryToken)(entities_1.RolePermission),
|
|
useValue: {
|
|
findOne: jest.fn(),
|
|
find: jest.fn(),
|
|
save: jest.fn(),
|
|
delete: jest.fn(),
|
|
},
|
|
},
|
|
],
|
|
}).compile();
|
|
service = module.get(rbac_service_1.RbacService);
|
|
roleRepository = module.get((0, typeorm_1.getRepositoryToken)(entities_1.Role));
|
|
permissionRepository = module.get((0, typeorm_1.getRepositoryToken)(entities_1.Permission));
|
|
userRoleRepository = module.get((0, typeorm_1.getRepositoryToken)(entities_1.UserRole));
|
|
rolePermissionRepository = module.get((0, typeorm_1.getRepositoryToken)(entities_1.RolePermission));
|
|
});
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
describe('createRole', () => {
|
|
const createDto = {
|
|
name: 'Manager',
|
|
code: 'manager',
|
|
description: 'Manager role',
|
|
permissions: ['users:read'],
|
|
};
|
|
it('should create a new role', async () => {
|
|
const createdRole = { ...mockRole, ...createDto, id: 'new-role-123' };
|
|
roleRepository.findOne
|
|
.mockResolvedValueOnce(null)
|
|
.mockResolvedValueOnce(createdRole);
|
|
roleRepository.create.mockReturnValue(createdRole);
|
|
roleRepository.save.mockResolvedValue(createdRole);
|
|
permissionRepository.find.mockResolvedValue([mockPermission]);
|
|
rolePermissionRepository.delete.mockResolvedValue({ affected: 0, raw: {} });
|
|
rolePermissionRepository.save.mockResolvedValue([mockRolePermission]);
|
|
const result = await service.createRole(createDto, 'tenant-123');
|
|
expect(result.name).toBe('Manager');
|
|
expect(roleRepository.create).toHaveBeenCalled();
|
|
expect(roleRepository.save).toHaveBeenCalled();
|
|
});
|
|
it('should throw ConflictException if role code exists', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockRole);
|
|
await expect(service.createRole(createDto, 'tenant-123')).rejects.toThrow(common_1.ConflictException);
|
|
});
|
|
});
|
|
describe('updateRole', () => {
|
|
const updateDto = { name: 'Updated Admin', description: 'Updated description' };
|
|
it('should update a role', async () => {
|
|
const roleCopy = { ...mockRole };
|
|
roleRepository.findOne.mockResolvedValue(roleCopy);
|
|
roleRepository.save.mockResolvedValue({ ...roleCopy, ...updateDto });
|
|
const result = await service.updateRole('role-123', updateDto, 'tenant-123');
|
|
expect(result.name).toBe('Updated Admin');
|
|
expect(roleRepository.save).toHaveBeenCalled();
|
|
});
|
|
it('should throw NotFoundException if role not found', async () => {
|
|
roleRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.updateRole('non-existent', updateDto, 'tenant-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
it('should throw ForbiddenException for system role', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockSystemRole);
|
|
await expect(service.updateRole('role-system', updateDto, 'tenant-123')).rejects.toThrow(common_1.ForbiddenException);
|
|
});
|
|
});
|
|
describe('deleteRole', () => {
|
|
it('should delete a role', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockRole);
|
|
userRoleRepository.count.mockResolvedValue(0);
|
|
rolePermissionRepository.delete.mockResolvedValue({ affected: 1, raw: {} });
|
|
roleRepository.delete.mockResolvedValue({ affected: 1, raw: {} });
|
|
await service.deleteRole('role-123', 'tenant-123');
|
|
expect(roleRepository.delete).toHaveBeenCalledWith({ id: 'role-123' });
|
|
});
|
|
it('should throw NotFoundException if role not found', async () => {
|
|
roleRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.deleteRole('non-existent', 'tenant-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
it('should throw ForbiddenException for system role', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockSystemRole);
|
|
await expect(service.deleteRole('role-system', 'tenant-123')).rejects.toThrow(common_1.ForbiddenException);
|
|
});
|
|
it('should throw ConflictException if role is assigned to users', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockRole);
|
|
userRoleRepository.count.mockResolvedValue(5);
|
|
await expect(service.deleteRole('role-123', 'tenant-123')).rejects.toThrow(common_1.ConflictException);
|
|
});
|
|
});
|
|
describe('findAllRoles', () => {
|
|
it('should return all active roles for tenant', async () => {
|
|
roleRepository.find.mockResolvedValue([mockRole]);
|
|
const result = await service.findAllRoles('tenant-123');
|
|
expect(result).toEqual([mockRole]);
|
|
expect(roleRepository.find).toHaveBeenCalledWith({
|
|
where: { tenant_id: 'tenant-123', is_active: true },
|
|
order: { is_system: 'DESC', name: 'ASC' },
|
|
});
|
|
});
|
|
});
|
|
describe('findRoleById', () => {
|
|
it('should return a role by id', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockRole);
|
|
const result = await service.findRoleById('role-123', 'tenant-123');
|
|
expect(result).toEqual(mockRole);
|
|
});
|
|
it('should throw NotFoundException if role not found', async () => {
|
|
roleRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.findRoleById('non-existent', 'tenant-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
});
|
|
describe('findAllPermissions', () => {
|
|
it('should return all permissions', async () => {
|
|
permissionRepository.find.mockResolvedValue([mockPermission]);
|
|
const result = await service.findAllPermissions();
|
|
expect(result).toEqual([mockPermission]);
|
|
expect(permissionRepository.find).toHaveBeenCalledWith({
|
|
order: { category: 'ASC', code: 'ASC' },
|
|
});
|
|
});
|
|
});
|
|
describe('assignRoleToUser', () => {
|
|
const assignDto = { userId: 'user-123', roleId: 'role-123' };
|
|
it('should assign a role to a user', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockRole);
|
|
userRoleRepository.findOne.mockResolvedValue(null);
|
|
userRoleRepository.create.mockReturnValue(mockUserRole);
|
|
userRoleRepository.save.mockResolvedValue(mockUserRole);
|
|
const result = await service.assignRoleToUser(assignDto, 'tenant-123', 'admin-123');
|
|
expect(result).toEqual(mockUserRole);
|
|
expect(userRoleRepository.save).toHaveBeenCalled();
|
|
});
|
|
it('should throw ConflictException if role already assigned', async () => {
|
|
roleRepository.findOne.mockResolvedValue(mockRole);
|
|
userRoleRepository.findOne.mockResolvedValue(mockUserRole);
|
|
await expect(service.assignRoleToUser(assignDto, 'tenant-123', 'admin-123')).rejects.toThrow(common_1.ConflictException);
|
|
});
|
|
it('should throw NotFoundException if role not found', async () => {
|
|
roleRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.assignRoleToUser(assignDto, 'tenant-123', 'admin-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
});
|
|
describe('removeRoleFromUser', () => {
|
|
it('should remove a role from a user', async () => {
|
|
userRoleRepository.delete.mockResolvedValue({ affected: 1, raw: {} });
|
|
await service.removeRoleFromUser('user-123', 'role-123', 'tenant-123');
|
|
expect(userRoleRepository.delete).toHaveBeenCalledWith({
|
|
user_id: 'user-123',
|
|
role_id: 'role-123',
|
|
tenant_id: 'tenant-123',
|
|
});
|
|
});
|
|
it('should throw NotFoundException if assignment not found', async () => {
|
|
userRoleRepository.delete.mockResolvedValue({ affected: 0, raw: {} });
|
|
await expect(service.removeRoleFromUser('user-123', 'role-123', 'tenant-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
});
|
|
describe('getUserRoles', () => {
|
|
it('should return all roles for a user', async () => {
|
|
userRoleRepository.find.mockResolvedValue([mockUserRole]);
|
|
roleRepository.find.mockResolvedValue([mockRole]);
|
|
const result = await service.getUserRoles('user-123', 'tenant-123');
|
|
expect(result).toEqual([mockRole]);
|
|
});
|
|
it('should return empty array if user has no roles', async () => {
|
|
userRoleRepository.find.mockResolvedValue([]);
|
|
const result = await service.getUserRoles('user-123', 'tenant-123');
|
|
expect(result).toEqual([]);
|
|
});
|
|
});
|
|
describe('getUserPermissions', () => {
|
|
it('should return all permissions for a user', async () => {
|
|
userRoleRepository.find.mockResolvedValue([mockUserRole]);
|
|
roleRepository.find.mockResolvedValue([mockRole]);
|
|
rolePermissionRepository.find.mockResolvedValue([mockRolePermission]);
|
|
permissionRepository.find.mockResolvedValue([mockPermission]);
|
|
const result = await service.getUserPermissions('user-123', 'tenant-123');
|
|
expect(result).toEqual([mockPermission]);
|
|
});
|
|
it('should return empty array if user has no roles', async () => {
|
|
userRoleRepository.find.mockResolvedValue([]);
|
|
const result = await service.getUserPermissions('user-123', 'tenant-123');
|
|
expect(result).toEqual([]);
|
|
});
|
|
});
|
|
describe('userHasPermission', () => {
|
|
it('should return true if user has permission', async () => {
|
|
userRoleRepository.find.mockResolvedValue([mockUserRole]);
|
|
roleRepository.find.mockResolvedValue([mockRole]);
|
|
rolePermissionRepository.find.mockResolvedValue([mockRolePermission]);
|
|
permissionRepository.find.mockResolvedValue([mockPermission]);
|
|
const result = await service.userHasPermission('user-123', 'tenant-123', 'users:read');
|
|
expect(result).toBe(true);
|
|
});
|
|
it('should return false if user lacks permission', async () => {
|
|
userRoleRepository.find.mockResolvedValue([mockUserRole]);
|
|
roleRepository.find.mockResolvedValue([mockRole]);
|
|
rolePermissionRepository.find.mockResolvedValue([mockRolePermission]);
|
|
permissionRepository.find.mockResolvedValue([mockPermission]);
|
|
const result = await service.userHasPermission('user-123', 'tenant-123', 'users:delete');
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
describe('userHasRole', () => {
|
|
it('should return true if user has role', async () => {
|
|
userRoleRepository.find.mockResolvedValue([mockUserRole]);
|
|
roleRepository.find.mockResolvedValue([mockRole]);
|
|
const result = await service.userHasRole('user-123', 'tenant-123', 'admin');
|
|
expect(result).toBe(true);
|
|
});
|
|
it('should return false if user lacks role', async () => {
|
|
userRoleRepository.find.mockResolvedValue([]);
|
|
const result = await service.userHasRole('user-123', 'tenant-123', 'admin');
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
//# sourceMappingURL=rbac.service.spec.js.map
|