import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { TaskHeader } from '../TaskHeader'; import { mockTask, mockCompletedTask, createMockTask, } from '@/__tests__/testUtils'; describe('TaskHeader', () => { const mockProps = { task: mockTask, hasSubtasks: false, showSubtasks: false, onSubtasksToggle: jest.fn(), onTaskClick: jest.fn(), onTaskUpdate: jest.fn(), onTaskDelete: jest.fn(), onEditClick: jest.fn(), isSelected: false, showTaskOptions: true, showProjectInfo: true, showTags: true, showDueDate: true, showPriority: true, showTodayToggle: true, showPlayButton: true, allowEdit: true, allowDelete: true, className: '', }; beforeEach(() => { jest.clearAllMocks(); }); describe('Subtasks Button Rendering', () => { it('should not show subtasks button when task has no subtasks', () => { render(); expect( screen.queryByTitle(/show subtasks/i) ).not.toBeInTheDocument(); expect( screen.queryByTitle(/hide subtasks/i) ).not.toBeInTheDocument(); }); it('should show subtasks button when task has subtasks', () => { render(); expect(screen.getByTitle(/show subtasks/i)).toBeInTheDocument(); }); it('should show hide subtasks button when subtasks are expanded', () => { render( ); expect(screen.getByTitle(/hide subtasks/i)).toBeInTheDocument(); }); it('should show subtasks button for completed tasks', () => { render( ); expect(screen.getByTitle(/show subtasks/i)).toBeInTheDocument(); }); it('should not show subtasks button for archived tasks', () => { const archivedTask = createMockTask({ status: 'archived' }); render( ); expect( screen.queryByTitle(/show subtasks/i) ).not.toBeInTheDocument(); }); }); describe('Subtasks Button Interaction', () => { it('should call onSubtasksToggle when subtasks button is clicked', async () => { const user = userEvent.setup(); const onSubtasksToggle = jest.fn(); render( ); const subtasksButton = screen.getByTitle(/show subtasks/i); await user.click(subtasksButton); expect(onSubtasksToggle).toHaveBeenCalledTimes(1); }); it('should prevent event propagation when subtasks button is clicked', async () => { const user = userEvent.setup(); const onTaskClick = jest.fn(); const onSubtasksToggle = jest.fn(); render( ); const subtasksButton = screen.getByTitle(/show subtasks/i); await user.click(subtasksButton); expect(onSubtasksToggle).toHaveBeenCalledTimes(1); expect(onTaskClick).not.toHaveBeenCalled(); }); it('should log subtasks button click for debugging', async () => { const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); const user = userEvent.setup(); render(); const subtasksButton = screen.getByTitle(/show subtasks/i); await user.click(subtasksButton); expect(consoleSpy).toHaveBeenCalledWith( 'Subtasks button clicked', expect.any(Object) ); consoleSpy.mockRestore(); }); }); describe('Subtasks Button Styling', () => { it('should have blue styling when subtasks are expanded', () => { render( ); const subtasksButton = screen.getByTitle(/hide subtasks/i); expect(subtasksButton).toHaveClass('bg-blue-100'); expect(subtasksButton).toHaveClass('text-blue-600'); }); it('should have gray styling when subtasks are collapsed', () => { render( ); const subtasksButton = screen.getByTitle(/show subtasks/i); expect(subtasksButton).toHaveClass('bg-gray-100'); expect(subtasksButton).toHaveClass('text-gray-600'); }); it('should have opacity-0 class when subtasks are collapsed', () => { render( ); const subtasksButton = screen.getByTitle(/show subtasks/i); expect(subtasksButton).toHaveClass('opacity-0'); expect(subtasksButton).toHaveClass('group-hover:opacity-100'); }); }); describe('Mobile Subtasks Button', () => { it('should show mobile subtasks button when hasSubtasks is true', () => { // Mock window.innerWidth to simulate mobile view Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 600, }); render(); // Should render both desktop and mobile versions const subtasksButtons = screen.getAllByTitle(/show subtasks/i); expect(subtasksButtons.length).toBeGreaterThan(1); }); it('should call onSubtasksToggle when mobile subtasks button is clicked', async () => { const user = userEvent.setup(); const onSubtasksToggle = jest.fn(); render( ); const subtasksButtons = screen.getAllByTitle(/show subtasks/i); await user.click(subtasksButtons[0]); // Click first button (could be mobile) expect(onSubtasksToggle).toHaveBeenCalledTimes(1); }); it('should log mobile subtasks button click for debugging', async () => { const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); const user = userEvent.setup(); render(); const subtasksButtons = screen.getAllByTitle(/show subtasks/i); await user.click(subtasksButtons[0]); expect(consoleSpy).toHaveBeenCalled(); consoleSpy.mockRestore(); }); }); describe('Task Status Integration', () => { it('should show all other controls alongside subtasks button', () => { const taskWithProject = createMockTask({ project_id: 1, due_date: '2023-12-31', priority: 'high', tags: [{ id: 1, name: 'important' }], }); render( ); // Should show subtasks button expect(screen.getByTitle(/show subtasks/i)).toBeInTheDocument(); // Should also show other controls (these would be tested in their respective components) expect(screen.getByText(taskWithProject.name)).toBeInTheDocument(); }); it('should handle task completion state properly with subtasks', () => { render( ); // Should show subtasks button even for completed tasks expect(screen.getByTitle(/show subtasks/i)).toBeInTheDocument(); }); }); describe('Accessibility', () => { it('should have proper ARIA attributes for subtasks button', () => { render(); const subtasksButton = screen.getByTitle(/show subtasks/i); expect(subtasksButton).toHaveAttribute('role', 'button'); expect(subtasksButton).toHaveAttribute('title', 'Show subtasks'); }); it('should update ARIA attributes when subtasks are expanded', () => { render( ); const subtasksButton = screen.getByTitle(/hide subtasks/i); expect(subtasksButton).toHaveAttribute('title', 'Hide subtasks'); }); it('should be keyboard accessible', async () => { const user = userEvent.setup(); const onSubtasksToggle = jest.fn(); render( ); const subtasksButton = screen.getByTitle(/show subtasks/i); await user.tab(); // Focus should be on the subtasks button (or at least navigable to it) expect(subtasksButton).toBeInTheDocument(); // Should be activatable with Enter or Space await user.keyboard('{Enter}'); // Note: This might not work perfectly due to the onClick handler, but the button should be focusable }); }); describe('Icon Rendering', () => { it('should render Squares2X2Icon in subtasks button', () => { render(); const subtasksButton = screen.getByTitle(/show subtasks/i); const icon = subtasksButton.querySelector('svg'); expect(icon).toBeInTheDocument(); expect(icon).toHaveClass('h-3', 'w-3'); }); }); describe('Task Header Layout', () => { it('should maintain proper layout with subtasks button', () => { render(); const subtasksButton = screen.getByTitle(/show subtasks/i); expect(subtasksButton).toHaveClass('w-6', 'h-6', 'rounded-full'); }); it('should position subtasks button correctly in button group', () => { render(); const subtasksButton = screen.getByTitle(/show subtasks/i); const buttonContainer = subtasksButton.closest('.flex'); expect(buttonContainer).toHaveClass('items-center'); }); }); });