-
Notifications
You must be signed in to change notification settings - Fork 0
🧪 Add missing error handling tests for handleRateLimit #488
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; | ||
| import { handleRateLimit } from "../../github"; | ||
| import { RateLimitError } from "../../types"; | ||
|
|
||
| describe("handleRateLimit", () => { | ||
| beforeEach(() => { | ||
| vi.useFakeTimers(); | ||
| vi.setSystemTime(new Date("2024-01-01T00:00:00Z")); // 1704067200 in seconds | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| vi.useRealTimers(); | ||
| }); | ||
|
|
||
| it("throws RateLimitError with valid X-RateLimit-Reset header", () => { | ||
| const validTimestamp = 1704070800; // 1 hour later | ||
| const res = { | ||
| headers: new Headers({ "X-RateLimit-Reset": validTimestamp.toString() }) | ||
| } as unknown as Response; | ||
|
|
||
| try { | ||
| handleRateLimit(res); | ||
| expect.fail("Should throw RateLimitError"); | ||
| } catch (e) { | ||
| expect(e).toBeInstanceOf(RateLimitError); | ||
| expect((e as RateLimitError).resetAt.getTime()).toBe(validTimestamp * 1000); | ||
| } | ||
| }); | ||
|
|
||
| it("throws RateLimitError with fallback timestamp when header is missing", () => { | ||
| const res = { | ||
| headers: new Headers() // Empty headers | ||
| } as unknown as Response; | ||
|
|
||
| const currentSeconds = Math.floor(Date.now() / 1000); | ||
| const expectedFallback = currentSeconds + 3600; | ||
|
|
||
| try { | ||
| handleRateLimit(res); | ||
| expect.fail("Should throw RateLimitError"); | ||
| } catch (e) { | ||
| expect(e).toBeInstanceOf(RateLimitError); | ||
| expect((e as RateLimitError).resetAt.getTime()).toBe(expectedFallback * 1000); | ||
| } | ||
|
Comment on lines
+38
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using A cleaner and safer pattern is to catch the error into a local variable and perform assertions on it outside the let error: unknown;
try {
handleRateLimit(res);
} catch (e) {
error = e;
}
expect(error).toBeInstanceOf(RateLimitError);
expect((error as RateLimitError).resetAt.getTime()).toBe(expectedFallback * 1000); |
||
| }); | ||
|
|
||
| it("throws RateLimitError with fallback timestamp when header is invalid", () => { | ||
| const res = { | ||
| headers: new Headers({ "X-RateLimit-Reset": "invalid_timestamp" }) | ||
| } as unknown as Response; | ||
|
|
||
| const currentSeconds = Math.floor(Date.now() / 1000); | ||
| const expectedFallback = currentSeconds + 3600; | ||
|
|
||
| try { | ||
| handleRateLimit(res); | ||
| expect.fail("Should throw RateLimitError"); | ||
| } catch (e) { | ||
| expect(e).toBeInstanceOf(RateLimitError); | ||
| expect((e as RateLimitError).resetAt.getTime()).toBe(expectedFallback * 1000); | ||
| } | ||
|
Comment on lines
+55
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using A cleaner and safer pattern is to catch the error into a local variable and perform assertions on it outside the let error: unknown;
try {
handleRateLimit(res);
} catch (e) {
error = e;
}
expect(error).toBeInstanceOf(RateLimitError);
expect((error as RateLimitError).resetAt.getTime()).toBe(expectedFallback * 1000); |
||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
expect.fail()inside atryblock where thecatchblock catches all errors is a test anti-pattern. IfhandleRateLimit(res)does not throw,expect.fail()will throw anAssertionError, which is then caught by thecatchblock. The assertionexpect(e).toBeInstanceOf(RateLimitError)will then fail, masking the originalexpect.fail()message and making debugging confusing.A cleaner and safer pattern is to catch the error into a local variable and perform assertions on it outside the
try/catchblock.