Files
github-stats-extended/packages/core/tests/retryer.test.js
T
MartinandMarco Pasqualetti d476f8cbe1 extract "core" package, small improvements (#137)
This PR mainly refactors the code by extracting a "core" package which
is then used by the "backend" and "frontend" apps.

Apart from this the PR also contains several smaller changes like fixing
dependabot, upgrading dependencies, aligned "package.json" files, added
tests, ...

addresses step 1 of #32 
closes #136

---------

Co-authored-by: Marco Pasqualetti <marco.pasqualetti@live.com>
2026-04-18 10:37:26 +02:00

97 lines
2.8 KiB
JavaScript

// @ts-check
import { describe, expect, it, vi } from "vitest";
import { logger } from "../src/common/log.js";
import { retryer } from "../src/common/retryer.js";
const fetcher = vi.fn((variables, token) => {
logger.log(variables, token);
return new Promise((res) => res({ data: "ok" }));
});
const fetcherFail = vi.fn(() => {
return new Promise((res) =>
res({ data: { errors: [{ type: "RATE_LIMITED" }] } }),
);
});
const fetcherFailOnSecondTry = vi.fn((_vars, _token, retries) => {
return new Promise((res) => {
// faking rate limit
// @ts-ignore
if (retries < 1) {
return res({ data: { errors: [{ type: "RATE_LIMITED" }] } });
}
return res({ data: "ok" });
});
});
const fetcherFailWithMessageBasedRateLimitErr = vi.fn(
(_vars, _token, retries) => {
return new Promise((res) => {
// faking rate limit
// @ts-ignore
if (retries < 1) {
return res({
data: {
errors: [
{
type: "ASDF",
message: "API rate limit already exceeded for user ID 11111111",
},
],
},
});
}
return res({ data: "ok" });
});
},
);
const customFetcher = vi.fn((variables, token) => {
logger.log(variables, token);
return Promise.resolve({ data: { token } });
});
describe("Test Retryer", () => {
it("retryer should return value and have zero retries on first try", async () => {
let res = await retryer(fetcher, {});
expect(fetcher).toHaveBeenCalledTimes(1);
expect(res).toStrictEqual({ data: "ok" });
});
it("retryer should return value and have 2 retries", async () => {
let res = await retryer(fetcherFailOnSecondTry, {});
expect(fetcherFailOnSecondTry).toHaveBeenCalledTimes(2);
expect(res).toStrictEqual({ data: "ok" });
});
it("retryer should return value and have 2 retries with message based rate limit error", async () => {
let res = await retryer(fetcherFailWithMessageBasedRateLimitErr, {});
expect(fetcherFailWithMessageBasedRateLimitErr).toHaveBeenCalledTimes(2);
expect(res).toStrictEqual({ data: "ok" });
});
it("retryer should throw specific error if maximum retries reached", async () => {
try {
await retryer(fetcherFail, {});
} catch (err) {
expect(fetcherFail).toHaveBeenCalledTimes(2);
// @ts-ignore
expect(err.message).toBe("Downtime due to GitHub API rate limiting");
}
});
it("retryer should use injected PATs when provided", async () => {
const res = await retryer(customFetcher, {}, "user-pat-token");
expect(customFetcher).toHaveBeenCalledTimes(1);
expect(customFetcher).toHaveBeenCalledWith({}, "user-pat-token", 0);
expect(res).toStrictEqual({ data: { token: "user-pat-token" } });
});
});