waffensachkunde
Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.
| 1 | /** |
| 2 | * Der Hinweis-Baustein. |
| 3 | * |
| 4 | * Anlass: Die Verlustanzeige der Datensicherung reicht Absätze und eine |
| 5 | * Liste als Kinder hinein. Bis 0.20.0 trug der Baustein jeden Inhalt in |
| 6 | * einem `<p>` – ungültiges HTML, React meldete im Testlauf „In HTML, <ul> |
| 7 | * cannot be a descendant of <p>“. Ein Browser, der solches HTML einliest, |
| 8 | * repariert den Baum still; was ein Screenreader vorliest, entspräche dann |
| 9 | * nicht mehr dem geschriebenen Code. Seither wählt `blockinhalt` einen |
| 10 | * `<div>` als Textträger – diese Tests halten beide Varianten fest. |
| 11 | */ |
| 12 | |
| 13 | import { render, screen } from '@testing-library/react'; |
| 14 | import { describe, expect, it, vi } from 'vitest'; |
| 15 | |
| 16 | import { Hinweis } from '../src/renderer/src/components/lernen/Hinweis'; |
| 17 | |
| 18 | describe('Hinweis mit reinem Text', () => { |
| 19 | it('trägt den Inhalt in einem echten Absatz', () => { |
| 20 | /* Die Absatzsemantik soll die Blockvariante nicht stillschweigend |
| 21 | verdrängen – kurze Hinweise bleiben, was sie sind: ein Absatz. */ |
| 22 | const { container } = render(<Hinweis art="hinweis">Nur ein Satz.</Hinweis>); |
| 23 | |
| 24 | const traeger = container.querySelector('.hinweis__text'); |
| 25 | expect(traeger?.tagName).toBe('P'); |
| 26 | expect(traeger).toHaveTextContent('Hinweis: Nur ein Satz.'); |
| 27 | }); |
| 28 | |
| 29 | it('wird auf Wunsch als Meldung angesagt', () => { |
| 30 | render( |
| 31 | <Hinweis art="fehler" alsMeldung> |
| 32 | Speichern fehlgeschlagen. |
| 33 | </Hinweis>, |
| 34 | ); |
| 35 | |
| 36 | expect(screen.getByRole('alert')).toHaveTextContent('Fehler: Speichern fehlgeschlagen.'); |
| 37 | }); |
| 38 | }); |
| 39 | |
| 40 | describe('Hinweis mit Blockinhalt', () => { |
| 41 | function blockbeispiel(): React.JSX.Element { |
| 42 | return ( |
| 43 | <Hinweis art="fehler" blockinhalt> |
| 44 | <p>Das geht verloren:</p> |
| 45 | <ul> |
| 46 | <li>Ein Profil</li> |
| 47 | </ul> |
| 48 | <p>Mehr nicht.</p> |
| 49 | </Hinweis> |
| 50 | ); |
| 51 | } |
| 52 | |
| 53 | it('legt Absätze und Liste nie in einen Absatz', () => { |
| 54 | const { container } = render(blockbeispiel()); |
| 55 | |
| 56 | expect(container.querySelector('.hinweis__text')?.tagName).toBe('DIV'); |
| 57 | expect(container.querySelector('p ul')).toBeNull(); |
| 58 | expect(container.querySelector('p p')).toBeNull(); |
| 59 | }); |
| 60 | |
| 61 | it('rendert ohne DOM-Verschachtelungswarnung von React', () => { |
| 62 | /* Genau die Meldung, die der Fehlerkasten der Datensicherung bis 0.20.0 |
| 63 | auslöste. `restoreMocks` räumt den Spion nach dem Test wieder ab. */ |
| 64 | const fehlerSpion = vi.spyOn(console, 'error'); |
| 65 | |
| 66 | render(blockbeispiel()); |
| 67 | |
| 68 | expect(fehlerSpion).not.toHaveBeenCalled(); |
| 69 | }); |
| 70 | |
| 71 | it('behält Vorspann und Inhalt in der Lesereihenfolge', () => { |
| 72 | render(blockbeispiel()); |
| 73 | |
| 74 | const vorspann = screen.getByText('Fehler:'); |
| 75 | expect(vorspann.compareDocumentPosition(screen.getByText('Das geht verloren:'))).toBe( |
| 76 | Node.DOCUMENT_POSITION_FOLLOWING, |
| 77 | ); |
| 78 | expect(screen.getByRole('list')).toBeInTheDocument(); |
| 79 | }); |
| 80 | }); |