- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8 - Actualizaciones de configuracion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
176 lines
8.0 KiB
JavaScript
176 lines
8.0 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 users_service_1 = require("../users.service");
|
|
const user_entity_1 = require("../../auth/entities/user.entity");
|
|
describe('UsersService', () => {
|
|
let service;
|
|
let userRepository;
|
|
const mockUser = {
|
|
id: 'user-123',
|
|
tenant_id: 'tenant-123',
|
|
email: 'test@example.com',
|
|
password_hash: 'hashed_password',
|
|
first_name: 'John',
|
|
last_name: 'Doe',
|
|
avatar_url: 'https://example.com/avatar.png',
|
|
phone: '+1234567890',
|
|
status: 'active',
|
|
email_verified: true,
|
|
email_verified_at: new Date('2026-01-01'),
|
|
last_login_at: new Date('2026-01-07'),
|
|
last_login_ip: '192.168.1.1',
|
|
metadata: { preferences: { theme: 'dark' } },
|
|
created_at: new Date('2026-01-01'),
|
|
updated_at: new Date('2026-01-07'),
|
|
get fullName() {
|
|
return [this.first_name, this.last_name].filter(Boolean).join(' ');
|
|
},
|
|
};
|
|
beforeEach(async () => {
|
|
const module = await testing_1.Test.createTestingModule({
|
|
providers: [
|
|
users_service_1.UsersService,
|
|
{
|
|
provide: (0, typeorm_1.getRepositoryToken)(user_entity_1.User),
|
|
useValue: {
|
|
findOne: jest.fn(),
|
|
find: jest.fn(),
|
|
findAndCount: jest.fn(),
|
|
save: jest.fn(),
|
|
create: jest.fn(),
|
|
update: jest.fn(),
|
|
delete: jest.fn(),
|
|
},
|
|
},
|
|
],
|
|
}).compile();
|
|
service = module.get(users_service_1.UsersService);
|
|
userRepository = module.get((0, typeorm_1.getRepositoryToken)(user_entity_1.User));
|
|
});
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
describe('findAllByTenant', () => {
|
|
it('should return paginated users for a tenant', async () => {
|
|
const users = [mockUser];
|
|
userRepository.findAndCount.mockResolvedValue([users, 1]);
|
|
const result = await service.findAllByTenant('tenant-123', 1, 10);
|
|
expect(result).toEqual({
|
|
data: [expect.objectContaining({ id: 'user-123' })],
|
|
total: 1,
|
|
page: 1,
|
|
limit: 10,
|
|
});
|
|
expect(userRepository.findAndCount).toHaveBeenCalledWith({
|
|
where: { tenant_id: 'tenant-123' },
|
|
skip: 0,
|
|
take: 10,
|
|
order: { created_at: 'DESC' },
|
|
});
|
|
});
|
|
it('should return sanitized users without password_hash', async () => {
|
|
userRepository.findAndCount.mockResolvedValue([[mockUser], 1]);
|
|
const result = await service.findAllByTenant('tenant-123', 1, 10);
|
|
expect(result.data[0]).not.toHaveProperty('password_hash');
|
|
expect(result.data[0]).toHaveProperty('email');
|
|
});
|
|
it('should handle pagination correctly', async () => {
|
|
userRepository.findAndCount.mockResolvedValue([[], 0]);
|
|
await service.findAllByTenant('tenant-123', 2, 20);
|
|
expect(userRepository.findAndCount).toHaveBeenCalledWith({
|
|
where: { tenant_id: 'tenant-123' },
|
|
skip: 20,
|
|
take: 20,
|
|
order: { created_at: 'DESC' },
|
|
});
|
|
});
|
|
it('should return empty array when no users found', async () => {
|
|
userRepository.findAndCount.mockResolvedValue([[], 0]);
|
|
const result = await service.findAllByTenant('tenant-123', 1, 10);
|
|
expect(result.data).toEqual([]);
|
|
expect(result.total).toBe(0);
|
|
});
|
|
});
|
|
describe('findOne', () => {
|
|
it('should return a user by id and tenant', async () => {
|
|
userRepository.findOne.mockResolvedValue(mockUser);
|
|
const result = await service.findOne('user-123', 'tenant-123');
|
|
expect(result).not.toHaveProperty('password_hash');
|
|
expect(result).toHaveProperty('email', 'test@example.com');
|
|
expect(userRepository.findOne).toHaveBeenCalledWith({
|
|
where: { id: 'user-123', tenant_id: 'tenant-123' },
|
|
});
|
|
});
|
|
it('should throw NotFoundException if user not found', async () => {
|
|
userRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.findOne('non-existent', 'tenant-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
it('should not return user from different tenant', async () => {
|
|
userRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.findOne('user-123', 'different-tenant')).rejects.toThrow(common_1.NotFoundException);
|
|
expect(userRepository.findOne).toHaveBeenCalledWith({
|
|
where: { id: 'user-123', tenant_id: 'different-tenant' },
|
|
});
|
|
});
|
|
});
|
|
describe('update', () => {
|
|
it('should update allowed user fields', async () => {
|
|
const userCopy = { ...mockUser };
|
|
userRepository.findOne.mockResolvedValue(userCopy);
|
|
userRepository.save.mockResolvedValue(userCopy);
|
|
const updateDto = {
|
|
first_name: 'Jane',
|
|
last_name: 'Smith',
|
|
};
|
|
const result = await service.update('user-123', updateDto, 'tenant-123');
|
|
expect(userRepository.save).toHaveBeenCalled();
|
|
expect(result).not.toHaveProperty('password_hash');
|
|
});
|
|
it('should throw NotFoundException if user not found', async () => {
|
|
userRepository.findOne.mockResolvedValue(null);
|
|
await expect(service.update('non-existent', { first_name: 'Test' }, 'tenant-123')).rejects.toThrow(common_1.NotFoundException);
|
|
});
|
|
it('should only update allowed fields', async () => {
|
|
const userCopy = { ...mockUser };
|
|
userRepository.findOne.mockResolvedValue(userCopy);
|
|
userRepository.save.mockResolvedValue(userCopy);
|
|
const updateDto = {
|
|
first_name: 'Jane',
|
|
email: 'hacker@example.com',
|
|
password_hash: 'new_hash',
|
|
};
|
|
await service.update('user-123', updateDto, 'tenant-123');
|
|
const savedUser = userRepository.save.mock.calls[0][0];
|
|
expect(savedUser.email).not.toBe('hacker@example.com');
|
|
});
|
|
it('should update phone number', async () => {
|
|
const userCopy = { ...mockUser };
|
|
userRepository.findOne.mockResolvedValue(userCopy);
|
|
userRepository.save.mockResolvedValue(userCopy);
|
|
await service.update('user-123', { phone: '+9876543210' }, 'tenant-123');
|
|
const savedUser = userRepository.save.mock.calls[0][0];
|
|
expect(savedUser.phone).toBe('+9876543210');
|
|
});
|
|
it('should update avatar_url', async () => {
|
|
const userCopy = { ...mockUser };
|
|
userRepository.findOne.mockResolvedValue(userCopy);
|
|
userRepository.save.mockResolvedValue(userCopy);
|
|
await service.update('user-123', { avatar_url: 'https://new-avatar.com/img.png' }, 'tenant-123');
|
|
const savedUser = userRepository.save.mock.calls[0][0];
|
|
expect(savedUser.avatar_url).toBe('https://new-avatar.com/img.png');
|
|
});
|
|
it('should update metadata', async () => {
|
|
const userCopy = { ...mockUser };
|
|
userRepository.findOne.mockResolvedValue(userCopy);
|
|
userRepository.save.mockResolvedValue(userCopy);
|
|
const newMetadata = { preferences: { language: 'es' } };
|
|
await service.update('user-123', { metadata: newMetadata }, 'tenant-123');
|
|
const savedUser = userRepository.save.mock.calls[0][0];
|
|
expect(savedUser.metadata).toEqual(newMetadata);
|
|
});
|
|
});
|
|
});
|
|
//# sourceMappingURL=users.service.spec.js.map
|