From 84d7ce0a8620a6a2665f21c3741bb03438708bae Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 03:10:03 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=A7=AA=20[testing=20improvement]=20Ad?= =?UTF-8?q?d=20unit=20tests=20for=20buildEventSeries?= 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/components/__tests__/DashboardStatsClient.test.ts | 9 +++++++++ vitest.config.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/__tests__/DashboardStatsClient.test.ts b/src/components/__tests__/DashboardStatsClient.test.ts index 4e20558..af51d0f 100644 --- a/src/components/__tests__/DashboardStatsClient.test.ts +++ b/src/components/__tests__/DashboardStatsClient.test.ts @@ -54,4 +54,13 @@ describe("buildEventSeries", () => { const expected = [{ name: "Push", count: 10 }]; expect(buildEventSeries(input)).toEqual(expected); }); + + it("should return an array mapping e.type to name and e.count to value if mapping to value is expected", () => { + // Testing the current behavior of the function, which actually maps to count, + // replacing Event in the name string based on the source code structure. + const input = [{ type: "PushEvent", count: 10 }]; + const result = buildEventSeries(input); + expect(result[0]).toHaveProperty('name', 'Push'); + expect(result[0]).toHaveProperty('count', 10); + }); }); diff --git a/vitest.config.ts b/vitest.config.ts index f5c9aea..4bb05e9 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -11,7 +11,7 @@ export default defineConfig({ coverage: { provider: "v8", reporter: ["text", "lcov"], - include: ["src/lib/**/*.ts", "src/hooks/**/*.ts"], + include: ["src/lib/**/*.ts", "src/hooks/**/*.ts", "src/components/DashboardStatsClient.tsx"], thresholds: { lines: 80, functions: 80, From 63ff1ff1dea47333a5363f40731575928e822217 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 03:18:22 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=A7=AA=20[testing=20improvement]=20Ad?= =?UTF-8?q?d=20unit=20tests=20for=20buildEventSeries?= 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> --- .../__tests__/DashboardStatsClient.test.ts | 66 -------- .../__tests__/DashboardStatsClient.test.tsx | 152 ++++++++++++++++++ 2 files changed, 152 insertions(+), 66 deletions(-) delete mode 100644 src/components/__tests__/DashboardStatsClient.test.ts create mode 100644 src/components/__tests__/DashboardStatsClient.test.tsx diff --git a/src/components/__tests__/DashboardStatsClient.test.ts b/src/components/__tests__/DashboardStatsClient.test.ts deleted file mode 100644 index af51d0f..0000000 --- a/src/components/__tests__/DashboardStatsClient.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { buildEventSeries } from "../DashboardStatsClient"; - -describe("buildEventSeries", () => { - it("should return an empty array when given an empty array", () => { - expect(buildEventSeries([])).toEqual([]); - }); - - it("should replace 'Event' with an empty string in the name property", () => { - const input = [ - { type: "PushEvent", count: 10 }, - { type: "PullRequestEvent", count: 5 }, - { type: "IssuesEvent", count: 2 }, - ]; - const expected = [ - { name: "Push", count: 10 }, - { name: "PullRequest", count: 5 }, - { name: "Issues", count: 2 }, - ]; - expect(buildEventSeries(input)).toEqual(expected); - }); - - it("should return at most 6 elements", () => { - const input = Array.from({ length: 10 }, (_, i) => ({ - type: `Type${i}Event`, - count: i, - })); - const result = buildEventSeries(input); - expect(result.length).toBe(6); - expect(result).toEqual([ - { name: "Type0", count: 0 }, - { name: "Type1", count: 1 }, - { name: "Type2", count: 2 }, - { name: "Type3", count: 3 }, - { name: "Type4", count: 4 }, - { name: "Type5", count: 5 }, - ]); - }); - - it("should correctly map the count property", () => { - const input = [ - { type: "PushEvent", count: 42 }, - { type: "CreateEvent", count: 1 }, - ]; - const expected = [ - { name: "Push", count: 42 }, - { name: "Create", count: 1 }, - ]; - expect(buildEventSeries(input)).toEqual(expected); - }); - - it("should not modify type if it does not contain 'Event'", () => { - const input = [{ type: "Push", count: 10 }]; - const expected = [{ name: "Push", count: 10 }]; - expect(buildEventSeries(input)).toEqual(expected); - }); - - it("should return an array mapping e.type to name and e.count to value if mapping to value is expected", () => { - // Testing the current behavior of the function, which actually maps to count, - // replacing Event in the name string based on the source code structure. - const input = [{ type: "PushEvent", count: 10 }]; - const result = buildEventSeries(input); - expect(result[0]).toHaveProperty('name', 'Push'); - expect(result[0]).toHaveProperty('count', 10); - }); -}); diff --git a/src/components/__tests__/DashboardStatsClient.test.tsx b/src/components/__tests__/DashboardStatsClient.test.tsx new file mode 100644 index 0000000..a8283ec --- /dev/null +++ b/src/components/__tests__/DashboardStatsClient.test.tsx @@ -0,0 +1,152 @@ +// @vitest-environment jsdom +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { render, screen } from "@testing-library/react"; +import DashboardStatsClient, { buildEventSeries } from "../DashboardStatsClient"; +import { useDashboardData, useDashboardStats } from "@/hooks/useDashboardData"; +import "@testing-library/jest-dom"; + +// Mock recharts to avoid rendering errors in jsdom +vi.mock("recharts", () => ({ + ResponsiveContainer: ({ children }: { children: React.ReactNode }) =>
{children}
, + BarChart: ({ children }: { children: React.ReactNode }) =>
{children}
, + Bar: () =>
, + XAxis: () =>
, + YAxis: () =>
, + CartesianGrid: () =>
, + Tooltip: () =>
, +})); + +vi.mock("@/components/ActivityHeatmapGrid", () => ({ + default: () =>
, +})); + +vi.mock("@/hooks/useDashboardData", () => ({ + useDashboardData: vi.fn(), + useDashboardStats: vi.fn(), +})); + +describe("buildEventSeries", () => { + it("should return an empty array when given an empty array", () => { + expect(buildEventSeries([])).toEqual([]); + }); + + it("should replace 'Event' with an empty string in the name property", () => { + const input = [ + { type: "PushEvent", count: 10 }, + { type: "PullRequestEvent", count: 5 }, + { type: "IssuesEvent", count: 2 }, + ]; + const expected = [ + { name: "Push", count: 10 }, + { name: "PullRequest", count: 5 }, + { name: "Issues", count: 2 }, + ]; + expect(buildEventSeries(input)).toEqual(expected); + }); + + it("should return at most 6 elements", () => { + const input = Array.from({ length: 10 }, (_, i) => ({ + type: `Type${i}Event`, + count: i, + })); + const result = buildEventSeries(input); + expect(result.length).toBe(6); + expect(result).toEqual([ + { name: "Type0", count: 0 }, + { name: "Type1", count: 1 }, + { name: "Type2", count: 2 }, + { name: "Type3", count: 3 }, + { name: "Type4", count: 4 }, + { name: "Type5", count: 5 }, + ]); + }); + + it("should correctly map the count property", () => { + const input = [ + { type: "PushEvent", count: 42 }, + { type: "CreateEvent", count: 1 }, + ]; + const expected = [ + { name: "Push", count: 42 }, + { name: "Create", count: 1 }, + ]; + expect(buildEventSeries(input)).toEqual(expected); + }); + + it("should not modify type if it does not contain 'Event'", () => { + const input = [{ type: "Push", count: 10 }]; + const expected = [{ name: "Push", count: 10 }]; + expect(buildEventSeries(input)).toEqual(expected); + }); +}); + +describe("DashboardStatsClient", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should render loading state when data is loading", () => { + vi.mocked(useDashboardData).mockReturnValue({ + summary: null, + isLoading: true, + error: null, + } as any); + vi.mocked(useDashboardStats).mockReturnValue({ + heatmap: null, + isLoading: false, + error: null, + } as any); + + render(); + expect(screen.getByText("Loading stats...")).toBeInTheDocument(); + }); + + it("should render error state when there is an error", () => { + vi.mocked(useDashboardData).mockReturnValue({ + summary: null, + isLoading: false, + error: new Error("Failed to load"), + } as any); + vi.mocked(useDashboardStats).mockReturnValue({ + heatmap: null, + isLoading: false, + error: null, + } as any); + + render(); + expect(screen.getByText("Failed to load stats.")).toBeInTheDocument(); + }); + + it("should render charts and heatmap when data is loaded successfully", () => { + const mockSummary = { + activity: { + eventBreakdown: [ + { type: "PushEvent", count: 10 }, + ], + }, + contributions: { + calendar: [ + { date: "2023-01-01", count: 5 }, + ], + }, + }; + + vi.mocked(useDashboardData).mockReturnValue({ + summary: mockSummary, + isLoading: false, + error: null, + } as any); + vi.mocked(useDashboardStats).mockReturnValue({ + heatmap: [[1, 2, 3]], + isLoading: false, + error: null, + } as any); + + render(); + + expect(screen.getByText("Activity Stats")).toBeInTheDocument(); + expect(screen.getByText("Recent Event Breakdown")).toBeInTheDocument(); + expect(screen.getByText("Monthly Contributions")).toBeInTheDocument(); + expect(screen.getByTestId("heatmap-grid")).toBeInTheDocument(); + }); +}); From ec504d71b71ee669f828e15b2a6dfae655ba0012 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 03:36:31 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=A7=AA=20[testing=20improvement]=20Ad?= =?UTF-8?q?d=20unit=20tests=20for=20buildEventSeries?= 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> --- .../__tests__/DashboardStatsClient.test.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/__tests__/DashboardStatsClient.test.tsx b/src/components/__tests__/DashboardStatsClient.test.tsx index a8283ec..62d5ffc 100644 --- a/src/components/__tests__/DashboardStatsClient.test.tsx +++ b/src/components/__tests__/DashboardStatsClient.test.tsx @@ -90,12 +90,12 @@ describe("DashboardStatsClient", () => { summary: null, isLoading: true, error: null, - } as any); + } as unknown as ReturnType); vi.mocked(useDashboardStats).mockReturnValue({ heatmap: null, isLoading: false, error: null, - } as any); + } as unknown as ReturnType); render(); expect(screen.getByText("Loading stats...")).toBeInTheDocument(); @@ -106,12 +106,12 @@ describe("DashboardStatsClient", () => { summary: null, isLoading: false, error: new Error("Failed to load"), - } as any); + } as unknown as ReturnType); vi.mocked(useDashboardStats).mockReturnValue({ heatmap: null, isLoading: false, error: null, - } as any); + } as unknown as ReturnType); render(); expect(screen.getByText("Failed to load stats.")).toBeInTheDocument(); @@ -135,12 +135,12 @@ describe("DashboardStatsClient", () => { summary: mockSummary, isLoading: false, error: null, - } as any); + } as unknown as ReturnType); vi.mocked(useDashboardStats).mockReturnValue({ heatmap: [[1, 2, 3]], isLoading: false, error: null, - } as any); + } as unknown as ReturnType); render();