profileShare

rasmusjy / roundtable

Read-only snapshot

No repository description.

main default branch 181 files Expires Sep 13, 2026, 9:06 AM

Commit

test rate limiter

commit a246141

1 changed file with +37 and −0

added src/lib/rate-limit.test.ts +37 −0
@@ -0,0 +1,37 @@
1 +import { describe, expect, it } from 'vitest';
2 +import { rateLimit } from './rate-limit';
3 +
4 +describe('rateLimit', () => {
5 + it('allows up to the limit, then blocks', () => {
6 + const key = 'test-block';
7 + const window = 60_000;
8 + expect(rateLimit(key, 3, window).allowed).toBe(true);
9 + expect(rateLimit(key, 3, window).allowed).toBe(true);
10 + expect(rateLimit(key, 3, window).allowed).toBe(true);
11 + const blocked = rateLimit(key, 3, window);
12 + expect(blocked.allowed).toBe(false);
13 + expect(blocked.remaining).toBe(0);
14 + expect(blocked.resetMs).toBeGreaterThan(0);
15 + });
16 +
17 + it('reports decreasing remaining budget', () => {
18 + const key = 'test-remaining';
19 + expect(rateLimit(key, 5, 60_000).remaining).toBe(4);
20 + expect(rateLimit(key, 5, 60_000).remaining).toBe(3);
21 + });
22 +
23 + it('tracks keys independently', () => {
24 + const window = 60_000;
25 + rateLimit('user-a', 1, window);
26 + expect(rateLimit('user-a', 1, window).allowed).toBe(false);
27 + // A different key still has its full budget.
28 + expect(rateLimit('user-b', 1, window).allowed).toBe(true);
29 + });
30 +
31 + it('lets requests through again once the window has passed', () => {
32 + const key = 'test-window';
33 + // Zero-length window: the previous hit is always outside it.
34 + expect(rateLimit(key, 1, 0).allowed).toBe(true);
35 + expect(rateLimit(key, 1, 0).allowed).toBe(true);
36 + });
37 +});