karbe/tests/lib/rate-limit.test.ts
Claude Integration a373bd60ad
All checks were successful
CI / test (pull_request) Successful in 2m10s
feat(hardening): rate limit (signup/reset/bookings) + tâches cron + backup PostgreSQL nocturne
2026-06-01 20:16:57 +00:00

44 lines
1.4 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { rateLimit } from "@/lib/rate-limit";
describe("rateLimit", () => {
it("allows up to limit calls in window", () => {
const key = "test:" + Math.random();
for (let i = 0; i < 5; i++) {
const r = rateLimit({ key, windowMs: 60_000, limit: 5 });
expect(r.ok).toBe(true);
}
});
it("blocks the (limit+1)th call with retryAfter > 0", () => {
const key = "test:" + Math.random();
for (let i = 0; i < 3; i++) {
rateLimit({ key, windowMs: 60_000, limit: 3 });
}
const r = rateLimit({ key, windowMs: 60_000, limit: 3 });
expect(r.ok).toBe(false);
expect(r.retryAfter).toBeGreaterThan(0);
expect(r.remaining).toBe(0);
});
it("isolates different keys", () => {
const k1 = "test:" + Math.random();
const k2 = "test:" + Math.random();
for (let i = 0; i < 5; i++) {
rateLimit({ key: k1, windowMs: 60_000, limit: 5 });
}
const r = rateLimit({ key: k2, windowMs: 60_000, limit: 5 });
expect(r.ok).toBe(true);
});
it("resets after window expires", async () => {
const key = "test:" + Math.random();
rateLimit({ key, windowMs: 10, limit: 1 });
const blocked = rateLimit({ key, windowMs: 10, limit: 1 });
expect(blocked.ok).toBe(false);
await new Promise((r) => setTimeout(r, 15));
const after = rateLimit({ key, windowMs: 10, limit: 1 });
expect(after.ok).toBe(true);
});
});