forked from cardosofelipe/fast-next-template
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.
This commit is contained in:
@@ -245,7 +245,10 @@ describe('HomePage', () => {
|
||||
const githubLinks = screen.getAllByRole('link', { name: /GitHub/i });
|
||||
expect(githubLinks.length).toBeGreaterThan(0);
|
||||
// Syndarix uses Gitea for version control
|
||||
expect(githubLinks[0]).toHaveAttribute('href', expect.stringContaining('gitea.pragmazest.com'));
|
||||
expect(githubLinks[0]).toHaveAttribute(
|
||||
'href',
|
||||
expect.stringContaining('gitea.pragmazest.com')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -356,9 +356,7 @@ describe('ActivityFeed', () => {
|
||||
await user.click(within(eventItem).getByTestId('approve-button'));
|
||||
|
||||
expect(onApprove).toHaveBeenCalledTimes(1);
|
||||
expect(onApprove).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ id: 'event-001' })
|
||||
);
|
||||
expect(onApprove).toHaveBeenCalledWith(expect.objectContaining({ id: 'event-001' }));
|
||||
});
|
||||
|
||||
it('calls onReject when reject button clicked', async () => {
|
||||
@@ -370,9 +368,7 @@ describe('ActivityFeed', () => {
|
||||
await user.click(within(eventItem).getByTestId('reject-button'));
|
||||
|
||||
expect(onReject).toHaveBeenCalledTimes(1);
|
||||
expect(onReject).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ id: 'event-001' })
|
||||
);
|
||||
expect(onReject).toHaveBeenCalledWith(expect.objectContaining({ id: 'event-001' }));
|
||||
});
|
||||
|
||||
it('shows pending count badge', () => {
|
||||
@@ -440,9 +436,7 @@ describe('ActivityFeed', () => {
|
||||
await user.click(screen.getByTestId('event-item-event-001'));
|
||||
|
||||
expect(onEventClick).toHaveBeenCalledTimes(1);
|
||||
expect(onEventClick).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ id: 'event-001' })
|
||||
);
|
||||
expect(onEventClick).toHaveBeenCalledWith(expect.objectContaining({ id: 'event-001' }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -459,7 +453,9 @@ describe('ActivityFeed', () => {
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('has proper ARIA labels for interactive elements', () => {
|
||||
render(<ActivityFeed {...defaultProps} onReconnect={jest.fn()} connectionState="disconnected" />);
|
||||
render(
|
||||
<ActivityFeed {...defaultProps} onReconnect={jest.fn()} connectionState="disconnected" />
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('Reconnect')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -160,9 +160,7 @@ describe('AgentTypeDetail', () => {
|
||||
it('shows not found state when agentType is null', () => {
|
||||
render(<AgentTypeDetail {...defaultProps} agentType={null} isLoading={false} />);
|
||||
expect(screen.getByText('Agent type not found')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('The requested agent type could not be found')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('The requested agent type could not be found')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows danger zone with deactivate button', () => {
|
||||
@@ -191,9 +189,7 @@ describe('AgentTypeDetail', () => {
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<AgentTypeDetail {...defaultProps} className="custom-class" />
|
||||
);
|
||||
const { container } = render(<AgentTypeDetail {...defaultProps} className="custom-class" />);
|
||||
expect(container.firstChild).toHaveClass('custom-class');
|
||||
});
|
||||
|
||||
@@ -205,18 +201,13 @@ describe('AgentTypeDetail', () => {
|
||||
});
|
||||
|
||||
it('shows no expertise message when expertise is empty', () => {
|
||||
render(
|
||||
<AgentTypeDetail {...defaultProps} agentType={{ ...mockAgentType, expertise: [] }} />
|
||||
);
|
||||
render(<AgentTypeDetail {...defaultProps} agentType={{ ...mockAgentType, expertise: [] }} />);
|
||||
expect(screen.getByText('No expertise areas defined')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows "None configured" when no fallback model', () => {
|
||||
render(
|
||||
<AgentTypeDetail
|
||||
{...defaultProps}
|
||||
agentType={{ ...mockAgentType, fallback_models: [] }}
|
||||
/>
|
||||
<AgentTypeDetail {...defaultProps} agentType={{ ...mockAgentType, fallback_models: [] }} />
|
||||
);
|
||||
expect(screen.getByText('None configured')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -36,9 +36,7 @@ describe('AgentTypeForm', () => {
|
||||
it('renders create form title', () => {
|
||||
render(<AgentTypeForm {...defaultProps} />);
|
||||
expect(screen.getByText('Create Agent Type')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Define a new agent type template')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('Define a new agent type template')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders all tabs', () => {
|
||||
@@ -233,9 +231,7 @@ describe('AgentTypeForm', () => {
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<AgentTypeForm {...defaultProps} className="custom-class" />
|
||||
);
|
||||
const { container } = render(<AgentTypeForm {...defaultProps} className="custom-class" />);
|
||||
expect(container.querySelector('form')).toHaveClass('custom-class');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -143,15 +143,11 @@ describe('AgentTypeList', () => {
|
||||
it('shows empty state when no agent types', () => {
|
||||
render(<AgentTypeList {...defaultProps} agentTypes={[]} />);
|
||||
expect(screen.getByText('No agent types found')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Create your first agent type to get started')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('Create your first agent type to get started')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows filter hint in empty state when filters are applied', () => {
|
||||
render(
|
||||
<AgentTypeList {...defaultProps} agentTypes={[]} searchQuery="nonexistent" />
|
||||
);
|
||||
render(<AgentTypeList {...defaultProps} agentTypes={[]} searchQuery="nonexistent" />);
|
||||
expect(screen.getByText('Try adjusting your search or filters')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -175,9 +171,7 @@ describe('AgentTypeList', () => {
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<AgentTypeList {...defaultProps} className="custom-class" />
|
||||
);
|
||||
const { container } = render(<AgentTypeList {...defaultProps} className="custom-class" />);
|
||||
expect(container.firstChild).toHaveClass('custom-class');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -182,9 +182,7 @@ describe('ConnectionStatus', () => {
|
||||
|
||||
describe('className prop', () => {
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<ConnectionStatus state="connected" className="custom-class" />
|
||||
);
|
||||
const { container } = render(<ConnectionStatus state="connected" className="custom-class" />);
|
||||
|
||||
expect(container.querySelector('.custom-class')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -71,7 +71,10 @@ describe('CTASection', () => {
|
||||
);
|
||||
|
||||
const githubLink = screen.getByRole('link', { name: /get started on github/i });
|
||||
expect(githubLink).toHaveAttribute('href', 'https://gitea.pragmazest.com/cardosofelipe/syndarix');
|
||||
expect(githubLink).toHaveAttribute(
|
||||
'href',
|
||||
'https://gitea.pragmazest.com/cardosofelipe/syndarix'
|
||||
);
|
||||
expect(githubLink).toHaveAttribute('target', '_blank');
|
||||
expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||
});
|
||||
|
||||
@@ -221,7 +221,10 @@ describe('Header', () => {
|
||||
const mobileGithubLink = githubLinks[1];
|
||||
fireEvent.click(mobileGithubLink);
|
||||
// Syndarix uses Gitea for version control
|
||||
expect(mobileGithubLink).toHaveAttribute('href', expect.stringContaining('gitea.pragmazest.com'));
|
||||
expect(mobileGithubLink).toHaveAttribute(
|
||||
'href',
|
||||
expect.stringContaining('gitea.pragmazest.com')
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -100,7 +100,10 @@ describe('HeroSection', () => {
|
||||
);
|
||||
|
||||
const githubLink = screen.getByRole('link', { name: /view on github/i });
|
||||
expect(githubLink).toHaveAttribute('href', 'https://gitea.pragmazest.com/cardosofelipe/syndarix');
|
||||
expect(githubLink).toHaveAttribute(
|
||||
'href',
|
||||
'https://gitea.pragmazest.com/cardosofelipe/syndarix'
|
||||
);
|
||||
expect(githubLink).toHaveAttribute('target', '_blank');
|
||||
expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||
});
|
||||
|
||||
@@ -123,12 +123,7 @@ describe('AppHeader', () => {
|
||||
});
|
||||
|
||||
it('displays current project name', () => {
|
||||
render(
|
||||
<AppHeader
|
||||
projects={mockProjects}
|
||||
currentProject={mockProjects[0]}
|
||||
/>
|
||||
);
|
||||
render(<AppHeader projects={mockProjects} currentProject={mockProjects[0]} />);
|
||||
|
||||
// Multiple instances may show the project name
|
||||
expect(screen.getAllByText('Project One').length).toBeGreaterThan(0);
|
||||
@@ -137,12 +132,7 @@ describe('AppHeader', () => {
|
||||
it('calls onProjectChange when project is changed', async () => {
|
||||
const mockOnChange = jest.fn();
|
||||
|
||||
render(
|
||||
<AppHeader
|
||||
projects={mockProjects}
|
||||
onProjectChange={mockOnChange}
|
||||
/>
|
||||
);
|
||||
render(<AppHeader projects={mockProjects} onProjectChange={mockOnChange} />);
|
||||
|
||||
// The actual test of project switching is in ProjectSwitcher.test.tsx
|
||||
// Here we just verify the prop is passed by checking switcher exists
|
||||
|
||||
@@ -145,9 +145,7 @@ describe('AppLayout', () => {
|
||||
});
|
||||
|
||||
it('passes custom breadcrumbs to AppBreadcrumbs', () => {
|
||||
const customBreadcrumbs = [
|
||||
{ label: 'Custom', href: '/custom', current: true },
|
||||
];
|
||||
const customBreadcrumbs = [{ label: 'Custom', href: '/custom', current: true }];
|
||||
|
||||
render(
|
||||
<AppLayout breadcrumbs={customBreadcrumbs}>
|
||||
@@ -344,10 +342,7 @@ describe('PageHeader', () => {
|
||||
|
||||
it('renders actions when provided', () => {
|
||||
render(
|
||||
<PageHeader
|
||||
title="Title"
|
||||
actions={<button data-testid="action-button">Action</button>}
|
||||
/>
|
||||
<PageHeader title="Title" actions={<button data-testid="action-button">Action</button>} />
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('action-button')).toBeInTheDocument();
|
||||
|
||||
@@ -45,12 +45,7 @@ describe('ProjectSwitcher', () => {
|
||||
});
|
||||
|
||||
it('displays current project name', () => {
|
||||
render(
|
||||
<ProjectSwitcher
|
||||
projects={mockProjects}
|
||||
currentProject={mockProjects[0]}
|
||||
/>
|
||||
);
|
||||
render(<ProjectSwitcher projects={mockProjects} currentProject={mockProjects[0]} />);
|
||||
|
||||
expect(screen.getByText('Project One')).toBeInTheDocument();
|
||||
});
|
||||
@@ -94,12 +89,7 @@ describe('ProjectSwitcher', () => {
|
||||
it('shows current indicator on selected project', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(
|
||||
<ProjectSwitcher
|
||||
projects={mockProjects}
|
||||
currentProject={mockProjects[0]}
|
||||
/>
|
||||
);
|
||||
render(<ProjectSwitcher projects={mockProjects} currentProject={mockProjects[0]} />);
|
||||
|
||||
const trigger = screen.getByTestId('project-switcher-trigger');
|
||||
await user.click(trigger);
|
||||
@@ -144,12 +134,7 @@ describe('ProjectSwitcher', () => {
|
||||
const user = userEvent.setup();
|
||||
const mockOnChange = jest.fn();
|
||||
|
||||
render(
|
||||
<ProjectSwitcher
|
||||
projects={mockProjects}
|
||||
onProjectChange={mockOnChange}
|
||||
/>
|
||||
);
|
||||
render(<ProjectSwitcher projects={mockProjects} onProjectChange={mockOnChange} />);
|
||||
|
||||
const trigger = screen.getByTestId('project-switcher-trigger');
|
||||
await user.click(trigger);
|
||||
@@ -189,18 +174,10 @@ describe('ProjectSwitcher', () => {
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('has accessible label on trigger', () => {
|
||||
render(
|
||||
<ProjectSwitcher
|
||||
projects={mockProjects}
|
||||
currentProject={mockProjects[0]}
|
||||
/>
|
||||
);
|
||||
render(<ProjectSwitcher projects={mockProjects} currentProject={mockProjects[0]} />);
|
||||
|
||||
const trigger = screen.getByTestId('project-switcher-trigger');
|
||||
expect(trigger).toHaveAttribute(
|
||||
'aria-label',
|
||||
'Switch project, current: Project One'
|
||||
);
|
||||
expect(trigger).toHaveAttribute('aria-label', 'Switch project, current: Project One');
|
||||
});
|
||||
|
||||
it('has accessible label when no current project', () => {
|
||||
@@ -220,12 +197,7 @@ describe('ProjectSelect', () => {
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('renders select component', () => {
|
||||
render(
|
||||
<ProjectSelect
|
||||
projects={mockProjects}
|
||||
onValueChange={jest.fn()}
|
||||
/>
|
||||
);
|
||||
render(<ProjectSelect projects={mockProjects} onValueChange={jest.fn()} />);
|
||||
|
||||
expect(screen.getByTestId('project-select')).toBeInTheDocument();
|
||||
});
|
||||
@@ -243,23 +215,14 @@ describe('ProjectSelect', () => {
|
||||
});
|
||||
|
||||
it('has combobox role', () => {
|
||||
render(
|
||||
<ProjectSelect
|
||||
projects={mockProjects}
|
||||
onValueChange={jest.fn()}
|
||||
/>
|
||||
);
|
||||
render(<ProjectSelect projects={mockProjects} onValueChange={jest.fn()} />);
|
||||
|
||||
expect(screen.getByRole('combobox')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
render(
|
||||
<ProjectSelect
|
||||
projects={mockProjects}
|
||||
onValueChange={jest.fn()}
|
||||
className="custom-class"
|
||||
/>
|
||||
<ProjectSelect projects={mockProjects} onValueChange={jest.fn()} className="custom-class" />
|
||||
);
|
||||
|
||||
const select = screen.getByTestId('project-select');
|
||||
|
||||
@@ -74,7 +74,12 @@ const mockUseProjectEventsDefault = {
|
||||
events: [] as ProjectEvent[],
|
||||
isConnected: true,
|
||||
connectionState: 'connected' as ConnectionState,
|
||||
error: null as { message: string; timestamp: string; code?: string; retryAttempt?: number } | null,
|
||||
error: null as {
|
||||
message: string;
|
||||
timestamp: string;
|
||||
code?: string;
|
||||
retryAttempt?: number;
|
||||
} | null,
|
||||
retryCount: 0,
|
||||
reconnect: mockReconnect,
|
||||
disconnect: mockDisconnect,
|
||||
@@ -389,11 +394,7 @@ describe('Event to Activity Conversion', () => {
|
||||
});
|
||||
|
||||
it('handles system actor type', () => {
|
||||
const event = createMockEvent(
|
||||
EventType.SPRINT_STARTED,
|
||||
{ sprint_name: 'Sprint 5' },
|
||||
'system'
|
||||
);
|
||||
const event = createMockEvent(EventType.SPRINT_STARTED, { sprint_name: 'Sprint 5' }, 'system');
|
||||
mockUseProjectEventsResult.events = [event];
|
||||
render(<ProjectDashboard projectId="test" />);
|
||||
expect(screen.getByTestId('mock-recent-activity')).toBeInTheDocument();
|
||||
|
||||
@@ -46,13 +46,7 @@ describe('ProjectHeader', () => {
|
||||
|
||||
it('shows pause button when canPause is true and project is active', () => {
|
||||
const onPauseProject = jest.fn();
|
||||
render(
|
||||
<ProjectHeader
|
||||
project={mockProject}
|
||||
canPause={true}
|
||||
onPauseProject={onPauseProject}
|
||||
/>
|
||||
);
|
||||
render(<ProjectHeader project={mockProject} canPause={true} onPauseProject={onPauseProject} />);
|
||||
expect(screen.getByRole('button', { name: /pause project/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -64,13 +58,7 @@ describe('ProjectHeader', () => {
|
||||
|
||||
it('shows run sprint button when canStart is true', () => {
|
||||
const onStartSprint = jest.fn();
|
||||
render(
|
||||
<ProjectHeader
|
||||
project={mockProject}
|
||||
canStart={true}
|
||||
onStartSprint={onStartSprint}
|
||||
/>
|
||||
);
|
||||
render(<ProjectHeader project={mockProject} canStart={true} onStartSprint={onStartSprint} />);
|
||||
expect(screen.getByRole('button', { name: /run sprint/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -83,13 +71,7 @@ describe('ProjectHeader', () => {
|
||||
it('calls onStartSprint when run sprint button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onStartSprint = jest.fn();
|
||||
render(
|
||||
<ProjectHeader
|
||||
project={mockProject}
|
||||
canStart={true}
|
||||
onStartSprint={onStartSprint}
|
||||
/>
|
||||
);
|
||||
render(<ProjectHeader project={mockProject} canStart={true} onStartSprint={onStartSprint} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /run sprint/i }));
|
||||
expect(onStartSprint).toHaveBeenCalledTimes(1);
|
||||
@@ -98,13 +80,7 @@ describe('ProjectHeader', () => {
|
||||
it('calls onPauseProject when pause button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onPauseProject = jest.fn();
|
||||
render(
|
||||
<ProjectHeader
|
||||
project={mockProject}
|
||||
canPause={true}
|
||||
onPauseProject={onPauseProject}
|
||||
/>
|
||||
);
|
||||
render(<ProjectHeader project={mockProject} canPause={true} onPauseProject={onPauseProject} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /pause project/i }));
|
||||
expect(onPauseProject).toHaveBeenCalledTimes(1);
|
||||
@@ -113,12 +89,7 @@ describe('ProjectHeader', () => {
|
||||
it('calls onCreateSprint when new sprint button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onCreateSprint = jest.fn();
|
||||
render(
|
||||
<ProjectHeader
|
||||
project={mockProject}
|
||||
onCreateSprint={onCreateSprint}
|
||||
/>
|
||||
);
|
||||
render(<ProjectHeader project={mockProject} onCreateSprint={onCreateSprint} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /new sprint/i }));
|
||||
expect(onCreateSprint).toHaveBeenCalledTimes(1);
|
||||
@@ -127,12 +98,7 @@ describe('ProjectHeader', () => {
|
||||
it('calls onSettings when settings button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onSettings = jest.fn();
|
||||
render(
|
||||
<ProjectHeader
|
||||
project={mockProject}
|
||||
onSettings={onSettings}
|
||||
/>
|
||||
);
|
||||
render(<ProjectHeader project={mockProject} onSettings={onSettings} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /project settings/i }));
|
||||
expect(onSettings).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -65,38 +65,20 @@ describe('RecentActivity', () => {
|
||||
|
||||
it('shows View All button when there are more activities than maxItems', () => {
|
||||
const onViewAll = jest.fn();
|
||||
render(
|
||||
<RecentActivity
|
||||
activities={mockActivities}
|
||||
maxItems={2}
|
||||
onViewAll={onViewAll}
|
||||
/>
|
||||
);
|
||||
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}
|
||||
/>
|
||||
);
|
||||
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}
|
||||
/>
|
||||
);
|
||||
render(<RecentActivity activities={mockActivities} maxItems={2} onViewAll={onViewAll} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /view all/i }));
|
||||
expect(onViewAll).toHaveBeenCalledTimes(1);
|
||||
@@ -104,24 +86,14 @@ describe('RecentActivity', () => {
|
||||
|
||||
it('shows Review Request button for items requiring action', () => {
|
||||
const onActionClick = jest.fn();
|
||||
render(
|
||||
<RecentActivity
|
||||
activities={mockActivities}
|
||||
onActionClick={onActionClick}
|
||||
/>
|
||||
);
|
||||
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}
|
||||
/>
|
||||
);
|
||||
render(<RecentActivity activities={mockActivities} onActionClick={onActionClick} />);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /review request/i }));
|
||||
expect(onActionClick).toHaveBeenCalledWith('act-003');
|
||||
|
||||
@@ -23,9 +23,7 @@ describe('ProjectStatusBadge', () => {
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<ProjectStatusBadge status="active" className="custom-class" />
|
||||
);
|
||||
const { container } = render(<ProjectStatusBadge status="active" className="custom-class" />);
|
||||
expect(container.firstChild).toHaveClass('custom-class');
|
||||
});
|
||||
});
|
||||
@@ -54,9 +52,7 @@ describe('AutonomyBadge', () => {
|
||||
});
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<AutonomyBadge level="milestone" className="custom-class" />
|
||||
);
|
||||
const { container } = render(<AutonomyBadge level="milestone" className="custom-class" />);
|
||||
expect(container.firstChild).toHaveClass('custom-class');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -264,7 +264,9 @@ describe('ProjectWizard', () => {
|
||||
await user.click(screen.getByRole('button', { name: /create project/i }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button', { name: /go to project dashboard/i })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('button', { name: /go to project dashboard/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /go to project dashboard/i }));
|
||||
|
||||
@@ -60,7 +60,9 @@ describe('AutonomyStep', () => {
|
||||
|
||||
it('has accessible radiogroup role', () => {
|
||||
render(<AutonomyStep state={defaultState} updateState={mockUpdateState} />);
|
||||
expect(screen.getByRole('radiogroup', { name: /autonomy level options/i })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('radiogroup', { name: /autonomy level options/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -69,7 +71,9 @@ describe('AutonomyStep', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<AutonomyStep state={defaultState} updateState={mockUpdateState} />);
|
||||
|
||||
const fullControlOption = screen.getByRole('button', { name: /full control.*review every action/i });
|
||||
const fullControlOption = screen.getByRole('button', {
|
||||
name: /full control.*review every action/i,
|
||||
});
|
||||
await user.click(fullControlOption);
|
||||
|
||||
expect(mockUpdateState).toHaveBeenCalledWith({ autonomyLevel: 'full_control' });
|
||||
@@ -89,7 +93,9 @@ describe('AutonomyStep', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<AutonomyStep state={defaultState} updateState={mockUpdateState} />);
|
||||
|
||||
const autonomousOption = screen.getByRole('button', { name: /autonomous.*only major decisions/i });
|
||||
const autonomousOption = screen.getByRole('button', {
|
||||
name: /autonomous.*only major decisions/i,
|
||||
});
|
||||
await user.click(autonomousOption);
|
||||
|
||||
expect(mockUpdateState).toHaveBeenCalledWith({ autonomyLevel: 'autonomous' });
|
||||
@@ -180,7 +186,7 @@ describe('AutonomyStep', () => {
|
||||
|
||||
autonomyOptions.forEach((option) => {
|
||||
const button = screen.getByRole('button', {
|
||||
name: new RegExp(`${option.label}.*${option.description}`, 'i')
|
||||
name: new RegExp(`${option.label}.*${option.description}`, 'i'),
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
@@ -207,7 +213,9 @@ describe('AutonomyStep', () => {
|
||||
};
|
||||
render(<AutonomyStep state={stateWithFullControl} updateState={mockUpdateState} />);
|
||||
|
||||
const autonomousOption = screen.getByRole('button', { name: /autonomous.*only major decisions/i });
|
||||
const autonomousOption = screen.getByRole('button', {
|
||||
name: /autonomous.*only major decisions/i,
|
||||
});
|
||||
await user.click(autonomousOption);
|
||||
|
||||
expect(mockUpdateState).toHaveBeenCalledWith({ autonomyLevel: 'autonomous' });
|
||||
|
||||
@@ -59,7 +59,9 @@ describe('ClientModeStep', () => {
|
||||
|
||||
it('has accessible radiogroup role', () => {
|
||||
render(<ClientModeStep state={defaultState} updateState={mockUpdateState} />);
|
||||
expect(screen.getByRole('radiogroup', { name: /client interaction mode options/i })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('radiogroup', { name: /client interaction mode options/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,7 +78,9 @@ describe('ClientModeStep', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<ClientModeStep state={defaultState} updateState={mockUpdateState} />);
|
||||
|
||||
const technicalOption = screen.getByRole('button', { name: /technical mode.*detailed technical/i });
|
||||
const technicalOption = screen.getByRole('button', {
|
||||
name: /technical mode.*detailed technical/i,
|
||||
});
|
||||
await user.click(technicalOption);
|
||||
|
||||
expect(mockUpdateState).toHaveBeenCalledWith({ clientMode: 'technical' });
|
||||
@@ -123,7 +127,7 @@ describe('ClientModeStep', () => {
|
||||
|
||||
clientModeOptions.forEach((option) => {
|
||||
const button = screen.getByRole('button', {
|
||||
name: new RegExp(`${option.label}.*${option.description}`, 'i')
|
||||
name: new RegExp(`${option.label}.*${option.description}`, 'i'),
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
@@ -168,7 +172,9 @@ describe('ClientModeStep', () => {
|
||||
};
|
||||
render(<ClientModeStep state={stateWithTechnical} updateState={mockUpdateState} />);
|
||||
|
||||
const technicalOption = screen.getByRole('button', { name: /technical mode.*detailed technical/i });
|
||||
const technicalOption = screen.getByRole('button', {
|
||||
name: /technical mode.*detailed technical/i,
|
||||
});
|
||||
await user.click(technicalOption);
|
||||
|
||||
// Should still call updateState
|
||||
|
||||
@@ -65,7 +65,9 @@ describe('ComplexityStep', () => {
|
||||
|
||||
it('has accessible radiogroup role', () => {
|
||||
render(<ComplexityStep state={defaultState} updateState={mockUpdateState} />);
|
||||
expect(screen.getByRole('radiogroup', { name: /project complexity options/i })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('radiogroup', { name: /project complexity options/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,7 +166,7 @@ describe('ComplexityStep', () => {
|
||||
|
||||
complexityOptions.forEach((option) => {
|
||||
const button = screen.getByRole('button', {
|
||||
name: new RegExp(`${option.label}.*${option.description}`, 'i')
|
||||
name: new RegExp(`${option.label}.*${option.description}`, 'i'),
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -211,9 +211,7 @@ describe('IssueDetailPanel', () => {
|
||||
it('renders labels without color property', () => {
|
||||
const issueWithColorlessLabels: IssueDetail = {
|
||||
...defaultIssue,
|
||||
labels: [
|
||||
{ id: 'lbl-1', name: 'colorless-label' },
|
||||
],
|
||||
labels: [{ id: 'lbl-1', name: 'colorless-label' }],
|
||||
};
|
||||
render(<IssueDetailPanel issue={issueWithColorlessLabels} />);
|
||||
expect(screen.getByText('colorless-label')).toBeInTheDocument();
|
||||
|
||||
@@ -14,9 +14,7 @@ describe('StatusWorkflow', () => {
|
||||
});
|
||||
|
||||
it('renders all status options', () => {
|
||||
render(
|
||||
<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} />
|
||||
);
|
||||
render(<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} />);
|
||||
|
||||
expect(screen.getByText('Open')).toBeInTheDocument();
|
||||
expect(screen.getByText('In Progress')).toBeInTheDocument();
|
||||
@@ -26,9 +24,7 @@ describe('StatusWorkflow', () => {
|
||||
});
|
||||
|
||||
it('highlights current status', () => {
|
||||
render(
|
||||
<StatusWorkflow currentStatus="in_progress" onStatusChange={mockOnStatusChange} />
|
||||
);
|
||||
render(<StatusWorkflow currentStatus="in_progress" onStatusChange={mockOnStatusChange} />);
|
||||
|
||||
const inProgressButton = screen.getByRole('radio', { name: /in progress/i });
|
||||
expect(inProgressButton).toHaveAttribute('aria-checked', 'true');
|
||||
@@ -36,9 +32,7 @@ describe('StatusWorkflow', () => {
|
||||
|
||||
it('calls onStatusChange when status is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} />
|
||||
);
|
||||
render(<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} />);
|
||||
|
||||
const inProgressButton = screen.getByRole('radio', { name: /in progress/i });
|
||||
await user.click(inProgressButton);
|
||||
@@ -48,9 +42,7 @@ describe('StatusWorkflow', () => {
|
||||
|
||||
it('disables status buttons when disabled prop is true', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} disabled />
|
||||
);
|
||||
render(<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} disabled />);
|
||||
|
||||
const inProgressButton = screen.getByRole('radio', { name: /in progress/i });
|
||||
expect(inProgressButton).toBeDisabled();
|
||||
@@ -72,9 +64,7 @@ describe('StatusWorkflow', () => {
|
||||
});
|
||||
|
||||
it('has proper radiogroup role', () => {
|
||||
render(
|
||||
<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} />
|
||||
);
|
||||
render(<StatusWorkflow currentStatus="open" onStatusChange={mockOnStatusChange} />);
|
||||
|
||||
expect(screen.getByRole('radiogroup', { name: /issue status/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -16,10 +16,9 @@ describe('useDebounce', () => {
|
||||
});
|
||||
|
||||
it('updates the debounced value after the delay', () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ value, delay }) => useDebounce(value, delay),
|
||||
{ initialProps: { value: 'initial', delay: 500 } }
|
||||
);
|
||||
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
||||
initialProps: { value: 'initial', delay: 500 },
|
||||
});
|
||||
|
||||
// Change the value
|
||||
rerender({ value: 'updated', delay: 500 });
|
||||
@@ -37,10 +36,9 @@ describe('useDebounce', () => {
|
||||
});
|
||||
|
||||
it('does not update the value before the delay', () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ value, delay }) => useDebounce(value, delay),
|
||||
{ initialProps: { value: 'initial', delay: 500 } }
|
||||
);
|
||||
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
||||
initialProps: { value: 'initial', delay: 500 },
|
||||
});
|
||||
|
||||
rerender({ value: 'updated', delay: 500 });
|
||||
|
||||
@@ -53,10 +51,9 @@ describe('useDebounce', () => {
|
||||
});
|
||||
|
||||
it('resets the timer when value changes rapidly', () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ value, delay }) => useDebounce(value, delay),
|
||||
{ initialProps: { value: 'initial', delay: 500 } }
|
||||
);
|
||||
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
||||
initialProps: { value: 'initial', delay: 500 },
|
||||
});
|
||||
|
||||
// First change
|
||||
rerender({ value: 'first', delay: 500 });
|
||||
@@ -89,10 +86,9 @@ describe('useDebounce', () => {
|
||||
it('cleans up timeout on unmount', () => {
|
||||
const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');
|
||||
|
||||
const { unmount, rerender } = renderHook(
|
||||
({ value, delay }) => useDebounce(value, delay),
|
||||
{ initialProps: { value: 'initial', delay: 500 } }
|
||||
);
|
||||
const { unmount, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
||||
initialProps: { value: 'initial', delay: 500 },
|
||||
});
|
||||
|
||||
rerender({ value: 'updated', delay: 500 });
|
||||
unmount();
|
||||
@@ -102,10 +98,9 @@ describe('useDebounce', () => {
|
||||
});
|
||||
|
||||
it('works with different delay values', () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ value, delay }) => useDebounce(value, delay),
|
||||
{ initialProps: { value: 'initial', delay: 1000 } }
|
||||
);
|
||||
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
||||
initialProps: { value: 'initial', delay: 1000 },
|
||||
});
|
||||
|
||||
rerender({ value: 'updated', delay: 1000 });
|
||||
|
||||
@@ -138,10 +133,9 @@ describe('useDebounce', () => {
|
||||
});
|
||||
|
||||
it('handles zero delay', () => {
|
||||
const { result, rerender } = renderHook(
|
||||
({ value, delay }) => useDebounce(value, delay),
|
||||
{ initialProps: { value: 'initial', delay: 0 } }
|
||||
);
|
||||
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
||||
initialProps: { value: 'initial', delay: 0 },
|
||||
});
|
||||
|
||||
rerender({ value: 'updated', delay: 0 });
|
||||
|
||||
|
||||
@@ -119,9 +119,7 @@ describe('useProjectEvents', () => {
|
||||
|
||||
describe('initialization', () => {
|
||||
it('should start disconnected', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useProjectEvents('project-123', { autoConnect: false })
|
||||
);
|
||||
const { result } = renderHook(() => useProjectEvents('project-123', { autoConnect: false }));
|
||||
|
||||
expect(result.current.connectionState).toBe('disconnected');
|
||||
expect(result.current.isConnected).toBe(false);
|
||||
|
||||
@@ -189,10 +189,9 @@ describe('Event Store', () => {
|
||||
|
||||
useEventStore.getState().addEvents([agentEvent, issueEvent, sprintEvent]);
|
||||
|
||||
const filtered = useEventStore.getState().getFilteredEvents('project-123', [
|
||||
EventType.AGENT_MESSAGE,
|
||||
EventType.ISSUE_CREATED,
|
||||
]);
|
||||
const filtered = useEventStore
|
||||
.getState()
|
||||
.getFilteredEvents('project-123', [EventType.AGENT_MESSAGE, EventType.ISSUE_CREATED]);
|
||||
|
||||
expect(filtered).toHaveLength(2);
|
||||
expect(filtered.map((e) => e.type)).toContain(EventType.AGENT_MESSAGE);
|
||||
@@ -210,9 +209,9 @@ describe('Event Store', () => {
|
||||
});
|
||||
|
||||
it('should return empty array for non-existent project', () => {
|
||||
const filtered = useEventStore.getState().getFilteredEvents('non-existent', [
|
||||
EventType.AGENT_MESSAGE,
|
||||
]);
|
||||
const filtered = useEventStore
|
||||
.getState()
|
||||
.getFilteredEvents('non-existent', [EventType.AGENT_MESSAGE]);
|
||||
expect(filtered).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user