lsa-planer
LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.
/ tests ui stilblattZusagen.test.ts
| 1 | import { readFileSync, readdirSync, statSync } from 'node:fs'; |
| 2 | import path from 'node:path'; |
| 3 | import { describe, expect, it } from 'vitest'; |
| 4 | |
| 5 | /** |
| 6 | * Zusagen, die im Stilblatt stehen und die jsdom nicht nachrechnet. |
| 7 | * |
| 8 | * `getComputedStyle` liefert unter jsdom keine Kaskade: Weder die Stapelfolge |
| 9 | * noch der Vorrang zweier Regeln laesst sich dort messen. Beide Aussagen sind |
| 10 | * aber Zusagen der Barrierefreiheit, und beide sind still zerfallen, als |
| 11 | * jemand an einer der beiden Regeln arbeitete. Deshalb werden sie hier am |
| 12 | * Quelltext des Stilblatts festgehalten - grob, aber genau an der Stelle, an |
| 13 | * der sie brechen. |
| 14 | */ |
| 15 | |
| 16 | const WURZEL = path.resolve(__dirname, '..', '..'); |
| 17 | const STILBLATT = path.join(WURZEL, 'src', 'styles', 'app.css'); |
| 18 | |
| 19 | function stilblatt(): string { |
| 20 | return readFileSync(STILBLATT, 'utf8'); |
| 21 | } |
| 22 | |
| 23 | /** Wert von `z-index` im Block der genannten Auswahlregel. */ |
| 24 | function stapelwert(css: string, auswahl: string): number { |
| 25 | const start = css.indexOf(`\n${auswahl} {`); |
| 26 | expect(start, `Regel "${auswahl}" fehlt`).toBeGreaterThanOrEqual(0); |
| 27 | const block = css.slice(start, css.indexOf('\n}', start)); |
| 28 | const treffer = /z-index:\s*(\d+)/.exec(block); |
| 29 | expect(treffer, `"${auswahl}" ohne z-index`).not.toBeNull(); |
| 30 | return Number(treffer![1]); |
| 31 | } |
| 32 | |
| 33 | describe('Meldungsstapel liegt über dem Fensterhintergrund (Befunde M4, L7)', () => { |
| 34 | it('gibt ihm eine höhere Stapelfolge als dem Fensterhintergrund', () => { |
| 35 | /* |
| 36 | * Der Meldungsstapel ist der einzige Teil des Hintergrunds, den ein |
| 37 | * geoeffnetes Fenster NICHT stilllegt: Seine Live-Bereiche sollen weiter |
| 38 | * ansagen, und eine stehengebliebene Warnung soll schliessbar bleiben |
| 39 | * (legeHintergrundStill in src/ui/feedback.ts). |
| 40 | * |
| 41 | * Bei z-index 200 gegen 300 traf beides nicht zu: Der halb deckende |
| 42 | * Fensterhintergrund lag darueber, die Meldung war abgedunkelt, und ein |
| 43 | * Klick auf ihren Schliessen-Knopf landete auf dem Hintergrund - der |
| 44 | * schliesst das FENSTER. Wer im Zwischenzeitenfenster eine Zahl vertippt, |
| 45 | * bekam so eine Warnung, die er nicht wegbekommt, ohne das Fenster zu |
| 46 | * verlieren. |
| 47 | */ |
| 48 | const css = stilblatt(); |
| 49 | expect(stapelwert(css, '.meldungen')).toBeGreaterThan(stapelwert(css, '.dialog-hintergrund')); |
| 50 | }); |
| 51 | }); |
| 52 | |
| 53 | describe('Zeilenzustände schlagen die Überfahr-Einfärbung', () => { |
| 54 | it('gibt den Zustandsregeln denselben Aufbau wie der Hover-Regel und stellt sie dahinter', () => { |
| 55 | /* |
| 56 | * `tbody tr:hover td` hat drei Typen und eine Pseudoklasse, also (0,1,3); |
| 57 | * `.lageplan-aktiv td` kam auf (0,1,1) und verlor. Sobald der Zeiger auf |
| 58 | * der Zeile stand, verschwand damit genau die Auskunft, die sie traegt - |
| 59 | * welche Haltlinie hervorgehoben ist und welcher Weg vom gemessenen Wert |
| 60 | * abweicht. |
| 61 | * |
| 62 | * Gleicher Aufbau UND spaeter im Blatt: Bei gleichem Gewicht entscheidet |
| 63 | * die Reihenfolge. |
| 64 | */ |
| 65 | const css = stilblatt(); |
| 66 | const hover = css.indexOf('tbody tr:hover td {'); |
| 67 | expect(hover, 'Hover-Regel fehlt').toBeGreaterThanOrEqual(0); |
| 68 | |
| 69 | for (const klasse of ['lageplan-aktiv', 'lageplan-abweichung']) { |
| 70 | const zustand = css.indexOf(`tbody tr.${klasse} td {`); |
| 71 | expect(zustand, `Zustandsregel "${klasse}" ohne tbody-tr-Aufbau`).toBeGreaterThanOrEqual(0); |
| 72 | expect(zustand, `"${klasse}" steht vor der Hover-Regel`).toBeGreaterThan(hover); |
| 73 | } |
| 74 | }); |
| 75 | }); |
| 76 | |
| 77 | describe('prefers-reduced-motion: der Kommentar beschreibt keinen Code, den es nicht gibt', () => { |
| 78 | it('wird ausschließlich im Stilblatt ausgewertet', () => { |
| 79 | /* |
| 80 | * Im Stilblatt stand: "Die Simulation laeuft weiter, aber sie startet dann |
| 81 | * nicht von selbst; das steuert die Ansicht". Die Simulationsansicht wertet |
| 82 | * die Einstellung nicht aus - sie muss es auch nicht, ihre Bildschleife |
| 83 | * laeuft nur nach einem Druck auf "Starten". |
| 84 | * |
| 85 | * Sollte je eine zweite Stelle hinzukommen, faellt dieser Fall und der |
| 86 | * Kommentar ist nachzuziehen. Das ist sein Zweck: Ein Kommentar, der eine |
| 87 | * erfundene Steuerung beschreibt, verleitet dazu, sie vorauszusetzen. |
| 88 | */ |
| 89 | const treffer: string[] = []; |
| 90 | const durchlaufe = (ordner: string): void => { |
| 91 | for (const eintrag of readdirSync(ordner)) { |
| 92 | const voll = path.join(ordner, eintrag); |
| 93 | if (statSync(voll).isDirectory()) { |
| 94 | durchlaufe(voll); |
| 95 | } else if (/\.(ts|css|html)$/.test(eintrag)) { |
| 96 | if (readFileSync(voll, 'utf8').includes('prefers-reduced-motion')) treffer.push(voll); |
| 97 | } |
| 98 | } |
| 99 | }; |
| 100 | durchlaufe(path.join(WURZEL, 'src')); |
| 101 | |
| 102 | expect(treffer).toEqual([STILBLATT]); |
| 103 | }); |
| 104 | }); |