UNPKG

@qazuor/react-hooks

Version:

A comprehensive collection of production-ready React hooks for modern web applications. Features type-safe implementations, extensive testing, and zero dependencies. Includes hooks for state management, browser APIs, user interactions, and development uti

174 lines (130 loc) 5.36 kB
import { act, renderHook } from '@testing-library/react'; import { useWindowWidth } from '../src/hooks/useWindowWidth'; describe('useWindowWidth', () => { let onChange: jest.Mock; let initialInnerWidth: number; beforeEach(() => { jest.useFakeTimers(); jest.clearAllTimers(); jest.clearAllMocks(); onChange = jest.fn(); initialInnerWidth = window.innerWidth; Object.defineProperty(window, 'innerWidth', { value: 1200, configurable: true }); }); afterEach(() => { jest.clearAllTimers(); jest.clearAllMocks(); Object.defineProperty(window, 'innerWidth', { value: initialInnerWidth, configurable: true }); }); it('should initialize with current window width', () => { const hook = renderHook(() => useWindowWidth({ onChange })); expect(hook.result.current.width).toBe(window.innerWidth); expect(onChange).not.toHaveBeenCalled(); hook.unmount(); }); it('should update width on resize with debounce', () => { const hook = renderHook(() => useWindowWidth({ onChange })); expect(hook.result.current.width).toBe(1200); const newWidth = 1024; act(() => { window.innerWidth = newWidth; window.dispatchEvent(new Event('resize')); }); expect(hook.result.current.width).toBe(1200); expect(onChange).not.toHaveBeenCalled(); act(() => { jest.advanceTimersByTime(250); }); expect(hook.result.current.width).toBe(newWidth); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(newWidth); hook.unmount(); }); it('should handle custom debounce delay', () => { const customDelayHook = renderHook(() => useWindowWidth({ debounceDelay: 500, onChange })); expect(customDelayHook.result.current.width).toBe(1200); act(() => { window.innerWidth = 800; window.dispatchEvent(new Event('resize')); jest.advanceTimersByTime(250); }); expect(customDelayHook.result.current.width).toBe(1200); expect(onChange).not.toHaveBeenCalled(); act(() => { jest.advanceTimersByTime(250); }); expect(customDelayHook.result.current.width).toBe(800); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(800); customDelayHook.unmount(); }); it('should handle start/stop monitoring', () => { const hook = renderHook(() => useWindowWidth({ onChange })); expect(hook.result.current.width).toBe(1200); act(() => { hook.result.current.stop(); }); expect(hook.result.current.width).toBe(1200); window.innerWidth = 1400; act(() => { window.dispatchEvent(new Event('resize')); jest.advanceTimersByTime(250); }); expect(hook.result.current.width).toBe(1200); expect(onChange).not.toHaveBeenCalled(); act(() => { hook.result.current.start(); }); expect(hook.result.current.width).toBe(1200); act(() => { window.innerWidth = 1300; window.dispatchEvent(new Event('resize')); jest.advanceTimersByTime(250); }); expect(hook.result.current.width).toBe(1300); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(1300); hook.unmount(); }); it('should respect startImmediately option', () => { const nonAutoStartHook = renderHook(() => useWindowWidth({ startImmediately: false, onChange }) ); expect(nonAutoStartHook.result.current.width).toBe(1200); expect(onChange).not.toHaveBeenCalled(); Object.defineProperty(window, 'innerWidth', { value: 1500, configurable: true }); act(() => { document.dispatchEvent(new Event('resize')); jest.advanceTimersByTime(250); }); expect(nonAutoStartHook.result.current.width).toBe(1200); expect(onChange).not.toHaveBeenCalled(); nonAutoStartHook.unmount(); }); it('should cleanup event listeners on unmount', () => { const hook = renderHook(() => useWindowWidth({ onChange })); const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener'); hook.unmount(); expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function)); removeEventListenerSpy.mockRestore(); }); it('should handle rapid resize events', () => { const hook = renderHook(() => useWindowWidth({ onChange })); act(() => { window.innerWidth = 800; window.dispatchEvent(new Event('resize')); window.innerWidth = 900; window.dispatchEvent(new Event('resize')); window.innerWidth = 1000; window.dispatchEvent(new Event('resize')); jest.advanceTimersByTime(250); }); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(1000); expect(hook.result.current.width).toBe(1000); hook.unmount(); }); });