import { afterEach, describe, expect, test } from "vitest"; import { check, reset } from "@/lib/rate-limit"; afterEach(() => reset()); describe("rate limiter", () => { test("allows requests under the limit", () => { for (let i = 0; i < 5; i++) { const r = check("k", 5, 60_000); expect(r.ok).toBe(true); } }); test("blocks at the limit and reports retry-after", () => { for (let i = 0; i < 5; i++) check("k", 5, 60_000); const r = check("k", 5, 60_000); expect(r.ok).toBe(false); if (!r.ok) { expect(r.retryAfterSec).toBeGreaterThan(0); expect(r.retryAfterSec).toBeLessThanOrEqual(60); } }); test("different keys are independent", () => { for (let i = 0; i < 5; i++) check("a", 5, 60_000); const r = check("b", 5, 60_000); expect(r.ok).toBe(true); }); test("window resets when expired", () => { // Use a 10ms window so the test runs fast for (let i = 0; i < 3; i++) check("k", 3, 10); const blocked = check("k", 3, 10); expect(blocked.ok).toBe(false); return new Promise((done) => { setTimeout(() => { const after = check("k", 3, 10); expect(after.ok).toBe(true); done(); }, 25); }); }); test("remaining count counts down", () => { const r1 = check("k", 3, 60_000); const r2 = check("k", 3, 60_000); expect(r1.ok && r1.remaining).toBe(2); expect(r2.ok && r2.remaining).toBe(1); }); });