test(frontend): add unit tests for Projects list components
Add comprehensive test coverage for projects list components: - ProjectCard.test.tsx: Card rendering, status badges, actions menu - ProjectFilters.test.tsx: Search, filters, view mode toggle - ProjectsGrid.test.tsx: Grid/list layout, loading, empty states 30 tests covering rendering, interactions, and edge cases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
107
frontend/tests/components/projects/ProjectsGrid.test.tsx
Normal file
107
frontend/tests/components/projects/ProjectsGrid.test.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* ProjectsGrid Component Tests
|
||||
*/
|
||||
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { ProjectsGrid } from '@/components/projects/ProjectsGrid';
|
||||
import type { ProjectListItem } from '@/lib/api/hooks/useProjects';
|
||||
|
||||
// Mock next-intl navigation
|
||||
jest.mock('@/lib/i18n/routing', () => ({
|
||||
Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
|
||||
<a href={href}>{children}</a>
|
||||
),
|
||||
}));
|
||||
|
||||
describe('ProjectsGrid', () => {
|
||||
const mockProjects: ProjectListItem[] = [
|
||||
{
|
||||
id: 'proj-1',
|
||||
name: 'Project One',
|
||||
description: 'First project',
|
||||
status: 'active',
|
||||
complexity: 'medium',
|
||||
progress: 50,
|
||||
openIssues: 5,
|
||||
activeAgents: 2,
|
||||
lastActivity: '5 min ago',
|
||||
createdAt: '2025-01-01T00:00:00Z',
|
||||
owner: { id: 'user-1', name: 'User One' },
|
||||
},
|
||||
{
|
||||
id: 'proj-2',
|
||||
name: 'Project Two',
|
||||
description: 'Second project',
|
||||
status: 'paused',
|
||||
complexity: 'high',
|
||||
progress: 75,
|
||||
openIssues: 3,
|
||||
activeAgents: 0,
|
||||
lastActivity: '1 day ago',
|
||||
createdAt: '2025-01-02T00:00:00Z',
|
||||
owner: { id: 'user-2', name: 'User Two' },
|
||||
},
|
||||
];
|
||||
|
||||
it('renders project cards', () => {
|
||||
render(<ProjectsGrid projects={mockProjects} />);
|
||||
|
||||
expect(screen.getByText('Project One')).toBeInTheDocument();
|
||||
expect(screen.getByText('Project Two')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders in grid layout by default', () => {
|
||||
const { container } = render(<ProjectsGrid projects={mockProjects} />);
|
||||
|
||||
// Should have grid classes
|
||||
expect(container.firstChild).toHaveClass('grid');
|
||||
});
|
||||
|
||||
it('renders in list layout when viewMode is list', () => {
|
||||
const { container } = render(<ProjectsGrid projects={mockProjects} viewMode="list" />);
|
||||
|
||||
// Should have space-y-4 class for list view
|
||||
expect(container.firstChild).toHaveClass('space-y-4');
|
||||
});
|
||||
|
||||
it('shows loading skeletons when isLoading is true', () => {
|
||||
const { container } = render(<ProjectsGrid projects={[]} isLoading />);
|
||||
|
||||
// Should render skeleton cards
|
||||
expect(container.querySelectorAll('.animate-pulse').length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('shows empty state when no projects and no filters', () => {
|
||||
render(<ProjectsGrid projects={[]} hasFilters={false} />);
|
||||
|
||||
expect(screen.getByText('No projects found')).toBeInTheDocument();
|
||||
expect(screen.getByText('Get started by creating your first project')).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: /Create Project/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows filter-adjusted empty state when no projects with filters', () => {
|
||||
render(<ProjectsGrid projects={[]} hasFilters={true} />);
|
||||
|
||||
expect(screen.getByText('No projects found')).toBeInTheDocument();
|
||||
expect(screen.getByText('Try adjusting your filters or search query')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onProjectClick when project card is clicked', () => {
|
||||
const onProjectClick = jest.fn();
|
||||
render(<ProjectsGrid projects={mockProjects} onProjectClick={onProjectClick} />);
|
||||
|
||||
// Click on the first project card
|
||||
const projectCards = screen.getAllByRole('button');
|
||||
fireEvent.click(projectCards[0]);
|
||||
|
||||
expect(onProjectClick).toHaveBeenCalledWith(mockProjects[0]);
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<ProjectsGrid projects={mockProjects} className="custom-class" />
|
||||
);
|
||||
|
||||
expect(container.firstChild).toHaveClass('custom-class');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user