Files
audi-app/companion-app/src/theme.test.ts
T
tobias e9c16325cc Musterseite verworfen, Zahnrad-Regression behoben, Fotomenue als Aktionsblatt
Musterseite entfernt (companion-app/muster, vite.muster.config.ts,
/config/www/dmmuster). Ansage des Eigentuemers: sie fuehrt nur zu neuen
Fehlerquellen. Ausloeser war ein Befund, den ich als App-Fehler gemeldet hatte
- Ringe und Typenschild schwarz auf schwarz - und der nur dort bestand.

Behoben:

* Das Zahnrad im Autohaus-Kasten hatte seine Ecke verlassen (58/288 statt
  8/8). Ursache war mein HIG-Durchgang von gestern: .zahnrad kam in die
  Gruppe fuer die 44x44-Trefferflaeche und bekam damit position:relative,
  was das absolute aus dem Basisblatt ueberschrieb. Die Auflage war
  ueberfluessig - .zahnrad ist dort schon 44x44.
* Das Fotomenue hing mit position:absolute an der Kachel statt am
  Bildschirm und lag bei der hohen Raeder-Kachel ausserhalb des Sichtfelds;
  einen Abbrechen-Knopf hatte es nie. Das Panel benutzt jetzt dasselbe
  Aktionsblatt wie die App. .bildmenu ist samt Zustand, Markup, totem
  Handler und CSS entfernt.
* Der Blattkopf las sich als dritte Auswahl (linksbuendig, 15px, --fg).
  Jetzt zentriert, 13px, gedaempft - Apples Muster, in beiden Codebasen.
* "Anstehende Termine" stand 5px ueber "Oelwechsel" und wirkte als dessen
  Beischrift. Entfernt.
* Wartungsplan-Formular: Art nach oben, Datum 124px statt Browser-Vorgabe,
  Werkstatt ueber die volle Zeile (218 -> 306px), Kosten 116px. Zwei
  Erklaertexte entfernt.
* Thema folgt jetzt einer Systemumstellung im laufenden Betrieb. Vorher las
  es prefers-color-scheme genau einmal beim Laden. Drei Tests, die ohne die
  Behebung nachweislich fallen.

Geprueft: 295 App-Tests, Panel node --check, 0 Tracebacks, alle Aenderungen
live an der Testinstanz gemessen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 02:24:08 +02:00

98 lines
3.3 KiB
TypeScript

/**
* 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<string> {
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")
})
})