import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { Header } from '../Header'; import { useAuthStore } from '@/stores/authStore'; import { usePathname } from 'next/navigation'; // Mock Next.js navigation jest.mock('next/navigation', () => ({ usePathname: jest.fn(), })); // Mock auth store jest.mock('@/stores/authStore', () => ({ useAuthStore: jest.fn(), })); describe('Header Component', () => { const mockLogout = jest.fn(); const mockUser = { user_id: 1, email: 'test@example.com', firstName: 'John', lastName: 'Doe', }; beforeEach(() => { jest.clearAllMocks(); (usePathname as jest.Mock).mockReturnValue('/dashboard'); (useAuthStore as unknown as jest.Mock).mockReturnValue({ user: mockUser, logout: mockLogout, }); }); it('renders the WellNuo logo and brand', () => { render(
); expect(screen.getByText('WellNuo')).toBeInTheDocument(); }); it('renders navigation items', () => { render(
); expect(screen.getAllByText('Dashboard')).toHaveLength(1); expect(screen.getAllByText('Loved Ones')).toHaveLength(1); }); it('highlights active navigation item', () => { render(
); const dashboardLink = screen.getAllByText('Dashboard')[0].closest('a'); expect(dashboardLink).toHaveClass('text-blue-600'); }); it('displays user initials in profile button', () => { render(
); // Desktop profile button shows initials expect(screen.getByText('JD')).toBeInTheDocument(); }); it('displays user full name on desktop', () => { render(
); expect(screen.getByText('John Doe')).toBeInTheDocument(); }); it('opens profile dropdown when clicked', async () => { render(
); // Get profile button (not the mobile menu button) const buttons = screen.getAllByRole('button', { expanded: false }); const profileButton = buttons.find(btn => btn.getAttribute('aria-haspopup') === 'true'); if (!profileButton) throw new Error('Profile button not found'); fireEvent.click(profileButton); await waitFor(() => { expect(screen.getByText('Profile Settings')).toBeInTheDocument(); expect(screen.getByText('Sign Out')).toBeInTheDocument(); }); }); it('calls logout when Sign Out is clicked in dropdown', async () => { render(
); // Open dropdown const buttons = screen.getAllByRole('button', { expanded: false }); const profileButton = buttons.find(btn => btn.getAttribute('aria-haspopup') === 'true'); if (!profileButton) throw new Error('Profile button not found'); fireEvent.click(profileButton); // Click Sign Out in dropdown (not mobile menu) await waitFor(() => { const signOutButtons = screen.getAllByRole('button', { name: /sign out/i }); fireEvent.click(signOutButtons[0]); }); expect(mockLogout).toHaveBeenCalled(); }); it('toggles mobile menu', async () => { render(
); const menuButton = screen.getByLabelText('Toggle menu'); fireEvent.click(menuButton); await waitFor(() => { // Mobile menu should show navigation items expect(screen.getByText('Profile Settings')).toBeInTheDocument(); }); // Close menu fireEvent.click(menuButton); }); it('displays user email when no first/last name', () => { (useAuthStore as unknown as jest.Mock).mockReturnValue({ user: { user_id: 1, email: 'test@example.com' }, logout: mockLogout, }); render(
); // Email displayed in profile section expect(screen.getByText('test@example.com')).toBeInTheDocument(); }); it('displays fallback initials when no user data', () => { (useAuthStore as unknown as jest.Mock).mockReturnValue({ user: { user_id: 1 }, logout: mockLogout, }); render(
); expect(screen.getByText('?')).toBeInTheDocument(); }); it('closes dropdown when clicking outside', async () => { render(
); // Open dropdown const buttons = screen.getAllByRole('button', { expanded: false }); const profileButton = buttons.find(btn => btn.getAttribute('aria-haspopup') === 'true'); if (!profileButton) throw new Error('Profile button not found'); fireEvent.click(profileButton); await waitFor(() => { expect(screen.getByText('Profile Settings')).toBeInTheDocument(); }); // Click outside fireEvent.mouseDown(document.body); await waitFor(() => { expect(screen.queryByText('Profile Settings')).not.toBeInTheDocument(); }); }); });