test: cover client state helpers

This commit is contained in:
Federico Jaramillo Martinez
2026-05-08 08:45:22 +02:00
parent e4293bbd9c
commit 9ce13df62d
3 changed files with 157 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
import { describe, expect, it } from "vitest";
import { groupChatMessages, summarizeChatGroup } from "./chatGroups";
import type { ChatLine } from "./components/shared";
const text = (role: ChatLine["role"], value: string): ChatLine => ({ role, parts: [{ type: "text", text: value }] });
describe("groupChatMessages", () => {
it("groups technical parts until a readable message is encountered", () => {
const messages: ChatLine[] = [
{ role: "assistant", parts: [{ type: "thinking", text: "plan" }, { type: "toolCall", toolName: "read", summary: "file" }] },
text("assistant", "visible answer"),
{ role: "tool", parts: [{ type: "toolResult", toolName: "read", text: "ok", isError: false }] },
];
expect(groupChatMessages(messages, 10)).toEqual([
{ kind: "group", startIndex: 10, messages: [messages[0]] },
{ kind: "message", index: 11, message: text("assistant", "visible answer") },
{ kind: "group", startIndex: 12, messages: [messages[2]] },
]);
});
it("splits mixed readable and technical parts from a single message", () => {
const messages: ChatLine[] = [
{ role: "assistant", parts: [{ type: "thinking", text: "hidden" }, { type: "text", text: "shown" }] },
];
expect(groupChatMessages(messages)).toEqual([
{ kind: "group", startIndex: 0, messages: [{ role: "assistant", parts: [{ type: "thinking", text: "hidden" }] }] },
{ kind: "message", index: 0, message: { role: "assistant", parts: [{ type: "text", text: "shown" }] } },
]);
});
it("treats compaction and branch summaries as grouped events", () => {
const messages: ChatLine[] = [
{ ...text("assistant", "summary"), source: "compaction" },
{ ...text("assistant", "branch"), source: "branch_summary" },
];
const groups = groupChatMessages(messages);
expect(groups).toHaveLength(1);
expect(groups[0]).toMatchObject({ kind: "group", startIndex: 0 });
});
});
describe("summarizeChatGroup", () => {
it("summarizes special event groups", () => {
expect(summarizeChatGroup([{ ...text("assistant", "a"), source: "compaction" }])).toBe("1 history compaction summary");
expect(summarizeChatGroup([
{ ...text("assistant", "a"), source: "branch_summary" },
{ ...text("assistant", "b"), source: "branch_summary" },
])).toBe("2 branch summaries");
});
it("summarizes mixed groups by role counts", () => {
expect(summarizeChatGroup([text("tool", "a"), text("system", "b"), text("tool", "c")])).toBe("3 events · 2 tool · 1 system");
});
});
+23
View File
@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import { inputModeForDraft, isShellInput } from "./inputModes";
describe("inputModeForDraft", () => {
it("detects shell input and context-excluded shell input after leading whitespace", () => {
expect(inputModeForDraft(" ! npm test")).toEqual({ kind: "shell", excludeFromContext: false });
expect(inputModeForDraft("\n!! secret command")).toEqual({ kind: "shell", excludeFromContext: true });
expect(isShellInput(" ! pwd")).toBe(true);
});
it("detects slash commands only for the current token", () => {
expect(inputModeForDraft("/compact")).toEqual({ kind: "command" });
expect(inputModeForDraft("please /compact")).toEqual({ kind: "command" });
expect(inputModeForDraft("please mention/path")).toEqual({ kind: "normal" });
});
it("detects file completion contexts", () => {
expect(inputModeForDraft("open @src/main.ts")).toEqual({ kind: "file" });
expect(inputModeForDraft("open @ ")).toEqual({ kind: "file" });
expect(inputModeForDraft("open @ \"src/main.ts")).toEqual({ kind: "file" });
expect(inputModeForDraft("open \"src/main.ts")).toEqual({ kind: "normal" });
});
});
+76
View File
@@ -0,0 +1,76 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { readRoute, writeRoute, type AppRoute } from "./route";
const originalWindow = globalThis.window;
afterEach(() => {
vi.restoreAllMocks();
Object.defineProperty(globalThis, "window", { value: originalWindow, configurable: true });
});
function installWindow(href: string): { pushed: string[] } {
const url = new URL(href);
const pushed: string[] = [];
const fakeWindow = {
location: {
href: url.href,
pathname: url.pathname,
search: url.search,
hash: url.hash,
},
history: {
pushState: vi.fn((_state: object, _title: string, next: URL | string) => {
pushed.push(String(next));
}),
},
};
Object.defineProperty(globalThis, "window", { value: fakeWindow, configurable: true });
return { pushed };
}
describe("route helpers", () => {
it("reads only supported route fields from the current URL", () => {
installWindow("http://localhost/app?project=p1&workspace=w1&session=s1&tool=git&view=files&file=src%2Fmain.ts&diff=README.md");
expect(readRoute()).toEqual({
projectId: "p1",
workspaceId: "w1",
sessionId: "s1",
tool: "git",
view: "files",
file: "src/main.ts",
diff: "README.md",
});
});
it("ignores unsupported tool and view values", () => {
installWindow("http://localhost/app?tool=terminal&view=settings");
expect(readRoute()).toMatchObject({ tool: undefined, view: undefined });
});
it("writes compact URLs and preserves path/hash", () => {
const { pushed } = installWindow("http://localhost/app?old=1#section");
const route: AppRoute = {
projectId: "project/id",
workspaceId: "workspace id",
sessionId: "",
tool: "files",
view: "chat",
file: "src/main.ts",
diff: undefined,
};
writeRoute(route);
expect(pushed).toEqual(["http://localhost/app?old=1&project=project%2Fid&workspace=workspace+id&tool=files&view=chat&file=src%2Fmain.ts#section"]);
});
it("does not push history when the route is unchanged", () => {
const { pushed } = installWindow("http://localhost/app?project=p1&tool=git");
writeRoute({ projectId: "p1", workspaceId: undefined, sessionId: undefined, tool: "git", view: undefined, file: undefined, diff: undefined });
expect(pushed).toEqual([]);
});
});