import { describe, it, expect, vi, Mocked } from 'vitest'; import { PaymentService } from './PaymentService'; import { PaymentsApiClient } from '@/lib/api/payments/PaymentsApiClient'; import { PaymentViewModel, MembershipFeeViewModel, PrizeViewModel, WalletViewModel } from '../../view-models'; describe('PaymentService', () => { let mockApiClient: Mocked; let service: PaymentService; beforeEach(() => { mockApiClient = { getPayments: vi.fn(), createPayment: vi.fn(), getMembershipFees: vi.fn(), getPrizes: vi.fn(), getWallet: vi.fn(), } as Mocked; service = new PaymentService(mockApiClient); }); describe('getPayments', () => { it('should call apiClient.getPayments and return PaymentViewModel array', async () => { const mockResponse = { payments: [ { id: 'payment-1', type: 'sponsorship' as const, amount: 100, platformFee: 10, netAmount: 90, payerId: 'user-1', payerType: 'sponsor' as const, leagueId: 'league-1', status: 'completed' as const, createdAt: new Date(), }, ], }; mockApiClient.getPayments.mockResolvedValue(mockResponse); const result = await service.getPayments(); expect(mockApiClient.getPayments).toHaveBeenCalledWith(undefined); expect(result).toHaveLength(1); expect(result[0]).toBeInstanceOf(PaymentViewModel); expect(result[0].id).toBe('payment-1'); }); it('should call apiClient.getPayments with filters', async () => { const mockResponse = { payments: [] }; mockApiClient.getPayments.mockResolvedValue(mockResponse); await service.getPayments('league-1', 'user-1'); expect(mockApiClient.getPayments).toHaveBeenCalledWith({ leagueId: 'league-1', payerId: 'user-1' }); }); }); describe('getPayment', () => { it('should return PaymentViewModel when payment exists', async () => { const mockResponse = { payments: [ { id: 'payment-1', type: 'sponsorship' as const, amount: 100, platformFee: 10, netAmount: 90, payerId: 'user-1', payerType: 'sponsor' as const, leagueId: 'league-1', status: 'completed' as const, createdAt: new Date(), }, ], }; mockApiClient.getPayments.mockResolvedValue(mockResponse); const result = await service.getPayment('payment-1'); expect(result).toBeInstanceOf(PaymentViewModel); expect(result.id).toBe('payment-1'); }); it('should throw error when payment does not exist', async () => { const mockResponse = { payments: [] }; mockApiClient.getPayments.mockResolvedValue(mockResponse); await expect(service.getPayment('non-existent')).rejects.toThrow( 'Payment with ID non-existent not found' ); }); }); describe('createPayment', () => { it('should call apiClient.createPayment and return PaymentViewModel', async () => { const input = { type: 'sponsorship' as const, amount: 100, payerId: 'user-1', payerType: 'sponsor' as const, leagueId: 'league-1', }; const mockResponse = { payment: { id: 'payment-1', type: 'sponsorship' as const, amount: 100, platformFee: 10, netAmount: 90, payerId: 'user-1', payerType: 'sponsor' as const, leagueId: 'league-1', status: 'pending' as const, createdAt: new Date(), }, }; mockApiClient.createPayment.mockResolvedValue(mockResponse); const result = await service.createPayment(input); expect(mockApiClient.createPayment).toHaveBeenCalledWith(input); expect(result).toBeInstanceOf(PaymentViewModel); expect(result.id).toBe('payment-1'); }); }); describe('getMembershipFees', () => { it('should return MembershipFeeViewModel when fee exists', async () => { const mockResponse = { fee: { id: 'fee-1', leagueId: 'league-1', type: 'season' as const, amount: 50, enabled: true, createdAt: new Date(), updatedAt: new Date(), }, payments: [], }; mockApiClient.getMembershipFees.mockResolvedValue(mockResponse); const result = await service.getMembershipFees('league-1'); expect(result).toBeInstanceOf(MembershipFeeViewModel); expect(result!.id).toBe('fee-1'); }); it('should return null when fee does not exist', async () => { const mockResponse = { fee: null, payments: [], }; mockApiClient.getMembershipFees.mockResolvedValue(mockResponse); const result = await service.getMembershipFees('league-1'); expect(result).toBeNull(); }); }); describe('getPrizes', () => { it('should call apiClient.getPrizes and return PrizeViewModel array', async () => { const mockResponse = { prizes: [ { id: 'prize-1', leagueId: 'league-1', seasonId: 'season-1', position: 1, name: 'First Place', amount: 100, type: 'cash' as const, awarded: false, createdAt: new Date(), }, ], }; mockApiClient.getPrizes.mockResolvedValue(mockResponse); const result = await service.getPrizes(); expect(mockApiClient.getPrizes).toHaveBeenCalledWith(undefined); expect(result).toHaveLength(1); expect(result[0]).toBeInstanceOf(PrizeViewModel); expect(result[0].id).toBe('prize-1'); }); it('should call apiClient.getPrizes with filters', async () => { const mockResponse = { prizes: [] }; mockApiClient.getPrizes.mockResolvedValue(mockResponse); await service.getPrizes('league-1', 'season-1'); expect(mockApiClient.getPrizes).toHaveBeenCalledWith({ leagueId: 'league-1', seasonId: 'season-1' }); }); }); describe('getWallet', () => { it('should call apiClient.getWallet and return WalletViewModel', async () => { const mockResponse = { wallet: { id: 'wallet-1', leagueId: 'league-1', balance: 1000, totalRevenue: 1500, totalPlatformFees: 100, totalWithdrawn: 400, createdAt: new Date(), currency: 'EUR', }, transactions: [ { id: 'tx-1', walletId: 'wallet-1', type: 'deposit' as const, amount: 500, description: 'Deposit', createdAt: new Date(), }, ], }; mockApiClient.getWallet.mockResolvedValue(mockResponse); const result = await service.getWallet('league-1'); expect(mockApiClient.getWallet).toHaveBeenCalledWith({ leagueId: 'league-1' }); expect(result).toBeInstanceOf(WalletViewModel); expect(result.id).toBe('wallet-1'); expect(result.balance).toBe(1000); expect(result.transactions).toHaveLength(1); }); }); });