Archived
test: cover client state helpers
This commit is contained in:
@@ -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");
|
||||
});
|
||||
});
|
||||
@@ -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" });
|
||||
});
|
||||
});
|
||||
@@ -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([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user