import { describe, expect, it } from 'vitest'; import { farbschemaFuer, istThemeAuswahl, startfarbeFuer, themeAufloesen, umschaltAnsage, type SystemAnzeigeSignale, } from '../src/shared/theme'; function signale(teil: Partial = {}): SystemAnzeigeSignale { return { bevorzugtDunkel: false, erzwungeneFarben: false, bevorzugtMehrKontrast: false, ...teil, }; } describe('themeAufloesen', () => { it('folgt bei "system" der hellen Systemvorgabe', () => { expect(themeAufloesen('system', signale())).toBe('hell'); }); it('folgt bei "system" der dunklen Systemvorgabe', () => { expect(themeAufloesen('system', signale({ bevorzugtDunkel: true }))).toBe('dunkel'); }); it('wählt bei "system" und prefers-contrast: more den hohen Kontrast', () => { expect(themeAufloesen('system', signale({ bevorzugtMehrKontrast: true }))).toBe('hochkontrast'); }); it('respektiert die manuelle Auswahl gegen die Systemvorgabe', () => { expect(themeAufloesen('hell', signale({ bevorzugtDunkel: true }))).toBe('hell'); expect(themeAufloesen('dunkel', signale())).toBe('dunkel'); }); it('lässt erzwungene Farben jede Auswahl überstimmen', () => { for (const auswahl of ['system', 'hell', 'dunkel', 'hochkontrast'] as const) { expect(themeAufloesen(auswahl, signale({ erzwungeneFarben: true }))).toBe('hochkontrast'); } }); }); describe('istThemeAuswahl', () => { it('erkennt gültige Werte', () => { expect(istThemeAuswahl('hochkontrast')).toBe(true); }); it('weist unbekannte oder falsch typisierte Werte ab', () => { expect(istThemeAuswahl('neon')).toBe(false); expect(istThemeAuswahl(null)).toBe(false); expect(istThemeAuswahl(42)).toBe(false); expect(istThemeAuswahl(undefined)).toBe(false); }); }); describe('farbschemaFuer', () => { it('stimmt mit den color-scheme-Angaben in tokens.css überein', () => { expect(farbschemaFuer('hell')).toBe('light'); expect(farbschemaFuer('dunkel')).toBe('dark'); // Hoher Kontrast ist weiße Schrift auf Schwarz – also ebenfalls dark. expect(farbschemaFuer('hochkontrast')).toBe('dark'); }); /* Beim Windows-Kontrastdesign sagt `hochkontrast` nur, dass die Farben von aussen kommen. Es gibt auch helle Kontrastdesigns; bis 0.24.1 stellte die Anwendung dort Scrollbalken und Formularelemente unbedingt auf dunkel. `startfarbeFuer` macht es seit jeher richtig – hier fehlte die Entsprechung. */ it('überlässt bei erzwungenen Farben dem System, ob hell oder dunkel', () => { expect(farbschemaFuer('hochkontrast', signale({ erzwungeneFarben: true }))).toBe('light'); expect( farbschemaFuer('hochkontrast', signale({ erzwungeneFarben: true, bevorzugtDunkel: true })), ).toBe('dark'); }); it('bleibt dieselbe Aussage wie startfarbeFuer', () => { /* Zwei Funktionen, eine Frage – sie dürfen nicht auseinanderlaufen. */ for (const dunkel of [false, true]) { const s = signale({ erzwungeneFarben: true, bevorzugtDunkel: dunkel }); const hellSchema = farbschemaFuer('hochkontrast', s) === 'light'; expect(startfarbeFuer('hochkontrast', s)).toBe(hellSchema ? '#ffffff' : '#000000'); } }); }); describe('startfarbeFuer', () => { /* Die Farbe, die das Fenster zeigt, bevor der Renderer das erste Bild liefert. Bis 0.21.0 fragte `fenster.ts` dafür nur `nativeTheme` – wer „Dunkel“ eingestellt hatte, während Windows hell läuft, sah bei jedem Start kurz eine helle Fläche. Seither entscheidet die gespeicherte Wahl. */ it('folgt der gespeicherten Wahl und nicht dem Systemdesign', () => { expect(startfarbeFuer('dunkel', signale())).toBe('#14161a'); expect(startfarbeFuer('hell', signale({ bevorzugtDunkel: true }))).toBe('#f7f7f5'); expect(startfarbeFuer('hochkontrast', signale())).toBe('#000000'); }); it('überlässt bei „system“ dem Betriebssystem die Entscheidung', () => { expect(startfarbeFuer('system', signale())).toBe('#f7f7f5'); expect(startfarbeFuer('system', signale({ bevorzugtDunkel: true }))).toBe('#14161a'); }); it('nimmt bei erzwungenen Farben die Farben des Betriebssystems', () => { /* Dort greift tokens.css auf `Canvas` zurück; ein helles Kontrastdesign ist weiß. Eine eigene Farbe wäre hier falsch – auch dann, wenn jemand „Dunkel“ eingestellt hat. */ expect(startfarbeFuer('dunkel', signale({ erzwungeneFarben: true }))).toBe('#ffffff'); expect(startfarbeFuer('hell', signale({ erzwungeneFarben: true, bevorzugtDunkel: true }))).toBe( '#000000', ); }); /* Dass diese drei Farben mit `--farbe-grund` in tokens.css übereinstimmen, prüft `tests/token-kontraste.test.ts` – dort liegt der Leser für die CSS-Datei bereits. */ }); describe('umschaltAnsage', () => { it('nennt bei "system" das tatsächlich aktive Theme', () => { expect(umschaltAnsage('system', 'dunkel')).toContain('Systemvorgabe'); expect(umschaltAnsage('system', 'dunkel')).toContain('Dunkel'); }); it('nennt bei manueller Wahl die gewählte Darstellung', () => { expect(umschaltAnsage('hochkontrast', 'hochkontrast')).toBe( 'Darstellung umgestellt auf Hoher Kontrast.', ); }); /* Läuft das Windows-Kontrastdesign, hat `themeAufloesen` unbedingten Vorrang: Die Wahl wird gespeichert, sichtbar wird sie nicht. Bis 0.24.1 meldete die Ansage trotzdem „Darstellung umgestellt auf Dunkel“ – für jemanden, der die Umstellung nicht sehen kann, die irreführendste Auskunft, die dort stehen kann. */ it('behauptet bei erzwungenen Farben keine Umstellung, die nicht stattfindet', () => { const ansage = umschaltAnsage('dunkel', 'hochkontrast', signale({ erzwungeneFarben: true })); expect(ansage).not.toContain('umgestellt'); expect(ansage).toContain('gespeichert'); expect(ansage).toContain('Kontrastdesign'); expect(ansage).toContain('Dunkel'); }); });