the-tip-top-frontend/__tests__/components/UserDropdown.test.tsx
soufiane 79b579ae55 fix: add displayName to MockLink in UserDropdown test
Fixes ESLint react/display-name error by adding displayName
property to the MockLink component in the jest mock.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 21:57:51 +01:00

214 lines
5.4 KiB
TypeScript

/**
* 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 }) => (
<a href={href}>{children}</a>
);
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(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
expect(screen.getByText('JD')).toBeInTheDocument();
});
it('should render user name and email', () => {
render(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('john.doe@example.com')).toBeInTheDocument();
});
it('should toggle dropdown on click', () => {
render(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
// 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(
<UserDropdown
user={mockUser}
profilePath="/admin/profil"
onLogout={mockOnLogout}
/>
);
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(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
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(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
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(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
const avatar = container.querySelector('.bg-blue-600');
expect(avatar).toBeInTheDocument();
});
it('should apply green accent color when specified', () => {
const { container } = render(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
accentColor="green"
/>
);
const avatar = container.querySelector('.bg-green-600');
expect(avatar).toBeInTheDocument();
});
it('should handle null user gracefully', () => {
const { container } = render(
<UserDropdown
user={null}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
// Should render empty initials
const avatarDiv = container.querySelector('.bg-blue-600');
expect(avatarDiv).toBeInTheDocument();
});
it('should handle user with missing firstName', () => {
render(
<UserDropdown
user={{ lastName: 'Doe', email: 'test@test.com' }}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
expect(screen.getByText('D')).toBeInTheDocument();
});
it('should apply custom className', () => {
const { container } = render(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
className="custom-class"
/>
);
expect(container.firstChild).toHaveClass('custom-class');
});
it('should rotate chevron icon when dropdown is open', () => {
const { container } = render(
<UserDropdown
user={mockUser}
profilePath="/profil"
onLogout={mockOnLogout}
/>
);
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();
});
});