import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; import { CreateSponsorUseCase, type CreateSponsorInput } from './CreateSponsorUseCase'; import type { ISponsorRepository } from '../../domain/repositories/ISponsorRepository'; import type { Logger } from '@core/shared/application'; import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort'; describe('CreateSponsorUseCase', () => { let useCase: CreateSponsorUseCase; let sponsorRepository: { create: Mock; }; let logger: { debug: Mock; info: Mock; warn: Mock; error: Mock; }; let output: { present: Mock; }; beforeEach(() => { sponsorRepository = { create: vi.fn(), }; logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), }; output = { present: vi.fn(), }; useCase = new CreateSponsorUseCase( sponsorRepository as unknown as ISponsorRepository, logger as unknown as Logger, output as unknown as UseCaseOutputPort, ); }); it('should create sponsor successfully', async () => { const input: CreateSponsorInput = { name: 'Test Sponsor', contactEmail: 'test@example.com', websiteUrl: 'https://example.com', logoUrl: 'https://example.com/logo.png', }; sponsorRepository.create.mockResolvedValue(undefined); const result = await useCase.execute(input); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(output.present).toHaveBeenCalledTimes(1); const presented = (output.present as Mock).mock.calls[0]?.[0]; expect(presented?.sponsor.id).toBeDefined(); expect(presented?.sponsor.name).toBe('Test Sponsor'); expect(presented?.sponsor.contactEmail).toBe('test@example.com'); expect(presented?.sponsor.websiteUrl).toBe('https://example.com'); expect(presented?.sponsor.logoUrl).toBe('https://example.com/logo.png'); expect(presented?.sponsor.createdAt).toBeInstanceOf(Date); expect(sponsorRepository.create).toHaveBeenCalledTimes(1); }); it('should create sponsor without optional fields', async () => { const input: CreateSponsorInput = { name: 'Test Sponsor', contactEmail: 'test@example.com', }; sponsorRepository.create.mockResolvedValue(undefined); const result = await useCase.execute(input); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(output.present).toHaveBeenCalledTimes(1); const presented = (output.present as Mock).mock.calls[0]?.[0]; expect(presented.sponsor.websiteUrl).toBeUndefined(); expect(presented.sponsor.logoUrl).toBeUndefined(); }); it('should return error when name is empty', async () => { const input: CreateSponsorInput = { name: '', contactEmail: 'test@example.com', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); expect(result.unwrapErr().details.message).toBe('Sponsor name is required'); expect(output.present).not.toHaveBeenCalled(); }); it('should return error when contactEmail is empty', async () => { const input: CreateSponsorInput = { name: 'Test Sponsor', contactEmail: '', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); expect(result.unwrapErr().details.message).toBe('Sponsor contact email is required'); expect(output.present).not.toHaveBeenCalled(); }); it('should return error when contactEmail is invalid', async () => { const input: CreateSponsorInput = { name: 'Test Sponsor', contactEmail: 'invalid-email', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); expect(result.unwrapErr().details.message).toBe('Invalid sponsor contact email format'); expect(output.present).not.toHaveBeenCalled(); }); it('should return error when websiteUrl is invalid', async () => { const input: CreateSponsorInput = { name: 'Test Sponsor', contactEmail: 'test@example.com', websiteUrl: 'invalid-url', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); expect(result.unwrapErr().details.message).toBe('Invalid sponsor website URL'); expect(output.present).not.toHaveBeenCalled(); }); it('should return error when repository throws', async () => { const input: CreateSponsorInput = { name: 'Test Sponsor', contactEmail: 'test@example.com', }; sponsorRepository.create.mockRejectedValue(new Error('DB error')); const result = await useCase.execute(input); expect(result.isErr()).toBe(true); expect(result.unwrapErr().details.message).toBe('DB error'); expect(output.present).not.toHaveBeenCalled(); }); });