import { renderHook, act, waitFor } from '@testing-library/react'; import { useFormAutosave } from './use-form-autosave'; describe('useFormAutosave', () => { const mockKey = 'test_form'; const mockInitialData = { name: '', email: '' }; beforeEach(() => { localStorage.clear(); jest.clearAllMocks(); jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); it('should initialize with initial data', () => { const { result } = renderHook(() => useFormAutosave({ key: mockKey, initialData: mockInitialData, }) ); expect(result.current.data).toEqual(mockInitialData); expect(result.current.lastSaved).toBeNull(); expect(result.current.isRestored).toBe(false); }); it('should restore data from localStorage', () => { const savedData = { data: { name: 'John', email: 'john@example.com' }, timestamp: new Date().toISOString(), }; localStorage.setItem(`form_autosave_${mockKey}`, JSON.stringify(savedData)); const { result } = renderHook(() => useFormAutosave({ key: mockKey, initialData: mockInitialData, }) ); expect(result.current.data).toEqual(savedData.data); expect(result.current.isRestored).toBe(true); }); it('should not restore expired data', () => { const expiredData = { data: { name: 'John', email: 'john@example.com' }, timestamp: new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString(), // 25 hours ago }; localStorage.setItem(`form_autosave_${mockKey}`, JSON.stringify(expiredData)); const { result } = renderHook(() => useFormAutosave({ key: mockKey, initialData: mockInitialData, maxAge: 24 * 60 * 60 * 1000, // 24 hours }) ); expect(result.current.data).toEqual(mockInitialData); expect(result.current.isRestored).toBe(false); }); it('should update data and auto-save after debounce', async () => { const onSave = jest.fn(); const { result } = renderHook(() => useFormAutosave({ key: mockKey, initialData: mockInitialData, onSave, debounceMs: 1000, }) ); act(() => { result.current.updateData({ name: 'John' }); }); expect(result.current.data.name).toBe('John'); expect(result.current.lastSaved).toBeNull(); act(() => { jest.advanceTimersByTime(1000); }); await waitFor(() => { expect(result.current.lastSaved).not.toBeNull(); }); expect(onSave).toHaveBeenCalledWith({ name: 'John', email: '' }); }); it('should clear saved data', () => { const savedData = { data: { name: 'John', email: 'john@example.com' }, timestamp: new Date().toISOString(), }; localStorage.setItem(`form_autosave_${mockKey}`, JSON.stringify(savedData)); const { result } = renderHook(() => useFormAutosave({ key: mockKey, initialData: mockInitialData, }) ); act(() => { result.current.clearSavedData(); }); expect(result.current.data).toEqual(mockInitialData); expect(result.current.lastSaved).toBeNull(); expect(result.current.isRestored).toBe(false); expect(localStorage.getItem(`form_autosave_${mockKey}`)).toBeNull(); }); it('should save immediately when called', async () => { const onSave = jest.fn(); const { result } = renderHook(() => useFormAutosave({ key: mockKey, initialData: mockInitialData, onSave, debounceMs: 5000, }) ); act(() => { result.current.updateData({ name: 'John' }); }); // 等待状态更新 await waitFor(() => { expect(result.current.data.name).toBe('John'); }); act(() => { result.current.saveImmediately(); }); await waitFor(() => { expect(onSave).toHaveBeenCalledWith({ name: 'John', email: '' }); }); expect(result.current.lastSaved).not.toBeNull(); }); });