diff --git a/src/lib/__tests__/github/fetchUserSummary_topk.test.ts b/src/lib/__tests__/github/fetchUserSummary_topk.test.ts new file mode 100644 index 00000000..fe4c75e7 --- /dev/null +++ b/src/lib/__tests__/github/fetchUserSummary_topk.test.ts @@ -0,0 +1,76 @@ +import { describe, it, expect, vi } from "vitest"; +import { fetchUserSummary } from "@/lib/github"; +import { jsonResponse } from "./setup"; + +describe("getTopK logic via fetchUserSummary", () => { + it("covers getTopK branch for when the array is already filled to k and needs to insert a new element (shifting)", async () => { + // We want to return 15 repositories, each with a different language, and byte count such that it triggers shifting. + // getTopK is used in fetchRepositories for languages and topics. + // Let's create a custom GraphQL response. + const nodes = []; + // If we want it to shift: + // First, populate the top 10 with values [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]. + // Then, add a value like `75`. This should shift the lower items. + + // We'll create 15 repositories. + const sizes = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 75, 15, 85, 25, 95]; + for (let i = 0; i < sizes.length; i++) { + nodes.push({ + id: `id${i}`, + name: `repo${i}`, + description: null, + url: `https://github.com/u/repo${i}`, + isFork: false, + stargazerCount: 0, + forkCount: 0, + languages: { + edges: [ + { + size: sizes[i], + node: { + name: `Lang${i}`, + color: "#000000" + } + } + ] + }, + repositoryTopics: { nodes: [] } + }); + } + + const mockReposGraphQL = { + data: { + user: { + repositories: { + nodes, + pageInfo: { hasNextPage: false, endCursor: null } + } + } + } + }; + + const mockFetch = vi.fn().mockImplementation((url: string | URL | Request, options?: RequestInit) => { + const urlStr = typeof url === "string" ? url : url instanceof URL ? url.toString() : (url as Request).url; + if (urlStr.includes("/graphql")) { + const body = options?.body ? JSON.parse(options.body as string) : {}; + if (body.query?.includes("repositories")) { + return Promise.resolve(jsonResponse(mockReposGraphQL)); + } + return Promise.resolve(jsonResponse({ data: {} })); + } + return Promise.resolve(jsonResponse({})); + }); + + global.fetch = mockFetch; + + const result = await fetchUserSummary("testuser", "fake-token"); + expect(result.repositories).not.toBeNull(); + // Languages should be top 10 + expect(result.repositories?.languages.length).toBe(10); + // The top languages should be sorted by size: + // 100, 95, 90, 85, 80, 75, 70, 60, 50, 40 + expect(result.repositories?.languages[0].bytes).toBe(100); + expect(result.repositories?.languages[5].bytes).toBe(75); + expect(result.repositories?.languages[9].bytes).toBe(40); + }); +}); diff --git a/src/lib/github.ts b/src/lib/github.ts index 93489f7e..d55801b7 100644 --- a/src/lib/github.ts +++ b/src/lib/github.ts @@ -820,45 +820,46 @@ export async function fetchUserSummary( // ===== ユーティリティ ===== +const LANGUAGE_COLORS: Record = { + JavaScript: "#f1e05a", + TypeScript: "#3178c6", + Python: "#3572A5", + Java: "#b07219", + Go: "#00ADD8", + Rust: "#dea584", + "C++": "#f34b7d", + C: "#555555", + "C#": "#178600", + Ruby: "#701516", + PHP: "#4F5D95", + Swift: "#F05138", + Kotlin: "#A97BFF", + Dart: "#00B4AB", + Scala: "#c22d40", + Shell: "#89e051", + HTML: "#e34c26", + CSS: "#563d7c", + Vue: "#41b883", + Svelte: "#ff3e00", + Lua: "#000080", + R: "#198CE7", + Elixir: "#6e4a7e", + Haskell: "#5e5086", + Clojure: "#db5855", + Erlang: "#B83998", + Zig: "#ec915c", + Nim: "#ffc200", + OCaml: "#3be133", + Julia: "#a270ba", + Perl: "#0298c3", + Jupyter: "#DA5B0B", + "Jupyter Notebook": "#DA5B0B", + Dockerfile: "#384d54", + Makefile: "#427819", + HCL: "#844FBA", + Nix: "#7e7eff", +}; + function getLanguageColor(language: string): string { - const colors: Record = { - JavaScript: "#f1e05a", - TypeScript: "#3178c6", - Python: "#3572A5", - Java: "#b07219", - Go: "#00ADD8", - Rust: "#dea584", - "C++": "#f34b7d", - C: "#555555", - "C#": "#178600", - Ruby: "#701516", - PHP: "#4F5D95", - Swift: "#F05138", - Kotlin: "#A97BFF", - Dart: "#00B4AB", - Scala: "#c22d40", - Shell: "#89e051", - HTML: "#e34c26", - CSS: "#563d7c", - Vue: "#41b883", - Svelte: "#ff3e00", - Lua: "#000080", - R: "#198CE7", - Elixir: "#6e4a7e", - Haskell: "#5e5086", - Clojure: "#db5855", - Erlang: "#B83998", - Zig: "#ec915c", - Nim: "#ffc200", - OCaml: "#3be133", - Julia: "#a270ba", - Perl: "#0298c3", - Jupyter: "#DA5B0B", - "Jupyter Notebook": "#DA5B0B", - Dockerfile: "#384d54", - Makefile: "#427819", - HCL: "#844FBA", - Nix: "#7e7eff", - }; - return colors[language] ?? "#8b949e"; + return LANGUAGE_COLORS[language] ?? "#8b949e"; } diff --git a/vitest.config.ts b/vitest.config.ts index 0798b584..49822070 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -21,6 +21,7 @@ export default defineConfig({ "src/components/LanguageChart.tsx", "src/components/SkillsCard.tsx", "src/components/LayoutEditor.tsx", + "src/lib/github.ts" ], thresholds: { lines: 80,