/** * Tests for the UserDropdown component * @jest-environment jsdom */ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { UserDropdown } from '@/components/UserDropdown'; // Mock next/link jest.mock('next/link', () => { const MockLink = ({ children, href }: { children: React.ReactNode; href: string }) => ( {children} ); MockLink.displayName = 'MockLink'; return MockLink; }); describe('UserDropdown', () => { const mockUser = { firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com', }; const mockOnLogout = jest.fn(); beforeEach(() => { jest.clearAllMocks(); }); it('should render user initials', () => { render( ); expect(screen.getByText('JD')).toBeInTheDocument(); }); it('should render user name and email', () => { render( ); expect(screen.getByText('John Doe')).toBeInTheDocument(); expect(screen.getByText('john.doe@example.com')).toBeInTheDocument(); }); it('should toggle dropdown on click', () => { render( ); // Dropdown should be closed initially expect(screen.queryByText('Profil')).not.toBeInTheDocument(); // Click to open - get the main trigger button (contains user name) const triggerButton = screen.getByText('John Doe').closest('button'); fireEvent.click(triggerButton!); expect(screen.getByText('Profil')).toBeInTheDocument(); expect(screen.getByText('Deconnexion')).toBeInTheDocument(); // Click to close fireEvent.click(triggerButton!); expect(screen.queryByText('Profil')).not.toBeInTheDocument(); }); it('should render profile link with correct path', () => { render( ); const triggerButton = screen.getByText('John Doe').closest('button'); fireEvent.click(triggerButton!); const profileLink = screen.getByText('Profil').closest('a'); expect(profileLink).toHaveAttribute('href', '/admin/profil'); }); it('should call onLogout when logout button is clicked', () => { render( ); const triggerButton = screen.getByText('John Doe').closest('button'); fireEvent.click(triggerButton!); fireEvent.click(screen.getByText('Deconnexion')); expect(mockOnLogout).toHaveBeenCalledTimes(1); }); it('should have onClick handler on profile link', () => { render( ); const triggerButton = screen.getByText('John Doe').closest('button'); fireEvent.click(triggerButton!); const profileLink = screen.getByText('Profil').closest('a'); expect(profileLink).toBeInTheDocument(); expect(profileLink).toHaveAttribute('href', '/profil'); }); it('should apply blue accent color by default', () => { const { container } = render( ); const avatar = container.querySelector('.bg-blue-600'); expect(avatar).toBeInTheDocument(); }); it('should apply green accent color when specified', () => { const { container } = render( ); const avatar = container.querySelector('.bg-green-600'); expect(avatar).toBeInTheDocument(); }); it('should handle null user gracefully', () => { const { container } = render( ); // Should render empty initials const avatarDiv = container.querySelector('.bg-blue-600'); expect(avatarDiv).toBeInTheDocument(); }); it('should handle user with missing firstName', () => { render( ); expect(screen.getByText('D')).toBeInTheDocument(); }); it('should apply custom className', () => { const { container } = render( ); expect(container.firstChild).toHaveClass('custom-class'); }); it('should rotate chevron icon when dropdown is open', () => { const { container } = render( ); const chevron = container.querySelector('.w-4.h-4.text-gray-500'); expect(chevron).not.toHaveClass('rotate-180'); const triggerButton = screen.getByText('John Doe').closest('button'); fireEvent.click(triggerButton!); const rotatedChevron = container.querySelector('.rotate-180'); expect(rotatedChevron).toBeInTheDocument(); }); });