import { renderHook, act } from '@testing-library/react'; import { describe, it, expect, beforeEach, vi } from 'vitest'; import { useSettings } from '../../../src/hooks/useSettings'; import { SettingsProvider } from '../../../src/hooks/SettingsProvider'; describe('useSettings hook', () => { // Mock implementation of localStorage const localStorageMock = (() => { let store: Record = {}; return { getItem: vi.fn((key: string) => store[key] || null), setItem: vi.fn((key: string, value: string) => { store[key] = value.toString(); }), removeItem: vi.fn((key: string) => { delete store[key]; }), clear: vi.fn(() => { store = {}; }), }; })(); beforeEach(() => { vi.stubGlobal('localStorage', localStorageMock); vi.clearAllMocks(); // Clear the mock store (localStorage as any).clear(); }); const wrapper = ({ children }: { children: React.ReactNode }) => ( {children} ); it('should return default settings when wrapped in SettingsProvider', () => { const { result } = renderHook(() => useSettings(), { wrapper }); expect(result.current.settings).toEqual({ dayStart: '07:00', dayEnd: '20:00', wakeupRef: '04:00', bedtimeRef: '19:00', statsInterval: 7, sessionsPerPage: 10, }); }); it('should throw an error when used outside of SettingsProvider', () => { expect(() => renderHook(() => useSettings())).toThrow( 'useSettings must be used within a SettingsProvider' ); }); it('should update settings correctly via the update function', () => { const { result } = renderHook(() => useSettings(), { wrapper }); act(() => { result.current.update('dayStart', '08:30'); }); expect(result.current.settings.dayStart).toBe('08:30'); // Verify other settings remain unchanged expect(result.current.settings.dayEnd).toBe('20:00'); }); it('should persist updated settings to localStorage', () => { const setItemSpy = vi.spyOn(localStorage, 'setItem'); const { result } = renderHook(() => useSettings(), { wrapper }); act(() => { result.current.update('statsInterval', 14); }); expect(setItemSpy).toHaveBeenCalledWith( 'baby-sleep-settings', expect.stringContaining('"statsInterval":14') ); }); it('should initialize with settings from localStorage if available', () => { const storedSettings = { dayStart: '10:00', dayEnd: '22:00', wakeupRef: '06:00', bedtimeRef: '21:00', statsInterval: 5, sessionsPerPage: 20, }; localStorage.setItem('baby-sleep-settings', JSON.stringify(storedSettings)); const { result } = renderHook(() => useSettings(), { wrapper }); expect(result.current.settings).toEqual(storedSettings); }); it('should fallback to default settings if localStorage contains invalid JSON', () => { localStorage.setItem('baby-sleep-settings', 'invalid-json'); const { result } = renderHook(() => useSettings(), { wrapper }); expect(result.current.settings).toEqual({ dayStart: '07:00', dayEnd: '20:00', wakeupRef: '04:00', bedtimeRef: '19:00', statsInterval: 7, sessionsPerPage: 10, }); }); it('should handle empty localStorage by using default settings', () => { localStorage.clear(); const { result } = renderHook(() => useSettings(), { wrapper }); expect(result.current.settings).toEqual({ dayStart: '07:00', dayEnd: '20:00', wakeupRef: '04:00', bedtimeRef: '19:00', statsInterval: 7, sessionsPerPage: 10, }); }); });