import { describe, it, expect, vi } from 'vitest'; import { distributeCampaignBudget } from './distributionEngine'; // Supabase Mocking representing both contributions view and distribution rules table vi.mock('./supabase', () => ({ supabase: { from: vi.fn((table: string) => { if (table === 'distribution_rules') { return { select: vi.fn(() => ({ eq: vi.fn(() => ({ maybeSingle: vi.fn(() => Promise.resolve({ data: { id: 'rule-001', campaign_id: 'camp-123', citizen_reward_ratio: 0.70, // 70% Citizen Reward sme_donation_ratio: 0.20, // 20% SME Donation platform_fee_ratio: 0.10, // 10% Platform Fee rule_type: 'CUSTOM', description: '테스트용 동적 비율' }, error: null })) })) })) }; } // Default fallback is my_nature_contributions_view return { select: vi.fn(() => ({ eq: vi.fn(() => ({ gt: vi.fn(() => Promise.resolve({ data: [ { user_id: 'user_1', display_name: '참여자A', co2_grams: 600 }, { user_id: 'user_2', display_name: '참여자B', co2_grams: 400 }, ], error: null })) })) })) }; }) } })); // Ledger Mocking vi.mock('./ledger', () => ({ appendLedgerEntry: vi.fn(() => Promise.resolve({ transactionId: 'test-tx-id' })) })); describe('Distribution Engine v1.2 Unit Tests', () => { it('1차 분배 (고정 파라미터): 수수료 10% 제외 후 기여도(6:4)에 따라 포인트가 배분되어야 한다', async () => { const params = { campaignId: 'camp-123', budgetAmount: 100000, // 10만원 platformFeeRate: 0.1, // 10% 수수료 }; const result = await distributeCampaignBudget(params); // 1. 플랫폼 수수료 확인: 100,000 * 0.1 = 10,000 expect(result.platformFee).toBe(10000); // 2. 총 분배액 확인: 100,000 * 0.70 (rules가 동적으로 불려져 70%로 정산됨) expect(result.totalDistributed).toBe(70000); expect(result.recipientCount).toBe(2); }); it('1차 분배 (동적 비율): DB distribution_rules에 정의된 시민 지분(70%)과 플랫폼 지분(10%)이 정상 반영되어야 한다', async () => { const params = { campaignId: 'camp-123', budgetAmount: 100000, // 10만원 }; const result = await distributeCampaignBudget(params); // 1. 동적 플랫폼 수수료 확인: 100,000 * 0.10 = 10,000 expect(result.platformFee).toBe(10000); // 2. 동적 총 시민 분배액 확인: 100,000 * 0.70 = 70,000 expect(result.totalDistributed).toBe(70000); expect(result.recipientCount).toBe(2); }); });