import { afterEach, describe, expect, it, vi } from 'vitest'; import { holeKartenbild } from '../../electron/karte'; /** * Abruf beim Kartendienst. * * Geprueft wird das Verhalten in genau den Faellen, die im Betrieb wirklich * auftreten und die sich von Hand kaum herstellen lassen: eine Fehlermeldung * des Dienstes mit Statuscode 200, eine unter Last abgebrochene Verbindung und * eine Adresse, die nicht freigegeben ist. * * `fetch` wird dazu ersetzt. Ein Test, der wirklich ins Netz greift, waere von * der Auslastung fremder Server abhaengig und damit wertlos. */ const echtesFetch = globalThis.fetch; afterEach(() => { globalThis.fetch = echtesFetch; vi.restoreAllMocks(); }); function bildAntwort(): Response { return new Response(new Uint8Array([0xff, 0xd8, 0xff, 0xdb]), { status: 200, headers: { 'content-type': 'image/jpeg' }, }); } const NRW = 'https://www.wms.nrw.de/geobasis/wms_nw_dop?SERVICE=WMS&REQUEST=GetMap'; describe('holeKartenbild', () => { it('greift bei einer nicht freigegebenen Adresse gar nicht erst zu', async () => { const gerufen = vi.fn(); globalThis.fetch = gerufen; const antwort = await holeKartenbild({ url: 'https://beispiel.example/wms?REQUEST=GetMap' }); expect(antwort.ok).toBe(false); expect(antwort.fehler).toContain('nicht freigegeben'); expect(gerufen).not.toHaveBeenCalled(); }); it('gibt die Bilddaten als Daten-URL zurueck', async () => { globalThis.fetch = vi.fn(async () => bildAntwort()); const antwort = await holeKartenbild({ url: NRW }); expect(antwort.ok).toBe(true); expect(antwort.datenUrl?.startsWith('data:image/jpeg;base64,')).toBe(true); expect(antwort.fehler).toBeNull(); }); it('erkennt eine Dienstmeldung, die als XML mit Statuscode 200 kommt', async () => { // Genau so meldet ein WMS einen unbekannten Ebenennamen. Ohne die Pruefung // des Inhaltstyps landete die Meldung als "Bild" im Projekt. globalThis.fetch = vi.fn( async () => new Response('LayerNotDefined', { status: 200, headers: { 'content-type': 'text/xml' }, }), ); const antwort = await holeKartenbild({ url: NRW }); expect(antwort.ok).toBe(false); expect(antwort.fehler).toContain('kein Bild'); expect(antwort.fehler).toContain('LayerNotDefined'); }); it('wiederholt einmal, wenn die Verbindung abbricht', async () => { let aufrufe = 0; globalThis.fetch = vi.fn(async () => { aufrufe += 1; if (aufrufe === 1) throw new TypeError('terminated'); return bildAntwort(); }); const antwort = await holeKartenbild({ url: NRW }); expect(aufrufe).toBe(2); expect(antwort.ok).toBe(true); }); it('wiederholt hoechstens einmal und meldet dann verstaendlich', async () => { let aufrufe = 0; globalThis.fetch = vi.fn(async () => { aufrufe += 1; throw new TypeError('terminated'); }); const antwort = await holeKartenbild({ url: NRW }); expect(aufrufe).toBe(2); expect(antwort.ok).toBe(false); expect(antwort.fehler).toContain('abgebrochen'); // Die rohe Meldung der Netzschicht darf nicht durchschlagen. expect(antwort.fehler).not.toContain('terminated'); }); it('wiederholt nach Ablauf der Wartezeit nicht', async () => { let aufrufe = 0; globalThis.fetch = vi.fn(async () => { aufrufe += 1; const fehler = new Error('The operation was aborted.'); fehler.name = 'AbortError'; throw fehler; }); const antwort = await holeKartenbild({ url: NRW }); expect(aufrufe).toBe(1); expect(antwort.ok).toBe(false); expect(antwort.fehler).toContain('nicht rechtzeitig'); }); it('meldet eine fehlende Namensaufloesung als Verbindungsproblem', async () => { globalThis.fetch = vi.fn(async () => { const fehler = new TypeError('fetch failed'); (fehler as { cause?: unknown }).cause = { code: 'ENOTFOUND' }; throw fehler; }); const antwort = await holeKartenbild({ url: NRW }); expect(antwort.ok).toBe(false); expect(antwort.fehler).toContain('nicht erreichbar'); }); it('reicht einen Statuscode des Dienstes weiter', async () => { globalThis.fetch = vi.fn( async () => new Response('gesperrt', { status: 403, statusText: 'Forbidden' }), ); const antwort = await holeKartenbild({ url: NRW }); expect(antwort.ok).toBe(false); expect(antwort.fehler).toContain('403'); }); });