perf(ui): trim chat test imports

This commit is contained in:
Peter Steinberger
2026-04-25 12:04:06 +01:00
parent 4484772e7d
commit e6fd1ccfd7
5 changed files with 88 additions and 12 deletions

View File

@@ -17,6 +17,15 @@ vi.mock("../markdown.ts", () => ({
toSanitizedMarkdownHtml: (value: string) => value,
}));
vi.mock("../icons.ts", () => ({
icons: new Proxy(
{},
{
get: () => "",
},
),
}));
vi.mock("../views/agents-utils.ts", () => ({
agentLogoUrl: () => "/openclaw-logo.svg",
isRenderableControlUiAvatarUrl: (value: string) =>
@@ -40,6 +49,15 @@ vi.mock("../views/agents-utils.ts", () => ({
},
}));
vi.mock("../tool-display.ts", () => ({
formatToolDetail: () => undefined,
resolveToolDisplay: ({ name }: { name: string }) => ({
name,
label: name,
icon: "zap",
}),
}));
vi.mock("./speech.ts", () => ({
isTtsSpeaking: () => false,
isTtsSupported: () => false,
@@ -729,11 +747,14 @@ describe("grouped chat rendering", () => {
},
);
await vi.waitFor(() => {
const image = container.querySelector<HTMLImageElement>(".chat-message-image");
expect(image?.getAttribute("src")).toBe(objectUrl);
expect(image?.getAttribute("alt")).toBe("Generated image 1");
});
await vi.waitFor(
() => {
const image = container.querySelector<HTMLImageElement>(".chat-message-image");
expect(image?.getAttribute("src")).toBe(objectUrl);
expect(image?.getAttribute("alt")).toBe("Generated image 1");
},
{ interval: 1, timeout: 100 },
);
expect(fetchMock).toHaveBeenCalledWith(
"/api/chat/media/outgoing/agent%3Amain%3Amain/00000000-0000-4000-8000-000000000000/full",
expect.objectContaining({

View File

@@ -12,6 +12,21 @@ import type { GatewayBrowserClient } from "../gateway.ts";
import type { ModelCatalogEntry } from "../types.ts";
import { renderChatSessionSelect } from "./session-controls.ts";
const refreshVisibleToolsEffectiveForCurrentSessionMock = vi.hoisted(() =>
vi.fn(async (state: AppViewState) => {
const agentId = state.agentsSelectedId ?? "main";
const sessionKey = state.sessionKey;
await state.client?.request("tools.effective", { agentId, sessionKey });
const override = state.chatModelOverrides[sessionKey];
state.toolsEffectiveResultKey = `${agentId}:${sessionKey}:model=${override?.value ?? "(default)"}`;
state.toolsEffectiveResult = { agentId, profile: "coding", groups: [] };
}),
);
vi.mock("../controllers/agents.ts", () => ({
refreshVisibleToolsEffectiveForCurrentSession: refreshVisibleToolsEffectiveForCurrentSessionMock,
}));
function createChatHeaderState(
overrides: {
model?: string | null;
@@ -193,12 +208,16 @@ describe("chat session controls", () => {
modelSelect!.value = "openai/gpt-5-mini";
modelSelect!.dispatchEvent(new Event("change", { bubbles: true }));
await flushTasks();
await vi.waitFor(
() => {
expect(request).toHaveBeenCalledWith("tools.effective", {
agentId: "main",
sessionKey: "main",
});
},
{ interval: 1, timeout: 100 },
);
expect(request).toHaveBeenCalledWith("tools.effective", {
agentId: "main",
sessionKey: "main",
});
expect(state.toolsEffectiveResultKey).toBe("main:main:model=openai/gpt-5-mini");
vi.unstubAllGlobals();
});

View File

@@ -6,7 +6,6 @@ import {
resolveChatModelOverrideValue,
resolveChatModelSelectState,
} from "../chat-model-select-state.ts";
import { refreshVisibleToolsEffectiveForCurrentSession } from "../controllers/agents.ts";
import { loadSessions } from "../controllers/sessions.ts";
import { pushUniqueTrimmedSelectOption } from "../select-options.ts";
import { parseAgentSessionKey } from "../session-key.ts";
@@ -80,6 +79,12 @@ async function refreshSessionOptions(state: AppViewState) {
});
}
async function refreshVisibleToolsEffectiveForCurrentSessionLazy(state: AppViewState) {
const { refreshVisibleToolsEffectiveForCurrentSession } =
await import("../controllers/agents.ts");
return refreshVisibleToolsEffectiveForCurrentSession(state);
}
function renderChatModelSelect(state: AppViewState) {
const { currentOverride, defaultLabel, options } = resolveChatModelSelectState(state);
const busy =
@@ -278,7 +283,7 @@ async function switchChatModel(state: AppViewState, nextModel: string) {
key: targetSessionKey,
model: nextModel || null,
});
void refreshVisibleToolsEffectiveForCurrentSession(state);
void refreshVisibleToolsEffectiveForCurrentSessionLazy(state);
await refreshSessionOptions(state);
} catch (err) {
// Roll back so the picker reflects the actual server model.

View File

@@ -4,6 +4,15 @@ import { render } from "lit";
import { describe, expect, it, vi } from "vitest";
import { buildToolCardSidebarContent, extractToolCards, renderToolCard } from "./tool-cards.ts";
vi.mock("../icons.ts", () => ({
icons: new Proxy(
{},
{
get: () => "",
},
),
}));
describe("tool-cards", () => {
it("pretty-prints structured args and pairs tool output onto the same card", () => {
const cards = extractToolCards(

View File

@@ -5,6 +5,28 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import type { ChatQueueItem } from "../ui-types.ts";
import { cleanupChatModuleState, renderChat, type ChatProps } from "./chat.ts";
vi.mock("../markdown.ts", () => ({
toSanitizedMarkdownHtml: (value: string) => value,
}));
vi.mock("../icons.ts", () => ({
icons: new Proxy(
{},
{
get: () => "",
},
),
}));
vi.mock("../tool-display.ts", () => ({
formatToolDetail: () => undefined,
resolveToolDisplay: ({ name }: { name: string }) => ({
name,
label: name,
icon: "zap",
}),
}));
function createProps(overrides: Partial<ChatProps> = {}): ChatProps {
return {
sessionKey: "agent:main:main",