lsa-planer

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

/ tests ui entwurfsanzeige.test.ts

4,7 KB Rohdatei
tests/ui/entwurfsanzeige.test.ts — 153 Zeilen
1 import { afterEach, describe, expect, it } from 'vitest';
2 import * as actions from '@/app/actions';
3 import { ProjectStore } from '@/app/store';
4 import type { Lageplan } from '@/domain/geometrie/lageplan';
5 import { ASSISTENT_VORGABE, projektAusAngaben } from '@/ui/assistent';
6 import { lageplanView } from '@/ui/views/lageplanView';
7
8 /**
9 * Befund 65: Nach einer abgewiesenen Fahrlinie meldete die Seitenleiste weiter
10 * gesetzte Punkte.
11 *
12 * WAS DER ANWENDER SONST ERLEBT
13 *
14 * Er setzt einen einzigen Punkt und drueckt die Eingabetaste. Die Meldung "Eine
15 * Fahrlinie braucht mindestens zwei Punkte" erscheint, der Entwurf ist
16 * verworfen - die Seitenleiste behauptet aber weiter "1 Punkt(e) gesetzt ...
17 * Beginnt an der Haltlinie 'X'. Naechster Punkt mit Klick oder Leertaste".
18 * Wer der Zeile folgt und einen Punkt setzt, beginnt in Wahrheit eine NEUE
19 * Linie an dieser Stelle, statt eine bestehende fortzusetzen; der erste Punkt
20 * ist aber der Nullpunkt von Raeum- und Einfahrweg.
21 *
22 * Dieselbe Ursache trifft die Ruecknahme mit der Rueckschritttaste: Auch dort
23 * wurde nur die Zeichenflaeche neu gemalt, nicht die Seitenleiste.
24 */
25
26 const FESTES_DATUM = '2026-01-01T00:00:00.000Z';
27
28 /** Plan mit Massstab und einer waagerechten Haltlinie bei y = 200. */
29 function planMitHaltlinie(): Lageplan {
30 return {
31 arbeitsbereiche: [],
32 signalgeber: [],
33 bild: null,
34 kalibrierung: {
35 von: { x: 0, y: 0 },
36 bis: { x: 100, y: 0 },
37 laengeMeter: 20,
38 herkunft: 'gemessen',
39 },
40 haltlinien: [
41 {
42 id: 'hl1',
43 name: 'Nord',
44 art: 'zufahrt',
45 armId: null,
46 von: { x: 100, y: 200 },
47 bis: { x: 220, y: 200 },
48 },
49 ],
50 linien: [],
51 };
52 }
53
54 interface Ansicht {
55 readonly store: ProjectStore;
56 readonly wurzel: HTMLElement;
57 readonly leinwand: HTMLCanvasElement;
58 readonly aufraeumen: () => void;
59 }
60
61 function baueAnsicht(): Ansicht {
62 const store = new ProjectStore(projektAusAngaben({ ...ASSISTENT_VORGABE }, FESTES_DATUM));
63 store.update((p) => actions.setLageplan(p, planMitHaltlinie()), { label: 'Pruefplan' });
64
65 const wurzel = document.createElement('div');
66 document.body.append(wurzel);
67 const schliessen = lageplanView.render(wurzel, {
68 store,
69 refresh: () => {},
70 navigate: () => {},
71 target: null,
72 });
73
74 const leinwand = wurzel.querySelector('canvas');
75 if (leinwand === null) throw new Error('Die Ansicht hat keine Zeichenflaeche.');
76
77 return {
78 store,
79 wurzel,
80 leinwand,
81 aufraeumen: () => {
82 leinwand.blur();
83 schliessen();
84 wurzel.remove();
85 },
86 };
87 }
88
89 afterEach(() => {
90 document.body.replaceChildren();
91 });
92
93 function waehleWerkzeug(ansicht: Ansicht, beschriftung: string): void {
94 const knopf = [
95 ...ansicht.wurzel.querySelectorAll<HTMLButtonElement>('.lageplan-werkzeuge button'),
96 ].find((b) => (b.textContent ?? '').trim() === beschriftung);
97 if (knopf === undefined) throw new Error(`Kein Werkzeug "${beschriftung}"`);
98 knopf.click();
99 }
100
101 function tippe(key: string, male = 1): void {
102 for (let i = 0; i < male; i += 1) {
103 const ziel = (document.activeElement as HTMLElement | null) ?? document.body;
104 ziel.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }));
105 }
106 }
107
108 /** Text der Seitenleiste - dort steht die Zeile mit den gesetzten Punkten. */
109 function seitentext(ansicht: Ansicht): string {
110 return ansicht.wurzel.querySelector('.lageplan-seite')?.textContent ?? '';
111 }
112
113 describe('Seitenleiste nach einem verworfenen Entwurf', () => {
114 it('meldet nach der abgewiesenen Fahrlinie keine gesetzten Punkte mehr', () => {
115 const ansicht = baueAnsicht();
116 try {
117 waehleWerkzeug(ansicht, 'Fahrlinie');
118 ansicht.leinwand.focus();
119 tippe(' ');
120 expect(seitentext(ansicht), 'die Statuszeile fehlt schon vorher').toContain(
121 '1 Punkt(e) gesetzt',
122 );
123
124 tippe('Enter');
125
126 expect(ansicht.store.getProject().lageplan.linien).toHaveLength(0);
127 expect(seitentext(ansicht)).not.toContain('Punkt(e) gesetzt');
128 } finally {
129 ansicht.aufraeumen();
130 }
131 });
132
133 it('führt die Zahl der Punkte auch beim Zurücknehmen mit', () => {
134 const ansicht = baueAnsicht();
135 try {
136 waehleWerkzeug(ansicht, 'Fahrlinie');
137 ansicht.leinwand.focus();
138 tippe(' ');
139 tippe('ArrowRight', 4);
140 tippe(' ');
141 expect(seitentext(ansicht)).toContain('2 Punkt(e) gesetzt');
142
143 tippe('Backspace');
144 expect(seitentext(ansicht)).toContain('1 Punkt(e) gesetzt');
145
146 tippe('Backspace');
147 // Kein Punkt mehr - die Zeile darf keinen mehr behaupten.
148 expect(seitentext(ansicht)).not.toContain('Punkt(e) gesetzt');
149 } finally {
150 ansicht.aufraeumen();
151 }
152 });
153 });