@ehsaneha/react-debounce
Version:
useDebounce is a custom React hook that delays invoking a function until a specified time has passed since the last call, ideal for handling user input like search fields.
60 lines (59 loc) • 2.66 kB
JavaScript
import React, { useState } from "react";
import { render, fireEvent, screen, act } from "@testing-library/react";
import { useDebounce } from "./index";
jest.useFakeTimers();
function TestComponent({ delay = 500 }) {
const [value, setValue] = useState("");
const debouncedSet = useDebounce((newVal) => {
setValue(newVal);
}, delay);
return (React.createElement("div", null,
React.createElement("input", { "data-testid": "input", onChange: (e) => debouncedSet(e.target.value), placeholder: "Type here" }),
React.createElement("div", { "data-testid": "output" }, value)));
}
describe("useDebounce", () => {
beforeEach(() => {
jest.clearAllTimers();
});
it("does not call function immediately", () => {
render(React.createElement(TestComponent, null));
const input = screen.getByTestId("input");
fireEvent.change(input, { target: { value: "a" } });
expect(screen.getByTestId("output").textContent).toBe("");
});
it("calls function after delay", () => {
render(React.createElement(TestComponent, null));
const input = screen.getByTestId("input");
fireEvent.change(input, { target: { value: "hello" } });
act(() => {
jest.advanceTimersByTime(500);
});
expect(screen.getByTestId("output").textContent).toBe("hello");
});
it("resets timer on rapid input changes", () => {
render(React.createElement(TestComponent, null));
const input = screen.getByTestId("input");
fireEvent.change(input, { target: { value: "a" } });
act(() => jest.advanceTimersByTime(300));
fireEvent.change(input, { target: { value: "ab" } });
act(() => jest.advanceTimersByTime(300));
fireEvent.change(input, { target: { value: "abc" } });
// Not enough time has passed
act(() => jest.advanceTimersByTime(400));
expect(screen.getByTestId("output").textContent).toBe("");
// Now enough time has passed
act(() => jest.advanceTimersByTime(100));
expect(screen.getByTestId("output").textContent).toBe("abc");
});
it("cleans up timer on unmount", () => {
const { unmount } = render(React.createElement(TestComponent, null));
const input = screen.getByTestId("input");
fireEvent.change(input, { target: { value: "abc" } });
unmount();
act(() => {
jest.runAllTimers();
});
// Should not throw or update state after unmount
// Can't assert output change, but ensures no error
});
});