123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- import { flushPromises } from '@vue/test-utils'
- import { createPinia, setActivePinia, storeToRefs } from 'pinia'
- import {
- addEventListener,
- mockMediaTheme,
- } from '#tests/support/mock-mediaTheme.ts'
- import { mockUserCurrent } from '#tests/support/mock-userCurrent.ts'
- import { EnumAppearanceTheme } from '#shared/graphql/types.ts'
- import { mockUserCurrentAppearanceMutation } from '#desktop/pages/personal-setting/graphql/mutations/userCurrentAppearance.mocks.ts'
- import { useThemeStore } from '#desktop/stores/theme.ts'
- const mockUserTheme = (theme: string | undefined) => {
- mockUserCurrent({
- preferences: {
- theme,
- },
- })
- }
- const getRoot = () => document.querySelector(':root') as HTMLElement
- const haveDOMTheme = (theme: string | undefined) => {
- const root = getRoot()
- if (!theme) {
- root.removeAttribute('data-theme')
- root.style.colorScheme = 'normal'
- } else {
- root.dataset.theme = theme
- root.style.colorScheme = theme
- }
- }
- const getDOMTheme = () => getRoot().dataset.theme
- const getDOMColorScheme = () => getRoot().style.colorScheme
- describe('useThemeStore', () => {
- beforeEach(() => {
- setActivePinia(createPinia())
- mockUserCurrent({
- lastname: 'Doe',
- firstname: 'John',
- preferences: {},
- })
- const { syncTheme } = useThemeStore()
- syncTheme()
- haveDOMTheme(undefined)
- mockMediaTheme(EnumAppearanceTheme.Light)
- })
- it('should fallback to auto when no theme present', () => {
- const { currentTheme } = useThemeStore()
- expect(currentTheme).toBe(EnumAppearanceTheme.Auto)
- })
- it('changes app theme', async () => {
- const mockerUserCurrentAppearanceUpdate = mockUserCurrentAppearanceMutation(
- {
- userCurrentAppearance: {
- success: true,
- },
- },
- )
- const themeStore = useThemeStore()
- const { updateTheme } = themeStore
- const { currentTheme, savingTheme } = storeToRefs(themeStore)
- await updateTheme(EnumAppearanceTheme.Dark)
- expect(currentTheme.value).toBe(EnumAppearanceTheme.Dark)
- const mockCalls = await mockerUserCurrentAppearanceUpdate.waitForCalls()
- expect(mockCalls).toHaveLength(1)
- await flushPromises()
- expect(savingTheme.value).toBe(false)
- expect(currentTheme.value).toBe(EnumAppearanceTheme.Dark)
- })
- it('should change theme value back to old value when update fails', async () => {
- const mockerUserCurrentAppearanceUpdate = mockUserCurrentAppearanceMutation(
- {
- userCurrentAppearance: {
- errors: [
- {
- message: 'Failed to update.',
- },
- ],
- },
- },
- )
- const themeStore = useThemeStore()
- const { updateTheme } = themeStore
- const { currentTheme, savingTheme } = storeToRefs(themeStore)
- await updateTheme(EnumAppearanceTheme.Dark)
- expect(currentTheme.value).toBe(EnumAppearanceTheme.Auto)
- const mockCalls = await mockerUserCurrentAppearanceUpdate.waitForCalls()
- expect(mockCalls).toHaveLength(1)
- await flushPromises()
- expect(savingTheme.value).toBe(false)
- expect(currentTheme.value).toBe(EnumAppearanceTheme.Auto)
- })
- it('when user has no theme preference, takes from media', () => {
- const { syncTheme } = useThemeStore()
- syncTheme()
- const { currentTheme } = useThemeStore()
- expect(currentTheme).toBe('auto')
- })
- it("changes in media don't affect theme", async () => {
- mockUserTheme(EnumAppearanceTheme.Dark)
- mockMediaTheme(EnumAppearanceTheme.Dark)
- const { syncTheme, currentTheme } = useThemeStore()
- syncTheme()
- expect(currentTheme).toBe(EnumAppearanceTheme.Dark)
- expect(getDOMTheme()).toBe(EnumAppearanceTheme.Dark)
- expect(getDOMColorScheme()).toBe(EnumAppearanceTheme.Dark)
- mockMediaTheme(EnumAppearanceTheme.Light)
- addEventListener.mock.calls[0][1]()
- expect(currentTheme).toBe(EnumAppearanceTheme.Dark)
- expect(getDOMTheme()).toBe(EnumAppearanceTheme.Dark)
- expect(getDOMColorScheme()).toBe(EnumAppearanceTheme.Dark)
- })
- describe('isDarkMode', () => {
- it('returns true when user prefers dark media theme', async () => {
- mockMediaTheme(EnumAppearanceTheme.Dark)
- const { isDarkMode } = useThemeStore()
- expect(isDarkMode).toBe(true)
- })
- it('returns false when user prefers light media theme', async () => {
- mockMediaTheme(EnumAppearanceTheme.Light)
- const { isDarkMode } = useThemeStore()
- expect(isDarkMode).toBe(false)
- })
- it('returns true when user has dark theme active', async () => {
- mockUserTheme(EnumAppearanceTheme.Dark) // has precedence
- mockMediaTheme(EnumAppearanceTheme.Light)
- const { isDarkMode } = useThemeStore()
- expect(isDarkMode).toBe(true)
- })
- it('returns false when user prefers light media theme', async () => {
- mockUserTheme(EnumAppearanceTheme.Light) // has precedence
- mockMediaTheme(EnumAppearanceTheme.Dark)
- const { isDarkMode } = useThemeStore()
- expect(isDarkMode).toBe(false)
- })
- })
- })
|