124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
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<string, string> = {};
|
|
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 }) => (
|
|
<SettingsProvider>{children}</SettingsProvider>
|
|
);
|
|
|
|
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,
|
|
});
|
|
});
|
|
});
|