From 02a43d1de40fa55cf7ee9d8b2fe1cc5ebdfa3c20 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 06:29:20 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A7=AA=20Add=20tests=20for=20dashboar?= =?UTF-8?q?d/stats=20API=20route?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com> --- src/app/api/dashboard/stats/route.test.ts | 149 ++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/app/api/dashboard/stats/route.test.ts diff --git a/src/app/api/dashboard/stats/route.test.ts b/src/app/api/dashboard/stats/route.test.ts new file mode 100644 index 0000000..b6b99f2 --- /dev/null +++ b/src/app/api/dashboard/stats/route.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, it, vi, beforeEach } from "vitest"; +import { NextRequest } from "next/server"; +import { GET } from "./route"; +import { getServerSession } from "next-auth"; +import { fetchViewerLogin } from "@/lib/githubViewer"; +import { fetchCommitActivityHeatmap } from "@/lib/githubYearInReview"; + +// Mock dependencies +vi.mock("next-auth", () => ({ + getServerSession: vi.fn(), +})); + +vi.mock("@/lib/githubViewer", () => ({ + fetchViewerLogin: vi.fn(), +})); + +vi.mock("@/lib/githubYearInReview", () => ({ + fetchCommitActivityHeatmap: vi.fn(), +})); + +describe("GET /api/dashboard/stats", () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + const createRequest = (url: string) => new NextRequest(new URL(url)); + + it("should return 401 if unauthorized (no session)", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce(null); + + const req = createRequest("http://localhost/api/dashboard/stats"); + const res = await GET(req); + + expect(res.status).toBe(401); + expect(await res.json()).toEqual({ error: "Unauthorized" }); + }); + + it("should return 401 if unauthorized (no token)", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { name: "Test User" }, + expires: "1", + }); + + const req = createRequest("http://localhost/api/dashboard/stats"); + const res = await GET(req); + + expect(res.status).toBe(401); + expect(await res.json()).toEqual({ error: "Unauthorized" }); + }); + + it("should return 400 for invalid year (too old)", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { name: "Test User" }, + accessToken: "mock-token", + expires: "1", + }); + + const req = createRequest("http://localhost/api/dashboard/stats?year=2000"); + const res = await GET(req); + + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ error: "Invalid year" }); + }); + + it("should return 400 for invalid year (future)", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { name: "Test User" }, + accessToken: "mock-token", + expires: "1", + }); + + const futureYear = new Date().getUTCFullYear() + 1; + const req = createRequest(`http://localhost/api/dashboard/stats?year=${futureYear}`); + const res = await GET(req); + + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ error: "Invalid year" }); + }); + + it("should handle error in catch block and return 500", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { login: "testuser" }, + accessToken: "mock-token", + expires: "1", + }); + + const errorMessage = "Failed to fetch heatmap"; + vi.mocked(fetchCommitActivityHeatmap).mockRejectedValueOnce(new Error(errorMessage)); + + const req = createRequest("http://localhost/api/dashboard/stats"); + const res = await GET(req); + + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ error: errorMessage }); + }); + + it("should handle unknown error in catch block and return 500", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { login: "testuser" }, + accessToken: "mock-token", + expires: "1", + }); + + vi.mocked(fetchCommitActivityHeatmap).mockRejectedValueOnce("String error, not an Error instance"); + + const req = createRequest("http://localhost/api/dashboard/stats"); + const res = await GET(req); + + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ error: "Unknown error" }); + }); + + it("should return 200 and heatmap data on success", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { login: "testuser" }, + accessToken: "mock-token", + expires: "1", + }); + + const mockHeatmap = { days: [], maxCount: 0 }; + vi.mocked(fetchCommitActivityHeatmap).mockResolvedValueOnce(mockHeatmap); + + const currentYear = new Date().getUTCFullYear(); + const req = createRequest("http://localhost/api/dashboard/stats"); + const res = await GET(req); + + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ year: currentYear, heatmap: mockHeatmap }); + }); + + it("should use fetchViewerLogin when user.login is missing", async () => { + vi.mocked(getServerSession).mockResolvedValueOnce({ + user: { name: "Test User" }, // no login + accessToken: "mock-token", + expires: "1", + }); + + vi.mocked(fetchViewerLogin).mockResolvedValueOnce("fetcheduser"); + const mockHeatmap = { days: [], maxCount: 0 }; + vi.mocked(fetchCommitActivityHeatmap).mockResolvedValueOnce(mockHeatmap); + + const req = createRequest("http://localhost/api/dashboard/stats"); + const res = await GET(req); + + expect(fetchViewerLogin).toHaveBeenCalledWith("mock-token"); + expect(fetchCommitActivityHeatmap).toHaveBeenCalledWith("fetcheduser", expect.any(Number), "mock-token"); + expect(res.status).toBe(200); + }); +}); From 69ebe169226ad486a98429499dd1c518802c0877 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 06:33:51 +0000 Subject: [PATCH 2/2] Fix type errors in dashboard/stats/route.test.ts Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com> --- src/app/api/dashboard/stats/route.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/api/dashboard/stats/route.test.ts b/src/app/api/dashboard/stats/route.test.ts index b6b99f2..8f4aace 100644 --- a/src/app/api/dashboard/stats/route.test.ts +++ b/src/app/api/dashboard/stats/route.test.ts @@ -117,7 +117,7 @@ describe("GET /api/dashboard/stats", () => { expires: "1", }); - const mockHeatmap = { days: [], maxCount: 0 }; + const mockHeatmap: number[][] = []; vi.mocked(fetchCommitActivityHeatmap).mockResolvedValueOnce(mockHeatmap); const currentYear = new Date().getUTCFullYear(); @@ -136,7 +136,7 @@ describe("GET /api/dashboard/stats", () => { }); vi.mocked(fetchViewerLogin).mockResolvedValueOnce("fetcheduser"); - const mockHeatmap = { days: [], maxCount: 0 }; + const mockHeatmap: number[][] = []; vi.mocked(fetchCommitActivityHeatmap).mockResolvedValueOnce(mockHeatmap); const req = createRequest("http://localhost/api/dashboard/stats");