forked from cardosofelipe/fast-next-template
- Refactored JSX elements to improve readability by collapsing multi-line props and attributes into single lines if their length permits. - Improved consistency in component imports by grouping and consolidating them. - No functional changes, purely restructuring for clarity and maintainability.
149 lines
4.0 KiB
TypeScript
149 lines
4.0 KiB
TypeScript
import { renderHook, act } from '@testing-library/react';
|
|
import { useDebounce } from '@/lib/hooks/useDebounce';
|
|
|
|
describe('useDebounce', () => {
|
|
beforeEach(() => {
|
|
jest.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
it('returns the initial value immediately', () => {
|
|
const { result } = renderHook(() => useDebounce('initial', 500));
|
|
expect(result.current).toBe('initial');
|
|
});
|
|
|
|
it('updates the debounced value after the delay', () => {
|
|
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
|
initialProps: { value: 'initial', delay: 500 },
|
|
});
|
|
|
|
// Change the value
|
|
rerender({ value: 'updated', delay: 500 });
|
|
|
|
// Value should still be initial before delay
|
|
expect(result.current).toBe('initial');
|
|
|
|
// Fast forward time
|
|
act(() => {
|
|
jest.advanceTimersByTime(500);
|
|
});
|
|
|
|
// Value should now be updated
|
|
expect(result.current).toBe('updated');
|
|
});
|
|
|
|
it('does not update the value before the delay', () => {
|
|
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
|
initialProps: { value: 'initial', delay: 500 },
|
|
});
|
|
|
|
rerender({ value: 'updated', delay: 500 });
|
|
|
|
// Only advance 300ms (not enough)
|
|
act(() => {
|
|
jest.advanceTimersByTime(300);
|
|
});
|
|
|
|
expect(result.current).toBe('initial');
|
|
});
|
|
|
|
it('resets the timer when value changes rapidly', () => {
|
|
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
|
initialProps: { value: 'initial', delay: 500 },
|
|
});
|
|
|
|
// First change
|
|
rerender({ value: 'first', delay: 500 });
|
|
|
|
// Advance 300ms
|
|
act(() => {
|
|
jest.advanceTimersByTime(300);
|
|
});
|
|
|
|
// Second change (should reset timer)
|
|
rerender({ value: 'second', delay: 500 });
|
|
|
|
// Advance another 300ms (total 600ms from first, but only 300ms from second)
|
|
act(() => {
|
|
jest.advanceTimersByTime(300);
|
|
});
|
|
|
|
// Value should still be initial (timer was reset)
|
|
expect(result.current).toBe('initial');
|
|
|
|
// Advance the remaining 200ms
|
|
act(() => {
|
|
jest.advanceTimersByTime(200);
|
|
});
|
|
|
|
// Now should show 'second'
|
|
expect(result.current).toBe('second');
|
|
});
|
|
|
|
it('cleans up timeout on unmount', () => {
|
|
const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');
|
|
|
|
const { unmount, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
|
initialProps: { value: 'initial', delay: 500 },
|
|
});
|
|
|
|
rerender({ value: 'updated', delay: 500 });
|
|
unmount();
|
|
|
|
expect(clearTimeoutSpy).toHaveBeenCalled();
|
|
clearTimeoutSpy.mockRestore();
|
|
});
|
|
|
|
it('works with different delay values', () => {
|
|
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
|
initialProps: { value: 'initial', delay: 1000 },
|
|
});
|
|
|
|
rerender({ value: 'updated', delay: 1000 });
|
|
|
|
act(() => {
|
|
jest.advanceTimersByTime(500);
|
|
});
|
|
|
|
expect(result.current).toBe('initial');
|
|
|
|
act(() => {
|
|
jest.advanceTimersByTime(500);
|
|
});
|
|
|
|
expect(result.current).toBe('updated');
|
|
});
|
|
|
|
it('works with different value types', () => {
|
|
// Test with number
|
|
const { result: numberResult } = renderHook(() => useDebounce(42, 500));
|
|
expect(numberResult.current).toBe(42);
|
|
|
|
// Test with object
|
|
const obj = { foo: 'bar' };
|
|
const { result: objectResult } = renderHook(() => useDebounce(obj, 500));
|
|
expect(objectResult.current).toEqual({ foo: 'bar' });
|
|
|
|
// Test with null
|
|
const { result: nullResult } = renderHook(() => useDebounce(null, 500));
|
|
expect(nullResult.current).toBeNull();
|
|
});
|
|
|
|
it('handles zero delay', () => {
|
|
const { result, rerender } = renderHook(({ value, delay }) => useDebounce(value, delay), {
|
|
initialProps: { value: 'initial', delay: 0 },
|
|
});
|
|
|
|
rerender({ value: 'updated', delay: 0 });
|
|
|
|
act(() => {
|
|
jest.advanceTimersByTime(0);
|
|
});
|
|
|
|
expect(result.current).toBe('updated');
|
|
});
|
|
});
|