import { describe, expect, it } from 'vitest'; import { ProjectStore } from '@/app/store'; import { createStandardIntersectionProject } from '@/domain/model/factory'; import { legeProgrammAn, programmanzahl, wechsleProgramm } from '@/domain/model/programme'; import { ERSTES_PROGRAMM } from '@/domain/model/programme'; import type { Project } from '@/domain/model/project'; import { phasesView } from '@/ui/views/phasesView'; /** * Die Auswahl der Tagesprogramme. * * WARUM DIE AUSWAHL UEBER DEM PROGRAMMKOPF STEHT: Jede Angabe darunter - * Bezeichnung, Verfahren, Umlaufzeit, Versatz - gilt dem hier gewaehlten * Programm. Stuende die Auswahl anderswo, traege der Bearbeiter Zahlen in ein * Programm ein, von dem er nicht weiss, dass es offen ist. */ const STICHTAG = new Date('2026-01-01T12:00:00Z'); function zeichne(project: Project): { wurzel: HTMLElement; store: ProjectStore; aufraeumen: () => void; } { const wurzel = document.createElement('div'); document.body.append(wurzel); const store = new ProjectStore(project); const ende = phasesView.render(wurzel, { store, refresh: () => {}, navigate: () => {}, target: null, }); return { wurzel, store, aufraeumen: () => { ende(); wurzel.remove(); }, }; } /** Die Auswahlliste der Tagesprogramme, an ihrer Beschriftung erkannt. */ function auswahl(wurzel: ParentNode): HTMLSelectElement { const treffer = [...wurzel.querySelectorAll('label')].find((l) => l.textContent?.includes('Bearbeitetes Tagesprogramm'), ); const feld = treffer?.querySelector('select') ?? treffer?.parentElement?.querySelector('select'); if (!feld) throw new Error('Auswahlliste der Tagesprogramme nicht gefunden.'); return feld; } function knopf(wurzel: ParentNode, text: string): HTMLButtonElement { const treffer = [...wurzel.querySelectorAll('button')].find( (b) => b.textContent?.trim() === text, ); if (!treffer) throw new Error(`Schaltfläche "${text}" nicht gefunden.`); return treffer; } function basis(): Project { return createStandardIntersectionProject('Hauptstraße / Bahnhofstraße', STICHTAG); } describe('Phasenansicht - Auswahl der Tagesprogramme', () => { it('führt jedes Programm in der Auswahl und schaltet um', () => { const zwei = wechsleProgramm(legeProgrammAn(basis(), 'Nacht'), ERSTES_PROGRAMM); const { wurzel, store, aufraeumen } = zeichne(zwei); try { const feld = auswahl(wurzel); expect([...feld.options].map((o) => o.textContent)).toEqual(['Programm 1', 'Nacht']); expect(feld.value).toBe(ERSTES_PROGRAMM); const nachtId = zwei.programmbibliothek[0]!.programm.id; feld.value = nachtId; feld.dispatchEvent(new Event('change')); expect(store.getProject().program.id, 'nach dem Umschalten').toBe(nachtId); expect(store.getProject().program.name).toBe('Nacht'); } finally { aufraeumen(); } }); it('legt ein weiteres Programm an und öffnet es', () => { const { wurzel, store, aufraeumen } = zeichne(basis()); try { knopf(wurzel, 'Weiteres Tagesprogramm').click(); expect(programmanzahl(store.getProject())).toBe(2); expect(store.getProject().program.name).toBe('Programm 2'); // Die Zaehlung beginnt bei null: Ein uebernommener Wert waere eine // Behauptung ueber eine Zaehlung, die fuer diese Tageszeit niemand // vorgenommen hat. expect(store.getProject().demands).toEqual([]); } finally { aufraeumen(); } }); it('bietet das Löschen erst ab dem zweiten Programm an', () => { // Ein Projekt ohne Programm hat keinen Signalzeitenplan. Die Schaltflaeche // gar nicht erst zu zeigen ist ehrlicher als eine, die nichts tut. const eines = zeichne(basis()); try { expect(() => knopf(eines.wurzel, 'Dieses Tagesprogramm löschen')).toThrow(); } finally { eines.aufraeumen(); } const zwei = zeichne(legeProgrammAn(basis(), 'Nacht')); try { expect(knopf(zwei.wurzel, 'Dieses Tagesprogramm löschen')).toBeTruthy(); } finally { zwei.aufraeumen(); } }); it('sagt bei mehreren Programmen, dass alle geprüft werden', () => { /* * Der Satz ist die Bedienoberflaeche zur Ausgabesperre: Wer einen Fehler * im Pruefbericht sieht, den er im sichtbaren Programm nicht findet, muss * hier lesen koennen, woher er kommt. */ const zwei = zeichne(legeProgrammAn(basis(), 'Nacht')); try { expect(zwei.wurzel.textContent).toContain('Geprüft werden alle'); expect(zwei.wurzel.textContent).toContain('sperrt die Ausgabe'); } finally { zwei.aufraeumen(); } const eines = zeichne(basis()); try { expect(eines.wurzel.textContent).toContain('führt ein Tagesprogramm'); } finally { eines.aufraeumen(); } }); });