import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; import { ThemeProvider, useTheme } from '../theme-provider'; // Provide a working localStorage mock for this test file const localStorageMock = (() => { let store: Record = {}; return { getItem: vi.fn((key: string) => store[key] ?? null), setItem: vi.fn((key: string, value: string) => { store[key] = value; }), removeItem: vi.fn((key: string) => { delete store[key]; }), clear: vi.fn(() => { store = {}; }), get length() { return Object.keys(store).length; }, key: vi.fn((index: number) => Object.keys(store)[index] ?? null), }; })(); Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock, writable: true }); // Mock window.matchMedia (not implemented in jsdom) Object.defineProperty(window, 'matchMedia', { writable: true, value: vi.fn().mockImplementation((query: string) => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), removeListener: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }); // Test consumer component function ThemeConsumer() { const { theme, toggleTheme } = useTheme(); return (
{theme}
); } describe('ThemeProvider', () => { beforeEach(() => { document.documentElement.classList.remove('dark'); localStorageMock.clear(); vi.clearAllMocks(); }); it('renders children', () => { render(
Child content
, ); expect(screen.getByText('Child content')).toBeInTheDocument(); }); it('defaults to light theme', () => { render( , ); expect(screen.getByTestId('theme')).toHaveTextContent('light'); }); it('toggles theme to dark', async () => { const user = userEvent.setup(); render( , ); await user.click(screen.getByText('Toggle')); expect(screen.getByTestId('theme')).toHaveTextContent('dark'); }); it('toggles theme back to light', async () => { const user = userEvent.setup(); render( , ); await user.click(screen.getByText('Toggle')); await user.click(screen.getByText('Toggle')); expect(screen.getByTestId('theme')).toHaveTextContent('light'); }); it('persists theme to localStorage', async () => { const user = userEvent.setup(); render( , ); await user.click(screen.getByText('Toggle')); expect(localStorageMock.setItem).toHaveBeenCalledWith('goodgo-theme', 'dark'); }); it('loads stored theme from localStorage', () => { localStorageMock.getItem.mockReturnValueOnce('dark'); render( , ); expect(screen.getByTestId('theme')).toHaveTextContent('dark'); }); }); describe('useTheme', () => { it('returns default values outside provider', () => { render(); expect(screen.getByTestId('theme')).toHaveTextContent('light'); }); });