import { describe, expect, test } from "bun:test"; import { deepLinkToastMessage, emptyTransitionToastMessage, extractRequestId, normalizeRunFileScope, } from "./run-files"; import { buildRunCommitOptions, fabroGeneratedCommitStage, } from "./run-files/commit-options"; function buildRunFilesPayload({ files = [], degraded = false, }: { files?: string[]; degraded?: boolean; }) { return { data: files.map((name, index) => ({ change_kind: "modified", old_file: { name, contents: degraded ? null : `old ${index}` }, new_file: { name, contents: degraded ? null : `new ${index}` }, ...(degraded ? { unified_patch: `diff --git a/${name} b/${name}` } : {}), })), meta: { degraded, total_changed: files.length, source: "sandbox", scope: "committed", stats: { additions: 0, deletions: 0 }, truncated: false, }, } as any; } describe("extractRequestId", () => { test("reads `request_id` from the top level of the error body", () => { expect(extractRequestId({ request_id: "abc-123" })).toBe("abc-123"); }); test("reads `request_id` from errors[0] under the uniform envelope", () => { expect( extractRequestId({ errors: [ { status: "500", title: "Internal", request_id: "evt_42" }, ], }), ).toBe("evt_42"); }); test("parses `Request ID: xyz` out of errors[0].detail", () => { expect( extractRequestId({ errors: [ { status: "500", title: "Internal Server Error", detail: "Run files failed. Request ID: req_999 on shard 2.", }, ], }), ).toBe("req_999"); }); test("returns null for bodies without any request_id", () => { expect(extractRequestId(null)).toBe(null); expect(extractRequestId(undefined)).toBe(null); expect(extractRequestId("not an object")).toBe(null); expect(extractRequestId({ errors: [] })).toBe(null); expect(extractRequestId({ errors: [{ detail: "no id in here" }] })).toBe( null, ); }); test("handles request_id values with hyphens and underscores", () => { expect( extractRequestId({ errors: [ { detail: "Something failed. request_id: RX-1A_2B-3C4D" }, ], }), ).toBe("RX-1A_2B-3C4D"); }); }); describe("emptyTransitionToastMessage", () => { test("returns the no-changes toast when a populated diff becomes empty", () => { expect(emptyTransitionToastMessage(3, 0)).toBe("No changes in this run."); }); test("returns null when the diff was already empty", () => { expect(emptyTransitionToastMessage(0, 0)).toBeNull(); expect(emptyTransitionToastMessage(null, 0)).toBeNull(); expect(emptyTransitionToastMessage(2, 1)).toBeNull(); }); }); describe("normalizeRunFileScope", () => { test("defaults missing or invalid values to committed", () => { expect(normalizeRunFileScope(null)).toBe("committed"); expect(normalizeRunFileScope("dirty")).toBe("committed"); }); test("accepts supported scope values", () => { expect(normalizeRunFileScope("committed")).toBe("committed"); expect(normalizeRunFileScope("uncommitted")).toBe("uncommitted"); expect(normalizeRunFileScope("all")).toBe("all"); }); }); describe("buildRunCommitOptions", () => { test("shortens Fabro-generated subjects to stage visits", () => { const commits = [ { sha: "a".repeat(40), short_sha: "aaaaaaa", subject: "fabro(run_1): implement (succeeded)", parents: [{ sha: "1".repeat(40), short_sha: "1111111" }], }, { sha: "b".repeat(40), short_sha: "bbbbbbb", subject: "fabro(run_1): implement (succeeded)", parents: [{ sha: "a".repeat(40), short_sha: "aaaaaaa" }], }, ]; expect(buildRunCommitOptions(commits).map((commit) => commit.label)).toEqual([ "implement@1", "implement@2", ]); }); test("leaves externally generated commit subjects intact", () => { const [option] = buildRunCommitOptions([ { sha: "a".repeat(40), short_sha: "aaaaaaa", subject: "Fix README typo", parents: [{ sha: "1".repeat(40), short_sha: "1111111" }], }, ]); expect(fabroGeneratedCommitStage("Fix README typo")).toBeNull(); expect(option.label).toBe("Fix README typo"); }); }); describe("deepLinkToastMessage", () => { test("returns the missing-file message when the requested file is absent", () => { expect( deepLinkToastMessage( "src/missing.ts", buildRunFilesPayload({ files: ["src/present.ts"] }), ), ).toBe("File src/missing.ts is not in this run."); }); test("returns null when the deep-linked file exists", () => { expect( deepLinkToastMessage( "src/present.ts", buildRunFilesPayload({ files: ["src/present.ts"] }), ), ).toBeNull(); }); test("returns null for degraded file-shaped payloads when the file exists", () => { expect( deepLinkToastMessage( "src/present.ts", buildRunFilesPayload({ degraded: true, files: ["src/present.ts"], }), ), ).toBeNull(); }); });