mirror of
https://github.com/Warky-Devs/artemis-kit.git
synced 2025-05-19 03:37:30 +00:00
224 lines
5.5 KiB
TypeScript
224 lines
5.5 KiB
TypeScript
import { describe, it, expect, afterEach, vi, beforeEach } from "vitest";
|
|
import { WaitUntil, debounce, throttle, measureTime } from "./index";
|
|
|
|
describe("WaitUntil", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("should resolve when condition becomes true", async () => {
|
|
let flag = false;
|
|
setTimeout(() => {
|
|
flag = true;
|
|
}, 1000);
|
|
|
|
const promise = WaitUntil(() => flag);
|
|
await vi.advanceTimersByTimeAsync(1000);
|
|
|
|
await promise; // Should resolve without throwing
|
|
});
|
|
|
|
it("should reject on timeout", async () => {
|
|
let rejected = false;
|
|
const promise = WaitUntil(() => false).catch((err) => {
|
|
expect(err.message).toBe("Wait Timeout");
|
|
rejected = true;
|
|
});
|
|
|
|
await vi.advanceTimersByTimeAsync(5000);
|
|
await promise;
|
|
expect(rejected).toBe(true);
|
|
});
|
|
|
|
it("should respect custom timeout", async () => {
|
|
let rejected = false;
|
|
const promise = WaitUntil(() => false, { timeout: 2000 }).catch((err) => {
|
|
expect(err.message).toBe("Wait Timeout");
|
|
rejected = true;
|
|
});
|
|
|
|
await vi.advanceTimersByTimeAsync(2000);
|
|
await promise;
|
|
expect(rejected).toBe(true);
|
|
});
|
|
|
|
it("should check condition at specified interval", async () => {
|
|
const mockCondition = vi.fn(() => false);
|
|
let rejected = false;
|
|
|
|
const promise = WaitUntil(mockCondition, { interval: 200 }).catch((err) => {
|
|
expect(err.message).toBe("Wait Timeout");
|
|
rejected = true;
|
|
});
|
|
|
|
await vi.advanceTimersByTimeAsync(1000);
|
|
expect(mockCondition).toHaveBeenCalledTimes(5); // 1000ms / 200ms = 5 calls
|
|
|
|
await vi.advanceTimersByTimeAsync(4000);
|
|
await promise;
|
|
expect(rejected).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("debounce", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("should delay function execution", () => {
|
|
const mockFn = vi.fn();
|
|
const debouncedFn = debounce(mockFn, 1000);
|
|
|
|
debouncedFn();
|
|
expect(mockFn).not.toBeCalled();
|
|
|
|
vi.advanceTimersByTime(1000);
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should only execute once for multiple calls within wait period", () => {
|
|
const mockFn = vi.fn();
|
|
const debouncedFn = debounce(mockFn, 1000);
|
|
|
|
debouncedFn();
|
|
debouncedFn();
|
|
debouncedFn();
|
|
|
|
vi.advanceTimersByTime(1000);
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should pass correct arguments to the debounced function", () => {
|
|
const mockFn = vi.fn();
|
|
const debouncedFn = debounce(mockFn, 1000);
|
|
|
|
debouncedFn("test", 123);
|
|
vi.advanceTimersByTime(1000);
|
|
|
|
expect(mockFn).toHaveBeenCalledWith("test", 123);
|
|
});
|
|
|
|
it("should reset timer on subsequent calls", () => {
|
|
const mockFn = vi.fn();
|
|
const debouncedFn = debounce(mockFn, 1000);
|
|
|
|
debouncedFn();
|
|
vi.advanceTimersByTime(500);
|
|
|
|
debouncedFn();
|
|
vi.advanceTimersByTime(500);
|
|
expect(mockFn).not.toBeCalled();
|
|
|
|
vi.advanceTimersByTime(500);
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe("throttle", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("should execute immediately on first call", () => {
|
|
const mockFn = vi.fn();
|
|
const throttledFn = throttle(mockFn, 1000);
|
|
|
|
throttledFn();
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should ignore calls within throttle period", () => {
|
|
const mockFn = vi.fn();
|
|
const throttledFn = throttle(mockFn, 1000);
|
|
|
|
throttledFn();
|
|
throttledFn();
|
|
throttledFn();
|
|
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should allow execution after throttle period", () => {
|
|
const mockFn = vi.fn();
|
|
const throttledFn = throttle(mockFn, 1000);
|
|
|
|
throttledFn();
|
|
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
|
|
vi.advanceTimersByTime(1000);
|
|
throttledFn();
|
|
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("should pass correct arguments to the throttled function", () => {
|
|
const mockFn = vi.fn();
|
|
const throttledFn = throttle(mockFn, 1000);
|
|
|
|
throttledFn("test", 123);
|
|
expect(mockFn).toHaveBeenCalledWith("test", 123);
|
|
});
|
|
});
|
|
|
|
describe("measureTime", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("should measure execution time of async function", async () => {
|
|
const delay = (ms: number) =>
|
|
new Promise((resolve) => setTimeout(resolve, ms));
|
|
const fn = async () => {
|
|
await delay(100);
|
|
return "result";
|
|
};
|
|
|
|
const measurePromise = measureTime(fn);
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
const { result, duration } = await measurePromise;
|
|
|
|
expect(result).toBe("result");
|
|
expect(duration).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should handle rejected promises", async () => {
|
|
const fn = async () => {
|
|
throw new Error("Test error");
|
|
};
|
|
|
|
await expect(measureTime(fn)).rejects.toThrow("Test error");
|
|
});
|
|
|
|
it("should return precise timing for fast operations", async () => {
|
|
const fn = async () => "quick result";
|
|
|
|
const { duration } = await measureTime(fn);
|
|
expect(duration).toBeLessThan(100); // Should be nearly instant
|
|
});
|
|
|
|
it("should handle functions returning different types", async () => {
|
|
const numberFn = async () => 42;
|
|
const { result: numResult } = await measureTime(numberFn);
|
|
expect(numResult).toBe(42);
|
|
|
|
const objectFn = async () => ({ key: "value" });
|
|
const { result: objResult } = await measureTime(objectFn);
|
|
expect(objResult).toEqual({ key: "value" });
|
|
});
|
|
});
|