diff --git a/web/src/routes/settings/Appearance.test.ts b/web/src/routes/settings/Appearance.test.ts new file mode 100644 index 00000000..a0364a9a --- /dev/null +++ b/web/src/routes/settings/Appearance.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, test, vi, beforeEach } from 'vitest'; +import { render, screen, fireEvent } from '@testing-library/svelte'; + +vi.mock('$lib/api/listenbrainz', () => ({ + createLBStatusQuery: () => ({ + subscribe: () => () => {}, + isPending: false, + isError: false, + data: { token_set: false, enabled: false } + }), + createTokenMutation: () => ({ subscribe: () => () => {}, mutate: vi.fn(), isPending: false }), + createEnabledMutation: () => ({ subscribe: () => () => {}, mutate: vi.fn(), isPending: false }) +})); + +vi.mock('@tanstack/svelte-query', async (orig) => { + const actual = (await orig()) as Record; + return { ...actual, useQueryClient: () => ({ invalidateQueries: vi.fn() }) }; +}); + +beforeEach(() => { + globalThis.localStorage.clear(); + document.documentElement.removeAttribute('data-theme'); +}); + +import SettingsPage from './+page.svelte'; + +describe('Settings → Appearance', () => { + test('renders three theme options', () => { + render(SettingsPage); + expect(screen.getByText(/^Appearance$/)).toBeInTheDocument(); + expect(screen.getByLabelText('dark', { exact: false })).toBeInTheDocument(); + expect(screen.getByLabelText('light', { exact: false })).toBeInTheDocument(); + expect(screen.getByLabelText('system', { exact: false })).toBeInTheDocument(); + }); + + test('clicking light writes localStorage and sets data-theme', async () => { + render(SettingsPage); + const lightRadio = screen.getByLabelText('light', { exact: false }) as HTMLInputElement; + await fireEvent.click(lightRadio); + expect(localStorage.getItem('minstrel:theme')).toBe('light'); + expect(document.documentElement.getAttribute('data-theme')).toBe('light'); + }); + + test('clicking dark writes localStorage and sets data-theme', async () => { + render(SettingsPage); + const darkRadio = screen.getByLabelText('dark', { exact: false }) as HTMLInputElement; + await fireEvent.click(darkRadio); + expect(localStorage.getItem('minstrel:theme')).toBe('dark'); + expect(document.documentElement.getAttribute('data-theme')).toBe('dark'); + }); +});