129 lines
3.6 KiB
TypeScript
129 lines
3.6 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||
|
|
import { renderHook, act } from '@testing-library/react';
|
||
|
|
import { useLocalStorage } from './useLocalStorage';
|
||
|
|
|
||
|
|
// Mock localStorage
|
||
|
|
const localStorageMock = (() => {
|
||
|
|
let store: Record<string, string> = {};
|
||
|
|
|
||
|
|
return {
|
||
|
|
getItem: (key: string) => store[key] || null,
|
||
|
|
setItem: (key: string, value: string) => {
|
||
|
|
store[key] = value.toString();
|
||
|
|
},
|
||
|
|
removeItem: (key: string) => {
|
||
|
|
delete store[key];
|
||
|
|
},
|
||
|
|
clear: () => {
|
||
|
|
store = {};
|
||
|
|
},
|
||
|
|
};
|
||
|
|
})();
|
||
|
|
|
||
|
|
Object.defineProperty(window, 'localStorage', {
|
||
|
|
value: localStorageMock,
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('useLocalStorage', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
localStorageMock.clear();
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
localStorageMock.clear();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return initial value when localStorage is empty', () => {
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', 'initial'));
|
||
|
|
|
||
|
|
expect(result.current[0]).toBe('initial');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return stored value from localStorage', () => {
|
||
|
|
localStorageMock.setItem('test-key', JSON.stringify('stored-value'));
|
||
|
|
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', 'initial'));
|
||
|
|
|
||
|
|
expect(result.current[0]).toBe('stored-value');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should update localStorage when value changes', () => {
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', 'initial'));
|
||
|
|
|
||
|
|
act(() => {
|
||
|
|
result.current[1]('new-value');
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result.current[0]).toBe('new-value');
|
||
|
|
expect(localStorageMock.getItem('test-key')).toBe(JSON.stringify('new-value'));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle function updater', () => {
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', 0));
|
||
|
|
|
||
|
|
act(() => {
|
||
|
|
result.current[1]((prev) => prev + 1);
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result.current[0]).toBe(1);
|
||
|
|
expect(localStorageMock.getItem('test-key')).toBe(JSON.stringify(1));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should remove value from localStorage', () => {
|
||
|
|
localStorageMock.setItem('test-key', JSON.stringify('stored-value'));
|
||
|
|
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', 'initial'));
|
||
|
|
|
||
|
|
act(() => {
|
||
|
|
result.current[2]();
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result.current[0]).toBe('initial');
|
||
|
|
expect(localStorageMock.getItem('test-key')).toBeNull();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle complex objects', () => {
|
||
|
|
const initialValue = { name: 'John', age: 30 };
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', initialValue));
|
||
|
|
|
||
|
|
expect(result.current[0]).toEqual(initialValue);
|
||
|
|
|
||
|
|
act(() => {
|
||
|
|
result.current[1]({ name: 'Jane', age: 25 });
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result.current[0]).toEqual({ name: 'Jane', age: 25 });
|
||
|
|
expect(localStorageMock.getItem('test-key')).toBe(
|
||
|
|
JSON.stringify({ name: 'Jane', age: 25 }),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle arrays', () => {
|
||
|
|
const initialValue = [1, 2, 3];
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', initialValue));
|
||
|
|
|
||
|
|
expect(result.current[0]).toEqual(initialValue);
|
||
|
|
|
||
|
|
act(() => {
|
||
|
|
result.current[1]([4, 5, 6]);
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result.current[0]).toEqual([4, 5, 6]);
|
||
|
|
expect(localStorageMock.getItem('test-key')).toBe(JSON.stringify([4, 5, 6]));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle invalid JSON gracefully', () => {
|
||
|
|
localStorageMock.setItem('test-key', 'invalid-json');
|
||
|
|
|
||
|
|
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||
|
|
|
||
|
|
const { result } = renderHook(() => useLocalStorage('test-key', 'initial'));
|
||
|
|
|
||
|
|
expect(result.current[0]).toBe('initial');
|
||
|
|
expect(consoleWarnSpy).toHaveBeenCalled();
|
||
|
|
|
||
|
|
consoleWarnSpy.mockRestore();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|