Files
oh-my-pi/packages/coding-agent/test/gallery-cli.test.ts
T
can1357 3b7a44cb49 test(coding-agent): realigned stale tests with intentional behavior changes
These three suites encoded pre-refactor behavior and broke the 15.10.3 release CI.

- event-controller read grouping: the group header count now reflects aggregated
  display rows (distinct files), and a mid-turn visible-reasoning break finalizes
  the prior group but keeps it live until pending reads settle (97ae0fd3, b5eff5b3).
- gallery harness: lsp no longer attaches an instance renderer (custom rendering
  removed in d9d06134), so the custom-branch regression guard is retargeted to
  task, which still attaches its renderer and merges call+result.
- eager-todo enforcement: the prelude reminder converts to a developer-role
  message now that auxiliary messages map to developer for compaction (e13f2de5).
2026-06-08 07:17:08 +02:00

92 lines
4.2 KiB
TypeScript

import { beforeAll, describe, expect, it } from "bun:test";
import { GALLERY_STATES, renderGalleryState, resolveFixture } from "../src/cli/gallery-cli";
import type { GalleryFixture } from "../src/cli/gallery-fixtures";
import { resetSettingsForTest, Settings } from "../src/config/settings";
import { initTheme } from "../src/modes/theme/theme";
import { toolRenderers } from "../src/tools/renderers";
beforeAll(async () => {
resetSettingsForTest();
await Settings.init({ inMemory: true });
await initTheme(false, undefined, undefined, "dark", "light");
});
describe("gallery harness", () => {
it("renders every registered tool in every lifecycle state without throwing", async () => {
for (const name in toolRenderers) {
const fixture = resolveFixture(name);
for (const state of GALLERY_STATES) {
const lines = await renderGalleryState(name, fixture, state, 100);
// A renderer that produces no lines for a state is a regression: the
// component should always emit at least the call header or result.
expect(lines.length, `${name}/${state} rendered nothing`).toBeGreaterThan(0);
}
}
});
it("routes each state to the matching args/result (streaming args vs result, success vs error)", async () => {
const fixture: GalleryFixture = {
label: "Bash",
streamingArgs: { command: "echo STREAM_MARK" },
args: { command: "echo PROGRESS_MARK" },
result: { content: [{ type: "text", text: "SUCCESS_OUT" }], details: { exitCode: 0 } },
errorResult: { content: [{ type: "text", text: "ERROR_OUT" }], isError: true, details: { exitCode: 1 } },
};
const render = async (state: (typeof GALLERY_STATES)[number]) =>
Bun.stripANSI((await renderGalleryState("bash", fixture, state, 100)).join("\n"));
const streaming = await render("streaming");
expect(streaming).toContain("STREAM_MARK");
expect(streaming).not.toContain("PROGRESS_MARK");
expect(streaming).not.toContain("SUCCESS_OUT");
const progress = await render("progress");
expect(progress).toContain("PROGRESS_MARK");
expect(progress).not.toContain("SUCCESS_OUT");
const success = await render("success");
expect(success).toContain("SUCCESS_OUT");
expect(success).not.toContain("ERROR_OUT");
const error = await render("error");
expect(error).toContain("ERROR_OUT");
expect(error).not.toContain("SUCCESS_OUT");
});
it("routes customRendered tools (task) through the custom-tool branch", async () => {
// `task` attaches its renderer on the real AgentTool, so the gallery must
// reproduce that path. With a result present and mergeCallAndResult, the
// custom branch must NOT emit a redundant tool-name line above the result box
// (regression guard for tool-execution's custom-branch fallback label).
const task = resolveFixture("task");
expect(task.customRendered).toBe(true);
const lines = await renderGalleryState("task", task, "error", 100);
const stripped = lines.map(line => Bun.stripANSI(line).trim());
// The framed result header carries the label inside the box border...
expect(stripped.some(line => line.startsWith("┌") && line.includes("Task"))).toBe(true);
// ...but no standalone "Task" label line precedes it.
expect(stripped).not.toContain("Task");
});
it("renders gallery-only read group fixtures", async () => {
const fixture = resolveFixture("read_group");
const success = Bun.stripANSI((await renderGalleryState("read_group", fixture, "success", 140)).join("\n"));
const renderPathMatches = success.match(/packages\/coding-agent\/src\/task\/render\.ts/g) ?? [];
expect(success).toContain("Read (4)");
expect(renderPathMatches).toHaveLength(1);
expect(success).toContain("packages/coding-agent/src/task/render.ts:507-605,1070-1194,…,1270-1274");
expect(success).not.toContain("1210-1240");
expect(success).not.toContain("full file");
});
it("falls back to a generic fixture for registry tools without curated sample data", () => {
// resolveFixture never returns undefined for a registry tool, even one
// missing from the curated fixtures, so the gallery cannot crash on a newly
// added renderer.
const fixture = resolveFixture("a-tool-that-has-no-fixture");
expect(fixture.args).toBeDefined();
expect(fixture.result.content.length).toBeGreaterThan(0);
});
});