Files
oh-my-pi/packages/coding-agent/test/modes/components/tree-selector-overflow.test.ts
T
can1357 2d56a37334 refactor(coding-agent): standardized ui dialogs to use overlay panel base
- Introduce OverlayPanel and PanelDivider classes to standardize rounded-box inline overlays and section rules.
- Migrate various UI dialog, selector, and panel components to inherit from OverlayPanel instead of Container.
- Remove manual DynamicBorder elements and custom title/header components across migrated components.
- Update test helpers and assertions to match the new overlay panel structure and rendering methods.
2026-08-20 04:47:33 +02:00

78 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { beforeAll, describe, expect, it } from "bun:test";
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
import { TreeSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/tree-selector";
import * as themeModule from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
import type { SessionEntry, SessionTreeNode } from "@oh-my-pi/pi-coding-agent/session/session-entries";
let counter = 0;
function makeUserNode(text: string, parentId: string | null = null): SessionTreeNode {
const id = `entry-${counter++}`;
const message: AgentMessage = { role: "user", content: text, timestamp: counter };
const entry: SessionEntry = {
type: "message",
id,
parentId,
timestamp: new Date().toISOString(),
message,
};
return { entry, children: [] };
}
/** Build a tree where every parent has two children, simulating heavy rewind branching. */
function buildBranchyTree(branchDepth: number): { root: SessionTreeNode; leaf: SessionTreeNode } {
const root = makeUserNode("root");
let current = root;
for (let i = 0; i < branchDepth; i++) {
const a = makeUserNode(`branch-${i}-a`, current.entry.id);
const b = makeUserNode(`branch-${i}-b-this-side-stays-active`, current.entry.id);
current.children.push(a, b);
current = b;
}
return { root, leaf: current };
}
function renderSelector(tree: SessionTreeNode, leafId: string, width: number): string[] {
const selector = new TreeSelectorComponent(
[tree],
leafId,
200,
() => {},
() => {},
);
return selector.renderContent(width).map(line => Bun.stripANSI(line));
}
describe("TreeSelectorComponent deep branching overflow", () => {
beforeAll(async () => {
await themeModule.initTheme(false, undefined, undefined, "dark", "light");
});
it("keeps the selected entry text visible when branching exceeds the viewport width", () => {
const { root, leaf } = buildBranchyTree(80);
const width = 120;
const rendered = renderSelector(root, leaf.entry.id, width);
// Every rendered row must fit the viewport — never wider than `width` display cols.
for (const line of rendered) {
expect(Bun.stringWidth(line, { countAnsiEscapeCodes: false })).toBeLessThanOrEqual(width);
}
// The selected row (marked with the `›` cursor) must still show the entry text
// instead of spending the whole viewport on branch gutters.
const selectedRow = rendered.find(line => line.trimStart().startsWith("›"));
expect(selectedRow).toBeDefined();
expect(selectedRow!).toContain("user:");
expect(selectedRow!).toMatch(/branch-\d+-b/);
});
it("preserves prefix budget so the selected entry text remains legible at narrow width", () => {
const { root, leaf } = buildBranchyTree(40);
const width = 80;
const rendered = renderSelector(root, leaf.entry.id, width);
const selectedRow = rendered.find(line => line.trimStart().startsWith("›"));
expect(selectedRow).toBeDefined();
expect(selectedRow!).toContain("user:");
});
});