lsa-planer

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

/ tests ui textfeldLaenge.test.ts

5,2 KB Rohdatei
tests/ui/textfeldLaenge.test.ts — 125 Zeilen
1 import { afterEach, describe, expect, it } from 'vitest';
2 import { beschrifteTabelle, el } from '@/ui/dom';
3 import { MAX_TEXTFELD_ZEICHEN, textCell } from '@/ui/inputs';
4
5 /**
6 * Laengengrenze der kompakten Textfelder, Befunde zur Fassung 5.10.0.
7 *
8 * BEFUND 40: Kein Eingabefeld trug eine Laengenbegrenzung - "maxlength" kam in
9 * src/ nicht vor. Eine in das Feld "Bezeichnung" einer Signalgruppe eingefuegte
10 * lange Zeichenkette ging ungekuerzt in das Zuordnungsbanner ueber der
11 * Zwischenzeitenmatrix; ab rund 7 000 Zeichen laeuft jspdf-autotable dort in
12 * `printFullRow` in eine Endlosteilung, und die Ausgabe bricht mit "Maximum
13 * call stack size exceeded" ab. Es entsteht dann ueberhaupt keine
14 * Planunterlage. Die Schranke in `matrixSatz` (src/services/export/pdf.ts)
15 * verschmaelert den Ausschnitt nur bis auf eine Spalte und ist dann erschoepft.
16 *
17 * Die Bezeichnung ist eine Plankennzeichnung ("Bezeichnung im Plan, z. B. K1,
18 * F2, R3"), keine Beschreibung. Sie wird beim Eintragen begrenzt und die
19 * Kuerzung gemeldet - wie `ganzzahlAbrunden` es bei den Zahlenfeldern vormacht.
20 */
21
22 afterEach(() => {
23 document.body.replaceChildren();
24 });
25
26 function meldungen(): string[] {
27 return [...document.querySelectorAll('.meldung-warnung')].map((m) => m.textContent ?? '');
28 }
29
30 function tippe(feld: HTMLInputElement, text: string): void {
31 feld.value = text;
32 feld.dispatchEvent(new Event('change'));
33 }
34
35 describe('Textfelder: Bezeichnungen sind in der Länge begrenzt (Befund 40)', () => {
36 it('trägt die Grenze als maxlength am Feld', () => {
37 const feld = textCell('K1', () => {});
38 expect(feld.getAttribute('maxlength')).toBe(String(MAX_TEXTFELD_ZEICHEN));
39 });
40
41 it('kürzt eine zu lange Eingabe und meldet die Kürzung', () => {
42 const angekommen: string[] = [];
43 // Ohne Optionen - genau so, wie die acht Aufrufstellen der Anwendung
44 // `textCell` benutzen (signalGroupsView, phasesView, projectView,
45 // lageplanView; settingsView nur mit `placeholder`).
46 const feld = textCell('K1', (wert) => angekommen.push(wert));
47 document.body.append(feld);
48
49 tippe(feld, 'A'.repeat(10_000));
50
51 expect(angekommen).toHaveLength(1);
52 expect(angekommen[0]).toHaveLength(MAX_TEXTFELD_ZEICHEN);
53 // Auch im Feld steht danach, was uebernommen wurde - sonst zeigte die
54 // Zelle einen Text, mit dem niemand mehr rechnet.
55 expect(feld.value).toHaveLength(MAX_TEXTFELD_ZEICHEN);
56 const gemeldet = meldungen();
57 expect(gemeldet).toHaveLength(1);
58 expect(gemeldet[0]).toContain(String(MAX_TEXTFELD_ZEICHEN));
59 });
60
61 it('nennt in der Meldung die Spalte und die Zeile der Tabellenzelle', () => {
62 /*
63 * NACHTRAG (Fassung 5.11.0). Die Meldung bildete den Feldnamen aus den
64 * OPTIONEN (`beschriftung ?? title ?? 'Der Text'`) - und kein einziger
65 * `textCell`-Aufruf der Anwendung uebergibt eines von beiden. In der
66 * Signalgruppentabelle mit ihren neunzehn Spalten und bis zu sechzehn
67 * Zeilen hiess die Warnung deshalb immer nur "Der Text: ...", und welche
68 * Bezeichnung gekuerzt wurde, stand nirgends.
69 *
70 * Den Namen bekommt das Feld erst beim Einhaengen, aus Spaltenkopf und
71 * Zeilenname (`beschrifteTabelle` -> `benenneBedienelemente`, ui/dom.ts).
72 * Genau dort liest ihn `numberCell` seit jeher - mit derselben Begruendung
73 * ("bei einer Tabelle mit sechzehn Spalten waere unklar, welche").
74 */
75 const feld = textCell('K1', () => {});
76 const tabelle = el(
77 'table',
78 {},
79 el('thead', {}, el('tr', {}, el('th', { text: 'Bezeichnung' }))),
80 el('tbody', {}, el('tr', {}, el('td', {}, feld))),
81 );
82 document.body.append(tabelle);
83 beschrifteTabelle(tabelle, { beschriftung: 'Signalgruppen' });
84 expect(feld.getAttribute('aria-label'), 'Vorbedingung: die Tabelle benennt das Feld').toBe(
85 'Bezeichnung, K1',
86 );
87
88 tippe(feld, 'A'.repeat(10_000));
89
90 const gemeldet = meldungen();
91 expect(gemeldet).toHaveLength(1);
92 expect(gemeldet[0], 'die Meldung nennt das gekürzte Feld nicht').toContain('Bezeichnung, K1');
93 });
94
95 it('lässt einen Text bis zur Grenze unverändert und meldet nichts', () => {
96 const angekommen: string[] = [];
97 const feld = textCell('', (wert) => angekommen.push(wert));
98 document.body.append(feld);
99
100 const gerade_noch = 'B'.repeat(MAX_TEXTFELD_ZEICHEN);
101 tippe(feld, gerade_noch);
102
103 expect(angekommen).toEqual([gerade_noch]);
104 expect(meldungen()).toHaveLength(0);
105 });
106
107 it('zählt die Länge nach dem Abschneiden der Leerzeichen', () => {
108 const angekommen: string[] = [];
109 const feld = textCell('', (wert) => angekommen.push(wert));
110 document.body.append(feld);
111
112 tippe(feld, ` ${'C'.repeat(MAX_TEXTFELD_ZEICHEN)} `);
113
114 expect(angekommen).toEqual(['C'.repeat(MAX_TEXTFELD_ZEICHEN)]);
115 expect(meldungen()).toHaveLength(0);
116 });
117
118 it('bleibt weit unter der Länge, an der die Zwischenzeitenmatrix im PDF abbricht', () => {
119 // Gemessen wurde: 6 000 Zeichen laufen durch, ab rund 7 000 bricht die
120 // Ausgabe ab. Der bestehende Test tests/export/pdfZwischenzeitenmatrix.test.ts
121 // haelt fest, dass zwoelf Gruppen mit 260 Zeichen langen Namen einen
122 // Ausdruck ergeben - die Grenze bleibt darunter.
123 expect(MAX_TEXTFELD_ZEICHEN).toBeLessThanOrEqual(260);
124 });
125 });