import { describe, expect, test } from "bun:test"; import { CommitService } from "../../../src/mutator/branch/commits"; function fakeClient(result: unknown) { return { executeWithPartial: () => Promise.resolve(result) } as any; } function failingClient(error: unknown) { return { executeWithPartial: () => Promise.reject(error) } as any; } describe("CommitService", () => { describe("pushBatched", () => { test("returns empty array for empty commits", async () => { const svc = new CommitService(fakeClient({}), "owner", "repo"); const result = await svc.pushBatched([]); expect(result).toEqual([]); }); test("returns failures for commits with no files", async () => { const svc = new CommitService(fakeClient({}), "owner", "repo"); const result = await svc.pushBatched([ { branchName: "main", expectedHeadOid: "abc", files: [], commitHeadline: "test" }, ]); expect(result[0].success).toBe(false); expect(result[0].error).toBe("No file changes provided."); }); test("returns success for batched commits", async () => { const client = fakeClient({ data: { b0: { commit: { oid: "abc123", url: "url" } }, b1: { commit: { oid: "def456", url: "url" } }, }, }); const svc = new CommitService(client, "owner", "repo"); const result = await svc.pushBatched([ { branchName: "main", expectedHeadOid: "eee", files: [{ path: "README.md", content: "hello" }], commitHeadline: "update main" }, { branchName: "develop", expectedHeadOid: "fff", files: [{ path: "README.md", content: "world" }], commitHeadline: "update develop" }, ]); expect(result).toHaveLength(2); expect(result[0]).toEqual({ branch: "main", success: true, commitOid: "abc123" }); expect(result[1]).toEqual({ branch: "develop", success: true, commitOid: "def456" }); }); test("handles partial failures in batched results", async () => { const client = fakeClient({ data: { b0: { commit: { oid: "abc123", url: "url" } }, b1: null }, errors: [{ message: "Branch is protected", path: ["b1"] }], }); const svc = new CommitService(client, "owner", "repo"); const result = await svc.pushBatched([ { branchName: "branch-a", expectedHeadOid: "a", files: [{ path: "x.txt", content: "ok" }], commitHeadline: "ok" }, { branchName: "branch-b", expectedHeadOid: "b", files: [{ path: "y.txt", content: "fail" }], commitHeadline: "fail" }, ]); expect(result[0].success).toBe(true); expect(result[1].success).toBe(false); expect(result[1].error).toBe("Branch is protected"); }); test("handles transport failure — all commits fail", async () => { const svc = new CommitService(failingClient(new Error("Network down")), "owner", "repo"); const result = await svc.pushBatched([ { branchName: "main", expectedHeadOid: "eee", files: [{ path: "README.md", content: "hello" }], commitHeadline: "test" }, ]); expect(result[0].success).toBe(false); expect(result[0].error).toBe("Network down"); }); }); describe("pushChunked", () => { test("throws for invalid chunkSize", async () => { const svc = new CommitService(fakeClient({}), "owner", "repo"); await expect(svc.pushChunked([], 0)).rejects.toThrow("pushChunked requires chunkSize >= 1"); }); test("splits commits into chunks", async () => { const client = fakeClient({ data: { b0: { commit: { oid: "ok", url: "url" } } } }); const svc = new CommitService(client, "owner", "repo"); const commits = Array.from({ length: 5 }, (_, i) => ({ branchName: `branch-${i}`, expectedHeadOid: "abc", files: [{ path: "README.md", content: "content" }], commitHeadline: `commit ${i}`, })); expect(await svc.pushChunked(commits, 2)).toHaveLength(5); }); test("calls onChunk callback for each chunk", async () => { const client = fakeClient({ data: { b0: { commit: { oid: "ok", url: "url" } } } }); const svc = new CommitService(client, "owner", "repo"); const chunks: any[] = []; const commits = Array.from({ length: 3 }, (_, i) => ({ branchName: `branch-${i}`, expectedHeadOid: "abc", files: [{ path: "README.md", content: "content" }], commitHeadline: `commit ${i}`, })); await svc.pushChunked(commits, 1, (r: any) => chunks.push(r)); expect(chunks).toHaveLength(3); }); }); });