import { afterEach, describe, expect, it } from 'vitest'; import { ProjectStore } from '@/app/store'; import { buildSignalPlan } from '@/domain/plan/signalPlan'; import { createStandardIntersectionProject } from '@/domain/model/factory'; import type { Project } from '@/domain/model/project'; import { simulationView } from '@/ui/views/simulationView'; /** * "Einen Umlauf" muss genau einen Umlauf weiterrechnen (Befund 55 zur * Fassung 5.8.0). * * Was der Anwender sonst erlebt: Bei der Regelumlaufzeit 90 s springt die * Laufmarke je Druck nur um 60 s weiter. "Position im Umlauf" steht danach auf * 60,0 s statt auf 0,0 s, "Simulationszeit" auf 60 s statt 90 s, und "Umläufe" * bleibt bei 0 - obwohl die Schaltflaeche "Rechnet genau einen Umlauf weiter" * zusagt. Ursache ist die Kappung bei 60 s in `advance`, die den langen * Zeitsprung des Animationspfads abfangen soll. */ const FESTES_DATUM = new Date('2026-01-01T00:00:00Z'); function zeichne(project: Project): { wurzel: HTMLElement; aufraeumen: () => void } { const wurzel = document.createElement('div'); document.body.append(wurzel); const store = new ProjectStore(project); const abmelden = simulationView.render(wurzel, { store, refresh: () => {}, navigate: () => {}, target: null, }); return { wurzel, aufraeumen: () => { abmelden(); wurzel.remove(); }, }; } function kennzahl(wurzel: ParentNode, beschriftung: string): string { const feld = [...wurzel.querySelectorAll('.kennzahl')].find( (k) => k.querySelector('dt')?.textContent === beschriftung, ); if (!feld) throw new Error(`Keine Kennzahl "${beschriftung}"`); return feld.querySelector('dd')?.textContent ?? ''; } function knopf(wurzel: ParentNode, beschriftung: string): HTMLButtonElement { const gefunden = [...wurzel.querySelectorAll('button')].find( (b) => b.textContent?.trim() === beschriftung, ); if (!gefunden) throw new Error(`Keine Schaltfläche "${beschriftung}"`); return gefunden; } afterEach(() => { document.body.replaceChildren(); }); describe('Simulation: Schaltflaeche "Einen Umlauf"', () => { it('rechnet bei Umlaufzeit 90 s einen vollen Umlauf weiter', () => { const project = createStandardIntersectionProject('Einen Umlauf', FESTES_DATUM); expect(buildSignalPlan(project).cycleTime).toBe(90); const { wurzel, aufraeumen } = zeichne(project); try { knopf(wurzel, 'Einen Umlauf').click(); expect(kennzahl(wurzel, 'Simulationszeit')).toBe('90 s'); expect(kennzahl(wurzel, 'Position im Umlauf')).toBe('0,0 s'); expect(kennzahl(wurzel, 'Umläufe')).toBe('1'); } finally { aufraeumen(); } }); it('zaehlt bei jedem Druck einen weiteren Umlauf', () => { const project = createStandardIntersectionProject('Einen Umlauf', FESTES_DATUM); const { wurzel, aufraeumen } = zeichne(project); try { const schalter = knopf(wurzel, 'Einen Umlauf'); schalter.click(); schalter.click(); schalter.click(); expect(kennzahl(wurzel, 'Umläufe')).toBe('3'); expect(kennzahl(wurzel, 'Position im Umlauf')).toBe('0,0 s'); expect(kennzahl(wurzel, 'Simulationszeit')).toBe('270 s'); } finally { aufraeumen(); } }); });