ThemeSwitch.spec.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { ref, type Ref } from 'vue'
  3. import { renderComponent } from '#tests/support/components/index.ts'
  4. import { waitForNextTick } from '#tests/support/utils.ts'
  5. import ThemeSwitch, { type Props } from '../ThemeSwitch.vue'
  6. export const renderThemeSwitch = (props?: Props, modelValue?: Ref) => {
  7. return renderComponent(ThemeSwitch, {
  8. props,
  9. vModel: {
  10. modelValue,
  11. },
  12. })
  13. }
  14. describe('ThemeSwitch', () => {
  15. it('cycles between checkbox states', async () => {
  16. const view = renderThemeSwitch()
  17. const button = view.getByLabelText('Dark Mode')
  18. expect(button).toBePartiallyChecked()
  19. await view.events.click(button)
  20. expect(button).toBeChecked()
  21. await view.events.click(button)
  22. expect(button).not.toBeChecked()
  23. await view.events.click(button)
  24. expect(button).toBePartiallyChecked()
  25. })
  26. it('supports model-value', async () => {
  27. const appearance = ref('dark')
  28. const view = renderThemeSwitch({}, appearance)
  29. const button = view.getByLabelText('Dark Mode')
  30. expect(button).toBeChecked()
  31. appearance.value = 'light'
  32. await waitForNextTick()
  33. expect(button).not.toBeChecked()
  34. appearance.value = 'auto'
  35. await waitForNextTick()
  36. expect(button).toBePartiallyChecked()
  37. })
  38. it('supports size prop', async () => {
  39. const view = renderThemeSwitch({
  40. size: 'small',
  41. })
  42. const button = view.getByLabelText('Dark Mode')
  43. expect(button).toHaveClasses(['w-11', 'h-[19px]'])
  44. await view.rerender({
  45. size: 'medium',
  46. })
  47. expect(button).toHaveClasses(['w-14', 'h-6'])
  48. })
  49. it('renders appropriate icons', async () => {
  50. const appearance = ref('') // checks fallback handling
  51. const view = renderThemeSwitch({}, appearance)
  52. expect(view.getByIconName('magic')).toBeInTheDocument()
  53. appearance.value = 'dark'
  54. await waitForNextTick()
  55. expect(view.getByIconName('moon-stars')).toBeInTheDocument()
  56. appearance.value = 'light'
  57. await waitForNextTick()
  58. expect(view.getByIconName('sun')).toBeInTheDocument()
  59. })
  60. it('supports keyboard activation', async () => {
  61. const view = renderThemeSwitch()
  62. const button = view.getByLabelText('Dark Mode')
  63. expect(button).toBePartiallyChecked()
  64. button.focus()
  65. await view.events.keyboard('{Space}')
  66. expect(button).toBeChecked()
  67. await view.events.keyboard('{Space}')
  68. expect(button).not.toBeChecked()
  69. await view.events.keyboard('{Space}')
  70. expect(button).toBePartiallyChecked()
  71. })
  72. })