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>
This commit is contained in:
1 parent
6b0302d226
commit
bbfd630fc5
5 files changed
+1006
-1
No files matched your search
@@ -0,0 +1,150 @@
|
||||
#!/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);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user