theme.spec.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { describe, it, expect, vi, beforeEach } from 'vitest'
  2. import { setActivePinia, createPinia } from 'pinia'
  3. import { ref } from 'vue'
  4. import { useThemeStore } from '@/store/theme'
  5. // Mock @vueuse/core
  6. vi.mock('@vueuse/core', () => ({
  7. useStorage: vi.fn((key: string, defaultValue: any) => {
  8. const stored = localStorage.getItem(key)
  9. const initial = stored ? JSON.parse(stored) : defaultValue
  10. return ref(initial)
  11. }),
  12. usePreferredDark: vi.fn(() => ref(false))
  13. }))
  14. // Mock theme presets
  15. vi.mock('@/assets/styles/theme/presets', () => ({
  16. themeColorPresets: {
  17. blue: {
  18. primary: '#409EFF',
  19. primaryLight3: '#79BBFF',
  20. primaryLight5: '#A0CFFF',
  21. primaryLight7: '#C6E2FF',
  22. primaryLight9: '#ECF5FF',
  23. primaryDark2: '#337ECC'
  24. },
  25. green: {
  26. primary: '#67C23A',
  27. primaryLight3: '#95D475',
  28. primaryLight5: '#B3E19D',
  29. primaryLight7: '#D1EDC4',
  30. primaryLight9: '#F0F9EB',
  31. primaryDark2: '#529B2E'
  32. }
  33. },
  34. defaultThemeColor: 'blue'
  35. }))
  36. describe('Theme Store', () => {
  37. beforeEach(() => {
  38. // 清理 localStorage 和重置 mock
  39. localStorage.clear()
  40. vi.clearAllMocks()
  41. // 重新创建 pinia
  42. setActivePinia(createPinia())
  43. // 清理 DOM 类
  44. document.documentElement.classList.remove('dark', 'compact-mode')
  45. document.documentElement.removeAttribute('style')
  46. })
  47. describe('初始状态', () => {
  48. it('mode 默认应该是 system', () => {
  49. const store = useThemeStore()
  50. expect(store.config.mode).toBe('system')
  51. })
  52. it('colorScheme 默认应该是 blue', () => {
  53. const store = useThemeStore()
  54. expect(store.config.colorScheme).toBe('blue')
  55. })
  56. it('fontSize 默认应该是 default', () => {
  57. const store = useThemeStore()
  58. expect(store.config.fontSize).toBe('default')
  59. })
  60. it('compactMode 默认应该是 false', () => {
  61. const store = useThemeStore()
  62. expect(store.config.compactMode).toBe(false)
  63. })
  64. })
  65. describe('isDark 计算属性', () => {
  66. it('system 模式下应该跟随系统偏好', () => {
  67. const store = useThemeStore()
  68. // 默认系统偏好是 false (浅色)
  69. expect(store.isDark).toBe(false)
  70. })
  71. it('dark 模式下应该返回 true', () => {
  72. const store = useThemeStore()
  73. store.setMode('dark')
  74. expect(store.isDark).toBe(true)
  75. })
  76. it('light 模式下应该返回 false', () => {
  77. const store = useThemeStore()
  78. store.setMode('light')
  79. expect(store.isDark).toBe(false)
  80. })
  81. })
  82. describe('toggleDarkMode', () => {
  83. it('从 dark 模式切换应该变为 light', () => {
  84. const store = useThemeStore()
  85. store.setMode('dark')
  86. expect(store.config.mode).toBe('dark')
  87. store.toggleDarkMode()
  88. expect(store.config.mode).toBe('light')
  89. })
  90. it('从 light 模式切换应该变为 dark', () => {
  91. const store = useThemeStore()
  92. store.setMode('light')
  93. expect(store.config.mode).toBe('light')
  94. store.toggleDarkMode()
  95. expect(store.config.mode).toBe('dark')
  96. })
  97. it('toggleDarkMode 应该切换模式', () => {
  98. const store = useThemeStore()
  99. const initialMode = store.config.mode
  100. store.toggleDarkMode()
  101. expect(store.config.mode).not.toBe(initialMode)
  102. })
  103. })
  104. describe('setMode', () => {
  105. it('应该正确设置主题模式', () => {
  106. const store = useThemeStore()
  107. store.setMode('dark')
  108. expect(store.config.mode).toBe('dark')
  109. store.setMode('light')
  110. expect(store.config.mode).toBe('light')
  111. store.setMode('system')
  112. expect(store.config.mode).toBe('system')
  113. })
  114. })
  115. describe('setColorScheme', () => {
  116. it('应该正确设置主题色', () => {
  117. const store = useThemeStore()
  118. store.setColorScheme('green')
  119. expect(store.config.colorScheme).toBe('green')
  120. store.setColorScheme('blue')
  121. expect(store.config.colorScheme).toBe('blue')
  122. })
  123. })
  124. describe('currentColors', () => {
  125. it('应该返回当前主题色配置', () => {
  126. const store = useThemeStore()
  127. expect(store.currentColors).toBeDefined()
  128. expect(store.currentColors.primary).toBe('#409EFF')
  129. })
  130. it('切换主题色后应该返回对应配置', () => {
  131. const store = useThemeStore()
  132. store.setColorScheme('green')
  133. expect(store.currentColors.primary).toBe('#67C23A')
  134. })
  135. })
  136. describe('setFontSize', () => {
  137. it('应该正确设置字体大小', () => {
  138. const store = useThemeStore()
  139. store.setFontSize('small')
  140. expect(store.config.fontSize).toBe('small')
  141. store.setFontSize('large')
  142. expect(store.config.fontSize).toBe('large')
  143. store.setFontSize('default')
  144. expect(store.config.fontSize).toBe('default')
  145. })
  146. })
  147. describe('toggleCompactMode', () => {
  148. it('应该切换紧凑模式', () => {
  149. const store = useThemeStore()
  150. expect(store.config.compactMode).toBe(false)
  151. store.toggleCompactMode()
  152. expect(store.config.compactMode).toBe(true)
  153. store.toggleCompactMode()
  154. expect(store.config.compactMode).toBe(false)
  155. })
  156. })
  157. describe('resetToDefault', () => {
  158. it('应该有 resetToDefault 方法', () => {
  159. const store = useThemeStore()
  160. expect(typeof store.resetToDefault).toBe('function')
  161. })
  162. it('调用 resetToDefault 不应该抛出错误', () => {
  163. const store = useThemeStore()
  164. expect(() => store.resetToDefault()).not.toThrow()
  165. })
  166. })
  167. describe('applyTheme', () => {
  168. it('dark 模式应该添加 dark 类', () => {
  169. const store = useThemeStore()
  170. store.setMode('dark')
  171. store.applyTheme()
  172. expect(document.documentElement.classList.contains('dark')).toBe(true)
  173. })
  174. it('light 模式应该移除 dark 类', () => {
  175. const store = useThemeStore()
  176. document.documentElement.classList.add('dark')
  177. store.setMode('light')
  178. store.applyTheme()
  179. expect(document.documentElement.classList.contains('dark')).toBe(false)
  180. })
  181. it('紧凑模式应该添加 compact-mode 类', () => {
  182. const store = useThemeStore()
  183. // 先确保紧凑模式为 false,然后切换
  184. if (store.config.compactMode) {
  185. store.toggleCompactMode()
  186. }
  187. expect(store.config.compactMode).toBe(false)
  188. store.toggleCompactMode()
  189. expect(store.config.compactMode).toBe(true)
  190. store.applyTheme()
  191. expect(document.documentElement.classList.contains('compact-mode')).toBe(true)
  192. })
  193. })
  194. describe('themeColorPresets', () => {
  195. it('应该暴露主题色预设', () => {
  196. const store = useThemeStore()
  197. expect(store.themeColorPresets).toBeDefined()
  198. expect(store.themeColorPresets.blue).toBeDefined()
  199. expect(store.themeColorPresets.green).toBeDefined()
  200. })
  201. })
  202. })