85 lines
3.1 KiB
TypeScript
85 lines
3.1 KiB
TypeScript
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||
|
|
import { useTheme } from '../app/composables/useTheme'
|
||
|
|
|
||
|
|
/** กำหนด prefers-color-scheme ของระบบ — initTheme ใช้เป็นค่า default เมื่อยังไม่มี preference */
|
||
|
|
function mockPrefersDark(matches: boolean) {
|
||
|
|
vi.stubGlobal('matchMedia', vi.fn().mockReturnValue({ matches }))
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('useTheme — light/dark toggle + persist + system default (Phase 6.1)', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.unstubAllGlobals()
|
||
|
|
})
|
||
|
|
|
||
|
|
it('state เริ่มที่ light และ toggle สลับไป-กลับ พร้อม class บน <html>', () => {
|
||
|
|
mockPrefersDark(false)
|
||
|
|
const { theme, isDark, toggle } = useTheme()
|
||
|
|
|
||
|
|
expect(theme.value).toBe('light')
|
||
|
|
expect(isDark.value).toBe(false)
|
||
|
|
|
||
|
|
toggle()
|
||
|
|
expect(theme.value).toBe('dark')
|
||
|
|
expect(isDark.value).toBe(true)
|
||
|
|
expect(document.documentElement.classList.contains('dark')).toBe(true)
|
||
|
|
|
||
|
|
toggle()
|
||
|
|
expect(theme.value).toBe('light')
|
||
|
|
expect(document.documentElement.classList.contains('dark')).toBe(false)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('toggle เขียน preference ลง localStorage (ข้อยกเว้นเดียวที่อนุญาต — ไม่ใช่ credential)', () => {
|
||
|
|
mockPrefersDark(false)
|
||
|
|
const { toggle } = useTheme()
|
||
|
|
|
||
|
|
toggle()
|
||
|
|
expect(localStorage.getItem('theme-preference')).toBe('dark')
|
||
|
|
|
||
|
|
toggle()
|
||
|
|
expect(localStorage.getItem('theme-preference')).toBe('light')
|
||
|
|
})
|
||
|
|
|
||
|
|
it('initTheme ใช้ค่าที่เคยบันทึกไว้ (แม้ระบบเป็นอีกค่า)', () => {
|
||
|
|
mockPrefersDark(true)
|
||
|
|
localStorage.setItem('theme-preference', 'light')
|
||
|
|
const { theme, initTheme } = useTheme()
|
||
|
|
|
||
|
|
initTheme()
|
||
|
|
|
||
|
|
expect(theme.value).toBe('light') // stored ชนะ system
|
||
|
|
expect(document.documentElement.classList.contains('dark')).toBe(false)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('initTheme ไม่มีค่าเก็บไว้ → ตาม prefers-color-scheme ของระบบ', () => {
|
||
|
|
mockPrefersDark(true)
|
||
|
|
const { theme, isDark, initTheme } = useTheme()
|
||
|
|
|
||
|
|
initTheme()
|
||
|
|
|
||
|
|
expect(theme.value).toBe('dark')
|
||
|
|
expect(isDark.value).toBe(true)
|
||
|
|
expect(document.documentElement.classList.contains('dark')).toBe(true)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('ค่าใน localStorage ที่ไม่ใช่ light/dark → ตกไปใช้ค่าระบบแทน (กันค่าเสีย)', () => {
|
||
|
|
mockPrefersDark(false)
|
||
|
|
localStorage.setItem('theme-preference', 'neon')
|
||
|
|
const { theme, initTheme } = useTheme()
|
||
|
|
|
||
|
|
initTheme()
|
||
|
|
|
||
|
|
expect(theme.value).toBe('light') // ค่าเสียถูกเมิน ใช้ system default
|
||
|
|
})
|
||
|
|
|
||
|
|
it('state แชร์กันตาม key (semantics ของ useState) — สอง instance เห็นค่าเดียวกัน', () => {
|
||
|
|
mockPrefersDark(false)
|
||
|
|
const first = useTheme()
|
||
|
|
const second = useTheme()
|
||
|
|
|
||
|
|
first.toggle()
|
||
|
|
|
||
|
|
expect(second.theme.value).toBe('dark')
|
||
|
|
expect(second.isDark.value).toBe(true)
|
||
|
|
})
|
||
|
|
})
|