import { describe, expect, it, vi } from "vitest"; import { parseGithubRepoUrl, verifyRepo } from "@/lib/github"; describe("parseGithubRepoUrl", () => { it("normalizes case, .git and trailing slash", () => { const a = parseGithubRepoUrl("https://github.com/Foo/Bar.git"); const b = parseGithubRepoUrl("https://github.com/foo/bar/"); expect(a?.repoKey).toBe("foo/bar"); expect(b?.repoKey).toBe("foo/bar"); expect(a?.canonicalUrl).toBe("https://github.com/Foo/Bar"); }); it.each([ "http://github.com/a/b", "https://gitlab.com/a/b", "https://github.com/a", "https://github.com/a/b/tree/main", "https://github.com/a/b?x=1", "https://user@github.com/a/b", "https://github.com/../b", ])("rejects %s", (value) => { expect(parseGithubRepoUrl(value)).toBeUndefined(); }); }); describe("verifyRepo", () => { const ref = { owner: "a", repo: "b" }; const reply = (status: number, body: unknown = {}) => vi.fn().mockResolvedValue(new Response(JSON.stringify(body), { status })); it("accepts a public repo", async () => { expect(await verifyRepo(ref, reply(200, { private: false }))).toEqual({ status: "ok" }); }); it("rejects missing and private repos", async () => { expect(await verifyRepo(ref, reply(404))).toEqual({ status: "not_found" }); expect(await verifyRepo(ref, reply(200, { private: true }))).toEqual({ status: "not_found" }); }); it("treats rate limits, 5xx and network errors as unavailable", async () => { expect(await verifyRepo(ref, reply(403))).toEqual({ status: "unavailable" }); expect(await verifyRepo(ref, reply(502))).toEqual({ status: "unavailable" }); expect(await verifyRepo(ref, vi.fn().mockRejectedValue(new Error("timeout")))).toEqual({ status: "unavailable", }); }); });