193 lines
7.4 KiB
TypeScript
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",
|
|
]);
|
|
});
|
|
});
|