Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

188 lines
6.8 KiB
TypeScript

import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { AgentGUIAgentTarget } from "../types";
import { AgentGuiWorkbenchHeader } from "./header";
afterEach(cleanup);
describe("AgentGuiWorkbenchHeader conversation identity", () => {
it.each([false, true])(
"hides conversation identity without a conversation when collapsed is %s",
(isConversationRailCollapsed) => {
render(
<AgentGuiWorkbenchHeader
agentTitle="Leaked agent"
conversationIconFallbackUrl="fallback-agent.png"
conversationIconUrl="conversation-agent.png"
conversationTitle="Leaked conversation"
conversationTitleDisplayPrompt="Leaked rich conversation"
copy={{
collapseConversationRail: "Collapse",
expandConversationRail: "Expand",
fallbackAgentLabel: "Agent",
newConversation: "New conversation",
untitledConversation: "Untitled conversation"
}}
hasConversation={false}
isConversationRailAutoCollapsed={false}
isConversationRailCollapsed={isConversationRailCollapsed}
nodeId="empty-agent-gui"
secondaryAccessory={<span>Session-independent accessory</span>}
showConversationRailToggle={false}
showWindowControls={false}
onToggleConversationRail={vi.fn()}
/>
);
expect(screen.queryByText("Leaked agent")).toBeNull();
expect(screen.queryByText("Leaked conversation")).toBeNull();
expect(screen.queryByText("Leaked rich conversation")).toBeNull();
expect(screen.queryByTestId("agent-gui-window-detail-title")).toBeNull();
expect(
document.querySelector(
'[data-testid^="agent-gui-window-detail-title-icon"]'
)
).toBeNull();
expect(
document.querySelector('[data-testid^="agent-gui-window-session-icon"]')
).toBeNull();
expect(screen.getByText("Session-independent accessory")).toBeTruthy();
}
);
it("owns tool-sidebar layout independently from the native window shell", () => {
const { container } = render(
<AgentGuiWorkbenchHeader
copy={{
collapseConversationRail: "Collapse",
expandConversationRail: "Expand",
fallbackAgentLabel: "Agent",
newConversation: "New conversation"
}}
isConversationRailAutoCollapsed={false}
isConversationRailCollapsed={false}
nodeId="host-owned-agent-gui"
showConversationRailToggle={false}
showWindowControls={false}
toolSidebar={{
actions: <span>Host-owned tools</span>,
isSidebarOpen: true,
layoutWidthPx: 432
}}
onToggleConversationRail={vi.fn()}
/>
);
const header = container.querySelector<HTMLElement>(
"[data-agent-gui-workbench-header]"
);
expect(header).toHaveAttribute(
"data-agent-gui-workbench-header-tool-sidebar",
"true"
);
expect(
header?.style.getPropertyValue("--agent-gui-tool-sidebar-layout-width")
).toBe("432px");
expect(screen.getByText("Host-owned tools")).toBeTruthy();
});
it.each([false, true])(
"lazily renders exact Host target information for the session icon when collapsed is %s",
async (isConversationRailCollapsed) => {
const onHeaderPointerDown = vi.fn();
const conversationAgentTarget: AgentGUIAgentTarget = {
agentTargetId: "agent:shared",
iconUrl: "shared-agent.png",
label: "Shared Codex",
provider: "codex",
ref: { kind: "shared", provider: "codex" },
targetId: "shared:codex"
};
const renderAgentTargetInfo = vi.fn(({ surface, target }) => (
<div>{`${surface}:${target.agentTargetId}`}</div>
));
render(
<AgentGuiWorkbenchHeader
conversationAgentTarget={conversationAgentTarget}
conversationIconUrl="shared-agent.png"
conversationTitle="Investigate skills"
copy={{
collapseConversationRail: "Collapse",
expandConversationRail: "Expand",
fallbackAgentLabel: "Agent",
newConversation: "New conversation"
}}
hasConversation
isConversationRailAutoCollapsed={false}
isConversationRailCollapsed={isConversationRailCollapsed}
nodeId="shared-agent-gui"
renderAgentTargetInfo={renderAgentTargetInfo}
showConversationRailToggle={false}
showWindowControls={false}
onPointerDown={onHeaderPointerDown}
onToggleConversationRail={vi.fn()}
/>
);
expect(renderAgentTargetInfo).not.toHaveBeenCalled();
const trigger = screen.getByRole("img", { name: "Shared Codex" });
fireEvent.focus(trigger);
const focusTooltip = await screen.findByRole("tooltip");
expect(focusTooltip).toHaveTextContent("workbench-header:agent:shared");
expect(trigger).toHaveAttribute("aria-describedby", focusTooltip.id);
expect(trigger).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(document, { key: "Escape" });
expect(screen.queryByRole("tooltip")).toBeNull();
fireEvent.blur(trigger);
fireEvent.pointerDown(trigger);
expect(onHeaderPointerDown).not.toHaveBeenCalled();
fireEvent.pointerUp(trigger);
fireEvent.pointerMove(trigger, { pointerType: "mouse" });
expect(await screen.findByRole("tooltip")).toHaveTextContent(
"workbench-header:agent:shared"
);
expect(renderAgentTargetInfo).toHaveBeenLastCalledWith({
surface: "workbench-header",
target: conversationAgentTarget
});
}
);
it("does not add interactive icon chrome without a Host renderer", () => {
render(
<AgentGuiWorkbenchHeader
conversationAgentTarget={{
agentTargetId: "agent:local",
label: "Local Codex",
provider: "codex",
ref: { kind: "local", provider: "codex" },
targetId: "local:codex"
}}
conversationIconUrl="local-agent.png"
conversationTitle="Local session"
copy={{
collapseConversationRail: "Collapse",
expandConversationRail: "Expand",
fallbackAgentLabel: "Agent",
newConversation: "New conversation"
}}
hasConversation
isConversationRailAutoCollapsed={false}
isConversationRailCollapsed={false}
nodeId="local-agent-gui"
showConversationRailToggle={false}
showWindowControls={false}
onToggleConversationRail={vi.fn()}
/>
);
expect(screen.queryByLabelText("Local Codex")).toBeNull();
expect(
screen.getByTestId("agent-gui-window-detail-title-icon")
).toBeInTheDocument();
});
});