- 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>
151 lines
4.3 KiB
TypeScript
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);
|
|
});
|
|
});
|