import { afterEach, describe, expect, it } from 'vitest'; import { ProjectStore } from '@/app/store'; import { RILSA_DEFAULTS } from '@/domain/rilsa/constants'; import { createStandardIntersectionProject } from '@/domain/model/factory'; import type { Project } from '@/domain/model/project'; import { erhoehterZeitbedarfBeschriftung, signalGroupsView } from '@/ui/views/signalGroupsView'; import { zugaenglicherName } from './zugaenglicherName'; /** * Befund 18 zur Fassung 5.10.0 - die beiden Kaestchenspalten der * Signalgruppentabelle. * * "Erhöhter Zeitbedarf" und "Blindenzusatz" entstehen ueber `checkboxCell`, * und das setzt seinen Beschriftungstext unmittelbar als `aria-label` * (src/ui/inputs.ts). `benenneBedienelemente` ueberspringt jedes Feld, das * schon einen Namen traegt (src/ui/dom.ts) - die Benennung aus Spaltenkopf und * Zeilenname erreichte diese beiden Spalten also nie. Jede Furtzeile trug * denselben Erklaersatz als Namen; welche Furt gemeint ist, sagte er nicht. * * Das ist genau das Muster, das Befund M2 in derselben Ansicht ueberall sonst * beseitigt hat (Auswahlfelder ueber `auswahlMitHinweis`, Farbfeld, Mindest- * und Hoechstfreigabezeit, Lastzuganteil), und der Zustand, der zu 1.3.1 als * beseitigt gilt. Die beiden ausgeschriebenen Kopfnamen lagen im * `ausgeschrieben`-Verzeichnis der Ansicht schon bereit und wurden wegen des * festen `aria-label` nie zu einem Feldnamen - toter Text hinter einer Zusage. * * FACHLICHES GEWICHT: `reducedMobility` senkt die Raeumgeschwindigkeit der Furt * von 1,2 auf 1,0 m/s, `blindenzusatz` verlangt die Freigabezeit fuer die ganze * statt fuer die halbe Furt. Am falschen Strom gesetzt oder entfernt, verkuerzt * beides Zwischenzeit oder Freigabezeit - die gefaehrliche Richtung. */ const STICHTAG = new Date('2026-01-01T00:00:00Z'); const BLINDENZUSATZ_SATZ = 'Zusatzeinrichtung für Blinde und Sehbehinderte (Freigabe für die ganze Furt statt für die halbe)'; let aufraeumen: (() => void) | null = null; afterEach(() => { aufraeumen?.(); aufraeumen = null; document.body.replaceChildren(); }); function zeichne(project: Project): HTMLElement { const wurzel = document.createElement('div'); document.body.append(wurzel); const schliessen = signalGroupsView.render(wurzel, { store: new ProjectStore(project), refresh: () => {}, navigate: () => {}, target: null, }); aufraeumen = () => { schliessen(); wurzel.remove(); }; return wurzel; } /** Alle Kontrollkaestchen, deren Kurzhinweis mit `anfang` beginnt. */ function kaestchen(wurzel: HTMLElement, anfang: string): HTMLInputElement[] { return [...wurzel.querySelectorAll('input[type="checkbox"]')].filter((i) => i.title.startsWith(anfang), ); } /** Text, den eine Sprachausgabe als Beschreibung des Feldes liest. */ function beschreibung(wurzel: HTMLElement, feld: HTMLElement): string { const id = feld.getAttribute('aria-describedby') ?? ''; const knoten = id === '' ? null : wurzel.querySelector(`[id="${id}"]`); return (knoten?.textContent ?? '').trim(); } describe('Befund 18 - die Furtkaestchen nennen ihre Signalgruppe', () => { it('benennt "Erhöhter Zeitbedarf" aus Spaltenkopf und Zeilenname', () => { const wurzel = zeichne(createStandardIntersectionProject('Kaestchen', STICHTAG)); const felder = kaestchen(wurzel, 'Furt mit erhöhtem Zeitbedarf'); expect(felder.length, 'Der Regelknotenpunkt hat zwei Fußgängergruppen').toBe(2); const namen = felder.map((f) => zugaenglicherName(f)); expect(namen).toEqual([ 'Erhöhter Zeitbedarf bei der Furt, F1', 'Erhöhter Zeitbedarf bei der Furt, F2', ]); }); it('benennt "Blindenzusatz" aus Spaltenkopf und Zeilenname', () => { const wurzel = zeichne(createStandardIntersectionProject('Kaestchen', STICHTAG)); const felder = kaestchen(wurzel, 'Zusatzeinrichtung für Blinde'); expect(felder.length).toBe(2); expect(felder.map((f) => zugaenglicherName(f))).toEqual([ 'Zusatzeinrichtung für Blinde und Sehbehinderte an der Furt, F1', 'Zusatzeinrichtung für Blinde und Sehbehinderte an der Furt, F2', ]); }); it('vergibt in der ganzen Tabelle keinen Namen zweimal', () => { const wurzel = zeichne(createStandardIntersectionProject('Kaestchen', STICHTAG)); const namen = [...wurzel.querySelectorAll('input[type="checkbox"]')].map( (f) => zugaenglicherName(f), ); expect(namen.length).toBeGreaterThan(0); expect(new Set(namen).size, `Doppelte Namen: ${namen.join(' | ')}`).toBe(namen.length); }); it('fuehrt den Erklaersatz als Beschreibung weiter - mit dem wirksamen Wert', () => { // Der Satz geht nicht verloren, er wechselt nur die Rolle: `aria-label` // ERSETZT den Namen, `aria-describedby` ergaenzt ihn (Begruendung bei // `ergaenzeBereichshinweis` in ui/dom.ts). Damit bleibt die Zusage aus // Befund C21 gewahrt - der wirksame Kennwert wird vorgelesen. const wurzel = zeichne(createStandardIntersectionProject('Kaestchen', STICHTAG)); const satz = erhoehterZeitbedarfBeschriftung(RILSA_DEFAULTS); expect(satz).toBe('Furt mit erhöhtem Zeitbedarf (1,0 m/s statt 1,2 m/s)'); for (const feld of kaestchen(wurzel, 'Furt mit erhöhtem Zeitbedarf')) { expect(feld.title).toBe(satz); expect(beschreibung(wurzel, feld)).toBe(satz); } for (const feld of kaestchen(wurzel, 'Zusatzeinrichtung für Blinde')) { expect(feld.title).toBe(BLINDENZUSATZ_SATZ); expect(beschreibung(wurzel, feld)).toBe(BLINDENZUSATZ_SATZ); } }); });