Files
syndarix/frontend/tests/lib/hooks/useDebounce.test.ts
Felipe Cardoso a4c91cb8c3 refactor(frontend): clean up code by consolidating multi-line JSX into single lines where feasible
- 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.
2026-01-01 11:46:57 +01:00

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');
});
});