Files
syndarix/frontend/tests/components/projects/ProjectCard.test.tsx
Felipe Cardoso 4f24cebf11 chore(frontend): improve code formatting for readability
Standardize multiline formatting across components, tests, and API hooks for better consistency and clarity:
- Adjusted function and object property indentation.
- Updated tests and components to align with clean coding practices.
2026-01-03 01:12:51 +01:00

106 lines
3.6 KiB
TypeScript

/**
* 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(<ProjectCard project={mockProject} />);
expect(screen.getByText('Test Project')).toBeInTheDocument();
});
it('renders project description', () => {
render(<ProjectCard project={mockProject} />);
expect(screen.getByText('This is a test project description')).toBeInTheDocument();
});
it('renders project status badge', () => {
render(<ProjectCard project={mockProject} />);
expect(screen.getByText('Active')).toBeInTheDocument();
});
it('renders current sprint', () => {
render(<ProjectCard project={mockProject} />);
// Sprint not shown in current card design, but progress is
expect(screen.getByText('65%')).toBeInTheDocument();
});
it('renders project metrics', () => {
render(<ProjectCard project={mockProject} />);
expect(screen.getByText('3')).toBeInTheDocument(); // agents
expect(screen.getByText('5')).toBeInTheDocument(); // issues
});
it('renders last activity time', () => {
render(<ProjectCard project={mockProject} />);
expect(screen.getByText('5 minutes ago')).toBeInTheDocument();
});
it('renders project tags', () => {
render(<ProjectCard project={mockProject} />);
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(<ProjectCard project={mockProject} onClick={onClick} />);
// 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(<ProjectCard project={mockProject} onAction={onAction} />);
// 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(<ProjectCard project={mockProject} />);
// 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(<ProjectCard project={mockProject} className="custom-class" />);
expect(container.querySelector('.custom-class')).toBeInTheDocument();
});
});
describe('ProjectCardSkeleton', () => {
it('renders skeleton elements', () => {
const { container } = render(<ProjectCardSkeleton />);
expect(container.querySelectorAll('.animate-pulse').length).toBeGreaterThan(0);
});
});