113 行
3.8 KiB
TypeScript
113 行
3.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { applyClientAnimationMode,
|
|
applyThemeTokens,
|
|
buildThemeTokens,
|
|
CLIENT_SETTINGS_STORAGE_KEY,
|
|
DARK_THEME_TOKENS,
|
|
DEFAULT_POST_LIST_ORDER,
|
|
getClientListLimit,
|
|
getClientListOrder,
|
|
getClientThemeMode,
|
|
LIGHT_THEME_TOKENS,
|
|
loadClientSettings,
|
|
setClientListSettings,
|
|
setClientThemeAppearance } from '@/lib/settings'
|
|
|
|
import type { FetchPostsOrder } from '@/types'
|
|
|
|
const installMatchMedia = (matches: boolean) => {
|
|
Object.defineProperty (window, 'matchMedia', {
|
|
configurable: true,
|
|
value: vi.fn ().mockImplementation (() => ({
|
|
matches,
|
|
addEventListener: vi.fn (),
|
|
removeEventListener: vi.fn () })) })
|
|
}
|
|
|
|
describe ('settings', () => {
|
|
beforeEach (() => {
|
|
localStorage.clear ()
|
|
document.documentElement.removeAttribute ('data-animation')
|
|
document.documentElement.removeAttribute ('style')
|
|
document.documentElement.className = ''
|
|
installMatchMedia (false)
|
|
})
|
|
|
|
it ('stores list settings under the shared client settings key', () => {
|
|
setClientListSettings ('postSearch', {
|
|
limit: 50,
|
|
order: 'title:asc' })
|
|
|
|
expect (getClientListLimit ('postSearch')).toBe (50)
|
|
expect (getClientListOrder<FetchPostsOrder> ('postSearch')).toBe ('title:asc')
|
|
expect (JSON.parse (localStorage.getItem (CLIENT_SETTINGS_STORAGE_KEY) ?? '{}'))
|
|
.toMatchObject ({ lists: { postSearch: { limit: 50, order: 'title:asc' } } })
|
|
})
|
|
|
|
it ('ignores invalid list limits and keeps stored order strings', () => {
|
|
localStorage.setItem (
|
|
CLIENT_SETTINGS_STORAGE_KEY,
|
|
JSON.stringify ({ lists: { postList: { limit: 30, order: DEFAULT_POST_LIST_ORDER } } }))
|
|
|
|
expect (getClientListLimit ('postList')).toBeNull ()
|
|
expect (getClientListOrder<FetchPostsOrder> ('postList')).toBe (
|
|
DEFAULT_POST_LIST_ORDER)
|
|
})
|
|
|
|
it ('stores theme mode and light/dark slot selections in client settings', () => {
|
|
setClientThemeAppearance ({
|
|
themeMode: 'dark',
|
|
activeLightThemeSlotNo: 2,
|
|
activeDarkThemeSlotNo: 3 })
|
|
|
|
expect (getClientThemeMode ()).toBe ('dark')
|
|
expect (loadClientSettings ().appearance).toMatchObject ({
|
|
themeMode: 'dark',
|
|
activeLightThemeSlotNo: 2,
|
|
activeDarkThemeSlotNo: 3 })
|
|
})
|
|
|
|
it ('applies animation mode to the document dataset', () => {
|
|
applyClientAnimationMode ('off')
|
|
expect (document.documentElement.dataset.animation).toBe ('off')
|
|
|
|
applyClientAnimationMode ('reduced')
|
|
expect (document.documentElement.dataset.animation).toBe ('reduced')
|
|
|
|
applyClientAnimationMode ('normal')
|
|
expect (document.documentElement.dataset.animation).toBeUndefined ()
|
|
})
|
|
|
|
it ('normalises TopNav menu link tokens to complete CSS colours', () => {
|
|
const tokens = buildThemeTokens ('light', {
|
|
link: '221.2 83.2% 53.3%',
|
|
topNavMenuLink: '221.2 83.2% 53.3%' })
|
|
|
|
expect (tokens.link).toBe ('221.2 83.2% 53.3%')
|
|
expect (tokens.topNavMenuLink).toBe ('hsl(221.2 83.2% 53.3%)')
|
|
})
|
|
|
|
it ('derives TopNav colours without mixing mobile active backgrounds', () => {
|
|
const tokens = buildThemeTokens ('light', { })
|
|
|
|
expect (tokens.topNavMobileActiveBackground).toBe (
|
|
LIGHT_THEME_TOKENS.topNavRootBackgroundDesktop)
|
|
expect (tokens.topNavMobileActiveBackground).not.toBe (
|
|
tokens.topNavRootBackgroundMobile)
|
|
expect (buildThemeTokens ('dark', { }).topNavMobileActiveBackground).toBe (
|
|
DARK_THEME_TOKENS.topNavActiveBackground)
|
|
})
|
|
|
|
it ('sets shadcn tokens and TopNav tokens with their different value formats', () => {
|
|
const tokens = buildThemeTokens ('dark', { link: '213.1 93.9% 67.8%' })
|
|
|
|
applyThemeTokens (tokens)
|
|
|
|
expect (document.documentElement.style.getPropertyValue ('--theme-link')).toBe (
|
|
'213.1 93.9% 67.8%')
|
|
expect (document.documentElement.style.getPropertyValue ('--top-nav-menu-link')).toBe (
|
|
'hsl(213.1 93.9% 67.8%)')
|
|
})
|
|
})
|