Files
claude-code-action/test/setup-branch-forgejo.test.ts
Vlad MocanuandClaude Opus 4.6 bbfd630fc5 fix(prd-7): M4 test coverage review — 28 new tests for comment operations and branch setup
- test/create-initial-comment.test.ts: 15 tests covering GitHub/Forgejo
  platform branches, sticky comment matching, review comment fallback,
  error handling with GITHUB_OUTPUT verification
- test/update-tracking-comment.test.ts: 11 tests covering body construction,
  branch link logic (issue vs PR), comment type routing, Forgejo URLs
- test/setup-branch-forgejo.test.ts: 2 tests verifying Forgejo uses
  repos.getBranch() while GitHub uses git.getRef() for source branch SHA
- test/COVERAGE-NOTES.md: documents all coverage status and accepted gaps
  (tag mode orchestrator, entrypoint) with rationale
- Notable finding: CLAUDE_APP_BOT_ID discrepancy flagged for M5

Progress: 67% complete (4/6 milestones) — M5 code quality next

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:51:08 +02:00

151 lines
4.3 KiB
TypeScript

#!/usr/bin/env bun
/**
* Tests the Forgejo API divergence in setupBranch().
*
* Forgejo uses repos.getBranch() to get source branch SHA because Forgejo's
* /git/refs (plural) API differs from GitHub's /git/ref (singular), causing
* git.getRef() to 404 on Forgejo.
*
* Approach: Call setupBranch() with mocked Octokit. The platform-specific
* API call records that it was called, then throws a sentinel error to stop
* execution before git shell commands run (avoiding real repo side effects).
*/
import {
describe,
test,
expect,
beforeEach,
afterEach,
spyOn,
type Mock,
} from "bun:test";
import { setupBranch } from "../src/github/operations/branch";
import { _resetPlatformCache } from "../src/platform/detector";
import { createMockContext } from "./mockContext";
import type { Octokits } from "../src/github/api/client";
import type { FetchDataResult } from "../src/github/data/fetcher";
const mockGithubData: FetchDataResult = {
contextData: {
title: "Test issue",
labels: { nodes: [{ name: "bug" }] },
},
comments: [],
changedFiles: [],
changedFilesWithSHA: [],
reviewData: null,
imageUrlMap: new Map(),
} as any;
function createBranchMockOctokits(
overrides: Record<string, any> = {},
): Octokits {
return {
rest: {
repos: {
get:
overrides.reposGet ??
(async () => ({ data: { default_branch: "main" } })),
getBranch:
overrides.getBranch ??
(async () => ({ data: { commit: { sha: "abc123" } } })),
},
git: {
getRef:
overrides.getRef ??
(async () => ({ data: { object: { sha: "abc123" } } })),
},
},
graphql: {} as any,
} as unknown as Octokits;
}
describe("setupBranch — Forgejo API divergence", () => {
let savedPlatform: string | undefined;
let savedServerUrl: string | undefined;
let consoleLogSpy: Mock<(...args: any[]) => void>;
let consoleErrorSpy: Mock<(...args: any[]) => void>;
beforeEach(() => {
_resetPlatformCache();
savedPlatform = process.env.PLATFORM;
savedServerUrl = process.env.GITHUB_SERVER_URL;
consoleLogSpy = spyOn(console, "log").mockImplementation(() => {});
consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
});
afterEach(() => {
if (savedPlatform !== undefined) process.env.PLATFORM = savedPlatform;
else delete process.env.PLATFORM;
if (savedServerUrl !== undefined)
process.env.GITHUB_SERVER_URL = savedServerUrl;
else delete process.env.GITHUB_SERVER_URL;
consoleLogSpy.mockRestore();
consoleErrorSpy.mockRestore();
_resetPlatformCache();
});
test("on Forgejo: calls repos.getBranch() instead of git.getRef()", async () => {
process.env.PLATFORM = "forgejo";
process.env.GITHUB_SERVER_URL = "https://git.example.com";
_resetPlatformCache();
let getBranchCalled = false;
let getRefCalled = false;
const mockOctokits = createBranchMockOctokits({
getBranch: async () => {
getBranchCalled = true;
// Throw sentinel error to stop before git commands execute
throw new Error("STOP_BEFORE_GIT_COMMANDS");
},
getRef: async () => {
getRefCalled = true;
throw new Error("STOP_BEFORE_GIT_COMMANDS");
},
});
const context = createMockContext({ isPR: false, entityNumber: 1 });
await expect(
setupBranch(mockOctokits, mockGithubData, context),
).rejects.toThrow("STOP_BEFORE_GIT_COMMANDS");
expect(getBranchCalled).toBe(true);
expect(getRefCalled).toBe(false);
});
test("on GitHub: calls git.getRef() instead of repos.getBranch()", async () => {
delete process.env.PLATFORM;
process.env.GITHUB_SERVER_URL = "https://github.com";
_resetPlatformCache();
let getBranchCalled = false;
let getRefCalled = false;
const mockOctokits = createBranchMockOctokits({
getBranch: async () => {
getBranchCalled = true;
throw new Error("STOP_BEFORE_GIT_COMMANDS");
},
getRef: async () => {
getRefCalled = true;
throw new Error("STOP_BEFORE_GIT_COMMANDS");
},
});
const context = createMockContext({ isPR: false, entityNumber: 1 });
await expect(
setupBranch(mockOctokits, mockGithubData, context),
).rejects.toThrow("STOP_BEFORE_GIT_COMMANDS");
expect(getRefCalled).toBe(true);
expect(getBranchCalled).toBe(false);
});
});