Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
196 lines
8.3 KiB
TypeScript
196 lines
8.3 KiB
TypeScript
// apps/desktop/tests/unit/AdMediationEngine.spec.ts
|
|
// Comprehensive Real Service Test Suite for 10+ Multi-Ad Network Mediation & Settlement
|
|
|
|
import { describe, it, expect, beforeEach } from 'vitest'
|
|
import { getAdMediationEngine, AdMediationEngine } from '../../src/main/services/ads/AdMediationEngine'
|
|
import { getAdSettlementService, AdSettlementService } from '../../src/main/services/ads/AdSettlementService'
|
|
import { EthicalAdsAdapter } from '../../src/main/services/ads/EthicalAdsAdapter'
|
|
import { CarbonAdsAdapter } from '../../src/main/services/ads/CarbonAdsAdapter'
|
|
import { PlaywireAdapter } from '../../src/main/services/ads/PlaywireAdapter'
|
|
import { UnityAdsAdapter } from '../../src/main/services/ads/UnityAdsAdapter'
|
|
import { AppLovinAdapter } from '../../src/main/services/ads/AppLovinAdapter'
|
|
import { GoogleAdManagerAdapter } from '../../src/main/services/ads/GoogleAdManagerAdapter'
|
|
import { InMobiAdapter } from '../../src/main/services/ads/InMobiAdapter'
|
|
import { PubMaticAdapter } from '../../src/main/services/ads/PubMaticAdapter'
|
|
import { MintegralAdapter } from '../../src/main/services/ads/MintegralAdapter'
|
|
import { DirectHouseSponsorAdapter } from '../../src/main/services/ads/DirectHouseSponsorAdapter'
|
|
|
|
describe('10+ Multi-Ad Network Adapters & Real Service Tests', () => {
|
|
it('1. EthicalAds Adapter bids on developer dock slots', async () => {
|
|
const adapter = new EthicalAdsAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(3.0)
|
|
expect(bid.creative?.networkId).toBe('ethical_ads')
|
|
expect(bid.creative?.title).toContain('MongoDB')
|
|
})
|
|
|
|
it('2. Carbon Ads Adapter provides tech native single-unit creatives', async () => {
|
|
const adapter = new CarbonAdsAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(3.5)
|
|
expect(bid.creative?.networkId).toBe('carbon_ads')
|
|
expect(bid.creative?.title).toContain('Linear')
|
|
})
|
|
|
|
it('3. Playwire RAMP Adapter participates in desktop header bidding', async () => {
|
|
const adapter = new PlaywireAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(4.5)
|
|
expect(bid.creative?.networkId).toBe('playwire')
|
|
})
|
|
|
|
it('4. Unity LevelPlay Adapter delivers high-yield rewarded video ads', async () => {
|
|
const adapter = new UnityAdsAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'rewarded_video_quota', format: 'rewarded_video' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(6.0)
|
|
expect(bid.creative?.networkId).toBe('unity_ads')
|
|
expect(bid.creative?.rewardTokens).toBe(50)
|
|
})
|
|
|
|
it('5. AppLovin MAX Adapter provides competitive in-app bidding', async () => {
|
|
const adapter = new AppLovinAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'rewarded_video_quota', format: 'rewarded_video' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(5.5)
|
|
expect(bid.creative?.networkId).toBe('applovin_max')
|
|
})
|
|
|
|
it('6. Google Ad Manager 360 Adapter offers reliable global demand', async () => {
|
|
const adapter = new GoogleAdManagerAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(2.0)
|
|
expect(bid.creative?.networkId).toBe('google_ad_manager')
|
|
})
|
|
|
|
it('7. InMobi Adapter handles programmatic exchange bids', async () => {
|
|
const adapter = new InMobiAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(2.8)
|
|
expect(bid.creative?.networkId).toBe('inmobi')
|
|
})
|
|
|
|
it('8. PubMatic OpenWrap SSP Adapter responds with Prebid bids', async () => {
|
|
const adapter = new PubMaticAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(3.0)
|
|
expect(bid.creative?.networkId).toBe('pubmatic')
|
|
})
|
|
|
|
it('9. Mintegral Adapter delivers APAC/global video demand', async () => {
|
|
const adapter = new MintegralAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'rewarded_video_quota', format: 'rewarded_video' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(4.0)
|
|
expect(bid.creative?.networkId).toBe('mintegral')
|
|
})
|
|
|
|
it('10. Direct House Sponsor Adapter provides 100% margin premium AI ads', async () => {
|
|
const adapter = new DirectHouseSponsorAdapter()
|
|
await adapter.init()
|
|
const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' })
|
|
expect(bid.hasBid).toBe(true)
|
|
expect(bid.bidEcpm).toBeGreaterThanOrEqual(12.0)
|
|
expect(bid.creative?.networkId).toBe('direct_sponsor')
|
|
})
|
|
})
|
|
|
|
describe('AdMediationEngine Header Bidding Auction & Telemetry', () => {
|
|
let engine: AdMediationEngine
|
|
|
|
beforeEach(() => {
|
|
engine = getAdMediationEngine()
|
|
})
|
|
|
|
it('executes parallel header bidding auction across all active networks', async () => {
|
|
const auctionResult = await engine.runAuction({
|
|
placement: 'bottom_dock_banner',
|
|
format: 'banner_dock',
|
|
floorEcpm: 2.0,
|
|
auctionTimeoutMs: 800,
|
|
})
|
|
|
|
expect(auctionResult).toBeDefined()
|
|
expect(auctionResult.winner).toBeDefined()
|
|
expect(auctionResult.winningBidEcpm).toBeGreaterThanOrEqual(2.0)
|
|
expect(auctionResult.participatingBids.length).toBeGreaterThanOrEqual(6)
|
|
expect(auctionResult.totalAuctionLatencyMs).toBeLessThanOrEqual(1200)
|
|
})
|
|
|
|
it('records ad impression and triggers adapter beacon', () => {
|
|
expect(() => {
|
|
engine.recordImpression({
|
|
adId: 'test_ad_001',
|
|
format: 'banner_dock',
|
|
network: 'ethical_ads',
|
|
earnedEcpm: 4.2,
|
|
})
|
|
}).not.toThrow()
|
|
})
|
|
|
|
it('records ad click-through tracking event', () => {
|
|
expect(() => {
|
|
engine.recordClick('test_ad_001', 'ethical_ads')
|
|
}).not.toThrow()
|
|
})
|
|
|
|
it('dispenses +50 tokens upon rewarded video completion and enforces cooldown', async () => {
|
|
const rewardRes = await engine.claimReward('test_video_ad', 'unity_ads')
|
|
expect(rewardRes.success).toBe(true)
|
|
expect(rewardRes.tokensAdded).toBe(50)
|
|
|
|
// Immediate second claim should be rejected by cooldown
|
|
const cooldownRes = await engine.claimReward('test_video_ad_2', 'unity_ads')
|
|
expect(cooldownRes.success).toBe(false)
|
|
expect(cooldownRes.tokensAdded).toBe(0)
|
|
expect(cooldownRes.nextAvailableAt).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('AdSettlementService Revenue Ledger & Tax Withholding', () => {
|
|
let settlement: AdSettlementService
|
|
|
|
beforeEach(() => {
|
|
settlement = getAdSettlementService()
|
|
})
|
|
|
|
it('retrieves registered publisher account metadata for yunchanpaca@gmail.com', () => {
|
|
const account = settlement.getPublisherAccount()
|
|
expect(account.accountEmail).toBe('yunchanpaca@gmail.com')
|
|
expect(account.payoutBank).toContain('KB국민은행')
|
|
expect(account.networksConfigured).toBe(10)
|
|
})
|
|
|
|
it('generates revenue statistics and computes Korean 3.3% withholding tax', () => {
|
|
const stats = settlement.getRevenueStats('2026-08')
|
|
expect(stats.totalRevenueUsd).toBeGreaterThan(0)
|
|
expect(stats.avgEcpm).toBeGreaterThan(0)
|
|
expect(stats.settlements.length).toBeGreaterThanOrEqual(5)
|
|
|
|
const first = stats.settlements[0]
|
|
expect(first.withholdingTaxRate).toBe(0.033)
|
|
expect(first.netPayoutKrw).toBe(Math.round(first.netRevenueUsd * 1350))
|
|
})
|
|
|
|
it('processes payout request and updates status to paid', () => {
|
|
const res = settlement.requestPayout('stl_202607_direct_sponsor')
|
|
expect(res.success).toBe(true)
|
|
expect(res.settlement?.payoutStatus).toBe('paid')
|
|
expect(res.message).toContain('KB국민은행')
|
|
})
|
|
})
|