lsa-planer

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

/ tests ui wiederanlaufUngespeichert.test.ts

3,3 KB Rohdatei
tests/ui/wiederanlaufUngespeichert.test.ts — 97 Zeilen
1 import { beforeAll, describe, expect, it, vi } from 'vitest';
2 import { createStandardIntersectionProject } from '@/domain/model/factory';
3 import { ladeSitzung, saveSession } from '@/services/storage';
4
5 /**
6 * Ein wiederhergestellter Sitzungsstand ist nicht "gespeichert" (Befund 20).
7 *
8 * Was der Anwender sonst erlebt: Er legt ein Projekt an, erfasst Signalgruppen
9 * und Konflikte und speichert es NICHT in eine Datei. Das Programm bricht ab
10 * oder wird geschlossen. Beim naechsten Start ist der Stand wieder da - und
11 * gilt sofort als gespeichert, weil `ProjectStore` mit `dirty = false` beginnt
12 * und der Wiederanlauf daran nichts aendert. Strg+N laeuft daraufhin ohne
13 * Rueckfrage durch `confirmDiscard`, `store.replace` leert die
14 * Rueckgaengig-Kette und der anschliessende `flush()` ueberschreibt den einen
15 * Sitzungssatz. Die Handarbeit eines ganzen Knotenpunkts ist damit weg;
16 * Wiederherstellungspunkte werden in der Oberflaeche nirgends angeboten.
17 *
18 * Geprueft wird am echten Einstiegspunkt: `src/main.ts` wird eingelesen und
19 * startet die ganze Anwendung; nur der Sitzungsspeicher ist ersetzt.
20 */
21
22 vi.mock('@/services/storage', async (importOriginal) => {
23 const echt = await importOriginal<typeof import('@/services/storage')>();
24 return {
25 ...echt,
26 ladeSitzung: vi.fn(),
27 saveSession: vi.fn(),
28 addRecoveryPoint: vi.fn(),
29 };
30 });
31
32 async function warte(ms = 0): Promise<void> {
33 await new Promise((fertig) => setTimeout(fertig, ms));
34 }
35
36 /** Die Ueberschriften aller gerade offenen Fenster. */
37 function offeneFenster(): string[] {
38 return [...document.querySelectorAll('.dialog-hintergrund h2')].map(
39 (h) => h.textContent?.trim() ?? '',
40 );
41 }
42
43 function schaltflaeche(text: string): HTMLButtonElement {
44 const treffer = [...document.querySelectorAll('button')].find(
45 (b) => b.textContent?.trim() === text || b.getAttribute('aria-label') === text,
46 );
47 if (!treffer) throw new Error(`Schaltflaeche "${text}" nicht gefunden.`);
48 return treffer;
49 }
50
51 function druecke(taste: string): void {
52 window.dispatchEvent(
53 new KeyboardEvent('keydown', { key: taste, ctrlKey: true, bubbles: true, cancelable: true }),
54 );
55 }
56
57 beforeAll(async () => {
58 vi.mocked(ladeSitzung).mockResolvedValue({
59 art: 'geladen',
60 stand: {
61 project: createStandardIntersectionProject(),
62 issues: [],
63 repaired: false,
64 migrated: false,
65 sourceVersion: '13',
66 intergreenComparison: [],
67 },
68 });
69 vi.mocked(saveSession).mockResolvedValue({ ok: true, message: '' });
70
71 document.body.replaceChildren();
72 const wurzel = document.createElement('div');
73 wurzel.id = 'anwendung';
74 document.body.append(wurzel);
75
76 await import('@/main');
77 await warte(20);
78 });
79
80 describe('Wiederhergestellter Sitzungsstand', () => {
81 it('fragt vor "Neu" zurueck, weil er in keiner Datei steht', async () => {
82 druecke('n');
83 await warte(10);
84
85 // Ohne die Rueckfrage stuende hier sofort die Vorlagenauswahl - und mit dem
86 // ersten Klick darin waere der wiederhergestellte Stand fort.
87 expect(offeneFenster()).toEqual(['Ungespeicherte Änderungen']);
88 });
89
90 it('laesst den Stand nach "Abbrechen" unangetastet', async () => {
91 schaltflaeche('Abbrechen').click();
92 await warte(10);
93
94 expect(offeneFenster()).toEqual([]);
95 expect(saveSession).not.toHaveBeenCalled();
96 });
97 });