import test from 'node:test'; import assert from 'node:assert/strict'; async function withFetch(mockFetch, fn) { const originalFetch = globalThis.fetch; const originalAdsbKey = process.env.ADSB_API_KEY; const originalRapidKey = process.env.RAPIDAPI_KEY; globalThis.fetch = mockFetch; delete process.env.ADSB_API_KEY; delete process.env.RAPIDAPI_KEY; try { return await fn(); } finally { globalThis.fetch = originalFetch; if (originalAdsbKey === undefined) delete process.env.ADSB_API_KEY; else process.env.ADSB_API_KEY = originalAdsbKey; if (originalRapidKey === undefined) delete process.env.RAPIDAPI_KEY; else process.env.RAPIDAPI_KEY = originalRapidKey; } } function jsonResponse(payload, ok = true, status = 200) { return { ok, status, headers: { get: () => 'application/json' }, text: async () => JSON.stringify(payload), }; } test('ADS-B reports disabled when no key is configured and public feed fails', async () => { await withFetch(async () => jsonResponse({ error: 'blocked' }, false, 403), async () => { const { briefing } = await import('../apis/sources/adsb.mjs'); const data = await briefing(); assert.equal(data.status, 'disabled'); assert.match(data.error, /ADSB_API_KEY|RAPIDAPI_KEY/); assert.equal(data.militaryAircraft.length, 0); }); }); test('ADS-B reports degraded when RapidAPI and public feed fail', async () => { await withFetch(async () => jsonResponse({ error: 'unavailable' }, false, 503), async () => { process.env.ADSB_API_KEY = 'test-key'; const { briefing } = await import('../apis/sources/adsb.mjs'); const data = await briefing(); assert.equal(data.status, 'degraded'); assert.match(data.error, /providers returned no usable/); assert.equal(data.failures.length, 2); }); }); test('ADS-B returns live RapidAPI military aircraft payloads', async () => { await withFetch(async () => jsonResponse({ ac: [{ hex: 'AE1234', flight: 'RCH123', t: 'KC135', lat: 50, lon: 8, mil: true, }], }), async () => { process.env.ADSB_API_KEY = 'test-key'; const { briefing } = await import('../apis/sources/adsb.mjs'); const data = await briefing(); assert.equal(data.status, 'live'); assert.equal(data.provider, 'rapidapi'); assert.equal(data.totalMilitary, 1); assert.equal(data.militaryAircraft[0].callsign, 'RCH123'); }); }); test('runSource treats disabled source status as degraded health', async () => { const { runSource } = await import('../apis/briefing.mjs'); const result = await runSource('ADS-B', async () => ({ status: 'disabled', message: 'missing key' })); assert.equal(result.status, 'degraded'); assert.equal(result.error, null); });