File size: 2,918 Bytes
5c98911
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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);
  });
});