chore(vendor): import pi 0.85.1
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
138
third_party/pi/packages/coding-agent/test/settings-selector.test.ts
vendored
Normal file
138
third_party/pi/packages/coding-agent/test/settings-selector.test.ts
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
import { setKeybindings } from "@earendil-works/pi-tui";
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { KeybindingsManager } from "../src/core/keybindings.ts";
|
||||
import {
|
||||
type SettingsCallbacks,
|
||||
type SettingsConfig,
|
||||
SettingsSelectorComponent,
|
||||
} from "../src/modes/interactive/components/settings-selector.ts";
|
||||
import { initTheme } from "../src/modes/interactive/theme/theme.ts";
|
||||
import { stripAnsi } from "../src/utils/ansi.ts";
|
||||
import { createHarness, type Harness } from "./suite/harness.ts";
|
||||
|
||||
describe("SettingsSelectorComponent", () => {
|
||||
let harness: Harness | undefined;
|
||||
beforeAll(() => {
|
||||
initTheme("dark");
|
||||
setKeybindings(new KeybindingsManager());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
harness?.cleanup();
|
||||
harness = undefined;
|
||||
});
|
||||
|
||||
it("cycles through fullscreen settings", () => {
|
||||
const onExitOutputChange = vi.fn();
|
||||
const onScrollbarChange = vi.fn();
|
||||
const onCopyOnSelectChange = vi.fn();
|
||||
const config = {
|
||||
fullscreenExitOutput: "transcript",
|
||||
fullscreenScrollbar: "auto",
|
||||
fullscreenCopyOnSelect: true,
|
||||
warnings: {},
|
||||
defaultModel: "not set",
|
||||
availableDefaultModels: [],
|
||||
availableThinkingLevels: [],
|
||||
modelThinkingLevels: {},
|
||||
availableThemes: [],
|
||||
} as unknown as SettingsConfig;
|
||||
const callbacks = {
|
||||
onFullscreenExitOutputChange: onExitOutputChange,
|
||||
onFullscreenScrollbarChange: onScrollbarChange,
|
||||
onFullscreenCopyOnSelectChange: onCopyOnSelectChange,
|
||||
} as unknown as SettingsCallbacks;
|
||||
|
||||
const cycle = (label: string, count: number) => {
|
||||
const list = new SettingsSelectorComponent(config, callbacks).getSettingsList();
|
||||
for (const character of label) list.handleInput(character);
|
||||
for (let i = 0; i < count; i++) list.handleInput("\r");
|
||||
};
|
||||
|
||||
cycle("Fullscreen exit output", 2);
|
||||
expect(onExitOutputChange.mock.calls.flat()).toEqual(["resume-hint", "transcript"]);
|
||||
cycle("Fullscreen scrollbar", 3);
|
||||
expect(onScrollbarChange.mock.calls.flat()).toEqual(["always", "hidden", "auto"]);
|
||||
cycle("Fullscreen copy on select", 2);
|
||||
expect(onCopyOnSelectChange.mock.calls.flat()).toEqual([false, true]);
|
||||
});
|
||||
|
||||
it("keeps the configured fixed theme marked while browsing", () => {
|
||||
const config = {
|
||||
defaultModel: "not set",
|
||||
availableDefaultModels: [],
|
||||
modelThinkingLevels: {},
|
||||
currentTheme: "dark",
|
||||
terminalTheme: "dark",
|
||||
availableThemes: ["dark", "light"],
|
||||
warnings: {},
|
||||
} as unknown as SettingsConfig;
|
||||
const callbacks = { onThemePreview: vi.fn(), onCancel: () => {} } as unknown as SettingsCallbacks;
|
||||
const list = new SettingsSelectorComponent(config, callbacks).getSettingsList();
|
||||
|
||||
list.selectItem("theme");
|
||||
list.handleInput("\r");
|
||||
let output = stripAnsi(list.render(120).join("\n"));
|
||||
expect(output).toContain(" Automatic");
|
||||
expect(output).toContain("→ ✓ dark");
|
||||
|
||||
list.handleInput("\x1b[B");
|
||||
output = stripAnsi(list.render(120).join("\n"));
|
||||
expect(output).toContain(" ✓ dark");
|
||||
expect(output).toContain("→ light");
|
||||
});
|
||||
|
||||
it("keeps a configured automatic theme marked while browsing", () => {
|
||||
const config = {
|
||||
defaultModel: "not set",
|
||||
availableDefaultModels: [],
|
||||
modelThinkingLevels: {},
|
||||
currentTheme: "light/dark",
|
||||
terminalTheme: "dark",
|
||||
availableThemes: ["dark", "light", "other"],
|
||||
warnings: {},
|
||||
} as unknown as SettingsConfig;
|
||||
const callbacks = { onThemePreview: vi.fn(), onCancel: () => {} } as unknown as SettingsCallbacks;
|
||||
const list = new SettingsSelectorComponent(config, callbacks).getSettingsList();
|
||||
|
||||
list.selectItem("theme");
|
||||
list.handleInput("\r");
|
||||
list.handleInput("\r");
|
||||
let output = stripAnsi(list.render(120).join("\n"));
|
||||
expect(output).toContain("→ ✓ light");
|
||||
|
||||
list.handleInput("\x1b[B");
|
||||
output = stripAnsi(list.render(120).join("\n"));
|
||||
expect(output).toContain(" ✓ light");
|
||||
expect(output).toContain("→ other");
|
||||
});
|
||||
|
||||
it("keeps the configured per-model thinking level marked while browsing", async () => {
|
||||
harness = await createHarness({
|
||||
models: [{ id: "thinking-model", reasoning: true }],
|
||||
});
|
||||
const model = harness.getModel("thinking-model")!;
|
||||
const modelKey = `${model.provider}/${model.id}`;
|
||||
const config = {
|
||||
defaultModel: modelKey,
|
||||
availableDefaultModels: [model],
|
||||
thinkingLevel: "high",
|
||||
modelThinkingLevels: { [modelKey]: "medium" },
|
||||
} as unknown as SettingsConfig;
|
||||
const callbacks = { onCancel: () => {} } as unknown as SettingsCallbacks;
|
||||
const list = new SettingsSelectorComponent(config, callbacks).getSettingsList();
|
||||
|
||||
list.selectItem("model-thinking");
|
||||
list.handleInput("\r");
|
||||
list.handleInput("\r");
|
||||
|
||||
let output = stripAnsi(list.render(120).join("\n"));
|
||||
expect(output).toContain("→ ✓ medium");
|
||||
expect(output).toContain(" (clear override)");
|
||||
|
||||
list.handleInput("\x1b[B");
|
||||
output = stripAnsi(list.render(120).join("\n"));
|
||||
expect(output).toContain(" ✓ medium");
|
||||
expect(output).toContain("→ high");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user