96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
import {
|
|
THEME_STORAGE_KEY,
|
|
applyResolvedTheme,
|
|
applyThemeFromPreference,
|
|
isThemePreference,
|
|
readThemePreference,
|
|
resolveTheme,
|
|
writeThemePreference,
|
|
} from './theme'
|
|
|
|
function createMemoryStorage(initial: Record<string, string> = {}) {
|
|
const store = new Map(Object.entries(initial))
|
|
return {
|
|
getItem(key: string) {
|
|
return store.has(key) ? store.get(key)! : null
|
|
},
|
|
setItem(key: string, value: string) {
|
|
store.set(key, value)
|
|
},
|
|
}
|
|
}
|
|
|
|
describe('isThemePreference', () => {
|
|
it('accepts light, dark, and auto', () => {
|
|
expect(isThemePreference('light')).toBe(true)
|
|
expect(isThemePreference('dark')).toBe(true)
|
|
expect(isThemePreference('auto')).toBe(true)
|
|
})
|
|
|
|
it('rejects invalid values', () => {
|
|
expect(isThemePreference('mocha')).toBe(false)
|
|
expect(isThemePreference('')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('readThemePreference', () => {
|
|
it('defaults to auto when nothing is stored', () => {
|
|
expect(readThemePreference(createMemoryStorage())).toBe('auto')
|
|
})
|
|
|
|
it('returns a stored preference', () => {
|
|
const storage = createMemoryStorage({ [THEME_STORAGE_KEY]: 'dark' })
|
|
expect(readThemePreference(storage)).toBe('dark')
|
|
})
|
|
|
|
it('falls back to auto for invalid stored values', () => {
|
|
const storage = createMemoryStorage({ [THEME_STORAGE_KEY]: 'neon' })
|
|
expect(readThemePreference(storage)).toBe('auto')
|
|
})
|
|
})
|
|
|
|
describe('writeThemePreference', () => {
|
|
it('persists the preference', () => {
|
|
const storage = createMemoryStorage()
|
|
writeThemePreference('light', storage)
|
|
expect(storage.getItem(THEME_STORAGE_KEY)).toBe('light')
|
|
})
|
|
})
|
|
|
|
describe('resolveTheme', () => {
|
|
it('maps light to latte and dark to mocha', () => {
|
|
expect(resolveTheme('light', true)).toBe('latte')
|
|
expect(resolveTheme('dark', false)).toBe('mocha')
|
|
})
|
|
|
|
it('maps auto from the browser preference', () => {
|
|
expect(resolveTheme('auto', true)).toBe('mocha')
|
|
expect(resolveTheme('auto', false)).toBe('latte')
|
|
})
|
|
})
|
|
|
|
describe('applyResolvedTheme', () => {
|
|
afterEach(() => {
|
|
delete document.documentElement.dataset.theme
|
|
})
|
|
|
|
it('sets data-theme on the root element', () => {
|
|
applyResolvedTheme('mocha')
|
|
expect(document.documentElement.dataset.theme).toBe('mocha')
|
|
})
|
|
})
|
|
|
|
describe('applyThemeFromPreference', () => {
|
|
afterEach(() => {
|
|
delete document.documentElement.dataset.theme
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('applies the resolved theme from preference and system preference', () => {
|
|
const resolved = applyThemeFromPreference('auto', true)
|
|
expect(resolved).toBe('mocha')
|
|
expect(document.documentElement.dataset.theme).toBe('mocha')
|
|
})
|
|
})
|