import { describe, it, expect, vi, beforeEach } from 'vitest'; import { screen, fireEvent, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import SleepButton from '../../src/components/tracker/SleepButton'; import { useSleepSession } from '../../src/hooks/useSleepSession'; import { renderWithProviders } from '../test-utils'; vi.mock('../../src/hooks/useSleepSession', () => ({ useSleepSession: vi.fn(), })); describe('SleepButton', () => { beforeEach(() => { vi.clearAllMocks(); }); it('renders "Start Sleep" when no active session', async () => { vi.mocked(useSleepSession).mockReturnValue({ activeSession: null, isCreating: false, isEnding: false, } as any); renderWithProviders(); expect(screen.getByRole('button', { name: /Start Sleep/i })).toBeInTheDocument(); }); it('renders "Stop Sleep" when session is active', async () => { vi.mocked(useSleepSession).mockReturnValue({ activeSession: { id: 1, start_time: '2024-01-01T12:00' }, isCreating: false, isEnding: false, } as any); renderWithProviders(); expect(screen.getByRole('button', { name: /Stop Sleep/i })).toBeInTheDocument(); }); it('calls createSession when no active session and button is clicked', async () => { const createSessionMock = vi.fn(); vi.mocked(useSleepSession).mockReturnValue({ activeSession: null, isCreating: false, isEnding: false, createSession: createSessionMock, } as any); renderWithProviders(); const button = screen.getByRole('button', { name: /Start Sleep/i }); fireEvent.click(button); await waitFor(() => expect(createSessionMock).toHaveBeenCalledWith({ start_time: '2024-01-01T12:00' })); }); it('calls endSession when session is active and button is clicked', async () => { const endSessionMock = vi.fn(); vi.mocked(useSleepSession).mockReturnValue({ activeSession: { id: 1, start_time: '2024-01-01T12:00' }, isCreating: false, isEnding: false, endSession: endSessionMock, } as any); renderWithProviders(); const button = screen.getByRole('button', { name: /Stop Sleep/i }); fireEvent.click(button); await waitFor(() => expect(endSessionMock).toHaveBeenCalledWith({ sessionId: 1, endTime: '2024-01-01T14:00' })); }); it('handles endSession error gracefully', async () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const endSessionMock = vi.fn().mockRejectedValue(new Error('Failed to stop')); vi.mocked(useSleepSession).mockReturnValue({ activeSession: { id: 1, start_time: '2024-01-01T12:00' }, isCreating: false, isEnding: false, endSession: endSessionMock, } as any); renderWithProviders(); const button = screen.getByRole('button', { name: /Stop Sleep/i }); fireEvent.click(button); await waitFor(() => expect(consoleSpy).toHaveBeenCalledWith('Failed to update sleep session:', 'Failed to stop')); consoleSpy.mockRestore(); }); it('handles createSession error gracefully', async () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const createSessionMock = vi.fn().mockRejectedValue(new Error('Failed to start')); vi.mocked(useSleepSession).mockReturnValue({ activeSession: null, isCreating: false, isEnding: false, createSession: createSessionMock, } as any); renderWithProviders(); const button = screen.getByRole('button', { name: /Start Sleep/i }); fireEvent.click(button); await waitFor(() => expect(consoleSpy).toHaveBeenCalledWith('Failed to update sleep session:', 'Failed to start')); consoleSpy.mockRestore(); }); it('shows alert when time is invalid', async () => { const alertSpy = vi.spyOn(window, 'alert').mockImplementation(() => {}); vi.mocked(useSleepSession).mockReturnValue({ activeSession: null, isCreating: false, isEnding: false, } as any); renderWithProviders(); const button = screen.getByRole('button', { name: /Start Sleep/i }); fireEvent.click(button); expect(alertSpy).toHaveBeenCalledWith('Please select a valid time.'); alertSpy.mockRestore(); }); it('renders "Processing..." and disables button when isCreating is true', async () => { vi.mocked(useSleepSession).mockReturnValue({ activeSession: null, isCreating: true, isEnding: false, } as any); renderWithProviders(); const button = screen.getByRole('button'); expect(button).toBeDisabled(); expect(screen.getByText(/Processing.../i)).toBeInTheDocument(); }); it('renders "Processing..." and disables button when isEnding is true', async () => { vi.mocked(useSleepSession).mockReturnValue({ activeSession: { id: 1, start_time: '2024-01-01T12:00' }, isCreating: false, isEnding: true, } as any); renderWithProviders(); const button = screen.getByRole('button'); expect(button).toBeDisabled(); expect(screen.getByText(/Processing.../i)).toBeInTheDocument(); }); });