Files
syndarix/frontend/tests/components/projects/wizard/constants.test.ts
Felipe Cardoso 5b1e2852ea feat(frontend): implement main dashboard page (#48)
Implement the main dashboard / projects list page for Syndarix as the landing
page after login. The implementation includes:

Dashboard Components:
- QuickStats: Overview cards showing active projects, agents, issues, approvals
- ProjectsSection: Grid/list view with filtering and sorting controls
- ProjectCardGrid: Rich project cards for grid view
- ProjectRowList: Compact rows for list view
- ActivityFeed: Real-time activity sidebar with connection status
- PerformanceCard: Performance metrics display
- EmptyState: Call-to-action for new users
- ProjectStatusBadge: Status indicator with icons
- ComplexityIndicator: Visual complexity dots
- ProgressBar: Accessible progress bar component

Features:
- Projects grid/list view with view mode toggle
- Filter by status (all, active, paused, completed, archived)
- Sort by recent, name, progress, or issues
- Quick stats overview with counts
- Real-time activity feed sidebar with live/reconnecting status
- Performance metrics card
- Create project button linking to wizard
- Responsive layout for mobile/desktop
- Loading skeleton states
- Empty state for new users

API Integration:
- useProjects hook for fetching projects (mock data until backend ready)
- useDashboardStats hook for statistics
- TanStack Query for caching and data fetching

Testing:
- 37 unit tests covering all dashboard components
- E2E test suite for dashboard functionality
- Accessibility tests (keyboard nav, aria attributes, heading hierarchy)

Technical:
- TypeScript strict mode compliance
- ESLint passing
- WCAG AA accessibility compliance
- Mobile-first responsive design
- Dark mode support via semantic tokens
- Follows design system guidelines

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 23:46:50 +01:00

155 lines
4.9 KiB
TypeScript

/**
* Tests for wizard constants and utility functions
*/
import {
complexityOptions,
clientModeOptions,
autonomyOptions,
getTotalSteps,
getStepLabels,
getDisplayStep,
WIZARD_STEPS,
} from '@/components/projects/wizard/constants';
describe('complexityOptions', () => {
it('has 4 options', () => {
expect(complexityOptions).toHaveLength(4);
});
it('includes script with skipConfig: true', () => {
const script = complexityOptions.find((o) => o.id === 'script');
expect(script).toBeDefined();
expect(script?.skipConfig).toBe(true);
});
it('has other options with skipConfig: false', () => {
const others = complexityOptions.filter((o) => o.id !== 'script');
expect(others.every((o) => o.skipConfig === false)).toBe(true);
});
it('has correct timelines', () => {
const script = complexityOptions.find((o) => o.id === 'script');
const simple = complexityOptions.find((o) => o.id === 'simple');
const medium = complexityOptions.find((o) => o.id === 'medium');
const complex = complexityOptions.find((o) => o.id === 'complex');
expect(script?.scope).toContain('Minutes to 1-2 hours');
expect(simple?.scope).toContain('2-3 days');
expect(medium?.scope).toContain('2-3 weeks');
expect(complex?.scope).toContain('2-3 months');
});
});
describe('clientModeOptions', () => {
it('has 2 options', () => {
expect(clientModeOptions).toHaveLength(2);
});
it('includes technical and auto modes', () => {
const ids = clientModeOptions.map((o) => o.id);
expect(ids).toContain('technical');
expect(ids).toContain('auto');
});
});
describe('autonomyOptions', () => {
it('has 3 options', () => {
expect(autonomyOptions).toHaveLength(3);
});
it('includes all autonomy levels', () => {
const ids = autonomyOptions.map((o) => o.id);
expect(ids).toContain('full_control');
expect(ids).toContain('milestone');
expect(ids).toContain('autonomous');
});
it('has valid approval matrices', () => {
autonomyOptions.forEach((option) => {
expect(option.approvals).toHaveProperty('codeChanges');
expect(option.approvals).toHaveProperty('issueUpdates');
expect(option.approvals).toHaveProperty('architectureDecisions');
expect(option.approvals).toHaveProperty('sprintPlanning');
expect(option.approvals).toHaveProperty('deployments');
});
});
it('full_control requires all approvals', () => {
const fullControl = autonomyOptions.find((o) => o.id === 'full_control');
expect(Object.values(fullControl!.approvals).every(Boolean)).toBe(true);
});
it('autonomous only requires architecture and deployments', () => {
const autonomous = autonomyOptions.find((o) => o.id === 'autonomous');
expect(autonomous!.approvals.codeChanges).toBe(false);
expect(autonomous!.approvals.issueUpdates).toBe(false);
expect(autonomous!.approvals.architectureDecisions).toBe(true);
expect(autonomous!.approvals.sprintPlanning).toBe(false);
expect(autonomous!.approvals.deployments).toBe(true);
});
});
describe('getTotalSteps', () => {
it('returns 6 for non-script mode', () => {
expect(getTotalSteps(false)).toBe(6);
});
it('returns 4 for script mode', () => {
expect(getTotalSteps(true)).toBe(4);
});
});
describe('getStepLabels', () => {
it('returns 6 labels for non-script mode', () => {
const labels = getStepLabels(false);
expect(labels).toHaveLength(6);
expect(labels).toEqual([
'Basic Info',
'Complexity',
'Client Mode',
'Autonomy',
'Agent Chat',
'Review',
]);
});
it('returns 4 labels for script mode (no Client Mode or Autonomy)', () => {
const labels = getStepLabels(true);
expect(labels).toHaveLength(4);
expect(labels).toEqual(['Basic Info', 'Complexity', 'Agent Chat', 'Review']);
});
});
describe('getDisplayStep', () => {
it('returns actual step for non-script mode', () => {
expect(getDisplayStep(1, false)).toBe(1);
expect(getDisplayStep(2, false)).toBe(2);
expect(getDisplayStep(3, false)).toBe(3);
expect(getDisplayStep(4, false)).toBe(4);
expect(getDisplayStep(5, false)).toBe(5);
expect(getDisplayStep(6, false)).toBe(6);
});
it('maps steps correctly for script mode', () => {
// Steps 1 and 2 stay the same
expect(getDisplayStep(1, true)).toBe(1);
expect(getDisplayStep(2, true)).toBe(2);
// Step 5 (Agent Chat) becomes display step 3
expect(getDisplayStep(5, true)).toBe(3);
// Step 6 (Review) becomes display step 4
expect(getDisplayStep(6, true)).toBe(4);
});
});
describe('WIZARD_STEPS', () => {
it('has correct step numbers', () => {
expect(WIZARD_STEPS.BASIC_INFO).toBe(1);
expect(WIZARD_STEPS.COMPLEXITY).toBe(2);
expect(WIZARD_STEPS.CLIENT_MODE).toBe(3);
expect(WIZARD_STEPS.AUTONOMY).toBe(4);
expect(WIZARD_STEPS.AGENT_CHAT).toBe(5);
expect(WIZARD_STEPS.REVIEW).toBe(6);
});
});