/** * Der Startwert des Themas wird beim Laden des Moduls **einmal** aus der * Ablage gelesen und danach im Speicher gehalten — das verlangt * `useSyncExternalStore`, dessen Momentaufnahme zwischen zwei Änderungen * stabil sein muss (siehe theme.ts). * * Deshalb muss jeder Fall das Modul frisch laden, statt die Ablage zu * beschreiben und dieselbe Instanz erneut zu fragen. Das ist keine * Umständlichkeit des Tests, sondern genau das, was in der App passiert: die * gespeicherte Wahl wirkt beim Start. */ import { beforeEach, describe, expect, it, vi } from "vitest" async function startwertNachLaden(): Promise { vi.resetModules() const { themeStartwert } = await import("./theme") return themeStartwert() } describe("Theme", () => { beforeEach(() => { localStorage.clear() }) it("startet ohne gespeicherte Wahl im Nachtmodus", async () => { expect(await startwertNachLaden()).toBe("nacht") }) it("übernimmt eine gespeicherte Wahl", async () => { localStorage.setItem("dm360.theme", "tag") expect(await startwertNachLaden()).toBe("tag") }) it("ignoriert unsinnige gespeicherte Werte", async () => { localStorage.setItem("dm360.theme", "irgendwas") expect(await startwertNachLaden()).toBe("nacht") }) }) /* Stellt das Gerät im laufenden Betrieb um - etwa durch die automatische Umschaltung bei Sonnenuntergang -, muss das Thema folgen. Bis zum 05.09.2026 las theme.ts die Systemeinstellung genau einmal beim Laden des Moduls und horchte danach nie wieder; ein Wechsel wirkte erst nach dem nächsten Neuladen. */ describe("Systemumstellung im laufenden Betrieb", () => { function medienabfrageStellen(dunkel: boolean) { const horcher: (() => void)[] = [] const stand = { dunkel } // matches als Getter, nicht als kopierter Wert: theme.ts haelt die // Abfrage vom Laden fest und liest matches erst im Horcher wieder. vi.stubGlobal("matchMedia", (text: string) => ({ get matches() { return text.includes("dark") ? stand.dunkel : !stand.dunkel }, addEventListener: (_art: string, bei: () => void) => horcher.push(bei), removeEventListener: () => {}, })) return { umstellenAuf(neuDunkel: boolean) { stand.dunkel = neuDunkel for (const bei of horcher) bei() }, } } beforeEach(() => { localStorage.clear() vi.resetModules() }) it("folgt dem Wechsel nach hell, ohne neu zu laden", async () => { const system = medienabfrageStellen(true) const { themeStartwert } = await import("./theme") expect(themeStartwert()).toBe("nacht") system.umstellenAuf(false) expect(themeStartwert()).toBe("tag") }) it("folgt dem Wechsel nach dunkel, ohne neu zu laden", async () => { const system = medienabfrageStellen(false) const { themeStartwert } = await import("./theme") expect(themeStartwert()).toBe("tag") system.umstellenAuf(true) expect(themeStartwert()).toBe("nacht") }) it("lässt eine selbst getroffene Wahl unangetastet", async () => { localStorage.setItem("dm360.theme", "tag") const system = medienabfrageStellen(false) const { themeStartwert } = await import("./theme") expect(themeStartwert()).toBe("tag") system.umstellenAuf(true) expect(themeStartwert()).toBe("tag") }) })