ThemeSwitch Tests
The ThemeSwitch component has 7 tests covering rendering, icon display, theme toggling, hook integration, and edge cases.
Test file location
src/components/ThemeSwitch.test.jsx
Running the tests
# Run all tests
npm test
# Run only ThemeSwitch tests
npm test -- ThemeSwitch.test.jsx
# Run tests in watch mode
npm test -- --watch ThemeSwitch.test.jsx
Test organization
1. Rendering & accessibility (2 tests)
- Renders a switch with the correct aria-label based on the theme (light → "switch to dark mode", dark → "switch to light mode")
- Uses
type="button"androle="switch"with properaria-checked
2. Icon display based on theme (2 tests)
- Shows Moon icon for light theme
- Shows Sun icon for dark theme
3. Theme toggling functionality (2 tests)
- Calls
toggleThemewhen clicked - Is keyboard accessible (focusable)
4. Integration with useTheme hook (1 test)
- Uses the
toggleThemefunction provided by the hook
5. Edge cases (1 test)
- Defaults to Moon icon when theme is undefined or falsy
Mocking strategy
- useTheme hook: mocked with
vi.spyOnto control theme and toggle function - Lucide icons: mocked with test spans for Moon/Sun icons (for easy querying)
Example test snippets
Rendering switch with light theme
vi.spyOn(useThemeModule, 'useTheme').mockReturnValue({ theme: 'light', toggleTheme: mockToggleTheme });
render(<ThemeSwitch />);
const button = screen.getByRole('switch', { name: 'switch to dark mode' });
expect(button).toBeInTheDocument();
expect(button).toHaveAttribute('type', 'button');
Testing icon display
const moonIcon = screen.getByTestId('moon-icon');
expect(moonIcon).toBeInTheDocument();
expect(screen.queryByTestId('sun-icon')).not.toBeInTheDocument();
Testing toggleTheme
const button = screen.getByRole('switch', { name: 'switch to dark mode' });
fireEvent.click(button);
expect(mockToggleTheme).toHaveBeenCalledTimes(1);
Edge case: undefined theme
vi.spyOn(useThemeModule, 'useTheme').mockReturnValue({ theme: undefined, toggleTheme: mockToggleTheme });
render(<ThemeSwitch />);
expect(screen.getByTestId('moon-icon')).toBeInTheDocument();
Test utilities
- Vitest - Test framework
- React Testing Library - Component rendering & queries
- vi.fn() / vi.spyOn() - Mocking
- fireEvent - User interactions
Coverage
- Component rendering (light/dark themes)
- User interactions (click, keyboard)
- Edge cases (undefined/falsy theme)
- Integration with hook
- Accessibility (aria-labels, focus)
- CSS class application
Best practices
- Isolation via mocking
- Accessibility testing
- Edge case handling
- Clear test organization
- Setup/teardown with beforeEach/afterEach