import { createDebouncedStorage } from '../store/debouncedStorage'; const makeBase = () => ({ getItem: jest.fn(async (_name: string): Promise => 'from-disk'), setItem: jest.fn(async (_name: string, _value: string) => {}), removeItem: jest.fn(async (_name: string) => {}), }); beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); describe('createDebouncedStorage', () => { it('collapses a burst of writes into one trailing write with the latest value', () => { const base = makeBase(); const storage = createDebouncedStorage(base, 400); storage.setItem('k', '1'); jest.advanceTimersByTime(300); storage.setItem('k', '2'); jest.advanceTimersByTime(300); storage.setItem('k', '3'); expect(base.setItem).not.toHaveBeenCalled(); jest.advanceTimersByTime(400); expect(base.setItem).toHaveBeenCalledTimes(1); expect(base.setItem).toHaveBeenCalledWith('k', '3'); }); it('reads a pending value before it reaches the disk, and falls back to the base storage', async () => { const base = makeBase(); const storage = createDebouncedStorage(base); await expect(storage.getItem('k')).resolves.toBe('from-disk'); storage.setItem('k', 'fresh'); await expect(storage.getItem('k')).resolves.toBe('fresh'); }); it('flush writes immediately and cancels the timer', async () => { const base = makeBase(); const storage = createDebouncedStorage(base); storage.setItem('a', '1'); storage.setItem('b', '2'); await storage.flush(); expect(base.setItem.mock.calls).toEqual([['a', '1'], ['b', '2']]); jest.advanceTimersByTime(1000); expect(base.setItem).toHaveBeenCalledTimes(2); }); it('flush with nothing pending does not write', async () => { const base = makeBase(); await createDebouncedStorage(base).flush(); expect(base.setItem).not.toHaveBeenCalled(); }); it('removeItem drops a pending write and removes from the base storage', async () => { const base = makeBase(); const storage = createDebouncedStorage(base); storage.setItem('k', '1'); await storage.removeItem('k'); jest.advanceTimersByTime(1000); expect(base.setItem).not.toHaveBeenCalled(); expect(base.removeItem).toHaveBeenCalledWith('k'); }); });