import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import userEvent from '@testing-library/user-event';
import { List, ListItem } from './List';
describe('List Component', () => {
const mockItems: ListItem[] = [
{
id: '1',
content: 'Item 1',
onClick: vi.fn(),
},
{
id: '2',
content: 'Item 2',
actions: ,
},
{
id: '3',
content: 'Item 3',
},
];
beforeEach(() => {
vi.clearAllMocks();
});
it('renders list items', () => {
render();
expect(screen.getByText('Item 1')).toBeInTheDocument();
expect(screen.getByText('Item 2')).toBeInTheDocument();
expect(screen.getByText('Item 3')).toBeInTheDocument();
});
it('renders empty message when items array is empty', () => {
render(
);
expect(screen.getByText('No items found')).toBeInTheDocument();
});
it('returns null when items array is empty and no empty message', () => {
const { container } = render(
);
expect(container.firstChild).toBeNull();
});
it('calls onClick when item is clicked', async () => {
const user = userEvent.setup();
const mockOnClick = vi.fn();
const itemsWithClick: ListItem[] = [
{
id: '1',
content: 'Clickable Item',
onClick: mockOnClick,
},
];
render(
);
const item = screen.getByText('Clickable Item');
await user.click(item);
expect(mockOnClick).toHaveBeenCalledTimes(1);
});
it('does not call onClick when item is disabled', async () => {
const user = userEvent.setup();
const mockOnClick = vi.fn();
const itemsWithDisabled: ListItem[] = [
{
id: '1',
content: 'Disabled Item',
onClick: mockOnClick,
disabled: true,
},
];
render(
);
const item = screen.getByText('Disabled Item');
await user.click(item);
expect(mockOnClick).not.toHaveBeenCalled();
});
it('renders actions on items', () => {
render(
);
const actionButton = screen.getByText('Action');
expect(actionButton).toBeInTheDocument();
});
it('does not trigger item onClick when clicking actions', async () => {
const user = userEvent.setup();
const mockOnClick = vi.fn();
const itemsWithActions: ListItem[] = [
{
id: '1',
content: 'Item with Actions',
actions: ,
onClick: mockOnClick,
},
];
render(
);
const actionButton = screen.getByText('Action');
await user.click(actionButton);
expect(mockOnClick).not.toHaveBeenCalled();
});
it('applies default variant styles', () => {
const { container } = render(
);
const list = container.querySelector('ul');
expect(list).toHaveClass('space-y-1');
});
it('applies bordered variant styles', () => {
const { container } = render(
);
const list = container.querySelector('ul');
expect(list).toHaveClass('border');
expect(list).toHaveClass('divide-y');
expect(list).toHaveClass('rounded-md');
});
it('applies spaced variant styles', () => {
const { container } = render(
);
const list = container.querySelector('ul');
expect(list).toHaveClass('space-y-2');
});
it('applies custom className', () => {
const { container } = render(
,
);
const list = container.querySelector('ul');
expect(list).toHaveClass('custom-class');
});
it('applies custom itemClassName', () => {
const { container } = render(
,
);
const firstItem = container.querySelector('li');
expect(firstItem).toHaveClass('custom-item-class');
});
it('applies hover styles when item is clickable', () => {
const clickableItems: ListItem[] = [
{
id: '1',
content: 'Clickable',
onClick: vi.fn(),
},
];
const { container } = render(
);
const item = container.querySelector('li');
expect(item).toHaveClass('cursor-pointer');
expect(item).toHaveClass('hover:bg-accent');
});
it('applies disabled styles when item is disabled', () => {
const disabledItems: ListItem[] = [
{
id: '1',
content: 'Disabled',
disabled: true,
},
];
const { container } = render(
);
const item = container.querySelector('li');
expect(item).toHaveClass('cursor-not-allowed');
expect(item).toHaveClass('opacity-50');
});
it('renders items with complex content', () => {
const complexItems: ListItem[] = [
{
id: '1',
content: (
Description