test(frontend): comprehensive test coverage improvements and bug fixes
- 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>
This commit is contained in:
@@ -10,7 +10,7 @@ import { EventType, type ProjectEvent } from '@/lib/types/events';
|
||||
*/
|
||||
function createMockEvent(overrides: Partial<ProjectEvent> = {}): ProjectEvent {
|
||||
return {
|
||||
id: `event-${Math.random().toString(36).substr(2, 9)}`,
|
||||
id: `event-${Math.random().toString(36).substring(2, 11)}`,
|
||||
type: EventType.AGENT_MESSAGE,
|
||||
timestamp: new Date().toISOString(),
|
||||
project_id: 'project-123',
|
||||
@@ -253,3 +253,118 @@ describe('Event Store', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests for Selector Hooks
|
||||
*/
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useProjectEventsFromStore, useLatestEvent, useEventCount } from '@/lib/stores/eventStore';
|
||||
|
||||
describe('Event Store Selector Hooks', () => {
|
||||
beforeEach(() => {
|
||||
// Reset store state
|
||||
useEventStore.setState({
|
||||
eventsByProject: {},
|
||||
maxEvents: 100,
|
||||
});
|
||||
});
|
||||
|
||||
describe('useProjectEventsFromStore', () => {
|
||||
it('should return empty array for non-existent project', () => {
|
||||
const { result } = renderHook(() => useProjectEventsFromStore('non-existent'));
|
||||
expect(result.current).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return events for existing project', () => {
|
||||
const event = createMockEvent();
|
||||
useEventStore.getState().addEvent(event);
|
||||
|
||||
const { result } = renderHook(() => useProjectEventsFromStore('project-123'));
|
||||
expect(result.current).toHaveLength(1);
|
||||
expect(result.current[0]).toEqual(event);
|
||||
});
|
||||
|
||||
it('should update when events are added', () => {
|
||||
const { result, rerender } = renderHook(() => useProjectEventsFromStore('project-123'));
|
||||
expect(result.current).toHaveLength(0);
|
||||
|
||||
useEventStore.getState().addEvent(createMockEvent());
|
||||
rerender();
|
||||
|
||||
expect(result.current).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useLatestEvent', () => {
|
||||
it('should return undefined for non-existent project', () => {
|
||||
const { result } = renderHook(() => useLatestEvent('non-existent'));
|
||||
expect(result.current).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined for empty project', () => {
|
||||
const { result } = renderHook(() => useLatestEvent('project-123'));
|
||||
expect(result.current).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return the last event added', () => {
|
||||
const event1 = createMockEvent({ id: 'event-1' });
|
||||
const event2 = createMockEvent({ id: 'event-2' });
|
||||
const event3 = createMockEvent({ id: 'event-3' });
|
||||
|
||||
useEventStore.getState().addEvents([event1, event2, event3]);
|
||||
|
||||
const { result } = renderHook(() => useLatestEvent('project-123'));
|
||||
expect(result.current?.id).toBe('event-3');
|
||||
});
|
||||
|
||||
it('should update when a new event is added', () => {
|
||||
const event1 = createMockEvent({ id: 'event-1' });
|
||||
useEventStore.getState().addEvent(event1);
|
||||
|
||||
const { result, rerender } = renderHook(() => useLatestEvent('project-123'));
|
||||
expect(result.current?.id).toBe('event-1');
|
||||
|
||||
const event2 = createMockEvent({ id: 'event-2' });
|
||||
useEventStore.getState().addEvent(event2);
|
||||
rerender();
|
||||
|
||||
expect(result.current?.id).toBe('event-2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('useEventCount', () => {
|
||||
it('should return 0 for non-existent project', () => {
|
||||
const { result } = renderHook(() => useEventCount('non-existent'));
|
||||
expect(result.current).toBe(0);
|
||||
});
|
||||
|
||||
it('should return correct count for existing project', () => {
|
||||
const events = [
|
||||
createMockEvent({ id: 'event-1' }),
|
||||
createMockEvent({ id: 'event-2' }),
|
||||
createMockEvent({ id: 'event-3' }),
|
||||
];
|
||||
useEventStore.getState().addEvents(events);
|
||||
|
||||
const { result } = renderHook(() => useEventCount('project-123'));
|
||||
expect(result.current).toBe(3);
|
||||
});
|
||||
|
||||
it('should update when events are added or removed', () => {
|
||||
const { result, rerender } = renderHook(() => useEventCount('project-123'));
|
||||
expect(result.current).toBe(0);
|
||||
|
||||
useEventStore.getState().addEvent(createMockEvent({ id: 'event-1' }));
|
||||
rerender();
|
||||
expect(result.current).toBe(1);
|
||||
|
||||
useEventStore.getState().addEvent(createMockEvent({ id: 'event-2' }));
|
||||
rerender();
|
||||
expect(result.current).toBe(2);
|
||||
|
||||
useEventStore.getState().clearProjectEvents('project-123');
|
||||
rerender();
|
||||
expect(result.current).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user