lsa-planer

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

/ tests ui versatzbereich.test.ts

4,9 KB Rohdatei
tests/ui/versatzbereich.test.ts — 112 Zeilen
1 import { afterEach, describe, expect, it } from 'vitest';
2 import { ProjectStore } from '@/app/store';
3 import { createStandardIntersectionProject } from '@/domain/model/factory';
4 import { bereichsHinweis } from '@/ui/inputs';
5 import { phasesView } from '@/ui/views/phasesView';
6
7 /**
8 * Strittiger Befund S5 zur Fassung 5.10.0 - das Feld "Versatz zur
9 * Koordinierung" nannte seinen Wertebereich nirgends.
10 *
11 * Das Feld traegt `min: 0, max: 300` und ist Pflichtangabe. Sein eigener
12 * Hinweis verdraengte aber den aus `numberCell` abgeleiteten Bereichssatz:
13 * `beschriftetesFeld` bildet `optionen.hinweis ?? eigenerBereich` und entfernt
14 * `data-bereich` unbenutzt (ui/dom.ts). Vor der Eingabe erfuhr weder ein
15 * Sehender noch eine Sprachausgabe, welche Grenzen gelten; wer 400 eintrug,
16 * bekam den Bereich erst in der Warnmeldung genannt - nachdem der Wert schon
17 * auf 300 gekuerzt war. Genau diesen Zustand beschreibt der Kommentar bei
18 * `bereichsHinweis` als den zu behebenden, und zu WCAG 3.3.2 ist ohne
19 * Einschraenkung zugesagt, JEDES Zahlenfeld fuehre seinen
20 * zulaessigen Bereich als ganzen Satz mit Einheit und Angabe, ob es leer
21 * bleiben darf.
22 *
23 * Die drei Nachbarstellen mit eigenem Hinweis machen es vor (Umlaufzeit und
24 * feste Freigabezeit in dieser Ansicht, vZul in der Projektansicht); der
25 * Versatz war die einzige Ausnahme im ganzen Programm.
26 *
27 * ZUM EINWAND ("keine fachliche Wirkung, und der Satz waere fachlich zu weit"):
28 * Der Satz spricht ueber das FELD, und was er sagt, setzt das Feld auch durch.
29 * Dass der Wert in keine Rechnung eingeht, steht im selben Hinweis unmittelbar
30 * dahinter - deshalb pruefen die Faelle unten beide Saetze zusammen.
31 */
32
33 const STICHTAG = new Date('2026-01-01T00:00:00Z');
34
35 let aufraeumen: (() => void) | null = null;
36 afterEach(() => {
37 aufraeumen?.();
38 aufraeumen = null;
39 document.body.replaceChildren();
40 });
41
42 function zeichne(): HTMLElement {
43 const wurzel = document.createElement('div');
44 document.body.append(wurzel);
45 const schliessen = phasesView.render(wurzel, {
46 store: new ProjectStore(createStandardIntersectionProject('Versatz', STICHTAG)),
47 refresh: () => {},
48 navigate: () => {},
49 target: null,
50 });
51 aufraeumen = () => {
52 schliessen();
53 wurzel.remove();
54 };
55 return wurzel;
56 }
57
58 /** Feld samt Beschriftung und Hinweis, an seiner Beschriftung gesucht. */
59 function feld(wurzel: HTMLElement, beschriftung: string): HTMLElement {
60 const knoten = [...wurzel.querySelectorAll<HTMLElement>('div.feld')].find(
61 (f) => f.querySelector('label')?.textContent === beschriftung,
62 );
63 expect(knoten, `Feld "${beschriftung}" fehlt`).toBeDefined();
64 return knoten as HTMLElement;
65 }
66
67 describe('Befund S5 - das Versatzfeld nennt seinen Wertebereich', () => {
68 it('stellt den Bereichssatz vor den fachlichen Satz', () => {
69 const versatz = feld(zeichne(), 'Versatz zur Koordinierung');
70 const eingabe = versatz.querySelector<HTMLInputElement>('input[type="number"]');
71 const hinweis = versatz.querySelector('.feld-hinweis')?.textContent ?? '';
72
73 expect(hinweis.startsWith('Zulässig sind 0 s bis 300 s.')).toBe(true);
74 expect(hinweis).toContain('Pflichtangabe – das Feld darf nicht leer bleiben.');
75 /*
76 * Der fachliche Satz bleibt - aber nur zur HAELFTE. Bis 5.34.0 hiess er
77 * "noch nicht ausgewertet: Diese Fassung berechnet keine Gruene Welle".
78 * Seit 5.35.0 rechnet sie eine (Ansicht "Koordinierung"); was bleibt, ist
79 * die Aussage, dass der Versatz den EIGENEN Signalzeitenplan nicht
80 * verschiebt. Eine halb zurueckgenommene Zusage waere hier der Fehler.
81 */
82 expect(hinweis).not.toContain('noch nicht ausgewertet');
83 expect(hinweis).toContain('verschiebt den Signalzeitenplan dieses Knotenpunkts nicht');
84 expect(hinweis).toContain('Ansicht „Koordinierung"');
85 // Und er wird mit vorgelesen, nicht nur gedruckt.
86 expect(eingabe?.getAttribute('aria-describedby')).toBe(
87 versatz.querySelector('.feld-hinweis')?.id,
88 );
89 });
90
91 it('bildet Satz und Feldgrenzen aus denselben Zahlen', () => {
92 // Von Hand danebengeschrieben liefe der Satz beim naechsten Grenzwechsel
93 // auseinander - genau davor warnt der Kommentar am Umlaufzeitfeld daneben.
94 const versatz = feld(zeichne(), 'Versatz zur Koordinierung');
95 const eingabe = versatz.querySelector<HTMLInputElement>('input[type="number"]');
96 const min = Number(eingabe?.getAttribute('min'));
97 const max = Number(eingabe?.getAttribute('max'));
98 expect(min).toBe(0);
99 expect(max).toBe(300);
100
101 const hinweis = versatz.querySelector('.feld-hinweis')?.textContent ?? '';
102 expect(hinweis.startsWith(bereichsHinweis({ min, max, step: 1, einheit: 's' }))).toBe(true);
103 });
104
105 it('laesst die Nachbarfelder unveraendert', () => {
106 const wurzel = zeichne();
107 const freigabe = feld(wurzel, 'Feste Freigabezeit der 1. Phase');
108 expect(freigabe.querySelector('.feld-hinweis')?.textContent).toBe(
109 'Zulässig sind 0 s bis 200 s. Leer lassen, um bedarfsgerecht zu verteilen.',
110 );
111 });
112 });