import { beforeAll, describe, expect, it, vi } from 'vitest'; import { ladeSitzung, saveSession } from '@/services/storage'; /** * Nach dem Befund "nicht-lesbar" darf kein Sitzungsstand geschrieben werden * (Befund 3). * * Was der Anwender sonst erlebt: Die Lesetransaktion des Sitzungsspeichers * scheitert einmal. Das Programm startet mit einem leeren Projekt und sagt * woertlich "Er ist nicht verloren - ... Speichern Sie jetzt nichts, sondern * starten Sie das Programm neu". Der Anwender befolgt das und minimiert oder * schliesst das Fenster. Genau dabei loest `visibilitychange` auf `hidden` die * Zwischenspeicherung aus, die das LEERE Projekt ueber den heilen Satz schreibt * (`stand.put(satz, SCHLUESSEL_SITZUNG)`); die zugehoerigen Grossdaten - das * Luftbild - werden anschliessend als unreferenziert weggeraeumt. Der Stand, * den das Programm im selben Atemzug als "nicht verloren" bezeichnet, ist * danach endgueltig weg; Wiederherstellungspunkte werden nirgends gelesen. * * Geprueft wird am echten Einstiegspunkt: `src/main.ts` wird eingelesen und * startet damit die ganze Anwendung. Nur der Sitzungsspeicher ist ersetzt. */ 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)); } /** Sucht eine Schaltflaeche an ihrer Aufschrift oder ihrem Vorlesenamen. */ function schaltflaeche(text: string): HTMLButtonElement { const treffer = [...document.querySelectorAll('button')].find( (b) => b.textContent?.trim() === text || b.getAttribute('aria-label') === text, ); if (!treffer) throw new Error(`Schaltflaeche "${text}" nicht gefunden.`); return treffer; } beforeAll(async () => { vi.mocked(ladeSitzung).mockResolvedValue({ art: 'nicht-lesbar' }); vi.mocked(saveSession).mockResolvedValue({ ok: true, message: '' }); document.body.replaceChildren(); const wurzel = document.createElement('div'); wurzel.id = 'anwendung'; document.body.append(wurzel); await import('@/main'); await warte(20); }); describe('Sitzungsstand nach dem Befund "nicht-lesbar"', () => { it('schreibt beim Wechsel in den Hintergrund nichts ueber den heilen Satz', async () => { Object.defineProperty(document, 'visibilityState', { value: 'hidden', configurable: true, }); document.dispatchEvent(new Event('visibilitychange')); await warte(10); expect(saveSession).not.toHaveBeenCalled(); Object.defineProperty(document, 'visibilityState', { value: 'visible', configurable: true, }); }); it('schreibt wieder, sobald der Anwender ueber "Neu" bewusst ein Projekt setzt', async () => { schaltflaeche('Neu').click(); await warte(10); schaltflaeche('Leeres Projekt').click(); await warte(10); // Erst diese ausdrueckliche Entscheidung gibt den Sitzungsspeicher wieder // frei - und belegt zugleich, dass der Schreibweg oben nicht aus einem // anderen Grund still war. expect(saveSession).toHaveBeenCalledTimes(1); }); });