lsa-planer

LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.

/ tests services karteAbruf.test.ts

4,4 KB Rohdatei
tests/services/karteAbruf.test.ts — 141 Zeilen
1 import { afterEach, describe, expect, it, vi } from 'vitest';
2 import { holeKartenbild } from '../../electron/karte';
3
4 /**
5 * Abruf beim Kartendienst.
6 *
7 * Geprueft wird das Verhalten in genau den Faellen, die im Betrieb wirklich
8 * auftreten und die sich von Hand kaum herstellen lassen: eine Fehlermeldung
9 * des Dienstes mit Statuscode 200, eine unter Last abgebrochene Verbindung und
10 * eine Adresse, die nicht freigegeben ist.
11 *
12 * `fetch` wird dazu ersetzt. Ein Test, der wirklich ins Netz greift, waere von
13 * der Auslastung fremder Server abhaengig und damit wertlos.
14 */
15
16 const echtesFetch = globalThis.fetch;
17
18 afterEach(() => {
19 globalThis.fetch = echtesFetch;
20 vi.restoreAllMocks();
21 });
22
23 function bildAntwort(): Response {
24 return new Response(new Uint8Array([0xff, 0xd8, 0xff, 0xdb]), {
25 status: 200,
26 headers: { 'content-type': 'image/jpeg' },
27 });
28 }
29
30 const NRW = 'https://www.wms.nrw.de/geobasis/wms_nw_dop?SERVICE=WMS&REQUEST=GetMap';
31
32 describe('holeKartenbild', () => {
33 it('greift bei einer nicht freigegebenen Adresse gar nicht erst zu', async () => {
34 const gerufen = vi.fn();
35 globalThis.fetch = gerufen;
36
37 const antwort = await holeKartenbild({ url: 'https://beispiel.example/wms?REQUEST=GetMap' });
38
39 expect(antwort.ok).toBe(false);
40 expect(antwort.fehler).toContain('nicht freigegeben');
41 expect(gerufen).not.toHaveBeenCalled();
42 });
43
44 it('gibt die Bilddaten als Daten-URL zurueck', async () => {
45 globalThis.fetch = vi.fn(async () => bildAntwort());
46
47 const antwort = await holeKartenbild({ url: NRW });
48
49 expect(antwort.ok).toBe(true);
50 expect(antwort.datenUrl?.startsWith('data:image/jpeg;base64,')).toBe(true);
51 expect(antwort.fehler).toBeNull();
52 });
53
54 it('erkennt eine Dienstmeldung, die als XML mit Statuscode 200 kommt', async () => {
55 // Genau so meldet ein WMS einen unbekannten Ebenennamen. Ohne die Pruefung
56 // des Inhaltstyps landete die Meldung als "Bild" im Projekt.
57 globalThis.fetch = vi.fn(
58 async () =>
59 new Response('<ServiceExceptionReport>LayerNotDefined</ServiceExceptionReport>', {
60 status: 200,
61 headers: { 'content-type': 'text/xml' },
62 }),
63 );
64
65 const antwort = await holeKartenbild({ url: NRW });
66
67 expect(antwort.ok).toBe(false);
68 expect(antwort.fehler).toContain('kein Bild');
69 expect(antwort.fehler).toContain('LayerNotDefined');
70 });
71
72 it('wiederholt einmal, wenn die Verbindung abbricht', async () => {
73 let aufrufe = 0;
74 globalThis.fetch = vi.fn(async () => {
75 aufrufe += 1;
76 if (aufrufe === 1) throw new TypeError('terminated');
77 return bildAntwort();
78 });
79
80 const antwort = await holeKartenbild({ url: NRW });
81
82 expect(aufrufe).toBe(2);
83 expect(antwort.ok).toBe(true);
84 });
85
86 it('wiederholt hoechstens einmal und meldet dann verstaendlich', async () => {
87 let aufrufe = 0;
88 globalThis.fetch = vi.fn(async () => {
89 aufrufe += 1;
90 throw new TypeError('terminated');
91 });
92
93 const antwort = await holeKartenbild({ url: NRW });
94
95 expect(aufrufe).toBe(2);
96 expect(antwort.ok).toBe(false);
97 expect(antwort.fehler).toContain('abgebrochen');
98 // Die rohe Meldung der Netzschicht darf nicht durchschlagen.
99 expect(antwort.fehler).not.toContain('terminated');
100 });
101
102 it('wiederholt nach Ablauf der Wartezeit nicht', async () => {
103 let aufrufe = 0;
104 globalThis.fetch = vi.fn(async () => {
105 aufrufe += 1;
106 const fehler = new Error('The operation was aborted.');
107 fehler.name = 'AbortError';
108 throw fehler;
109 });
110
111 const antwort = await holeKartenbild({ url: NRW });
112
113 expect(aufrufe).toBe(1);
114 expect(antwort.ok).toBe(false);
115 expect(antwort.fehler).toContain('nicht rechtzeitig');
116 });
117
118 it('meldet eine fehlende Namensaufloesung als Verbindungsproblem', async () => {
119 globalThis.fetch = vi.fn(async () => {
120 const fehler = new TypeError('fetch failed');
121 (fehler as { cause?: unknown }).cause = { code: 'ENOTFOUND' };
122 throw fehler;
123 });
124
125 const antwort = await holeKartenbild({ url: NRW });
126
127 expect(antwort.ok).toBe(false);
128 expect(antwort.fehler).toContain('nicht erreichbar');
129 });
130
131 it('reicht einen Statuscode des Dienstes weiter', async () => {
132 globalThis.fetch = vi.fn(
133 async () => new Response('gesperrt', { status: 403, statusText: 'Forbidden' }),
134 );
135
136 const antwort = await holeKartenbild({ url: NRW });
137
138 expect(antwort.ok).toBe(false);
139 expect(antwort.fehler).toContain('403');
140 });
141 });