Skip to content
Merged
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
71 changes: 66 additions & 5 deletions src/lib/__tests__/github.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,10 @@

describe("fetchActivity", () => {
it("ヒートマップが 7×24 で初期化される", async () => {
mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS));
mockFetch
.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS))
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const result = await fetchActivity("testuser", "fake-token");
Expand All @@ -411,7 +414,10 @@
});

it("イベントが正しい曜日×時間帯スロットに加算される", async () => {
mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS));
mockFetch
.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS))
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const result = await fetchActivity("testuser", "fake-token");
Expand All @@ -423,7 +429,10 @@
});

it("イベント内訳がカウント順に並ぶ", async () => {
mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS));
mockFetch
.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS))
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const result = await fetchActivity("testuser", "fake-token");
Expand All @@ -434,7 +443,10 @@
});

it("totalEvents がイベント総数と一致する", async () => {
mockFetch.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS));
mockFetch
.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS))
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const result = await fetchActivity("testuser", "fake-token");
Expand All @@ -443,7 +455,10 @@
});

it("空のイベント配列を正しく処理する", async () => {
mockFetch.mockResolvedValueOnce(jsonResponse([]));
mockFetch
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const result = await fetchActivity("testuser", "fake-token");
Expand All @@ -454,6 +469,52 @@
const totalHeatmap = result.heatmap.flat().reduce((a, b) => a + b, 0);
expect(totalHeatmap).toBe(0);
});
describe("Error handling", () => {
it("ユーザーが存在しない場合 UserNotFoundError をスローする", async () => {
mockFetch
.mockResolvedValueOnce(jsonResponse(null, 404))
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const { UserNotFoundError } = await import("../types");

await expect(fetchActivity("nonexistent", "fake-token")).rejects.toThrow(
UserNotFoundError
);
});

it("レート制限の場合 RateLimitError をスローする", async () => {
mockFetch
.mockResolvedValueOnce(
jsonResponse(null, 403, { "X-RateLimit-Reset": "1700000000" })
)
.mockResolvedValueOnce(jsonResponse([]))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const { RateLimitError } = await import("../types");

await expect(fetchActivity("testuser", "fake-token")).rejects.toThrow(
RateLimitError
);
});

it("APIエラー(500)等の場合、それまでの結果を返す(早期終了)", async () => {
// 1ページ目は成功、2ページ目で500エラー、3ページ目も成功(ただし無視される)
mockFetch
.mockResolvedValueOnce(jsonResponse(MOCK_EVENTS))
.mockResolvedValueOnce(jsonResponse(null, 500))
.mockResolvedValueOnce(jsonResponse([]));

const { fetchActivity } = await import("../github");
const result = await fetchActivity("testuser", "fake-token");

// 1ページ目のイベント(3件)が取得できているはず
expect(result.totalEvents).toBe(MOCK_EVENTS.length);
expect(result.eventBreakdown[0].type).toBe("PushEvent");
});
});
});

// ---------- fetchStarredRepos ----------
Expand Down Expand Up @@ -508,7 +569,7 @@
*/
function setupUrlBasedMock() {
// GraphQL 呼び出しカウンター (pinned → repos → contributions の順で異なるデータを返す)
let graphqlCallCount = 0;

Check warning on line 572 in src/lib/__tests__/github.test.ts

View workflow job for this annotation

GitHub Actions / Lint

'graphqlCallCount' is assigned a value but never used

mockFetch.mockImplementation((url: string | URL | Request, options?: RequestInit) => {
const urlStr = typeof url === "string" ? url : url instanceof URL ? url.toString() : url.url;
Expand Down
Loading