diff --git a/src/lib/__tests__/github/fetchRepositories.test.ts b/src/lib/__tests__/github/fetchRepositories.test.ts deleted file mode 100644 index 7f47f97..0000000 --- a/src/lib/__tests__/github/fetchRepositories.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { mockFetch, jsonResponse, MOCK_REPOS_GRAPHQL } from "./setup"; - -describe("fetchRepositories", () => { - it("GraphQL レスポンスから言語統計を正しく集計する", async () => { - mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_REPOS_GRAPHQL)); // POST graphql - - const { fetchRepositories } = await import("../../github"); - const result = await fetchRepositories("testuser", "fake-token"); - - // フォークを除外した2リポジトリ - expect(result.totalCount).toBe(2); - - // 言語統計: Python 8000bytes, TypeScript 5000bytes, JavaScript 2000bytes - expect(result.languages.length).toBeGreaterThanOrEqual(2); - expect(result.languages[0].name).toBe("Python"); - expect(result.languages[0].bytes).toBe(8000); - expect(result.languages[1].name).toBe("TypeScript"); - expect(result.languages[1].bytes).toBe(5000); - }); - - it("GraphQL レスポンスからトピックを正しく集計する", async () => { - mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_REPOS_GRAPHQL)); - - const { fetchRepositories } = await import("../../github"); - const result = await fetchRepositories("testuser", "fake-token"); - - const topicNames = result.topics.map((t) => t.name); - expect(topicNames).toContain("react"); - expect(topicNames).toContain("nextjs"); - expect(topicNames).toContain("machine-learning"); - }); - - it("言語のパーセンテージが正しく計算される", async () => { - mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_REPOS_GRAPHQL)); - - const { fetchRepositories } = await import("../../github"); - const result = await fetchRepositories("testuser", "fake-token"); - - const totalBytes = result.languages.reduce((sum, l) => sum + l.bytes, 0); - expect(totalBytes).toBe(15000); // 5000 + 2000 + 8000 - - for (const lang of result.languages) { - const expectedPct = Math.round((lang.bytes / totalBytes) * 1000) / 10; - expect(lang.percentage).toBe(expectedPct); - } - }); - - it("topRepos は最大5件で stargazerCount 順に返される", async () => { - mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_REPOS_GRAPHQL)); - - const { fetchRepositories } = await import("../../github"); - const result = await fetchRepositories("testuser", "fake-token"); - - expect(result.topRepos.length).toBeLessThanOrEqual(5); - expect(result.topRepos[0].name).toBe("repo-a"); - expect(result.topRepos[0].stargazerCount).toBe(50); - }); - - it("token なしの場合 REST にフォールバックする", async () => { - const restRepos = [ - { - name: "rest-repo", - description: "A REST repo", - html_url: "https://github.com/testuser/rest-repo", - stargazers_count: 25, - forks_count: 3, - fork: false, - language: "JavaScript", - topics: ["web"], - }, - ]; - mockFetch.mockResolvedValueOnce(jsonResponse(restRepos)); - - const { fetchRepositories } = await import("../../github"); - const result = await fetchRepositories("testuser"); - - expect(result.totalCount).toBe(1); - expect(result.topRepos[0].name).toBe("rest-repo"); - expect(result.languages[0].name).toBe("JavaScript"); - }); - - it("ユーザーが存在しない場合 UserNotFoundError をスローする", async () => { - mockFetch.mockResolvedValueOnce( - jsonResponse({ data: { user: null } }) - ); - - const { fetchRepositories } = await import("../../github"); - const { UserNotFoundError } = await import("../../types"); - - await expect(fetchRepositories("nonexistent", "fake-token")).rejects.toThrow( - UserNotFoundError - ); - }); -}); diff --git a/src/lib/github.ts b/src/lib/github.ts index ed7dd37..df06c2e 100644 --- a/src/lib/github.ts +++ b/src/lib/github.ts @@ -301,7 +301,7 @@ type RepositoriesResponse = { * @throws {UserNotFoundError} ユーザーが存在しない場合 * @throws {RateLimitError} APIレート制限に達した場合 */ -export const fetchRepositories = cache(async function fetchRepositories( +const fetchRepositories = cache(async function fetchRepositories( username: string, token?: string ): Promise {