import { readFileSync } from 'node:fs'; import path from 'node:path'; import { beforeAll, describe, expect, it, vi } from 'vitest'; import { createStandardIntersectionProject } from '@/domain/model/factory'; import { ladeSitzung, saveSession } from '@/services/storage'; /** * Einlesemeldungen erreichen den Bearbeiter auch auf dem Sitzungsweg * (zweiter Anteil von Befund 12). * * Beim Oeffnen einer Datei zeigt `showImportIssues` jede einzelne Meldung mit * Art, Bereich und Wortlaut. Der Wiederanlauf aus dem Sitzungsspeicher nannte * dagegen nur die ANZAHL - "(1 Hinweise beim Einlesen)". Gerade der Wortlaut * ist aber die Auskunft: Wurde ein Raeumweg beim Einlesen auf den zulaessigen * Hoechstwert der Anlagenart begrenzt, aendert das die Zwischenzeiten und damit * den ganzen Signalzeitenplan. Wer nur eine Zahl liest, erfaehrt nie, welcher * Wert angefasst wurde. * * Geprueft wird am echten Einstiegspunkt: `src/main.ts` wird eingelesen und * startet die ganze Anwendung; nur der Sitzungsspeicher ist ersetzt. */ const MELDUNG = 'Räumweg (Anlagenart Fußgängerschutzanlage) liegt mit 400 über dem zulässigen ' + 'Höchstwert 100; der Wert wurde begrenzt'; vi.mock('@/services/storage', async (importOriginal) => { const echt = await importOriginal(); return { ...echt, ladeSitzung: vi.fn(), saveSession: vi.fn(), addRecoveryPoint: vi.fn(), }; }); async function warte(ms = 0): Promise { await new Promise((fertig) => setTimeout(fertig, ms)); } /** Die Ueberschriften aller gerade offenen Fenster. */ function offeneFenster(): string[] { return [...document.querySelectorAll('.dialog-hintergrund h2')].map( (h) => h.textContent?.trim() ?? '', ); } beforeAll(async () => { vi.mocked(ladeSitzung).mockResolvedValue({ art: 'geladen', stand: { project: createStandardIntersectionProject(), issues: [{ path: 'signalGroups[0].clearingPath', severity: 'warnung', message: MELDUNG }], repaired: true, migrated: false, sourceVersion: '13', intergreenComparison: [], }, }); vi.mocked(saveSession).mockResolvedValue({ ok: true, message: '' }); localStorage.clear(); document.body.replaceChildren(); const wurzel = document.createElement('div'); wurzel.id = 'anwendung'; document.body.append(wurzel); await import('@/main'); // Laenger als die 400 ms, mit denen der Wiederanlauf seine Kurzmeldungen // nachreicht - sonst waere der alte Zaehlhinweis noch gar nicht da. await warte(500); }); describe('Einlesemeldungen beim Wiederanlauf', () => { it('zeigt dieselbe Aufstellung wie der Öffnen-Weg', () => { expect(offeneFenster()).toContain('Hinweise zum Import'); }); it('nennt den Wortlaut der Meldung, nicht nur ihre Anzahl', () => { const fenster = document.querySelector('.dialog-hintergrund'); expect(fenster?.textContent).toContain(MELDUNG); }); }); /** * WANN die Aufstellung erscheint, wird an einer Stelle entschieden. * * Seit der Sitzungsweg dieselbe Aufstellung zeigt wie der Oeffnen-Weg, stand * die Bedingung "Meldungen ODER Gegenueberstellung" wortgleich an beiden * Aufrufstellen. Die Begruendung fuer ihren zweiten Teil - bei einem * uebernommenen 4.x-Projekt ist die Gegenueberstellung die wichtigste Auskunft, * auch wenn sonst nichts auffiel - stand nur an einer davon. Wer die Bedingung * spaeter erweitert, findet die zweite Stelle nicht, und die beiden Wege zeigen * wieder Unterschiedliches. Deshalb steht die Entscheidung an einer Stelle. * * Am Quelltext festgehalten und nicht am Verhalten: Beide Fassungen zeigen * heute dasselbe Fenster - die Doppelung ist kein Unterschied im Ergebnis, * sondern die Anlage dafuer, dass einer entsteht. Dieselbe Ueberlegung traegt * `tests/ui/stilblattZusagen.test.ts`. */ describe('Die Entscheidung über die Aufstellung "Hinweise zum Import"', () => { const quelltext = (): string => readFileSync(path.resolve(__dirname, '..', '..', 'src', 'main.ts'), 'utf8'); it('steht an keiner Aufrufstelle mehr', () => { const stellen = quelltext().split('intergreenComparison.length').length - 1; expect( stellen, 'Eine Aufrufstelle entscheidet wieder selbst, ob die Aufstellung erscheint.', ).toBe(0); }); it('steht in showImportIssues selbst', () => { const text = quelltext(); const beginn = text.indexOf('function showImportIssues('); expect(beginn, 'showImportIssues nicht gefunden').toBeGreaterThanOrEqual(0); const bisFenster = text.slice(beginn, text.indexOf('new Panel(', beginn)); // Vor dem ersten Fenster steht der fruehe Ruecksprung, und er wiegt beides // ab: die Meldungen und die Gegenueberstellung. expect(bisFenster).toContain('issues.length'); expect(bisFenster).toContain('vergleich.length'); expect(bisFenster).toContain('return;'); }); });