test(web/m7-362): theme store unit test (default/persist/matchMedia)

This commit is contained in:
2026-05-03 13:53:03 -04:00
parent 0f83b2d6ae
commit dd50ce09fd
+79
View File
@@ -0,0 +1,79 @@
import { describe, expect, test, beforeEach, vi } from 'vitest';
function setupLocalStorage(initial: Record<string, string> = {}) {
const store: Record<string, string> = { ...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) => 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');
});
});