import { describe, it, expect, vi, type Mock } from 'vitest'; import { LoginUseCase } from './LoginUseCase'; import type { IAuthRepository } from '../../domain/repositories/IAuthRepository'; import type { IPasswordHashingService } from '../../domain/services/PasswordHashingService'; import type { Logger } from '@core/shared/application'; import { Result } from '@core/shared/application/Result'; import { User } from '../../domain/entities/User'; import { UserId } from '../../domain/value-objects/UserId'; import { PasswordHash } from '../../domain/value-objects/PasswordHash'; import { EmailAddress } from '../../domain/value-objects/EmailAddress'; describe('LoginUseCase', () => { let authRepo: { findByEmail: Mock; }; let passwordService: { verify: Mock; }; let logger: Logger; let useCase: LoginUseCase; beforeEach(() => { authRepo = { findByEmail: vi.fn(), }; passwordService = { verify: vi.fn(), }; logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), } as unknown as Logger; useCase = new LoginUseCase( authRepo as unknown as IAuthRepository, passwordService as unknown as IPasswordHashingService, logger, ); }); it('successfully logs in with valid credentials', async () => { const user = User.create({ id: UserId.create(), displayName: 'John Smith', email: 'test@example.com', passwordHash: PasswordHash.fromHash('hashed-password'), }); authRepo.findByEmail.mockResolvedValue(user); passwordService.verify.mockResolvedValue(true); const result = await useCase.execute({ email: 'test@example.com', password: 'Password123', }); expect(result.isOk()).toBe(true); const loginResult = result.unwrap(); expect(loginResult.user).toBe(user); expect(authRepo.findByEmail).toHaveBeenCalledTimes(1); expect(passwordService.verify).toHaveBeenCalledTimes(1); }); it('returns error for invalid credentials', async () => { const user = User.create({ id: UserId.create(), displayName: 'John Smith', email: 'test@example.com', passwordHash: PasswordHash.fromHash('hashed-password'), }); authRepo.findByEmail.mockResolvedValue(user); passwordService.verify.mockResolvedValue(false); const result = await useCase.execute({ email: 'test@example.com', password: 'WrongPassword', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('INVALID_CREDENTIALS'); }); it('returns error when user does not exist', async () => { authRepo.findByEmail.mockResolvedValue(null); const result = await useCase.execute({ email: 'nonexistent@example.com', password: 'Password123', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('INVALID_CREDENTIALS'); }); });