openclaw/src/tui/tui-command-handlers.test.ts
2026-02-21 20:05:25 -08:00

139 lines
4.4 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { createCommandHandlers } from "./tui-command-handlers.js";
describe("tui command handlers", () => {
it("renders the sending indicator before chat.send resolves", async () => {
let resolveSend: ((value: { runId: string }) => void) | null = null;
const sendChat = vi.fn(
() =>
new Promise<{ runId: string }>((resolve) => {
resolveSend = resolve;
}),
);
const addUser = vi.fn();
const requestRender = vi.fn();
const setActivityStatus = vi.fn();
const { handleCommand } = createCommandHandlers({
client: { sendChat } as never,
chatLog: { addUser, addSystem: vi.fn() } as never,
tui: { requestRender } as never,
opts: {},
state: {
currentSessionKey: "agent:main:main",
activeChatRunId: null,
sessionInfo: {},
} as never,
deliverDefault: false,
openOverlay: vi.fn(),
closeOverlay: vi.fn(),
refreshSessionInfo: vi.fn(),
loadHistory: vi.fn(),
setSession: vi.fn(),
refreshAgents: vi.fn(),
abortActive: vi.fn(),
setActivityStatus,
formatSessionKey: vi.fn(),
applySessionInfoFromPatch: vi.fn(),
noteLocalRunId: vi.fn(),
});
const pending = handleCommand("/context");
await Promise.resolve();
expect(setActivityStatus).toHaveBeenCalledWith("sending");
const sendingOrder = setActivityStatus.mock.invocationCallOrder[0] ?? 0;
const renderOrders = requestRender.mock.invocationCallOrder;
expect(renderOrders.some((order) => order > sendingOrder)).toBe(true);
if (typeof resolveSend !== "function") {
throw new Error("expected sendChat to be pending");
}
(resolveSend as (value: { runId: string }) => void)({ runId: "r1" });
await pending;
expect(setActivityStatus).toHaveBeenCalledWith("waiting");
});
it("forwards unknown slash commands to the gateway", async () => {
const sendChat = vi.fn().mockResolvedValue({ runId: "r1" });
const addUser = vi.fn();
const addSystem = vi.fn();
const requestRender = vi.fn();
const setActivityStatus = vi.fn();
const { handleCommand } = createCommandHandlers({
client: { sendChat } as never,
chatLog: { addUser, addSystem } as never,
tui: { requestRender } as never,
opts: {},
state: {
currentSessionKey: "agent:main:main",
activeChatRunId: null,
sessionInfo: {},
} as never,
deliverDefault: false,
openOverlay: vi.fn(),
closeOverlay: vi.fn(),
refreshSessionInfo: vi.fn(),
loadHistory: vi.fn(),
setSession: vi.fn(),
refreshAgents: vi.fn(),
abortActive: vi.fn(),
setActivityStatus,
formatSessionKey: vi.fn(),
applySessionInfoFromPatch: vi.fn(),
noteLocalRunId: vi.fn(),
});
await handleCommand("/context");
expect(addSystem).not.toHaveBeenCalled();
expect(addUser).toHaveBeenCalledWith("/context");
expect(sendChat).toHaveBeenCalledWith(
expect.objectContaining({
sessionKey: "agent:main:main",
message: "/context",
}),
);
expect(requestRender).toHaveBeenCalled();
});
it("passes reset reason when handling /new and /reset", async () => {
const resetSession = vi.fn().mockResolvedValue({ ok: true });
const addSystem = vi.fn();
const requestRender = vi.fn();
const loadHistory = vi.fn().mockResolvedValue(undefined);
const { handleCommand } = createCommandHandlers({
client: { resetSession } as never,
chatLog: { addSystem } as never,
tui: { requestRender } as never,
opts: {},
state: {
currentSessionKey: "agent:main:main",
activeChatRunId: null,
sessionInfo: {},
} as never,
deliverDefault: false,
openOverlay: vi.fn(),
closeOverlay: vi.fn(),
refreshSessionInfo: vi.fn(),
loadHistory,
setSession: vi.fn(),
refreshAgents: vi.fn(),
abortActive: vi.fn(),
setActivityStatus: vi.fn(),
formatSessionKey: vi.fn(),
applySessionInfoFromPatch: vi.fn(),
noteLocalRunId: vi.fn(),
});
await handleCommand("/new");
await handleCommand("/reset");
expect(resetSession).toHaveBeenNthCalledWith(1, "agent:main:main", "new");
expect(resetSession).toHaveBeenNthCalledWith(2, "agent:main:main", "reset");
expect(loadHistory).toHaveBeenCalledTimes(2);
});
});