const RegisterUserCommandHandler = require('../../../src/application/auth/commands/RegisterUserCommandHandler'); const RegisterUserCommand = require('../../../src/application/auth/commands/RegisterUserCommand'); const bcrypt = require('bcryptjs'); const JwtService = require('../../../src/application/services/JwtService'); // Mock dependencies jest.mock('bcryptjs'); jest.mock('../../../src/application/services/JwtService'); describe('RegisterUserCommandHandler', () => { let handler; let mockPrisma; let mockEmailService; let mockJwtService; beforeEach(() => { // Mock JwtService instance mockJwtService = { generateToken: jest.fn() }; JwtService.mockImplementation(() => mockJwtService); // Mock Prisma mockPrisma = { user: { findUnique: jest.fn(), create: jest.fn() } }; // Mock EmailService mockEmailService = { sendWelcomeEmail: jest.fn().mockResolvedValue(true) }; handler = new RegisterUserCommandHandler(mockPrisma, mockEmailService); // Reset all mocks jest.clearAllMocks(); }); describe('handle - success cases', () => { it('should register a new user successfully', async () => { // Arrange const command = new RegisterUserCommand('John Doe', 'john@example.com', 'password123'); mockPrisma.user.findUnique.mockResolvedValue(null); // No existing user bcrypt.hash.mockResolvedValue('hashed_password'); mockPrisma.user.create.mockResolvedValue({ id: 1, name: 'John Doe', email: 'john@example.com', password: 'hashed_password', createdAt: new Date(), updatedAt: new Date() }); mockJwtService.generateToken.mockReturnValue('mock_jwt_token'); // Act const result = await handler.handle(command); // Assert expect(mockPrisma.user.findUnique).toHaveBeenCalledWith({ where: { email: 'john@example.com' } }); expect(bcrypt.hash).toHaveBeenCalledWith('password123', 10); expect(mockPrisma.user.create).toHaveBeenCalledWith({ data: { name: 'John Doe', email: 'john@example.com', password: 'hashed_password' } }); expect(mockJwtService.generateToken).toHaveBeenCalledWith({ userId: 1, email: 'john@example.com' }); expect(result.user).toEqual({ id: 1, name: 'John Doe', email: 'john@example.com', createdAt: expect.any(Date), updatedAt: expect.any(Date) }); expect(result.token).toBe('mock_jwt_token'); expect(result.user.password).toBeUndefined(); // Password should not be returned }); it('should send welcome email after registration', async () => { // Arrange const command = new RegisterUserCommand('Jane Doe', 'jane@example.com', 'password123'); mockPrisma.user.findUnique.mockResolvedValue(null); bcrypt.hash.mockResolvedValue('hashed_password'); mockPrisma.user.create.mockResolvedValue({ id: 2, name: 'Jane Doe', email: 'jane@example.com', password: 'hashed_password', createdAt: new Date(), updatedAt: new Date() }); mockJwtService.generateToken.mockReturnValue('mock_jwt_token'); // Act await handler.handle(command); // Assert expect(mockEmailService.sendWelcomeEmail).toHaveBeenCalledWith('jane@example.com', 'Jane Doe'); }); }); describe('handle - validation errors', () => { it('should throw error if name is missing', async () => { // Arrange const command = new RegisterUserCommand('', 'john@example.com', 'password123'); // Act & Assert await expect(handler.handle(command)).rejects.toThrow('Name, email and password are required'); }); it('should throw error if email is missing', async () => { // Arrange const command = new RegisterUserCommand('John Doe', '', 'password123'); // Act & Assert await expect(handler.handle(command)).rejects.toThrow('Name, email and password are required'); }); it('should throw error if password is missing', async () => { // Arrange const command = new RegisterUserCommand('John Doe', 'john@example.com', ''); // Act & Assert await expect(handler.handle(command)).rejects.toThrow('Name, email and password are required'); }); it('should throw error if password is too short', async () => { // Arrange const command = new RegisterUserCommand('John Doe', 'john@example.com', '12345'); // Act & Assert await expect(handler.handle(command)).rejects.toThrow('Password must be at least 6 characters long'); }); it('should throw error if email format is invalid', async () => { // Arrange const command = new RegisterUserCommand('John Doe', 'invalid-email', 'password123'); // Act & Assert await expect(handler.handle(command)).rejects.toThrow('Invalid email format'); }); it('should throw error if user already exists', async () => { // Arrange const command = new RegisterUserCommand('John Doe', 'john@example.com', 'password123'); mockPrisma.user.findUnique.mockResolvedValue({ id: 1, email: 'john@example.com' }); // Act & Assert await expect(handler.handle(command)).rejects.toThrow('User with this email already exists'); }); }); describe('handle - error handling', () => { it('should not fail if email service throws error', async () => { // Arrange const command = new RegisterUserCommand('John Doe', 'john@example.com', 'password123'); mockPrisma.user.findUnique.mockResolvedValue(null); bcrypt.hash.mockResolvedValue('hashed_password'); mockPrisma.user.create.mockResolvedValue({ id: 1, name: 'John Doe', email: 'john@example.com', password: 'hashed_password', createdAt: new Date(), updatedAt: new Date() }); mockJwtService.generateToken.mockReturnValue('mock_jwt_token'); mockEmailService.sendWelcomeEmail.mockRejectedValue(new Error('Email service error')); // Act const result = await handler.handle(command); // Assert - should still return user and token even if email fails expect(result.user.email).toBe('john@example.com'); expect(result.token).toBe('mock_jwt_token'); }); }); });