test(FN-4993): add AI parity and pr router coverage
Fusion-Task-Id: FN-4993 Fusion-Task-Lineage: 20ce6d5f-ef33-49e6-8519-648d769cc473
This commit is contained in:
committed by
gsxdsm
parent
60d3da7394
commit
e0b1e6ac37
20
packages/cli/src/__tests__/bin-pr-router.test.ts
Normal file
20
packages/cli/src/__tests__/bin-pr-router.test.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("bin pr router wiring", () => {
|
||||
const source = readFileSync(resolve(__dirname, "../bin.ts"), "utf8");
|
||||
|
||||
it("includes top-level pr create router", () => {
|
||||
expect(source).toContain('case "pr":');
|
||||
expect(source).toContain('case "create":');
|
||||
expect(source).toContain("runTaskPrCreate(id, parsePrCreateOptions(args.slice(3)), projectName)");
|
||||
});
|
||||
|
||||
it("parses draft/no-ai/reviewer flags for pr-create aliases", () => {
|
||||
expect(source).toContain('const draft = args.includes("--draft")');
|
||||
expect(source).toContain('const ai = !args.includes("--no-ai")');
|
||||
expect(source).toContain('args[i] === "--reviewer"');
|
||||
expect(source).toContain('case "pr-create":');
|
||||
});
|
||||
});
|
||||
@@ -2924,6 +2924,50 @@ describe("runTaskPrCreate", () => {
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Using AI-generated title/body"));
|
||||
});
|
||||
|
||||
it("uses user title + AI body when only title is provided", async () => {
|
||||
const task = makeInReviewTask();
|
||||
mockGetTask.mockResolvedValueOnce(task);
|
||||
vi.mocked(generatePrMetadata).mockResolvedValueOnce({ title: "AI Title", body: "AI Body", templateUsed: false });
|
||||
mockCreatePr.mockResolvedValueOnce(makePrInfo());
|
||||
|
||||
await runTaskPrCreate("FN-001", { title: "User Title" });
|
||||
|
||||
expect(mockCreatePr).toHaveBeenCalledWith(expect.objectContaining({ title: "User Title", body: "AI Body" }));
|
||||
});
|
||||
|
||||
it("uses AI title + user body when only body is provided", async () => {
|
||||
const task = makeInReviewTask();
|
||||
mockGetTask.mockResolvedValueOnce(task);
|
||||
vi.mocked(generatePrMetadata).mockResolvedValueOnce({ title: "AI Title", body: "AI Body", templateUsed: false });
|
||||
mockCreatePr.mockResolvedValueOnce(makePrInfo());
|
||||
|
||||
await runTaskPrCreate("FN-001", { body: "User Body" });
|
||||
|
||||
expect(mockCreatePr).toHaveBeenCalledWith(expect.objectContaining({ title: "AI Title", body: "User Body" }));
|
||||
});
|
||||
|
||||
it("does not call AI when both title and body are provided", async () => {
|
||||
const task = makeInReviewTask();
|
||||
mockGetTask.mockResolvedValueOnce(task);
|
||||
mockCreatePr.mockResolvedValueOnce(makePrInfo());
|
||||
|
||||
await runTaskPrCreate("FN-001", { title: "User Title", body: "User Body" });
|
||||
|
||||
expect(generatePrMetadata).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back when AI metadata generation fails", async () => {
|
||||
const task = makeInReviewTask({ title: undefined, description: "fallback description value for title" });
|
||||
mockGetTask.mockResolvedValueOnce(task);
|
||||
vi.mocked(generatePrMetadata).mockRejectedValueOnce(new Error("ai failed"));
|
||||
mockCreatePr.mockResolvedValueOnce(makePrInfo());
|
||||
|
||||
await runTaskPrCreate("FN-001", {});
|
||||
|
||||
expect(mockCreatePr).toHaveBeenCalledWith(expect.objectContaining({ title: "Fallback description value for title".slice(0, 50) }));
|
||||
expect(stderrWriteSpy).toHaveBeenCalledWith(expect.stringContaining("AI metadata generation failed"));
|
||||
});
|
||||
|
||||
it("skips AI metadata when --no-ai is set", async () => {
|
||||
const task = makeInReviewTask();
|
||||
mockGetTask.mockResolvedValueOnce(task);
|
||||
|
||||
Reference in New Issue
Block a user