lsa-planer
LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.
/ tests ui hilfeAmFeld.test.ts
| 1 | import { afterEach, describe, expect, it } from 'vitest'; |
| 2 | import { ProjectStore } from '@/app/store'; |
| 3 | import { createStandardIntersectionProject } from '@/domain/model/factory'; |
| 4 | import type { Project } from '@/domain/model/project'; |
| 5 | import { beschriftetesFeld, el } from '@/ui/dom'; |
| 6 | import type { ViewContext } from '@/ui/shell'; |
| 7 | import { phasesView } from '@/ui/views/phasesView'; |
| 8 | |
| 9 | /** |
| 10 | * Befund 62 zur Fassung 5.9.0, der Rest. |
| 11 | * |
| 12 | * Der Hilfeeintrag "Feste Freigabezeit einer Phase" ist ueber den Verweis aus |
| 13 | * `freigabezeit.siehe` erreichbar - das Feld selbst hat aber kein |
| 14 | * Fragezeichen. Es ist das einzige Bedienfeld der Phasenansicht, das eine |
| 15 | * Vorgabe der bedarfsgerechten Verteilung uebergeht; wer wissen will, was der |
| 16 | * Eintrag bewirkt, muss dazu einen anderen Eintrag oeffnen. |
| 17 | * |
| 18 | * `beschriftetesFeld` nahm bislang nur `{ hinweis, einheit }` entgegen. Der |
| 19 | * Knopf gehoert NEBEN die Beschriftung und nicht hinein: Was im `label` steht, |
| 20 | * ist der Name des Feldes - es hiesse sonst "Feste Freigabezeit der 1. Phase |
| 21 | * Hilfe zu Feste Freigabezeit einer Phase". Denselben Weg gehen `feld()` im |
| 22 | * Assistenten und `mitHilfe()` in der Projektansicht. |
| 23 | */ |
| 24 | |
| 25 | const FESTES_DATUM = new Date('2026-01-01T00:00:00Z'); |
| 26 | |
| 27 | let aufraeumen: (() => void) | null = null; |
| 28 | afterEach(() => { |
| 29 | aufraeumen?.(); |
| 30 | aufraeumen = null; |
| 31 | document.body.replaceChildren(); |
| 32 | }); |
| 33 | |
| 34 | function zeichne(project: Project): HTMLElement { |
| 35 | const wurzel = document.createElement('div'); |
| 36 | document.body.append(wurzel); |
| 37 | const store = new ProjectStore(project); |
| 38 | const context: ViewContext = { |
| 39 | store, |
| 40 | refresh: () => {}, |
| 41 | navigate: () => {}, |
| 42 | target: null, |
| 43 | }; |
| 44 | const abmelden = phasesView.render(wurzel, context); |
| 45 | aufraeumen = () => { |
| 46 | abmelden(); |
| 47 | wurzel.remove(); |
| 48 | }; |
| 49 | return wurzel; |
| 50 | } |
| 51 | |
| 52 | /** Das Feld mit dieser Beschriftung - samt seiner Umgebung. */ |
| 53 | function feldMitBeschriftung( |
| 54 | wurzel: HTMLElement, |
| 55 | beschriftung: string, |
| 56 | ): { readonly label: HTMLLabelElement; readonly feld: HTMLElement } { |
| 57 | const label = [...wurzel.querySelectorAll('label')].find( |
| 58 | (l) => l.textContent?.trim() === beschriftung, |
| 59 | ); |
| 60 | if (label === undefined) throw new Error(`Keine Beschriftung "${beschriftung}"`); |
| 61 | const feld = label.closest('.feld'); |
| 62 | if (!(feld instanceof HTMLElement)) throw new Error(`Beschriftung "${beschriftung}" ohne Feld`); |
| 63 | return { label, feld }; |
| 64 | } |
| 65 | |
| 66 | describe('Phasen: das Feld "Feste Freigabezeit" trägt einen Hilfeknopf', () => { |
| 67 | it('stellt den Knopf neben die Beschriftung, nicht hinein', () => { |
| 68 | const wurzel = zeichne(createStandardIntersectionProject('Phasen', FESTES_DATUM)); |
| 69 | const { label, feld } = feldMitBeschriftung(wurzel, 'Feste Freigabezeit der 1. Phase'); |
| 70 | |
| 71 | const knopf = feld.querySelector<HTMLButtonElement>('button.hilfe-knopf'); |
| 72 | expect(knopf, 'Das Feld hat kein Fragezeichen').not.toBeNull(); |
| 73 | expect(knopf?.getAttribute('aria-label')).toBe('Hilfe zu Feste Freigabezeit einer Phase'); |
| 74 | expect( |
| 75 | label.contains(knopf), |
| 76 | 'Der Knopf steht in der Beschriftung und geht damit in den Namen des Feldes ein', |
| 77 | ).toBe(false); |
| 78 | }); |
| 79 | |
| 80 | it('lässt die Beschriftung mit dem Eingabefeld verknüpft', () => { |
| 81 | // Der Knopf darf die Verknuepfung nicht zerreissen: Ohne sie meldet eine |
| 82 | // Sprachausgabe wieder nur "Eingabefeld". |
| 83 | const wurzel = zeichne(createStandardIntersectionProject('Phasen', FESTES_DATUM)); |
| 84 | const { label } = feldMitBeschriftung(wurzel, 'Feste Freigabezeit der 1. Phase'); |
| 85 | const ziel = document.getElementById(label.htmlFor); |
| 86 | |
| 87 | expect(ziel).toBeInstanceOf(HTMLInputElement); |
| 88 | }); |
| 89 | }); |
| 90 | |
| 91 | describe('beschriftetesFeld: der Hilfeknopf ist eine Zugabe', () => { |
| 92 | it('lässt ein Feld ohne Hilfeknopf unverändert', () => { |
| 93 | // Grenzwache: Alle bestehenden Aufrufe geben keinen Knopf mit. Fuer sie |
| 94 | // bleibt die Beschriftung unmittelbares Kind des Feldes - ohne Kopfzeile. |
| 95 | const eingabe = el('input', { type: 'number' }); |
| 96 | const feld = beschriftetesFeld('Umlaufzeit', eingabe, { einheit: 's' }); |
| 97 | |
| 98 | expect(feld.querySelector(':scope > label')).not.toBeNull(); |
| 99 | expect(feld.querySelector('.feld-kopf')).toBeNull(); |
| 100 | expect(feld.querySelector('button')).toBeNull(); |
| 101 | }); |
| 102 | }); |