Skip to content

Commit 3c38075

Browse files
committed
test: add refresh-rate-limiter responsive breakpoint coverage
1 parent c091e3e commit 3c38075

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import refreshRateLimiter from './refresh-rate-limiter';
3+
4+
function setViewportWidth(width: number) {
5+
Object.defineProperty(window, 'innerWidth', {
6+
configurable: true,
7+
writable: true,
8+
value: width,
9+
});
10+
window.dispatchEvent(new Event('resize'));
11+
}
12+
13+
function mockMatchMedia(matches: boolean) {
14+
Object.defineProperty(window, 'matchMedia', {
15+
configurable: true,
16+
writable: true,
17+
value: vi.fn().mockImplementation((query: string) => ({
18+
matches,
19+
media: query,
20+
onchange: null,
21+
addListener: vi.fn(),
22+
removeListener: vi.fn(),
23+
addEventListener: vi.fn(),
24+
removeEventListener: vi.fn(),
25+
dispatchEvent: vi.fn(),
26+
})),
27+
});
28+
}
29+
30+
describe('RefreshRateLimiter responsive breakpoints', () => {
31+
beforeEach(() => {
32+
refreshRateLimiter.reset();
33+
setViewportWidth(1280);
34+
mockMatchMedia(false);
35+
});
36+
37+
it('allows refreshes normally on a mobile-width viewport (375px)', () => {
38+
setViewportWidth(375);
39+
mockMatchMedia(true);
40+
41+
const response = refreshRateLimiter.checkLimit('203.0.113.5');
42+
43+
expect(window.innerWidth).toBe(375);
44+
expect(response.success).toBe(true);
45+
expect(response.limit).toBe(3);
46+
expect(response.remaining).toBe(2);
47+
});
48+
49+
it('maintains the same rate-limit behavior when switching from desktop to mobile widths', () => {
50+
setViewportWidth(1280);
51+
const desktopResponse = refreshRateLimiter.checkLimit('198.51.100.10');
52+
53+
setViewportWidth(375);
54+
mockMatchMedia(true);
55+
const mobileResponse = refreshRateLimiter.checkLimit('198.51.100.10');
56+
57+
expect(window.innerWidth).toBe(375);
58+
expect(desktopResponse.success).toBe(true);
59+
expect(mobileResponse.success).toBe(true);
60+
expect(mobileResponse.remaining).toBe(desktopResponse.remaining - 1);
61+
});
62+
63+
it('reports cleanly when a mobile breakpoint is active and the same IP checks again', () => {
64+
setViewportWidth(375);
65+
mockMatchMedia(true);
66+
67+
const first = refreshRateLimiter.checkLimit('127.0.0.1');
68+
const second = refreshRateLimiter.checkLimit('127.0.0.1');
69+
70+
expect(first.success).toBe(true);
71+
expect(second.success).toBe(true);
72+
expect(second.remaining).toBe(1);
73+
expect(first.limit).toBe(3);
74+
});
75+
76+
it('enforces a custom mobile friendly limit without breaking on narrow viewports', () => {
77+
setViewportWidth(375);
78+
mockMatchMedia(true);
79+
refreshRateLimiter.setLimit(1, 60 * 60 * 1000);
80+
81+
const allowed = refreshRateLimiter.checkLimit('203.0.113.15');
82+
const blocked = refreshRateLimiter.checkLimit('203.0.113.15');
83+
84+
expect(allowed.success).toBe(true);
85+
expect(allowed.remaining).toBe(0);
86+
expect(blocked.success).toBe(false);
87+
expect(blocked.remaining).toBe(0);
88+
expect(blocked.limit).toBe(1);
89+
});
90+
91+
it('keeps responsive viewport simulation clean and does not depend on absolute width assumptions', () => {
92+
setViewportWidth(375);
93+
mockMatchMedia(true);
94+
95+
const response = refreshRateLimiter.checkLimit('192.0.2.1');
96+
97+
expect(window.innerWidth).toBeLessThanOrEqual(375);
98+
expect(response.success).toBe(true);
99+
expect(response.reset).toBeGreaterThan(Date.now() - 1000);
100+
expect(response.limit).toBe(3);
101+
});
102+
});

0 commit comments

Comments
 (0)