Files
syndarix/frontend/tests/components/projects/RecentActivity.test.tsx
Felipe Cardoso a4c91cb8c3 refactor(frontend): clean up code by consolidating multi-line JSX into single lines where feasible
- Refactored JSX elements to improve readability by collapsing multi-line props and attributes into single lines if their length permits.
- Improved consistency in component imports by grouping and consolidating them.
- No functional changes, purely restructuring for clarity and maintainability.
2026-01-01 11:46:57 +01:00

120 lines
4.6 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { RecentActivity } from '@/components/projects/RecentActivity';
import type { ActivityItem } from '@/components/projects/types';
const mockActivities: ActivityItem[] = [
{
id: 'act-001',
type: 'agent_message',
agent: 'Product Owner',
message: 'Approved user story #42',
timestamp: new Date().toISOString(),
},
{
id: 'act-002',
type: 'issue_update',
agent: 'Backend Engineer',
message: 'Moved issue #38 to review',
timestamp: new Date().toISOString(),
},
{
id: 'act-003',
type: 'approval_request',
agent: 'Architect',
message: 'Requesting API design approval',
timestamp: new Date().toISOString(),
requires_action: true,
},
];
describe('RecentActivity', () => {
it('renders recent activity with title', () => {
render(<RecentActivity activities={mockActivities} />);
expect(screen.getByText('Recent Activity')).toBeInTheDocument();
});
it('displays all activities', () => {
render(<RecentActivity activities={mockActivities} />);
expect(screen.getByText('Product Owner')).toBeInTheDocument();
expect(screen.getByText('Approved user story #42')).toBeInTheDocument();
expect(screen.getByText('Backend Engineer')).toBeInTheDocument();
expect(screen.getByText('Moved issue #38 to review')).toBeInTheDocument();
expect(screen.getByText('Architect')).toBeInTheDocument();
expect(screen.getByText('Requesting API design approval')).toBeInTheDocument();
});
it('renders empty state when no activities', () => {
render(<RecentActivity activities={[]} />);
expect(screen.getByText('No recent activity')).toBeInTheDocument();
});
it('shows loading skeleton when isLoading is true', () => {
const { container } = render(<RecentActivity activities={[]} isLoading />);
expect(container.querySelectorAll('.animate-pulse').length).toBeGreaterThan(0);
});
it('respects maxItems prop', () => {
render(<RecentActivity activities={mockActivities} maxItems={2} />);
expect(screen.getByText('Product Owner')).toBeInTheDocument();
expect(screen.getByText('Backend Engineer')).toBeInTheDocument();
expect(screen.queryByText('Architect')).not.toBeInTheDocument();
});
it('shows View All button when there are more activities than maxItems', () => {
const onViewAll = jest.fn();
render(<RecentActivity activities={mockActivities} maxItems={2} onViewAll={onViewAll} />);
expect(screen.getByRole('button', { name: /view all/i })).toBeInTheDocument();
});
it('does not show View All button when all activities are shown', () => {
const onViewAll = jest.fn();
render(<RecentActivity activities={mockActivities} maxItems={5} onViewAll={onViewAll} />);
expect(screen.queryByRole('button', { name: /view all/i })).not.toBeInTheDocument();
});
it('calls onViewAll when View All button is clicked', async () => {
const user = userEvent.setup();
const onViewAll = jest.fn();
render(<RecentActivity activities={mockActivities} maxItems={2} onViewAll={onViewAll} />);
await user.click(screen.getByRole('button', { name: /view all/i }));
expect(onViewAll).toHaveBeenCalledTimes(1);
});
it('shows Review Request button for items requiring action', () => {
const onActionClick = jest.fn();
render(<RecentActivity activities={mockActivities} onActionClick={onActionClick} />);
expect(screen.getByRole('button', { name: /review request/i })).toBeInTheDocument();
});
it('calls onActionClick when Review Request button is clicked', async () => {
const user = userEvent.setup();
const onActionClick = jest.fn();
render(<RecentActivity activities={mockActivities} onActionClick={onActionClick} />);
await user.click(screen.getByRole('button', { name: /review request/i }));
expect(onActionClick).toHaveBeenCalledWith('act-003');
});
it('highlights activities requiring action', () => {
render(<RecentActivity activities={mockActivities} />);
const activityItem = screen.getByTestId('activity-item-act-003');
const iconContainer = activityItem.querySelector('.bg-yellow-100');
expect(iconContainer).toBeInTheDocument();
});
it('applies custom className', () => {
render(<RecentActivity activities={mockActivities} className="custom-class" />);
expect(screen.getByTestId('recent-activity')).toHaveClass('custom-class');
});
it('has accessible list role', () => {
render(<RecentActivity activities={mockActivities} />);
expect(screen.getByRole('list', { name: /recent project activity/i })).toBeInTheDocument();
});
});