theme-presenter.spec.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // @vitest-environment jsdom
  2. // ThemePresenter behavior account: root color-scheme and the palette attribute
  3. // follow active.colorScheme only, token variables replace the previous apply's
  4. // set, and dispose retracts everything the presenter wrote.
  5. import { beforeEach, describe, expect, it } from 'vitest'
  6. import type { ThemeSnapshot } from '@deepseek-ai/dsh-client-ui-theme/client'
  7. import { DARK_ATTRIBUTE, ThemePresenter } from '@deepseek-ai/dsh-client-ui-layout/src/client/theme-presenter.ts'
  8. function snapshot(colorScheme: 'light' | 'dark', tokens: Record<string, string> = {}): ThemeSnapshot {
  9. // The presenter must key off colorScheme, not the id — keep them distinct.
  10. const active = { id: `${colorScheme}-test`, colorScheme, tokens }
  11. return { preference: colorScheme, active, themes: [active], revision: 1 }
  12. }
  13. beforeEach(() => {
  14. document.documentElement.style.removeProperty('color-scheme')
  15. document.body.removeAttribute(DARK_ATTRIBUTE)
  16. document.body.removeAttribute('style')
  17. })
  18. describe('ThemePresenter', () => {
  19. it('light scheme sets root color-scheme and leaves the dark attribute absent', () => {
  20. const presenter = new ThemePresenter()
  21. presenter.apply(snapshot('light'))
  22. expect(document.documentElement.style.colorScheme).toBe('light')
  23. expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(false)
  24. })
  25. it('dark scheme sets root color-scheme and the attribute; switching to light clears both', () => {
  26. const presenter = new ThemePresenter()
  27. presenter.apply(snapshot('dark'))
  28. expect(document.documentElement.style.colorScheme).toBe('dark')
  29. expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(true)
  30. presenter.apply(snapshot('light'))
  31. expect(document.documentElement.style.colorScheme).toBe('light')
  32. expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(false)
  33. })
  34. it('applies tokens as inline variables and clears the previous set on theme change', () => {
  35. const presenter = new ThemePresenter()
  36. presenter.apply(snapshot('dark', { '--dsw-alias-bg': '#111', '--dsw-alias-fg': '#eee' }))
  37. expect(document.body.style.getPropertyValue('--dsw-alias-bg')).toBe('#111')
  38. expect(document.body.style.getPropertyValue('--dsw-alias-fg')).toBe('#eee')
  39. presenter.apply(snapshot('light', { '--dsw-alias-bg': '#fff' }))
  40. expect(document.body.style.getPropertyValue('--dsw-alias-bg')).toBe('#fff')
  41. // The old theme's extra variable is gone, not merged.
  42. expect(document.body.style.getPropertyValue('--dsw-alias-fg')).toBe('')
  43. })
  44. it('dispose removes color-scheme, the attribute, and every applied variable, sparing foreign inline styles', () => {
  45. document.body.style.setProperty('--foreign', 'kept')
  46. const presenter = new ThemePresenter()
  47. presenter.apply(snapshot('dark', { '--dsw-alias-bg': '#111' }))
  48. presenter.dispose()
  49. expect(document.documentElement.style.colorScheme).toBe('')
  50. expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(false)
  51. expect(document.body.style.getPropertyValue('--dsw-alias-bg')).toBe('')
  52. expect(document.body.style.getPropertyValue('--foreign')).toBe('kept')
  53. })
  54. })