Roo-Code/src/utils/__tests__/commit-message-generator.spec.ts
Roo Code 364941f17c fix: improve commit message generator quality and test coverage
- Rewrite getGitDiff tests with proper assertions (3 new tests)
- Fix markdown stripping regex to handle language-tagged code blocks
- Add --no-color flag to git diff commands for clean output
- Internationalize hardcoded error strings in setScmInputBoxMessage
- Add no_git_extension and no_git_repo i18n keys to all locales
2026-03-27 00:34:48 +00:00

157 lines
4.6 KiB
TypeScript

import { generateCommitMessageFromDiff, getGitDiff } from "../commit-message-generator"
import * as singleCompletionHandlerModule from "../single-completion-handler"
import type { ProviderSettings } from "@roo-code/types"
vi.mock("../single-completion-handler")
// Mock child_process.exec to simulate git commands
const mockExecImpl = vi.fn()
vi.mock("child_process", async (importOriginal) => {
const actual = await importOriginal<typeof import("child_process")>()
return {
...actual,
exec: (...args: any[]) => mockExecImpl(...args),
}
})
vi.mock("util", async (importOriginal) => {
const actual = await importOriginal<typeof import("util")>()
return {
...actual,
promisify:
(fn: any) =>
(...args: any[]) =>
new Promise((resolve, reject) => {
fn(...args, (err: Error | null, result: any) => {
if (err) {
reject(err)
} else {
resolve(result)
}
})
}),
}
})
describe("commit-message-generator", () => {
let mockSingleCompletionHandler: ReturnType<typeof vi.fn>
const mockApiConfig: ProviderSettings = {
apiProvider: "anthropic",
apiKey: "test-key",
apiModelId: "claude-sonnet-4-20250514",
} as ProviderSettings
beforeEach(() => {
vi.clearAllMocks()
mockSingleCompletionHandler = vi.fn().mockResolvedValue("feat: add user authentication")
vi.mocked(singleCompletionHandlerModule).singleCompletionHandler = mockSingleCompletionHandler
})
describe("generateCommitMessageFromDiff", () => {
it("generates a commit message from a diff", async () => {
const diff = `diff --git a/src/auth.ts b/src/auth.ts
+export function login(user: string) {
+ return true
+}`
const result = await generateCommitMessageFromDiff(mockApiConfig, diff)
expect(result).toBe("feat: add user authentication")
expect(mockSingleCompletionHandler).toHaveBeenCalledWith(mockApiConfig, expect.stringContaining(diff))
})
it("truncates very large diffs", async () => {
const largeDiff = "a".repeat(15000)
await generateCommitMessageFromDiff(mockApiConfig, largeDiff)
const calledPrompt = mockSingleCompletionHandler.mock.calls[0][1]
expect(calledPrompt).toContain("...(truncated)")
})
it("strips markdown code blocks from the result", async () => {
mockSingleCompletionHandler.mockResolvedValue("```\nfeat: add feature\n```")
const result = await generateCommitMessageFromDiff(mockApiConfig, "some diff")
expect(result).toBe("feat: add feature")
})
it("strips language-tagged markdown code blocks from the result", async () => {
mockSingleCompletionHandler.mockResolvedValue("```text\nfix: resolve null check\n```")
const result = await generateCommitMessageFromDiff(mockApiConfig, "some diff")
expect(result).toBe("fix: resolve null check")
})
it("propagates errors from the completion handler", async () => {
mockSingleCompletionHandler.mockRejectedValue(new Error("API Error"))
await expect(generateCommitMessageFromDiff(mockApiConfig, "some diff")).rejects.toThrow("API Error")
})
})
describe("getGitDiff", () => {
it("returns staged diff when available", async () => {
mockExecImpl.mockImplementation(
(
cmd: string,
_opts: unknown,
callback: (err: Error | null, result: { stdout: string; stderr: string }) => void,
) => {
if (cmd.includes("--cached")) {
callback(null, { stdout: "staged changes", stderr: "" })
} else {
callback(null, { stdout: "unstaged changes", stderr: "" })
}
},
)
const result = await getGitDiff("/workspace")
expect(result).toBe("staged changes")
expect(mockExecImpl).toHaveBeenCalledWith(
"git diff --cached --no-color",
expect.objectContaining({ cwd: "/workspace" }),
expect.any(Function),
)
})
it("falls back to unstaged diff when nothing is staged", async () => {
mockExecImpl.mockImplementation(
(
cmd: string,
_opts: unknown,
callback: (err: Error | null, result: { stdout: string; stderr: string }) => void,
) => {
if (cmd.includes("--cached")) {
callback(null, { stdout: "", stderr: "" })
} else {
callback(null, { stdout: "unstaged changes", stderr: "" })
}
},
)
const result = await getGitDiff("/workspace")
expect(result).toBe("unstaged changes")
})
it("throws an error when git command fails", async () => {
mockExecImpl.mockImplementation(
(
_cmd: string,
_opts: unknown,
callback: (err: Error | null, result: { stdout: string; stderr: string }) => void,
) => {
callback(new Error("git not found"), { stdout: "", stderr: "" })
},
)
await expect(getGitDiff("/workspace")).rejects.toThrow("Failed to get git diff")
})
})
})