@zendesk/react-measure-timing-hooks
Version:
react hooks for measuring time to interactive and time to render of components
149 lines (125 loc) • 4.54 kB
text/typescript
import {
afterEach,
beforeEach,
describe,
expect,
it,
vitest as jest,
} from 'vitest'
import {
debounce,
type DebouncedFn,
type DebounceOptionsRef,
DebounceReason,
TimeoutReason,
} from './debounce'
describe('debounce', () => {
let mockFn: jest.Mock
let optionsRef: DebounceOptionsRef<readonly [string]>
let debouncedFn: DebouncedFn<readonly [string]>
beforeEach(() => {
jest.useFakeTimers()
mockFn = jest.fn()
optionsRef = {
fn: mockFn,
debounceMs: 100,
}
debouncedFn = debounce(optionsRef)
})
afterEach(() => {
jest.useRealTimers()
})
it('should call the debounced function once after the debounce period', () => {
debouncedFn('test')
expect(mockFn).not.toHaveBeenCalled()
jest.advanceTimersByTime(100)
expect(mockFn).toHaveBeenCalledWith('test', DebounceReason)
})
it('should not call the debounced function if it is cancelled before the debounce period', () => {
debouncedFn('test')
expect(mockFn).not.toHaveBeenCalled()
debouncedFn.cancel()
jest.advanceTimersByTime(100)
expect(mockFn).not.toHaveBeenCalled()
})
it('should call the debounced function with the TimeoutReason if a timeout is set', () => {
debouncedFn = debounce({ ...optionsRef, timeoutMs: 200 })
debouncedFn('test')
expect(mockFn).not.toHaveBeenCalled()
// keep timeout after regular debounce:
mockFn.mockReturnValue(true)
jest.advanceTimersByTime(200)
expect(mockFn).toHaveBeenNthCalledWith(1, 'test', DebounceReason)
expect(mockFn).toHaveBeenNthCalledWith(2, 'test', TimeoutReason)
})
it('should reset the debounce function state', () => {
debouncedFn('test')
debouncedFn.reset()
expect(debouncedFn.getIsScheduled()).toBe(false)
expect(debouncedFn.reset()).toBeUndefined()
jest.advanceTimersByTime(100)
expect(mockFn).not.toHaveBeenCalled()
})
it('should manually flush the debounced function', () => {
debouncedFn('test')
const wasFlushed = debouncedFn.flush()
expect(wasFlushed).toBe(true)
expect(mockFn).toHaveBeenCalledWith('test', 'manual')
})
it('should not flush if there is nothing scheduled', () => {
const wasFlushed = debouncedFn.flush()
expect(wasFlushed).toBe(false)
expect(mockFn).not.toHaveBeenCalled()
})
it('should keep the timeout if the debounced function returns true', () => {
mockFn.mockReturnValue(true)
debouncedFn = debounce({ ...optionsRef, timeoutMs: 200 })
debouncedFn('test')
jest.advanceTimersByTime(100)
expect(mockFn).toHaveBeenCalledWith('test', DebounceReason)
expect(debouncedFn.getIsScheduled()).toBe(true)
})
it('should clear the timeout if the debounced function returns false', () => {
mockFn.mockReturnValue(false)
debouncedFn = debounce({ ...optionsRef, timeoutMs: 200 })
debouncedFn('test')
jest.advanceTimersByTime(100)
expect(mockFn).toHaveBeenCalledWith('test', DebounceReason)
expect(debouncedFn.getIsScheduled()).toBe(false)
})
it('should pass FlushReason as the last argument to the debounced function', () => {
debouncedFn('test')
jest.advanceTimersByTime(100)
expect(mockFn).toHaveBeenCalledWith('test', DebounceReason)
})
it('should correctly handle optionsRef being mutated after the debounced function was created', () => {
debouncedFn('test')
const otherMockFn = jest.fn()
optionsRef.debounceMs = 200
optionsRef.timeoutMs = 300
optionsRef.fn = otherMockFn
debouncedFn('test2')
jest.advanceTimersByTime(100)
expect(mockFn).not.toHaveBeenCalled()
expect(otherMockFn).not.toHaveBeenCalled()
jest.advanceTimersByTime(100)
expect(mockFn).not.toHaveBeenCalled()
expect(otherMockFn).toHaveBeenLastCalledWith('test2', DebounceReason)
otherMockFn.mockReturnValue(true)
debouncedFn('test3')
jest.advanceTimersByTime(200)
expect(mockFn).not.toHaveBeenCalled()
expect(otherMockFn).toHaveBeenLastCalledWith('test3', DebounceReason)
jest.advanceTimersByTime(100)
expect(otherMockFn).toHaveBeenLastCalledWith('test3', TimeoutReason)
})
it('should correctly call the underlying function once, even when run multiple times in a row with different arguments', () => {
debouncedFn('test1')
debouncedFn('test2')
debouncedFn('test3')
expect(mockFn).not.toHaveBeenCalled()
jest.advanceTimersByTime(100)
expect(mockFn).toHaveBeenCalledTimes(1)
expect(mockFn).toHaveBeenCalledWith('test3', DebounceReason)
})
})