import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, act } from '@testing-library/react'; import { ThemeProvider, useTheme } from '../ThemeProvider'; import { Providers } from '../Providers'; // Mock next-auth SessionProvider vi.mock('next-auth/react', () => ({ SessionProvider: ({ children }: { children: React.ReactNode }) => <>{children}, })); function ThemeConsumer() { const { theme, accent, setTheme, setAccent, toggleTheme } = useTheme(); return (
{theme} {accent}
); } describe('ThemeProvider', () => { beforeEach(() => { localStorage.clear(); document.documentElement.removeAttribute('data-theme'); document.documentElement.style.cssText = ''; }); it('provides default light/sage theme', () => { render( , ); expect(screen.getByTestId('theme').textContent).toBe('light'); expect(screen.getByTestId('accent').textContent).toBe('sage'); }); it('hydrates from localStorage', () => { localStorage.setItem('mt-theme', 'dark'); localStorage.setItem('mt-accent', 'terracotta'); render( , ); expect(screen.getByTestId('theme').textContent).toBe('dark'); expect(screen.getByTestId('accent').textContent).toBe('terracotta'); }); it('setTheme updates theme and persists', () => { render( , ); act(() => fireEvent.click(screen.getByText('Set dark'))); expect(screen.getByTestId('theme').textContent).toBe('dark'); expect(localStorage.getItem('mt-theme')).toBe('dark'); expect(document.documentElement.getAttribute('data-theme')).toBe('dark'); }); it('setAccent updates accent and applies CSS vars', () => { render( , ); act(() => fireEvent.click(screen.getByText('Set cobalt'))); expect(screen.getByTestId('accent').textContent).toBe('cobalt'); expect(localStorage.getItem('mt-accent')).toBe('cobalt'); expect(document.documentElement.style.getPropertyValue('--brand')).toBe('#3b82f6'); }); it('toggleTheme flips light to dark', () => { render( , ); act(() => fireEvent.click(screen.getByText('Toggle'))); expect(screen.getByTestId('theme').textContent).toBe('dark'); }); it('toggleTheme flips dark to light', () => { localStorage.setItem('mt-theme', 'dark'); render( , ); act(() => fireEvent.click(screen.getByText('Toggle'))); expect(screen.getByTestId('theme').textContent).toBe('light'); }); it('useTheme throws outside provider', () => { expect(() => render()).toThrow('useTheme must be used inside ThemeProvider'); }); }); describe('Providers', () => { it('renders children with session and theme providers', () => { render( child content , ); expect(screen.getByText('child content')).toBeInTheDocument(); }); });