Skip to content

Instantly share code, notes, and snippets.

@ranpa
Created May 23, 2023 13:08
Show Gist options
  • Save ranpa/385411f3f289709413de59c4bf7edb16 to your computer and use it in GitHub Desktop.
Save ranpa/385411f3f289709413de59c4bf7edb16 to your computer and use it in GitHub Desktop.
Test scenarios for a declarative way of calling a callback from time to time (polling)
import {
afterAll,
afterEach,
beforeAll,
describe,
expect,
test,
vi,
} from "vitest";
import { renderHook } from "@testing-library/react";
import { usePolling } from "./usePolling";
describe("usePolling Hook", () => {
beforeAll(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.resetAllMocks();
});
afterAll(() => {
vi.useRealTimers();
vi.restoreAllMocks();
});
describe("Scenario: start polling", () => {
test(`
GIVEN an interval period in milliseconds
AND a callback function
WHEN the hook is rendered
THEN it should start polling (invoke the callback)
`, () => {
const interval = 5000;
const callback = vi.fn();
const { rerender } = renderHook(() => usePolling({ callback, interval }));
rerender();
expect(callback).toHaveBeenCalledTimes(1);
vi.advanceTimersToNextTimer();
rerender();
expect(callback).toHaveBeenCalledTimes(2);
vi.advanceTimersByTime(10 * interval);
rerender();
expect(callback).toHaveBeenCalledTimes(12);
});
});
describe("Scenario: start polling after a given delay", () => {
test(`
GIVEN an interval period (in milliseconds)
AND a delay period (in millisecond)
AND a callback function
WHEN the hook is renreded
THEN it should wait the delay period
AND start polling (invoke the callback)
`, () => {
const interval = 1000;
const delay = 20000;
const callback = vi.fn();
const { rerender } = renderHook(() =>
usePolling({ callback, interval, delay }),
);
rerender();
expect(callback).toHaveBeenCalledTimes(0);
vi.advanceTimersByTime(delay);
rerender();
expect(callback).toHaveBeenCalledTimes(1);
vi.advanceTimersByTime(interval / 2);
rerender();
expect(callback).toHaveBeenCalledTimes(1);
vi.advanceTimersByTime(10 * interval);
rerender();
expect(callback).toHaveBeenCalledTimes(11);
});
});
describe("Scenario: stop polling", () => {
test(`
GIVEN an already started polling process
WHEN a undefined interval is passed
THEN it should stop polling (clear the timer)
`, () => {
const initialInterval = 1000;
const callback = vi.fn();
const { rerender } = renderHook(
({ interval }) => usePolling({ callback, interval }),
{
initialProps: { interval: initialInterval },
},
);
rerender({ interval: initialInterval });
expect(callback).toHaveBeenCalledTimes(1);
rerender({ interval: undefined });
vi.advanceTimersByTime(10 * initialInterval);
rerender({ interval: undefined });
expect(callback).toHaveBeenCalledTimes(1);
});
});
describe("Scenario: stop polling before unmount", () => {
test(`
GIVEN an already started polling process
WHEN the component which renders the hook is unomounted
THEN it should stop polling (clear the timer)
`, () => {
const interval = 1000;
const callback = vi.fn();
const { rerender, unmount } = renderHook(() =>
usePolling({ callback, interval }),
);
rerender();
expect(callback).toHaveBeenCalledTimes(1);
unmount();
vi.advanceTimersByTime(10 * interval);
expect(callback).toHaveBeenCalledTimes(1);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment