Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/app/api/dashboard/year/route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { describe, expect, it, vi } from "vitest";
import { NextRequest } from "next/server";

vi.mock("next-auth", () => ({
getServerSession: vi.fn(),
}));

vi.mock("@/lib/auth", () => ({
authOptions: {},
}));

vi.mock("@/lib/githubViewer", () => ({
fetchViewerLogin: vi.fn(),
}));

vi.mock("@/lib/githubYearInReview", () => ({
fetchYearInReviewData: vi.fn(),
}));

describe("GET /api/dashboard/year", () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This test suite is a great start, but it doesn't cover all execution paths in the GET handler. The PR description claims 'full coverage', but some important cases are missed. Here are a few scenarios that should also be tested:

  • An authorized request where the session exists but is missing the accessToken. This should also result in a 401.
  • When the year query parameter is not provided, causing the year to default to the current year.
  • Boundary conditions for the year validation, e.g., a year before 2008 or a year in the future. The current test only covers a non-numeric year ('invalid').
  • The case where session.user.login is missing and fetchViewerLogin is called to get the username.

Adding tests for these cases would make the test suite truly comprehensive.

it("returns 401 if unauthorized", async () => {
const { getServerSession } = await import("next-auth");
vi.mocked(getServerSession).mockResolvedValueOnce(null);

const { GET } = await import("./route");
const req = new NextRequest("http://localhost/api/dashboard/year?year=2023");

const response = await GET(req);
expect(response.status).toBe(401);

const data = await response.json();
expect(data).toEqual({ error: "Unauthorized" });
});

it("returns 400 if year is invalid", async () => {
const { getServerSession } = await import("next-auth");
vi.mocked(getServerSession).mockResolvedValueOnce({
user: { login: "testuser" },
accessToken: "testtoken",
expires: "9999-12-31T23:59:59.999Z",
});
Comment on lines +37 to +41

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This mock session object is duplicated across multiple tests (lines 55-59 and 76-80). To improve maintainability and reduce code duplication, consider extracting this object into a constant at the top of the describe block and reusing it in the tests.


const { GET } = await import("./route");
const req = new NextRequest("http://localhost/api/dashboard/year?year=invalid");

const response = await GET(req);
expect(response.status).toBe(400);

const data = await response.json();
expect(data).toEqual({ error: "Invalid year" });
});

it("handles error path when fetching data fails", async () => {
const { getServerSession } = await import("next-auth");
vi.mocked(getServerSession).mockResolvedValueOnce({
user: { login: "testuser" },
accessToken: "testtoken",
expires: "9999-12-31T23:59:59.999Z",
});

const { fetchYearInReviewData } = await import("@/lib/githubYearInReview");
vi.mocked(fetchYearInReviewData).mockRejectedValueOnce(new Error("API Error"));

const { GET } = await import("./route");
const req = new NextRequest("http://localhost/api/dashboard/year?year=2023");

const response = await GET(req);
expect(response.status).toBe(500);

const data = await response.json();
expect(data).toEqual({ error: "API Error" });
});

it("returns 200 and data on success", async () => {
const { getServerSession } = await import("next-auth");
vi.mocked(getServerSession).mockResolvedValueOnce({
user: { login: "testuser" },
accessToken: "testtoken",
expires: "9999-12-31T23:59:59.999Z",
});

const { fetchYearInReviewData } = await import("@/lib/githubYearInReview");
const mockData = { totalContributions: 1000 };
vi.mocked(fetchYearInReviewData).mockResolvedValueOnce(mockData as unknown as Awaited<ReturnType<typeof fetchYearInReviewData>>);

const { GET } = await import("./route");
const req = new NextRequest("http://localhost/api/dashboard/year?year=2023");

const response = await GET(req);
expect(response.status).toBe(200);

const data = await response.json();
expect(data).toEqual(mockData);
});
});
Loading