import { describe, expect, it } from 'vitest'; import { ProjectStore } from '@/app/store'; import { createEmptyProject, createStandardIntersectionProject } from '@/domain/model/factory'; /** * Ein neu gesetzter Stand ohne Datei ist nicht "gespeichert" (Befund 38). * * `replace()` loeschte den Aenderungsmerker bedingungslos - auch dort, wo kein * Dateipfad mitkam. Nach "Neu" > "Gefuehrter Einstieg" steht das Ergebnis von * drei bis vier beantworteten Fragen samt Signalgruppen, Konflikten und Phasen * in keiner Datei, die Kopfzeile meldete trotzdem "gespeichert", und die * Waechter vor dem Verwerfen ("Neu", "Öffnen", Fenster schliessen) haengen * alle an diesem Merker. Ein zweites Strg+N lief deshalb ohne Rueckfrage * durch, `replace` leerte die Rueckgaengig-Kette, und der anschliessende * `flush()` schrieb ueber den einen Sitzungssatz. * * Dieselbe Lage war fuer den Wiederanlauf aus dem Sitzungsspeicher bereits * behoben (src/main.ts, `store.markDirty()`); der zweite Weg zu einem Projekt * ohne Datei hatte sie nicht. * * GEGEN DEN ALTSTAND schlagen der erste und der vierte Fall fehl (dirty war * false; die Benachrichtigung trug false statt true). Der zweite und der dritte * halten die Grenzen der Regel fest und bestehen auch dort - sie sind der * Nachweis, dass die Behebung nicht ueber das Ziel hinausschiesst. */ const FESTES_DATUM = new Date('2026-01-01T00:00:00Z'); describe('Neu gesetzter Stand ohne Datei', () => { it('gilt als ungespeichert, sobald etwas darin steht', () => { const store = new ProjectStore(createEmptyProject()); // Genau das, was "Neu" mit dem Ergebnis des gefuehrten Einstiegs tut: // ersetzen ohne Dateipfad. store.replace(createStandardIntersectionProject('Gefuehrter Einstieg', FESTES_DATUM)); expect(store.getState().dirty).toBe(true); expect(store.getState().filePath).toBe(null); }); it('gilt als gespeichert, wenn ein Dateipfad mitkommt', () => { const store = new ProjectStore(createEmptyProject()); store.replace( createStandardIntersectionProject('Geoeffnet', FESTES_DATUM), 'C:/tmp/knotenpunkt.lsap', ); // Beim Oeffnen steht der Stand in einer Datei - da ist nichts ungesichert. expect(store.getState().dirty).toBe(false); expect(store.getState().filePath).toBe('C:/tmp/knotenpunkt.lsap'); }); it('laesst ein unberuehrtes Projekt sauber', () => { const store = new ProjectStore(createStandardIntersectionProject('Vorher', FESTES_DATUM)); store.replace(createEmptyProject()); // "Neu" > "Leeres Projekt": Es gibt keine Arbeit, die verloren gehen // koennte. Eine Rueckfrage, die immer kommt, schuetzt nichts. expect(store.getState().dirty).toBe(false); }); it('meldet den Merker in derselben Benachrichtigung wie den Stand', () => { const store = new ProjectStore(createEmptyProject()); const gesehen: boolean[] = []; store.subscribe((state) => { gesehen.push(state.dirty); }); store.replace(createStandardIntersectionProject('Assistent', FESTES_DATUM)); // Kopfzeile, Fenstertitel und Statusleiste lesen genau diesen Zustand; // ein nachgereichter zweiter Merker liesse sie kurz etwas anderes sagen. expect(gesehen).toEqual([true]); }); });