import { beforeEach, describe, expect, it, vi } from 'vitest' import type { AdMediationConfig } from '@d3ro/core/types' import { getAdMediationEngine } from '../../src/main/services/ads/AdMediationEngine' import { getAdSettlementService } 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' const adapterCases = [ ['EthicalAds', new EthicalAdsAdapter()], ['Carbon Ads', new CarbonAdsAdapter()], ['Playwire', new PlaywireAdapter()], ['Unity Ads', new UnityAdsAdapter()], ['AppLovin', new AppLovinAdapter()], ['Google Ad Manager', new GoogleAdManagerAdapter()], ['InMobi', new InMobiAdapter()], ['PubMatic', new PubMaticAdapter()], ['Mintegral', new MintegralAdapter()], ] as const describe('desktop ad provider boundaries', () => { it.each(adapterCases)('%s returns no bid until a real provider is integrated', async (_name, adapter) => { await adapter.init() const bid = await adapter.requestBid({ placement: adapter.supportedFormats.includes('rewarded_video') ? 'rewarded_video_quota' : 'bottom_dock_banner', format: adapter.supportedFormats[0], }) expect(bid).toEqual({ hasBid: false, bidEcpm: 0, latencyMs: 0, error: 'provider_not_integrated', }) await expect(adapter.reportRewardCompletion('forged-ad-id')).resolves.toEqual({ success: false, tokenReward: 0, }) }) }) describe('DirectHouseSponsorAdapter live decision endpoint', () => { it('is fail-closed until an endpoint is configured', async () => { const adapter = new DirectHouseSponsorAdapter() await adapter.init() const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock' }) expect(bid).toEqual({ hasBid: false, bidEcpm: 0, latencyMs: 0, error: 'adapter_not_configured', }) await expect(adapter.reportRewardCompletion('forged-ad-id')).resolves.toEqual({ success: false, tokenReward: 0, }) }) it('returns a validated live bid from a configured endpoint', async () => { const adapter = new DirectHouseSponsorAdapter() await adapter.init({ endpointUrl: 'https://ads.example.com', apiSecret: 'secret' }) const fetchMock = vi.fn().mockResolvedValue( new Response( JSON.stringify({ bidEcpm: 9.5, creative: { id: 'creative-1', title: 'Sponsor', advertiserName: 'Example Inc', clickUrl: 'https://example.com/offer', format: 'banner_dock', }, }), { status: 200 }, ), ) vi.stubGlobal('fetch', fetchMock) try { const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock', floorEcpm: 2, }) expect(bid.hasBid).toBe(true) expect(bid.bidEcpm).toBe(9.5) expect(bid.creative?.networkId).toBe('direct_sponsor') expect(bid.creative?.clickUrl).toBe('https://example.com/offer') const [url, init] = fetchMock.mock.calls[0] as [string, RequestInit] expect(String(url)).toBe('https://ads.example.com/bid') expect(init.headers).toMatchObject({ Authorization: 'Bearer secret' }) } finally { vi.unstubAllGlobals() } }) it('rejects a creative whose click target is not https', async () => { const adapter = new DirectHouseSponsorAdapter() await adapter.init({ endpointUrl: 'https://ads.example.com' }) vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue( new Response( JSON.stringify({ bidEcpm: 9.5, creative: { id: 'c', title: 't', advertiserName: 'a', clickUrl: 'http://insecure.example.com', format: 'banner_dock', }, }), { status: 200 }, ), ), ) try { const bid = await adapter.requestBid({ placement: 'bottom_dock_banner', format: 'banner_dock', }) expect(bid.hasBid).toBe(false) expect(bid.error).toBe('invalid_creative') } finally { vi.unstubAllGlobals() } }) }) describe('AdMediationEngine fail-closed auction and telemetry', () => { const engine = getAdMediationEngine() const settlement = getAdSettlementService() const knownNetworks = engine.getConfig().networks let disabledNetworks: AdMediationConfig['networks'] beforeEach(() => { disabledNetworks = knownNetworks.map((network) => ({ ...network, enabled: false, })) engine.setConfig({ networks: disabledNetworks, houseAdFallback: false }) }) it('returns a real no-fill result instead of inventing a winner', async () => { const result = await engine.runAuction({ placement: 'bottom_dock_banner', format: 'banner_dock', floorEcpm: 2, auctionTimeoutMs: 800, }) expect(result.winner).toBeNull() expect(result.winningBidEcpm).toBe(0) expect(result.participatingBids).toEqual([]) expect(result.totalAuctionLatencyMs).toBeGreaterThanOrEqual(0) }) it('keeps provider shells no-bid even if an operator enables them prematurely', async () => { engine.setConfig({ networks: disabledNetworks.map((network) => ({ ...network, enabled: true })), }) const result = await engine.runAuction({ placement: 'bottom_dock_banner', format: 'banner_dock', floorEcpm: 0.01, auctionTimeoutMs: 800, }) expect(result.winner).toBeNull() expect(result.winningBidEcpm).toBe(0) expect(result.participatingBids.length).toBeGreaterThan(0) expect(result.participatingBids.every((bid) => bid.status === 'no_bid')).toBe(true) }) it('does not enable an adapter merely because its config entry is omitted', async () => { engine.setConfig({ networks: [] }) const result = await engine.runAuction({ placement: 'bottom_dock_banner', format: 'banner_dock', }) expect(result.winner).toBeNull() expect(result.participatingBids).toEqual([]) }) it('returns a defensive config copy', () => { const exposedConfig = engine.getConfig() exposedConfig.networks[0].enabled = true expect(engine.getConfig().networks[0].enabled).toBe(false) }) it('ignores renderer-forged impressions and clicks', () => { const before = settlement.getRevenueStats('2026-08') engine.recordImpression({ adId: 'forged-ad-id', format: 'banner_dock', network: 'ethical_ads', earnedEcpm: 999, }) engine.recordClick('forged-ad-id', 'ethical_ads') const after = settlement.getRevenueStats('2026-08') expect(after.totalImpressions).toBe(before.totalImpressions) expect(after.totalClicks).toBe(before.totalClicks) expect(after.totalRevenueUsd).toBe(before.totalRevenueUsd) }) it('never grants desktop quota without server-verified completion', async () => { await expect(engine.claimReward('forged-reward-id', 'unity_ads')).resolves.toEqual({ success: false, tokensAdded: 0, newTotalQuota: 0, }) }) }) describe('AdSettlementService fail-closed ledger', () => { const settlement = getAdSettlementService() it('does not ship personal payout details or pretend providers are configured', () => { expect(settlement.getPublisherAccount()).toEqual({ accountEmail: '', beneficiaryName: '', payoutBank: '', payoutAccountNumber: '', taxRegistrationNumber: '', paypalEmail: '', networksConfigured: 0, }) }) it('does not synthesize revenue, fill rate, or settlement history', () => { const stats = settlement.getRevenueStats('2026-08') expect(stats.totalImpressions).toBe(0) expect(stats.totalClicks).toBe(0) expect(stats.totalCompletions).toBe(0) expect(stats.totalRevenueUsd).toBe(0) expect(stats.avgEcpm).toBe(0) expect(stats.fillRatePercent).toBe(0) expect(stats.networkBreakdown).toEqual([]) expect(stats.settlements).toEqual([]) }) it('rejects payout without an external settlement provider', () => { expect(settlement.requestPayout('forged-settlement-id')).toEqual({ success: false, message: 'external_settlement_not_configured', }) }) it('ignores invalid or unattested settlement events', () => { const before = settlement.getRevenueStats('2026-08') settlement.recordImpression('', 10) settlement.recordImpression('forged-network', Number.NaN) settlement.recordImpression('forged-network', -10) settlement.recordClick('forged-network') settlement.recordCompletion('forged-network') expect(settlement.getRevenueStats('2026-08')).toEqual(before) }) })