import { beforeEach, describe, expect, it } from "bun:test"; import { Hono } from "hono"; import { _resetForTesting, rateLimit, } from "../../src/server/middleware/rateLimit"; function createApp() { const app = new Hono(); app.post("/login", rateLimit, (c) => c.json({ ok: true })); app.post("/setup", rateLimit, (c) => c.json({ ok: true })); return app; } function makeRequest(app: Hono, path: string, ip = "127.0.0.1") { return app.request(path, { method: "POST", headers: { "x-forwarded-for": ip }, }); } describe("rateLimit middleware", () => { beforeEach(() => { _resetForTesting(); }); it("allows first request through", async () => { const app = createApp(); const res = await makeRequest(app, "/login"); expect(res.status).toBe(200); }); it("allows up to 5 requests", async () => { const app = createApp(); for (let i = 0; i < 5; i++) { const res = await makeRequest(app, "/login"); expect(res.status).toBe(200); } }); it("returns 429 after 5 requests", async () => { const app = createApp(); for (let i = 0; i < 5; i++) { await makeRequest(app, "/login"); } const res = await makeRequest(app, "/login"); expect(res.status).toBe(429); const body = await res.json(); expect(body.error).toBe("Too many attempts. Try again later."); }); it("includes Retry-After header on 429", async () => { const app = createApp(); for (let i = 0; i < 5; i++) { await makeRequest(app, "/login"); } const res = await makeRequest(app, "/login"); expect(res.status).toBe(429); const retryAfter = res.headers.get("Retry-After"); expect(retryAfter).toBeTruthy(); expect(Number(retryAfter)).toBeGreaterThan(0); }); it("tracks different IPs independently", async () => { const app = createApp(); for (let i = 0; i < 5; i++) { await makeRequest(app, "/login", "10.0.0.1"); } const blocked = await makeRequest(app, "/login", "10.0.0.1"); expect(blocked.status).toBe(429); const allowed = await makeRequest(app, "/login", "10.0.0.2"); expect(allowed.status).toBe(200); }); it("tracks different paths independently", async () => { const app = createApp(); for (let i = 0; i < 5; i++) { await makeRequest(app, "/login"); } const blockedLogin = await makeRequest(app, "/login"); expect(blockedLogin.status).toBe(429); const allowedSetup = await makeRequest(app, "/setup"); expect(allowedSetup.status).toBe(200); }); });