arugyani_depends/tests/debounce.test.ts
2026-04-29 19:11:59 -04:00

71 lines
1.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { debounce } from "../src/debounce";
describe("debounce", () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it("calls on the trailing edge after the delay", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d();
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(99);
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(1);
expect(fn).toHaveBeenCalledTimes(1);
});
it("coalesces rapid calls into a single trailing invocation", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d(1);
d(2);
d(3);
vi.advanceTimersByTime(100);
expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith(3);
});
it("resets the timer on each call", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d();
vi.advanceTimersByTime(80);
d();
vi.advanceTimersByTime(80);
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(20);
expect(fn).toHaveBeenCalledTimes(1);
});
it("cancel() prevents pending invocation", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d();
d.cancel();
vi.advanceTimersByTime(200);
expect(fn).not.toHaveBeenCalled();
});
it("flush() invokes immediately if pending", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d("a");
d.flush();
expect(fn).toHaveBeenCalledWith("a");
vi.advanceTimersByTime(200);
expect(fn).toHaveBeenCalledTimes(1);
});
it("flush() is a no-op when nothing pending", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d.flush();
expect(fn).not.toHaveBeenCalled();
});
});