import type { Logger } from '@core/shared/domain/Logger'; import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'; import type { AuthRepository } from '../../domain/repositories/AuthRepository'; import type { CompanyRepository } from '../../domain/repositories/CompanyRepository'; import type { PasswordHashingService } from '../ports/PasswordHashingService'; import { SignupSponsorUseCase } from './SignupSponsorUseCase'; describe('SignupSponsorUseCase', () => { let authRepo: { findByEmail: Mock; save: Mock; }; let companyRepo: { create: Mock; save: Mock; delete: Mock; }; let passwordService: { hash: Mock; }; let logger: Logger; let useCase: SignupSponsorUseCase; beforeEach(() => { authRepo = { findByEmail: vi.fn(), save: vi.fn(), }; companyRepo = { create: vi.fn(), save: vi.fn(), delete: vi.fn(), }; passwordService = { hash: vi.fn(), }; logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), } as unknown as Logger; useCase = new SignupSponsorUseCase( authRepo as unknown as AuthRepository, companyRepo as unknown as CompanyRepository, passwordService as unknown as PasswordHashingService, logger, ); }); it('creates user and company successfully when email is free', async () => { authRepo.findByEmail.mockResolvedValue(null); passwordService.hash.mockResolvedValue('hashed-password'); companyRepo.create.mockImplementation((data) => ({ getId: () => 'company-1', ...data, })); companyRepo.save.mockResolvedValue(undefined); authRepo.save.mockResolvedValue(undefined); const result = await useCase.execute({ email: 'sponsor@example.com', password: 'Password123', displayName: 'Sponsor User', companyName: 'Sponsor Inc', }); expect(result.isOk()).toBe(true); const signupResult = result.unwrap(); expect(signupResult.user).toBeDefined(); expect(signupResult.company).toBeDefined(); expect(signupResult.user.getEmail()).toBe('sponsor@example.com'); expect(signupResult.user.getDisplayName()).toBe('Sponsor User'); expect(companyRepo.create).toHaveBeenCalled(); expect(companyRepo.save).toHaveBeenCalled(); expect(authRepo.save).toHaveBeenCalled(); }); it('returns error when user already exists', async () => { const existingUser = { getId: () => ({ value: 'existing-user' }), getEmail: () => 'sponsor@example.com', getDisplayName: () => 'Existing User', getPasswordHash: () => ({ value: 'hash' }), }; authRepo.findByEmail.mockResolvedValue(existingUser); const result = await useCase.execute({ email: 'sponsor@example.com', password: 'Password123', displayName: 'Sponsor User', companyName: 'Sponsor Inc', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('USER_ALREADY_EXISTS'); }); it('returns error for weak password', async () => { const result = await useCase.execute({ email: 'sponsor@example.com', password: 'weak', displayName: 'Sponsor User', companyName: 'Sponsor Inc', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('WEAK_PASSWORD'); }); it('returns error for invalid display name', async () => { const result = await useCase.execute({ email: 'sponsor@example.com', password: 'Password123', displayName: 'A', companyName: 'Sponsor Inc', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('INVALID_DISPLAY_NAME'); }); it('rolls back company creation on failure', async () => { authRepo.findByEmail.mockResolvedValue(null); passwordService.hash.mockResolvedValue('hashed-password'); companyRepo.create.mockImplementation((data) => ({ getId: () => 'company-1', ...data, })); companyRepo.save.mockResolvedValue(undefined); authRepo.save.mockRejectedValue(new Error('Database error')); const result = await useCase.execute({ email: 'sponsor@example.com', password: 'Password123', displayName: 'Sponsor User', companyName: 'Sponsor Inc', }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR'); expect(companyRepo.delete).toHaveBeenCalledWith('company-1'); }); });