forked from cardosofelipe/fast-next-template
Add unit tests for core components and layouts
- **ThemeToggle:** Introduce comprehensive tests to validate button functionality, dropdown options, and active theme indicators. - **ThemeProvider:** Add tests for theme management, localStorage persistence, system preferences, and DOM updates. - **Header & Footer:** Verify header rendering, user menu functionality, and footer content consistency. - **AuthInitializer:** Ensure authentication state is correctly loaded from storage on mount.
This commit is contained in:
186
frontend/tests/components/theme/ThemeToggle.test.tsx
Normal file
186
frontend/tests/components/theme/ThemeToggle.test.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Tests for ThemeToggle
|
||||
* Verifies theme toggle button functionality and dropdown menu
|
||||
*/
|
||||
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { ThemeToggle } from '@/components/theme/ThemeToggle';
|
||||
import { ThemeProvider, useTheme } from '@/components/theme/ThemeProvider';
|
||||
|
||||
// Mock theme provider for controlled testing
|
||||
jest.mock('@/components/theme/ThemeProvider', () => {
|
||||
const actual = jest.requireActual('@/components/theme/ThemeProvider');
|
||||
return {
|
||||
...actual,
|
||||
useTheme: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ThemeToggle', () => {
|
||||
const mockSetTheme = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Default mock return value
|
||||
(useTheme as jest.Mock).mockReturnValue({
|
||||
theme: 'system',
|
||||
setTheme: mockSetTheme,
|
||||
resolvedTheme: 'light',
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('renders theme toggle button', () => {
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays sun icon when resolved theme is light', () => {
|
||||
(useTheme as jest.Mock).mockReturnValue({
|
||||
theme: 'light',
|
||||
setTheme: mockSetTheme,
|
||||
resolvedTheme: 'light',
|
||||
});
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
// Sun icon should be visible
|
||||
expect(button.querySelector('svg')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays moon icon when resolved theme is dark', () => {
|
||||
(useTheme as jest.Mock).mockReturnValue({
|
||||
theme: 'dark',
|
||||
setTheme: mockSetTheme,
|
||||
resolvedTheme: 'dark',
|
||||
});
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
// Moon icon should be visible
|
||||
expect(button.querySelector('svg')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dropdown Menu', () => {
|
||||
it('opens dropdown menu when button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menuitem', { name: /light/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole('menuitem', { name: /dark/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole('menuitem', { name: /system/i })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls setTheme with "light" when light option is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
const lightOption = await screen.findByRole('menuitem', { name: /light/i });
|
||||
await user.click(lightOption);
|
||||
|
||||
expect(mockSetTheme).toHaveBeenCalledWith('light');
|
||||
});
|
||||
|
||||
it('calls setTheme with "dark" when dark option is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
const darkOption = await screen.findByRole('menuitem', { name: /dark/i });
|
||||
await user.click(darkOption);
|
||||
|
||||
expect(mockSetTheme).toHaveBeenCalledWith('dark');
|
||||
});
|
||||
|
||||
it('calls setTheme with "system" when system option is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
const systemOption = await screen.findByRole('menuitem', { name: /system/i });
|
||||
await user.click(systemOption);
|
||||
|
||||
expect(mockSetTheme).toHaveBeenCalledWith('system');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Active Theme Indicator', () => {
|
||||
it('shows checkmark for light theme when active', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
(useTheme as jest.Mock).mockReturnValue({
|
||||
theme: 'light',
|
||||
setTheme: mockSetTheme,
|
||||
resolvedTheme: 'light',
|
||||
});
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
const lightOption = await screen.findByRole('menuitem', { name: /light/i });
|
||||
expect(lightOption).toHaveTextContent('✓');
|
||||
});
|
||||
|
||||
it('shows checkmark for dark theme when active', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
(useTheme as jest.Mock).mockReturnValue({
|
||||
theme: 'dark',
|
||||
setTheme: mockSetTheme,
|
||||
resolvedTheme: 'dark',
|
||||
});
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
const darkOption = await screen.findByRole('menuitem', { name: /dark/i });
|
||||
expect(darkOption).toHaveTextContent('✓');
|
||||
});
|
||||
|
||||
it('shows checkmark for system theme when active', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
(useTheme as jest.Mock).mockReturnValue({
|
||||
theme: 'system',
|
||||
setTheme: mockSetTheme,
|
||||
resolvedTheme: 'light',
|
||||
});
|
||||
|
||||
render(<ThemeToggle />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /toggle theme/i });
|
||||
await user.click(button);
|
||||
|
||||
const systemOption = await screen.findByRole('menuitem', { name: /system/i });
|
||||
expect(systemOption).toHaveTextContent('✓');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user