/** * ProjectCard Component Tests */ import { render, screen, fireEvent } from '@testing-library/react'; import { ProjectCard, ProjectCardSkeleton } from '@/components/projects/ProjectCard'; import type { ProjectListItem } from '@/lib/api/hooks/useProjects'; describe('ProjectCard', () => { const mockProject: ProjectListItem = { id: 'proj-1', name: 'Test Project', description: 'This is a test project description', status: 'active', complexity: 'medium', progress: 65, openIssues: 5, activeAgents: 3, currentSprint: 'Sprint 2', lastActivity: '5 minutes ago', createdAt: '2025-01-01T00:00:00Z', owner: { id: 'user-1', name: 'Test User' }, tags: ['frontend', 'react', 'typescript'], }; it('renders project name', () => { render(); expect(screen.getByText('Test Project')).toBeInTheDocument(); }); it('renders project description', () => { render(); expect(screen.getByText('This is a test project description')).toBeInTheDocument(); }); it('renders project status badge', () => { render(); expect(screen.getByText('Active')).toBeInTheDocument(); }); it('renders current sprint', () => { render(); // Sprint not shown in current card design, but progress is expect(screen.getByText('65%')).toBeInTheDocument(); }); it('renders project metrics', () => { render(); expect(screen.getByText('3')).toBeInTheDocument(); // agents expect(screen.getByText('5')).toBeInTheDocument(); // issues }); it('renders last activity time', () => { render(); expect(screen.getByText('5 minutes ago')).toBeInTheDocument(); }); it('renders project tags', () => { render(); expect(screen.getByText('frontend')).toBeInTheDocument(); expect(screen.getByText('react')).toBeInTheDocument(); expect(screen.getByText('typescript')).toBeInTheDocument(); }); it('calls onClick when card is clicked', () => { const onClick = jest.fn(); render(); // Click the card (first button, which is the card itself) const buttons = screen.getAllByRole('button'); fireEvent.click(buttons[0]); expect(onClick).toHaveBeenCalledTimes(1); }); it('renders action menu when onAction is provided', () => { const onAction = jest.fn(); render(); // Menu button should exist with sr-only text const menuButtons = screen.getAllByRole('button'); const menuButton = menuButtons.find((btn) => btn.querySelector('.sr-only')); expect(menuButton).toBeDefined(); expect(menuButton!.querySelector('.sr-only')).toHaveTextContent('Project actions'); }); it('does not render action menu when onAction is not provided', () => { render(); // Only the card itself should be a button const buttons = screen.getAllByRole('button'); expect(buttons.length).toBe(1); }); it('applies custom className', () => { const { container } = render(); expect(container.querySelector('.custom-class')).toBeInTheDocument(); }); }); describe('ProjectCardSkeleton', () => { it('renders skeleton elements', () => { const { container } = render(); expect(container.querySelectorAll('.animate-pulse').length).toBeGreaterThan(0); }); });