Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164// src/plugin/__tests__/debouncer.test.tsimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'import { Debouncer } from '../utils/debouncer'
describe('Debouncer', () => { beforeEach(() => { vi.useFakeTimers() })
afterEach(() => { vi.useRealTimers() })
describe('basic debounce', () => { it('calls callback after delay expires', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('arg1') expect(callback).not.toHaveBeenCalled()
vi.advanceTimersByTime(100) expect(callback).toHaveBeenCalledWith('arg1') expect(callback).toHaveBeenCalledTimes(1) })
it('coalesces rapid calls and uses latest arguments', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('first') vi.advanceTimersByTime(50) debouncer.call('second') vi.advanceTimersByTime(50) debouncer.call('third')
// Only 100ms from last call vi.advanceTimersByTime(100) expect(callback).toHaveBeenCalledWith('third') expect(callback).toHaveBeenCalledTimes(1) }) })
describe('flush', () => { it('immediately invokes callback with pending arguments', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('pending') debouncer.flush()
expect(callback).toHaveBeenCalledWith('pending') expect(callback).toHaveBeenCalledTimes(1) })
it('does nothing if no pending call', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.flush() expect(callback).not.toHaveBeenCalled() })
it('clears pending state after flush', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('arg') debouncer.flush() expect(debouncer.isPending()).toBe(false)
// Advancing time should not trigger another call vi.advanceTimersByTime(200) expect(callback).toHaveBeenCalledTimes(1) }) })
describe('cancel', () => { it('cancels pending call without invoking callback', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('arg') debouncer.cancel()
vi.advanceTimersByTime(200) expect(callback).not.toHaveBeenCalled() expect(debouncer.isPending()).toBe(false) }) })
describe('edge cases', () => { it('handles zero delay', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 0)
debouncer.call('immediate') vi.advanceTimersByTime(0)
expect(callback).toHaveBeenCalledWith('immediate') })
it('isPending returns true during callback execution', () => { let pendingDuringCallback: boolean | undefined const debouncer = new Debouncer((_arg: string) => { pendingDuringCallback = debouncer.isPending() }, 100)
debouncer.call('arg') vi.advanceTimersByTime(100)
// isPending should have been true during callback execution expect(pendingDuringCallback).toBe(true) // But false after callback completes expect(debouncer.isPending()).toBe(false) }) })
describe('dispose', () => { it('cancels pending and rejects future calls', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('before') debouncer.dispose() debouncer.call('after')
vi.advanceTimersByTime(200) expect(callback).not.toHaveBeenCalled() expect(debouncer.isDisposed()).toBe(true) })
it('flush does nothing after dispose', () => { const callback = vi.fn() const debouncer = new Debouncer(callback, 100)
debouncer.call('pending') debouncer.dispose() debouncer.flush()
expect(callback).not.toHaveBeenCalled() }) })
describe('multiple instances', () => { it('each debouncer operates independently', () => { const callback1 = vi.fn() const callback2 = vi.fn() const debouncer1 = new Debouncer(callback1, 100) const debouncer2 = new Debouncer(callback2, 50)
debouncer1.call('a') debouncer2.call('b')
vi.advanceTimersByTime(50) expect(callback1).not.toHaveBeenCalled() expect(callback2).toHaveBeenCalledWith('b')
vi.advanceTimersByTime(50) expect(callback1).toHaveBeenCalledWith('a') }) })})