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';
// Mock next-themes
const mockSetTheme = vi.fn();
let mockTheme = 'dark';
let mockResolvedTheme = 'dark';
vi.mock('next-themes', () => ({
ThemeProvider: ({ children }: { children: React.ReactNode }) => <>{children}>,
useTheme: () => ({
theme: mockTheme,
resolvedTheme: mockResolvedTheme,
setTheme: (t: string) => {
mockSetTheme(t);
mockTheme = t;
mockResolvedTheme = t;
},
}),
}));
// Test consumer component
function ThemeConsumer() {
const { theme, toggleTheme } = useTheme();
return (
{theme}
);
}
describe('ThemeProvider', () => {
beforeEach(() => {
mockTheme = 'dark';
mockResolvedTheme = 'dark';
vi.clearAllMocks();
});
it('renders children', () => {
render(
Child content
,
);
expect(screen.getByText('Child content')).toBeInTheDocument();
});
it('defaults to dark theme', () => {
render(
,
);
expect(screen.getByTestId('theme')).toHaveTextContent('dark');
});
it('toggles theme to light', async () => {
const user = userEvent.setup();
render(
,
);
await user.click(screen.getByText('Toggle'));
expect(mockSetTheme).toHaveBeenCalledWith('light');
});
it('toggles theme back to dark', async () => {
mockTheme = 'light';
mockResolvedTheme = 'light';
const user = userEvent.setup();
render(
,
);
await user.click(screen.getByText('Toggle'));
expect(mockSetTheme).toHaveBeenCalledWith('dark');
});
});
describe('useTheme', () => {
it('returns dark as default outside provider', () => {
render();
expect(screen.getByTestId('theme')).toHaveTextContent('dark');
});
});