import React from 'react'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { render, screen, fireEvent, act } from '../../../helpers/render'; import MUserMenu from '../../../../src/mobile/screens/dashboard/MUserMenu'; import { useAuthStore } from '../../../../src/store/authStore'; import { useSettingsStore } from '../../../../src/store/settingsStore'; // FE-MOB-MENU-001 onwards function seedUser(role: 'user' | 'admin') { useAuthStore.setState({ isAuthenticated: true, user: { id: 1, username: 'Maurice', email: 'maurice@trek.app', role, avatar_url: '' } as never, }); } describe('MUserMenu', () => { beforeEach(() => { seedUser('user'); useSettingsStore.setState(s => ({ settings: { ...s.settings, dark_mode: 'dark' } })); }); it('FE-MOB-MENU-001: shows profile header and hides the admin entry for regular users', () => { render( {}} />); expect(screen.getByText('Maurice')).toBeInTheDocument(); expect(screen.getByText('maurice@trek.app')).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Settings' })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Admin Settings' })).not.toBeInTheDocument(); }); it('FE-MOB-MENU-002: shows the admin entry and badge for admins', () => { seedUser('admin'); render( {}} />); expect(screen.getByRole('button', { name: 'Admin Settings' })).toBeInTheDocument(); expect(screen.getByText('Admin')).toBeInTheDocument(); }); it('FE-MOB-MENU-003: the theme row cycles dark → light → auto', () => { const updateSetting = vi.fn(async () => {}); useSettingsStore.setState({ updateSetting }); render( {}} />); fireEvent.click(screen.getByRole('button', { name: /Color Mode/ })); expect(updateSetting).toHaveBeenCalledWith('dark_mode', 'light'); act(() => { useSettingsStore.setState(s => ({ settings: { ...s.settings, dark_mode: 'light' } })); }); fireEvent.click(screen.getByRole('button', { name: /Color Mode/ })); expect(updateSetting).toHaveBeenCalledWith('dark_mode', 'auto'); }); it('FE-MOB-MENU-004: auto cycles back to dark', () => { const updateSetting = vi.fn(async () => {}); useSettingsStore.setState({ updateSetting }); useSettingsStore.setState(s => ({ settings: { ...s.settings, dark_mode: 'auto' } })); render( {}} />); fireEvent.click(screen.getByRole('button', { name: /Color Mode/ })); expect(updateSetting).toHaveBeenCalledWith('dark_mode', 'dark'); }); it('FE-MOB-MENU-005: a legacy boolean dark_mode still resolves to dark', () => { const updateSetting = vi.fn(async () => {}); useSettingsStore.setState({ updateSetting }); useSettingsStore.setState(s => ({ settings: { ...s.settings, dark_mode: true } })); render( {}} />); fireEvent.click(screen.getByRole('button', { name: /Color Mode/ })); expect(updateSetting).toHaveBeenCalledWith('dark_mode', 'light'); }); it('FE-MOB-MENU-006: opening settings closes the menu first', () => { const onClose = vi.fn(); render(); fireEvent.click(screen.getByRole('button', { name: 'Settings' })); expect(onClose).toHaveBeenCalledTimes(1); }); it('FE-MOB-MENU-007: signing out closes the menu and clears the session', async () => { const onClose = vi.fn(); const logout = vi.fn(async () => {}); useAuthStore.setState({ logout }); render(); await act(async () => { fireEvent.click(screen.getByRole('button', { name: 'Logout' })); }); expect(onClose).toHaveBeenCalledTimes(1); expect(logout).toHaveBeenCalledTimes(1); }); it('FE-MOB-MENU-008: an uploaded avatar replaces the initial', () => { useAuthStore.setState({ isAuthenticated: true, user: { id: 1, username: 'Maurice', email: 'm@trek.app', role: 'user', avatar_url: '/uploads/avatars/m.jpg' } as never, }); const { container } = render( {}} />); expect(container.querySelector('img')).toHaveAttribute('src', '/uploads/avatars/m.jpg'); }); });