- Raise coverage thresholds to 90% statements/lines/functions, 85% branches - Add comprehensive tests for ProjectDashboard, ProjectWizard, and all wizard steps - Add tests for issue management: IssueDetailPanel, BulkActions, IssueFilters - Expand IssueTable tests with keyboard navigation, dropdown menu, edge cases - Add useIssues hook tests covering all mutations and optimistic updates - Expand eventStore tests with selector hooks and additional scenarios - Expand useProjectEvents tests with error recovery, ping events, edge cases - Add PriorityBadge, StatusBadge, SyncStatusIndicator fallback branch tests - Add constants.test.ts for comprehensive constant validation Bug fixes: - Fix false positive rollback test to properly verify onMutate context setup - Replace deprecated substr() with substring() in mock helpers - Fix type errors: ProjectComplexity, ClientMode enum values - Fix unused imports and variables across test files - Fix @ts-expect-error directives and method override signatures 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
260 lines
9.0 KiB
TypeScript
260 lines
9.0 KiB
TypeScript
/**
|
|
* ReviewStep Component Tests
|
|
*
|
|
* Tests for the project review/summary step.
|
|
*/
|
|
|
|
import { render, screen } from '@testing-library/react';
|
|
import { ReviewStep } from '@/components/projects/wizard/steps/ReviewStep';
|
|
import type { WizardState } from '@/components/projects/wizard/types';
|
|
|
|
describe('ReviewStep', () => {
|
|
const completeState: WizardState = {
|
|
step: 6,
|
|
projectName: 'My Test Project',
|
|
description: 'A comprehensive test project description',
|
|
repoUrl: 'https://github.com/test/repo',
|
|
complexity: 'medium',
|
|
clientMode: 'technical',
|
|
autonomyLevel: 'milestone',
|
|
};
|
|
|
|
const minimalState: WizardState = {
|
|
step: 6,
|
|
projectName: '',
|
|
description: '',
|
|
repoUrl: '',
|
|
complexity: null,
|
|
clientMode: null,
|
|
autonomyLevel: null,
|
|
};
|
|
|
|
const scriptState: WizardState = {
|
|
step: 6,
|
|
projectName: 'Quick Script',
|
|
description: 'A simple script',
|
|
repoUrl: '',
|
|
complexity: 'script',
|
|
clientMode: null,
|
|
autonomyLevel: null,
|
|
};
|
|
|
|
describe('Rendering', () => {
|
|
it('renders the step title', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Review Your Project')).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders the description text', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText(/please review your selections/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Basic Information Card', () => {
|
|
it('displays project name', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Project Name')).toBeInTheDocument();
|
|
expect(screen.getByText('My Test Project')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays description', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
expect(screen.getByText('A comprehensive test project description')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays repository URL', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Repository')).toBeInTheDocument();
|
|
expect(screen.getByText('https://github.com/test/repo')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "Not specified" for empty project name', () => {
|
|
render(<ReviewStep state={minimalState} />);
|
|
expect(screen.getByText('Not specified')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "No description provided" for empty description', () => {
|
|
render(<ReviewStep state={minimalState} />);
|
|
expect(screen.getByText('No description provided')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "New repository will be created" for empty repo URL', () => {
|
|
render(<ReviewStep state={minimalState} />);
|
|
expect(screen.getByText('New repository will be created')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Complexity Card', () => {
|
|
it('displays complexity card title', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Project Complexity')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays selected complexity with details', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Medium')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "Not selected" when no complexity chosen', () => {
|
|
render(<ReviewStep state={minimalState} />);
|
|
const notSelectedTexts = screen.getAllByText('Not selected');
|
|
expect(notSelectedTexts.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('displays Script complexity correctly', () => {
|
|
render(<ReviewStep state={scriptState} />);
|
|
expect(screen.getByText('Script')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Interaction Mode Card', () => {
|
|
it('displays interaction mode card title', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Interaction Mode')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays selected client mode with details', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Technical Mode')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "Not selected" when no client mode chosen', () => {
|
|
render(<ReviewStep state={minimalState} />);
|
|
// Find within the Interaction Mode card context
|
|
const cards = screen.getAllByText('Not selected');
|
|
expect(cards.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('shows auto mode message for script projects', () => {
|
|
render(<ReviewStep state={scriptState} />);
|
|
const autoModeTexts = screen.getAllByText(/automatically set for script/i);
|
|
expect(autoModeTexts.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Autonomy Level Card', () => {
|
|
it('displays autonomy level card title', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Autonomy Level')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays selected autonomy level with details', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Milestone')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "Not selected" when no autonomy level chosen', () => {
|
|
render(<ReviewStep state={minimalState} />);
|
|
const cards = screen.getAllByText('Not selected');
|
|
expect(cards.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('shows autonomous message for script projects', () => {
|
|
render(<ReviewStep state={scriptState} />);
|
|
const autonomousMessages = screen.getAllByText(/autonomous/i);
|
|
expect(autonomousMessages.length).toBeGreaterThan(0);
|
|
const scriptMessages = screen.getAllByText(/automatically set for script/i);
|
|
expect(scriptMessages.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Ready to Create Card', () => {
|
|
it('displays the ready to create card', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Ready to Create')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays the summary message', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText(/once you create this project/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/product owner agent/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Script Mode Display', () => {
|
|
it('shows script complexity selected', () => {
|
|
render(<ReviewStep state={scriptState} />);
|
|
expect(screen.getByText('Script')).toBeInTheDocument();
|
|
});
|
|
|
|
it('auto-fills interaction mode for script projects', () => {
|
|
render(<ReviewStep state={scriptState} />);
|
|
// Auto Mode text appears for script projects
|
|
const autoModeTexts = screen.getAllByText(/automatically set for script/i);
|
|
expect(autoModeTexts.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('auto-fills autonomy level for script projects', () => {
|
|
render(<ReviewStep state={scriptState} />);
|
|
// Autonomous text appears for script projects
|
|
const autonomousTexts = screen.getAllByText(/autonomous.*automatically set for script/i);
|
|
expect(autonomousTexts.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Different Selections', () => {
|
|
it('displays Simple complexity', () => {
|
|
const simpleState: WizardState = {
|
|
...completeState,
|
|
complexity: 'simple',
|
|
};
|
|
render(<ReviewStep state={simpleState} />);
|
|
expect(screen.getByText('Simple')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays Complex complexity', () => {
|
|
const complexState: WizardState = {
|
|
...completeState,
|
|
complexity: 'complex',
|
|
};
|
|
render(<ReviewStep state={complexState} />);
|
|
expect(screen.getByText('Complex')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays Auto Mode client mode', () => {
|
|
const autoState: WizardState = {
|
|
...completeState,
|
|
clientMode: 'auto',
|
|
};
|
|
render(<ReviewStep state={autoState} />);
|
|
expect(screen.getByText('Auto Mode')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays Full Control autonomy', () => {
|
|
const fullControlState: WizardState = {
|
|
...completeState,
|
|
autonomyLevel: 'full_control',
|
|
};
|
|
render(<ReviewStep state={fullControlState} />);
|
|
expect(screen.getByText('Full Control')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays Autonomous autonomy level', () => {
|
|
const autonomousState: WizardState = {
|
|
...completeState,
|
|
autonomyLevel: 'autonomous',
|
|
};
|
|
render(<ReviewStep state={autonomousState} />);
|
|
expect(screen.getByText('Autonomous')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Accessibility', () => {
|
|
it('icons have aria-hidden attribute', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
const hiddenIcons = document.querySelectorAll('[aria-hidden="true"]');
|
|
expect(hiddenIcons.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('renders card titles as headings', () => {
|
|
render(<ReviewStep state={completeState} />);
|
|
expect(screen.getByText('Basic Information')).toBeInTheDocument();
|
|
expect(screen.getByText('Project Complexity')).toBeInTheDocument();
|
|
expect(screen.getByText('Interaction Mode')).toBeInTheDocument();
|
|
expect(screen.getByText('Autonomy Level')).toBeInTheDocument();
|
|
});
|
|
});
|
|
});
|