Skip to content

Instantly share code, notes, and snippets.

@ranpa
Created May 23, 2023 12:32
Show Gist options
  • Save ranpa/68ceb9b09382e5d0f93c957eb83aea9c to your computer and use it in GitHub Desktop.
Save ranpa/68ceb9b09382e5d0f93c957eb83aea9c to your computer and use it in GitHub Desktop.
Test scenarios for a declarative implementation of the setInterval method
import {
afterAll,
afterEach,
beforeAll,
describe,
expect,
test,
vi,
} from "vitest";
import { renderHook } from "@testing-library/react";
import { useInterval } from "./useInterval";
describe("useInterval Hook", () => {
beforeAll(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.restoreAllMocks();
vi.clearAllTimers();
});
afterAll(() => {
vi.useRealTimers();
});
describe("Scenario: start Interval", () => {
test(`
GIVEN an interval period in milliseconds
AND a callback function
WHEN this interval period has passed
THEN it should invoke the callback
`, () => {
const interval = 5000;
const callback = vi.fn();
const { rerender } = renderHook(() => {
useInterval(callback, interval);
});
rerender();
expect(callback).toHaveBeenCalledTimes(0);
vi.advanceTimersToNextTimer();
rerender();
expect(callback).toHaveBeenCalledTimes(1);
vi.advanceTimersByTime(10 * interval);
rerender();
expect(callback).toHaveBeenCalledTimes(11);
});
});
describe("Scenario: stop Interval", () => {
test(`
GIVEN an already started process
WHEN a undefined interval is passed
THEN it should stop (clear the timer)
`, () => {
const initialInterval = 1000;
const callback = vi.fn();
const { rerender } = renderHook(
({ interval }) => {
useInterval(callback, interval);
},
{ initialProps: { interval: initialInterval } },
);
expect(callback).toHaveBeenCalledTimes(0);
vi.advanceTimersToNextTimer();
rerender({ interval: initialInterval });
expect(callback).toHaveBeenCalledTimes(1);
// @ts-expect-error Although the params from useInterval accept `undefined`, `rerender` doesn't get it
rerender({ interval: undefined });
vi.advanceTimersByTime(10 * initialInterval);
// @ts-expect-error Although the params from useInterval accept `undefined`, `rerender` doesn't get it
rerender({ interval: undefined });
expect(callback).toHaveBeenCalledTimes(1);
});
});
describe("Scenario: stop Interval before unmount", () => {
test(`
GIVEN an already started process
WHEN the component which renders the hook is unmounted
THEN it should stop (clear the timer)
`, () => {
const interval = 1000;
const callback = vi.fn();
const { rerender, unmount } = renderHook(() => {
useInterval(callback, interval);
});
vi.advanceTimersToNextTimer();
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