Files
pikasTech-unidesk/scripts/src/gh-default-render.test.ts
T
2026-07-13 05:48:00 +02:00

193 lines
7.4 KiB
TypeScript

import { afterEach, describe, expect, test } from "bun:test";
import { prFiles, prView } from "./gh/auth-pr-read";
import { issueBodyReadCommands, prBodyReadCommands } from "./gh/client";
import { withGhDefaultRendered } from "./gh/default-render";
import { ghScopedHelp, ghScopedHelpNotes } from "./gh/help";
import { runGhCommand } from "./gh/index";
import { renderIssueCreateTable } from "./gh/issue-write";
import { readViewSupportedCommands } from "./gh/refs";
const originalFetch = globalThis.fetch;
afterEach(() => {
globalThis.fetch = originalFetch;
});
function renderedText(value: unknown): string {
return String((value as { renderedText?: unknown }).renderedText ?? "");
}
function nextSection(text: string): string {
return text.split("Next:\n", 2)[1]?.split("\n\nDisclosure:", 1)[0] ?? "";
}
describe("gh default body read path", () => {
test("puts trans gh issue cat first and keeps comments bounded", () => {
const repo = "pikasTech/unidesk";
const rendered = renderedText(withGhDefaultRendered(["issue", "view", "1890", "--repo", repo], {
ok: true,
command: "issue view",
repo,
issue: {
number: 1890,
title: "trans 文本短路径",
state: "open",
updatedAt: "2026-07-13T00:00:00Z",
commentCount: 8,
bodyChars: 30_000,
bodySha: "abc123",
bodyPreview: "preview",
bodyOmitted: true,
},
readCommands: issueBodyReadCommands(repo, 1890),
}));
const next = nextSection(rendered);
expect(next.trimStart().split("\n")[0]).toBe("trans gh:/pikasTech/unidesk/issue/1890 cat");
expect(next).toContain("trans gh:/pikasTech/unidesk/issue/1890 rg <pattern>");
expect(next).toContain("bun scripts/cli.ts gh issue comments 1890 --repo pikasTech/unidesk");
expect(next).not.toContain("--json body");
expect(next).not.toContain("--full");
expect(rendered).not.toContain("/tmp/unidesk-cli-output");
});
test("puts trans gh PR cat before file review commands", () => {
const repo = "pikasTech/unidesk";
const rendered = renderedText(withGhDefaultRendered(["pr", "view", "1893", "--repo", repo], {
ok: true,
command: "pr view",
repo,
pullRequest: {
number: 1893,
title: "fix trans",
state: "open",
stateDetail: "open",
head: { ref: "fix/trans" },
base: { ref: "master" },
bodyChars: 1_000,
bodySha: "def456",
bodyPreview: "preview",
bodyOmitted: true,
},
readCommands: prBodyReadCommands(repo, 1893),
}));
const next = nextSection(rendered);
expect(next.trimStart().split("\n")[0]).toBe("trans gh:/pikasTech/unidesk/pr/1893 cat");
expect(next).toContain("trans gh:/pikasTech/unidesk/pr/1893 rg <pattern>");
expect(next).toContain("bun scripts/cli.ts gh pr files 1893 --repo pikasTech/unidesk");
expect(next).not.toContain("--json body");
expect(next).not.toContain("--full");
expect(rendered).not.toContain("/tmp/unidesk-cli-output");
});
test("keeps machine body disclosure explicit in shared read commands", () => {
expect(issueBodyReadCommands("owner/repo", 12)).toMatchObject({
body: "trans gh:/owner/repo/issue/12 cat",
json: "bun scripts/cli.ts gh issue view 12 --repo owner/repo --json body",
});
expect(prBodyReadCommands("owner/repo", 34)).toMatchObject({
body: "trans gh:/owner/repo/pr/34 cat",
json: "bun scripts/cli.ts gh pr view 34 --repo owner/repo --json body",
});
});
test("scoped help separates human body reads from machine disclosure", () => {
const issueNotes = ghScopedHelpNotes(["issue", "view"]).join("\n");
const prNotes = ghScopedHelpNotes(["pr", "view"]).join("\n");
expect(issueNotes).toContain("trans gh:/owner/repo/issue/<number> cat");
expect(issueNotes).toContain("explicit structured machine disclosure");
expect(prNotes).toContain("trans gh:/owner/repo/pr/<number> cat");
expect(prNotes).toContain("explicit structured machine disclosure");
const issueHelp = JSON.stringify(ghScopedHelp(["issue", "view", "--help"]));
const prHelp = JSON.stringify(ghScopedHelp(["pr", "view", "--help"]));
expect(issueHelp).toContain("trans gh:/owner/repo/issue/<number> cat");
expect(prHelp).toContain("trans gh:/owner/repo/pr/<number> cat");
});
test("uses PR cat after a complete bounded file listing", async () => {
globalThis.fetch = (async (input: string | URL | Request) => {
const url = new URL(typeof input === "string" || input instanceof URL ? input.toString() : input.url);
if (url.pathname.endsWith("/pulls/42")) {
return Response.json({
id: 42,
number: 42,
title: "bounded PR",
body: "body",
state: "open",
html_url: "https://github.com/owner/repo/pull/42",
head: { ref: "fix/test", sha: "a".repeat(40) },
base: { ref: "master", sha: "b".repeat(40) },
changed_files: 1,
additions: 2,
deletions: 1,
commits: 1,
});
}
return Response.json([{ filename: "src/test.ts", status: "modified", additions: 2, deletions: 1, changes: 3 }]);
}) as typeof fetch;
const result = await prFiles("owner/repo", "token", 42, 30);
expect((result.next as { command?: string }).command).toBe("trans gh:/owner/repo/pr/42 cat");
expect(result.readCommands).toMatchObject({
body: "trans gh:/owner/repo/pr/42 cat",
metadata: "bun scripts/cli.ts gh pr view 42 --repo owner/repo",
});
const view = await prView("owner/repo", "token", 42, undefined);
expect(view.readCommands).toMatchObject({
body: "trans gh:/owner/repo/pr/42 cat",
search: "trans gh:/owner/repo/pr/42 rg <pattern>",
});
});
test("uses cat and rg after issue create and PR writes", () => {
const issueRendered = renderIssueCreateTable({
ok: true,
command: "issue create",
repo: "owner/repo",
issue: { number: 12, title: "new issue", state: "open" },
});
const prRendered = renderedText(withGhDefaultRendered(["pr", "update", "34", "--repo", "owner/repo"], {
ok: true,
command: "pr update",
repo: "owner/repo",
number: 34,
pullRequest: { number: 34, title: "updated PR", state: "open" },
}));
for (const [text, route] of [
[issueRendered, "trans gh:/owner/repo/issue/12"],
[prRendered, "trans gh:/owner/repo/pr/34"],
] as const) {
const next = nextSection(text);
expect(next).toContain(`${route} cat`);
expect(next).toContain(`${route} rg <pattern>`);
expect(next).not.toContain("--json body");
expect(next).not.toContain("--full");
expect(text).not.toContain("/tmp/unidesk-cli-output");
}
});
test("keeps invalid --number guidance on human issue and PR routes", async () => {
const result = await runGhCommand(["issue", "list", "--number", "12", "--repo", "owner/repo"]) as {
supportedCommands?: string[];
};
expect(result.supportedCommands).toEqual([
"trans gh:/owner/name/issue/<number> cat",
"trans gh:/owner/name/issue/<number> rg <pattern>",
"trans gh:/owner/name/pr/<number> cat",
"trans gh:/owner/name/pr/<number> rg <pattern>",
]);
expect(readViewSupportedCommands("issue", "owner/repo", 12)).toEqual([
"trans gh:/owner/repo/issue/12 cat",
"trans gh:/owner/repo/issue/12 rg <pattern>",
"bun scripts/cli.ts gh issue view 12 --repo owner/repo",
]);
});
});