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>
97 lines
2.8 KiB
JavaScript
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" } });
|
|
});
|
|
});
|