/* eslint-disable @typescript-eslint/no-explicit-any */ import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom'; import { vi, describe, it, expect, beforeEach } from 'vitest'; import Timetable from '../../../../src/components/stats/SleepTimetable'; import { useStats } from '../../../../src/hooks/useStats'; vi.mock('../../../../src/hooks/useStats', () => ({ useStats: vi.fn(), })); describe('SleepTimetable', () => { const defaultProps = { from_date: '2025-04-18', to_date: '2025-04-25', day_start: '22:00', day_end: '08:00', }; beforeEach(() => { vi.clearAllMocks(); vi.stubGlobal('innerWidth', 1024); }); it('renders loading state', () => { (useStats as any).mockReturnValue({ timetable: null, isLoading: true }); render(); expect(screen.getByText(/Loading timetable.../i)).toBeInTheDocument(); }); it('renders empty state when no data is available', () => { (useStats as any).mockReturnValue({ timetable: { slots: [] }, isLoading: false }); render(); expect(screen.getByText(/No data available/i)).toBeInTheDocument(); }); it('renders in desktop mode (chronological order)', () => { (useStats as any).mockReturnValue({ timetable: { slots: [{ date: '2025-04-18', sleeping: true, slot_start: '01:00', slot_end: '05:00' }] }, isLoading: false, }); vi.stubGlobal('innerWidth', 1024); render(); // Check for day headers in chronological order const days = screen.getAllByText(/^[A-Z]{3}$/i); // SUN, MON, etc. // 2025-04-18 is Friday (FRI) expect(days[0]).toHaveTextContent(/FRI/i); expect(days[1]).toHaveTextContent(/SAT/i); }); it('renders in medium mode (3-day tabs and 3-column grid)', () => { (useStats as any).mockReturnValue({ timetable: { slots: [{ date: '2025-04-18', sleeping: true, slot_start: '01:00', slot_end: '05:00' }] }, isLoading: false, }); vi.stubGlobal('innerWidth', 600); render(); fireEvent(window, new Event('resize')); // Check for 3-day interval tabs // In reversed order (25, 24, 23...), the first group is Fri - Wed expect(screen.getByRole('button', { name: /FRI - WED/i })).toBeInTheDocument(); }); it('renders in small mode (single-day tabs and 1-column grid)', () => { (useStats as any).mockReturnValue({ timetable: { slots: [{ date: '2025-04-18', sleeping: true, slot_start: '01:00', slot_end: '05:00' }] }, isLoading: false, }); vi.stubGlobal('innerWidth', 300); render(); fireEvent(window, new Event('resize')); // Check for single-day tabs const dayTabs = screen.getAllByRole('button'); // At least one tab should have the text FRI const friTab = dayTabs.find(tab => tab.textContent?.toUpperCase().includes('FRI')); expect(friTab).toBeInTheDocument(); }); it('colors sleeping intervals correctly', () => { (useStats as any).mockReturnValue({ timetable: { slots: [ { date: '2025-04-18', sleeping: true, slot_start: '01:00', slot_end: '03:00', // Covers 01:00 and 02:00 }, ], }, isLoading: false, }); const { container } = render(); // We are looking for the grid cells. // Since they don't have text, we look at their classes/backgrounds. const greenCells = container.querySelectorAll('.bg-green-500'); expect(greenCells.length).toBeGreaterThan(0); const grayCells = container.querySelectorAll('.bg-gray-50'); expect(grayCells.length).toBeGreaterThan(0); }); });