import type { MenuItemProps } from './menu-item' import { fireEvent, render, screen } from '@testing-library/react' import MenuItem from './menu-item' const MockIcon = (props: React.SVGProps) => const defaultProps: MenuItemProps = { icon: MockIcon, label: 'Rename', onClick: vi.fn(), } const renderMenuItem = (overrides: Partial = {}) => { const props = { ...defaultProps, ...overrides } return { ...render(), onClick: props.onClick, } } describe('MenuItem', () => { beforeEach(() => { vi.clearAllMocks() }) // Menu item should render its interactive label and style variants. describe('Rendering', () => { it('should render a button with the provided label', () => { // Arrange renderMenuItem() // Assert expect(screen.getByRole('button', { name: /rename/i })).toBeInTheDocument() }) it('should apply destructive variant styles when variant is destructive', () => { // Arrange renderMenuItem({ variant: 'destructive', label: 'Delete' }) // Act const button = screen.getByRole('button', { name: /delete/i }) // Assert expect(button).toHaveClass('group') expect(button).toHaveClass('hover:bg-state-destructive-hover') }) }) // Optional props should alter the visible content. describe('Props', () => { it('should render keyboard shortcut hints when kbd has values', () => { // Arrange renderMenuItem({ kbd: ['k'] }) // Assert expect(screen.getByText('k')).toBeInTheDocument() }) it('should not render keyboard shortcut hints when kbd is empty', () => { // Arrange renderMenuItem({ kbd: [] }) // Assert expect(screen.queryByText('k')).not.toBeInTheDocument() }) it('should show tooltip content when hovering the tooltip trigger', async () => { // Arrange const tooltipText = 'Show help' const { container } = renderMenuItem({ tooltip: tooltipText }) const tooltipIcon = container.querySelector('.i-ri-question-line') // Act expect(tooltipIcon).toBeTruthy() fireEvent.mouseEnter(tooltipIcon!) // Assert expect(await screen.findByText(tooltipText)).toBeInTheDocument() }) }) // Click handling should call actions without leaking events upward. describe('Interactions', () => { it('should call onClick and stop click propagation when button is clicked', () => { // Arrange const outerClick = vi.fn() const onClick = vi.fn() render(
, ) // Act fireEvent.click(screen.getByRole('button', { name: /rename/i })) // Assert expect(onClick).toHaveBeenCalledTimes(1) expect(outerClick).not.toHaveBeenCalled() }) it('should not trigger onClick when tooltip icon is clicked', () => { // Arrange const onClick = vi.fn() const { container } = renderMenuItem({ onClick, tooltip: 'Help' }) const tooltipIcon = container.querySelector('.i-ri-question-line') // Act expect(tooltipIcon).toBeTruthy() fireEvent.click(tooltipIcon!) // Assert expect(onClick).not.toHaveBeenCalled() }) }) // Disabled state should block interaction. describe('Edge cases', () => { it('should disable the button and ignore click when disabled is true', () => { // Arrange const onClick = vi.fn() renderMenuItem({ onClick, disabled: true }) const button = screen.getByRole('button', { name: /rename/i }) // Act fireEvent.click(button) // Assert expect(button).toBeDisabled() expect(onClick).not.toHaveBeenCalled() }) }) })