import { describe, it, expect, vi, beforeEach } from 'vitest'; import { CompleteRaceCreationUseCase } from '@/packages/application/use-cases/CompleteRaceCreationUseCase'; import { Result } from '@/packages/shared/result/Result'; import { RaceCreationResult } from '@/packages/domain/value-objects/RaceCreationResult'; import { CheckoutPrice } from '@/packages/domain/value-objects/CheckoutPrice'; import type { ICheckoutService } from '@/packages/application/ports/ICheckoutService'; import { CheckoutState } from '@/packages/domain/value-objects/CheckoutState'; describe('CompleteRaceCreationUseCase', () => { let mockCheckoutService: ICheckoutService; let useCase: CompleteRaceCreationUseCase; beforeEach(() => { mockCheckoutService = { extractCheckoutInfo: vi.fn(), proceedWithCheckout: vi.fn(), }; useCase = new CompleteRaceCreationUseCase(mockCheckoutService); }); describe('execute', () => { it('should extract checkout price and create RaceCreationResult', async () => { const price = CheckoutPrice.fromString('$25.50'); const state = CheckoutState.ready(); const sessionId = 'test-session-123'; vi.mocked(mockCheckoutService.extractCheckoutInfo).mockResolvedValue( Result.ok({ price, state, buttonHtml: '$25.50' }) ); const result = await useCase.execute(sessionId); expect(mockCheckoutService.extractCheckoutInfo).toHaveBeenCalled(); expect(result.isOk()).toBe(true); const raceCreationResult = result.unwrap(); expect(raceCreationResult).toBeInstanceOf(RaceCreationResult); expect(raceCreationResult.sessionId).toBe(sessionId); expect(raceCreationResult.price).toBe('$25.50'); expect(raceCreationResult.timestamp).toBeInstanceOf(Date); }); it('should return error if checkout info extraction fails', async () => { vi.mocked(mockCheckoutService.extractCheckoutInfo).mockResolvedValue( Result.err(new Error('Failed to extract checkout info')) ); const result = await useCase.execute('test-session-123'); expect(result.isErr()).toBe(true); expect(result.unwrapErr().message).toContain('Failed to extract checkout info'); }); it('should return error if price is missing', async () => { const state = CheckoutState.ready(); vi.mocked(mockCheckoutService.extractCheckoutInfo).mockResolvedValue( Result.ok({ price: undefined as any, state, buttonHtml: 'n/a' }) ); const result = await useCase.execute('test-session-123'); expect(result.isErr()).toBe(true); expect(result.unwrapErr().message).toContain('Could not extract price'); }); it('should validate session ID is provided', async () => { const result = await useCase.execute(''); expect(result.isErr()).toBe(true); expect(result.unwrapErr().message).toContain('Session ID is required'); }); it('should format different price values correctly', async () => { const testCases = [ { input: '$10.00', expected: '$10.00' }, { input: '$100.50', expected: '$100.50' }, { input: '$0.99', expected: '$0.99' }, ]; for (const testCase of testCases) { const price = CheckoutPrice.fromString(testCase.input); const state = CheckoutState.ready(); vi.mocked(mockCheckoutService.extractCheckoutInfo).mockResolvedValue( Result.ok({ price, state, buttonHtml: `${testCase.input}` }) ); const result = await useCase.execute('test-session'); expect(result.isOk()).toBe(true); const raceCreationResult = result.unwrap(); expect(raceCreationResult.price).toBe(testCase.expected); } }); it('should capture current timestamp when creating result', async () => { const price = CheckoutPrice.fromString('$25.50'); const state = CheckoutState.ready(); const beforeExecution = new Date(); vi.mocked(mockCheckoutService.extractCheckoutInfo).mockResolvedValue( Result.ok({ price, state, buttonHtml: '$25.50' }) ); const result = await useCase.execute('test-session'); const afterExecution = new Date(); expect(result.isOk()).toBe(true); const raceCreationResult = result.unwrap(); expect(raceCreationResult.timestamp.getTime()).toBeGreaterThanOrEqual( beforeExecution.getTime() ); expect(raceCreationResult.timestamp.getTime()).toBeLessThanOrEqual( afterExecution.getTime() ); }); }); });