diff --git a/src/components/theme-toggle/ThemeToggle.test.tsx b/src/components/theme-toggle/ThemeToggle.test.tsx
index c2b7373..4e3ca4e 100644
--- a/src/components/theme-toggle/ThemeToggle.test.tsx
+++ b/src/components/theme-toggle/ThemeToggle.test.tsx
@@ -49,7 +49,7 @@ describe("ThemeToggle component", () => {
});
- it('should display dark icon when in system mode and effective theme is dark', async () => {
+ it('should display system icon when theme is system', async () => {
mockedUseTheme.mockReturnValue({
theme: Theme.SYSTEM,
setTheme: vi.fn(),
@@ -59,8 +59,8 @@ describe("ThemeToggle component", () => {
await act(async () => {
render();
});
-
- expect(screen.getByText('🌙')).toBeInTheDocument();
+ expect(screen.getByText('💻')).toBeInTheDocument();
+ expect(screen.queryByText('🌙')).not.toBeInTheDocument();
expect(screen.queryByText('☀️️')).not.toBeInTheDocument();
});
@@ -75,8 +75,9 @@ describe("ThemeToggle component", () => {
render();
});
- expect(screen.getByText('☀️')).toBeInTheDocument();
+ expect(screen.getByText('💻')).toBeInTheDocument();
expect(screen.queryByText('🌙')).not.toBeInTheDocument();
+ expect(screen.queryByText('☀️')).not.toBeInTheDocument();
});
it('should show all options when the dropdown is opened', async () => {
@@ -106,4 +107,59 @@ describe("ThemeToggle component", () => {
expect(lightOption).not.toHaveClass('themeOption--active');
expect(systemOption).not.toHaveClass('themeOption--active');
});
+
+ it('should not show the dropdown on initial render', async () => {
+ await act(async () => {
+ render();
+ });
+
+ expect(screen.queryByText('Light')).not.toBeInTheDocument();
+ expect(screen.queryByText('Dark')).not.toBeInTheDocument();
+ expect(screen.queryByText('System')).not.toBeInTheDocument();
+ });
+
+ it('should call setTheme with the selected value and close the dropdown', async () => {
+ const setTheme = vi.fn();
+ mockedUseTheme.mockReturnValue({
+ theme: Theme.DARK,
+ setTheme,
+ getEffectiveTheme: vi.fn(() => Theme.DARK),
+ });
+
+ await act(async () => {
+ render();
+ });
+
+ fireEvent.click(screen.getByRole('button', { name: '🌙' }));
+ fireEvent.click(screen.getByText('Light').closest('button')!);
+
+ expect(setTheme).toHaveBeenCalledWith(Theme.LIGHT);
+ expect(screen.queryByText('Light')).not.toBeInTheDocument();
+ });
+
+ it('should close the dropdown when clicking outside', async () => {
+ await act(async () => {
+ render();
+ });
+
+ fireEvent.click(screen.getByRole('button', { name: '🌙' }));
+ expect(screen.getByText('Light')).toBeInTheDocument();
+
+ fireEvent.mouseDown(document.body);
+ expect(screen.queryByText('Light')).not.toBeInTheDocument();
+ });
+
+ it('should show a checkmark only on the active theme option', async () => {
+ await act(async () => {
+ render();
+ });
+
+ fireEvent.click(screen.getByRole('button', { name: '🌙' }));
+
+ const darkOption = screen.getByText('Dark').closest('button')!;
+ const lightOption = screen.getByText('Light').closest('button')!;
+
+ expect(darkOption).toHaveTextContent('✓');
+ expect(lightOption).not.toHaveTextContent('✓');
+ });
});
diff --git a/src/components/theme-toggle/ThemeToggle.tsx b/src/components/theme-toggle/ThemeToggle.tsx
index 7c825a4..319f442 100644
--- a/src/components/theme-toggle/ThemeToggle.tsx
+++ b/src/components/theme-toggle/ThemeToggle.tsx
@@ -1,14 +1,14 @@
import {useEffect, useRef, useState} from "react";
import {useTheme} from "../../context/hooks.tsx";
-import {Theme} from "../../context/theme/ThemeContextTypes.ts";
import {THEME_OPTIONS} from "../../constants/Theme.ts";
import styles from "./ThemeToggle.module.css"
export function ThemeToggle() {
- const { theme, setTheme, getEffectiveTheme } = useTheme();
+ const { theme, setTheme } = useTheme();
const [themeMenuOpen, setThemeMenuOpen] = useState(false);
const themeMenuRef = useRef(null);
- const themeIcon = getEffectiveTheme() === Theme.DARK ? '🌙' : '☀️';
+ const themeIcon = THEME_OPTIONS.find(o => o.value === theme)?.icon;
+
useEffect(() => {
if (!themeMenuOpen) return;