perf(test): avoid app chat slash reload

This commit is contained in:
Peter Steinberger
2026-04-20 20:47:35 +01:00
parent 8aaea14209
commit 2d55e0a00b
2 changed files with 38 additions and 21 deletions

View File

@@ -2,6 +2,7 @@
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ChatHost } from "./app-chat.ts";
import type { GatewaySessionRow, SessionsListResult } from "./types.ts";
const { setLastActiveSessionKeyMock } = vi.hoisted(() => ({
setLastActiveSessionKeyMock: vi.fn(),
@@ -15,10 +16,7 @@ let handleSendChat: typeof import("./app-chat.ts").handleSendChat;
let refreshChatAvatar: typeof import("./app-chat.ts").refreshChatAvatar;
let clearPendingQueueItemsForRun: typeof import("./app-chat.ts").clearPendingQueueItemsForRun;
async function loadChatHelpers(params?: { reload?: boolean }): Promise<void> {
if (params?.reload) {
vi.resetModules();
}
async function loadChatHelpers(): Promise<void> {
({ handleSendChat, refreshChatAvatar, clearPendingQueueItemsForRun } =
await import("./app-chat.ts"));
}
@@ -60,6 +58,25 @@ function makeHost(overrides?: Partial<ChatHost>): ChatHost {
};
}
function createSessionsResult(sessions: GatewaySessionRow[]): SessionsListResult {
return {
ts: 0,
path: "",
count: sessions.length,
defaults: { modelProvider: null, model: null, contextTokens: null },
sessions,
};
}
function row(key: string, overrides?: Partial<GatewaySessionRow>): GatewaySessionRow {
return {
key,
kind: "direct",
updatedAt: null,
...overrides,
};
}
function createDeferred<T>() {
let resolve!: (value: T) => void;
let reject!: (reason?: unknown) => void;
@@ -172,7 +189,6 @@ describe("handleSendChat", () => {
afterEach(() => {
vi.unstubAllGlobals();
vi.doUnmock("./chat/slash-command-executor.ts");
});
it("keeps slash-command model changes in sync with the chat header cache", async () => {
@@ -354,24 +370,19 @@ describe("handleSendChat", () => {
});
it("shows a visible pending item for /steer on the active run", async () => {
vi.doMock("./chat/slash-command-executor.ts", async () => {
const actual = await vi.importActual<typeof import("./chat/slash-command-executor.ts")>(
"./chat/slash-command-executor.ts",
);
return {
...actual,
executeSlashCommand: vi.fn(async () => ({
content: "Steered.",
pendingCurrentRun: true,
})),
};
});
await loadChatHelpers({ reload: true });
const host = makeHost({
client: { request: vi.fn() } as unknown as ChatHost["client"],
client: {
request: vi.fn(async (method: string) => {
if (method === "chat.send") {
return { status: "started", runId: "run-1", messageSeq: 2 };
}
throw new Error(`Unexpected request: ${method}`);
}),
} as unknown as ChatHost["client"],
chatRunId: "run-1",
chatMessage: "/steer tighten the plan",
sessionKey: "agent:main:main",
sessionsResult: createSessionsResult([row("agent:main:main", { status: "running" })]),
});
await handleSendChat(host);

View File

@@ -743,6 +743,7 @@ async function resolveSteerTarget(
return { error: "empty" };
}
const spaceIdx = trimmed.indexOf(" ");
let resolvedSessions: SessionsListResult | undefined;
if (spaceIdx > 0) {
const maybeTarget = trimmed.slice(0, spaceIdx);
const rest = trimmed.slice(spaceIdx + 1).trim();
@@ -751,6 +752,7 @@ async function resolveSteerTarget(
if (rest && normalizeLowercaseStringOrEmpty(maybeTarget) !== "all") {
const sessions =
context.sessionsResult ?? (await client.request<SessionsListResult>("sessions.list", {}));
resolvedSessions = sessions;
const matched = resolveSteerSubagent(sessions?.sessions ?? [], sessionKey, maybeTarget);
if (matched.length === 1) {
return { key: matched[0], message: rest, label: maybeTarget, sessions };
@@ -760,7 +762,11 @@ async function resolveSteerTarget(
}
}
}
return { key: sessionKey, message: trimmed };
return {
key: sessionKey,
message: trimmed,
sessions: resolvedSessions ?? context.sessionsResult ?? undefined,
};
}
function isActiveSteerSession(session: GatewaySessionRow | undefined): boolean {