import { describe, expect, test, beforeEach, vi } from 'vitest'; function setupLocalStorage(initial: Record = {}) { const store: Record = { ...initial }; vi.stubGlobal('localStorage', { getItem: (k: string) => (k in store ? store[k] : null), setItem: (k: string, v: string) => { store[k] = v; }, removeItem: (k: string) => { delete store[k]; } }); return store; } function setupMatchMedia(prefersLight: boolean) { const listeners: ((e: { matches: boolean }) => void)[] = []; const mql = { matches: prefersLight, addEventListener: (_: string, cb: (e: { matches: boolean }) => void) => listeners.push(cb), removeEventListener: () => {} }; vi.stubGlobal('window', { matchMedia: () => mql }); return { mql, listeners, fire: (matches: boolean) => { mql.matches = matches; listeners.forEach((cb) => cb({ matches })); } }; } beforeEach(() => { vi.resetModules(); vi.unstubAllGlobals(); if (typeof document !== 'undefined') { document.documentElement.removeAttribute('data-theme'); } }); describe('theme store', () => { test('default preference is system; resolves via matchMedia', async () => { setupLocalStorage(); setupMatchMedia(false); // prefers-dark const mod = await import('./theme.svelte'); expect(mod.theme.value).toBe('system'); expect(mod.resolvedTheme.value).toBe('dark'); }); test('explicit preference from localStorage is honored', async () => { setupLocalStorage({ 'minstrel:theme': 'light' }); setupMatchMedia(false); const mod = await import('./theme.svelte'); expect(mod.theme.value).toBe('light'); expect(mod.resolvedTheme.value).toBe('light'); }); test('setTheme persists, updates resolved, sets data-theme attribute', async () => { const store = setupLocalStorage(); setupMatchMedia(true); const mod = await import('./theme.svelte'); mod.setTheme('dark'); expect(store['minstrel:theme']).toBe('dark'); expect(mod.theme.value).toBe('dark'); expect(mod.resolvedTheme.value).toBe('dark'); expect(document.documentElement.getAttribute('data-theme')).toBe('dark'); }); test('matchMedia change updates resolved while in system mode', async () => { setupLocalStorage(); const mm = setupMatchMedia(false); // prefers-dark const mod = await import('./theme.svelte'); expect(mod.resolvedTheme.value).toBe('dark'); mm.fire(true); // OS flipped to light expect(mod.resolvedTheme.value).toBe('light'); }); test('matchMedia change does NOT update resolved when explicit preference set', async () => { setupLocalStorage({ 'minstrel:theme': 'dark' }); const mm = setupMatchMedia(false); const mod = await import('./theme.svelte'); expect(mod.resolvedTheme.value).toBe('dark'); mm.fire(true); // OS prefers light, but user explicitly chose dark expect(mod.resolvedTheme.value).toBe('dark'); }); });