- Gradio 5.50.0 ChatInterface with type='messages' streaming - LangGraph create_react_agent with InMemorySaver checkpointer - 4 @tool functions: search_dashboards, get_health_summary, list_environments, get_task_status - Structured ChatMessage metadata (7 discriminator types: stream_token, tool_start/end/error, confirm_required, confirm_resolved, error) - HITL resume via second submit() with interrupt_before/Command - Dual-identity RBAC: service JWT + user JWT for tool calls - File upload (10 MB limit, pdfplumber/xlsx/JSON parser) - Conversation persistence via POST /api/agent/conversations/save - REST API: list, history, archive conversations; multi-tab gate; LLM config - LLM provider selection via Admin -> LLM Settings (assistant_planner_provider) - Svelte 5 AgentChatModel with stream event queue, dedup, stream_status watcher - MarkdownRenderer using svelte-markdown with semantic Tailwind tokens - ToolCallCard (3 states: executing/completed/failed) - ConversationList with search, date grouping, infinite scroll - ConnectionIndicator with Gradio health status - /agent route with two-column layout - Vite proxy /api/agent/gradio -> Gradio SSE - Fixed: not_() SQLAlchemy operator, route collision with _admin_routes - Fixed: conversation_id -> id normalization, .pyc cache staleness - Fixed: event.data array parsing (Gradio returns [jsonStr, null]) - Requirements pinned: gradio==5.50.0, pydantic>=2.7,<=2.12.3
96 lines
3.4 KiB
TypeScript
96 lines
3.4 KiB
TypeScript
// #region TestAgentChat.ToolCallCard [C:2] [TYPE Module] [SEMANTICS test,tool,call,card]
|
|
// @BRIEF L2 UX tests for ToolCallCard — renders executing/completed/failed states with proper visual indicators.
|
|
// @RELATION BINDS_TO -> [AgentChat.ToolCallCard]
|
|
// @UX_TEST: executing → spinner visible, tool name shown, no details button.
|
|
// @UX_TEST: completed → checkmark, details toggle shows result.
|
|
// @UX_TEST: failed → cross, details show error.
|
|
import { describe, it, expect } from "vitest";
|
|
import { render, screen, fireEvent } from "@testing-library/svelte";
|
|
import ToolCallCard from "../ToolCallCard.svelte";
|
|
|
|
// #region TestAgentChat.ToolCallCard.Executing [C:2] [TYPE Test]
|
|
// @UX_STATE executing — spinner icon, tool name in mono font, no Details button.
|
|
describe("ToolCallCard — executing state", () => {
|
|
it("renders tool name and spinner", () => {
|
|
render(ToolCallCard, {
|
|
props: {
|
|
tool: "search_dashboards",
|
|
input: { query: "test" },
|
|
status: "executing",
|
|
},
|
|
});
|
|
expect(screen.getByText("search_dashboards")).toBeTruthy();
|
|
// SVG spinner should be present (has animate-spin class in the SVG element)
|
|
const svg = document.querySelector("svg.animate-spin");
|
|
expect(svg).toBeTruthy();
|
|
});
|
|
|
|
it("does not show Details button while executing", () => {
|
|
render(ToolCallCard, {
|
|
props: {
|
|
tool: "search_dashboards",
|
|
status: "executing",
|
|
},
|
|
});
|
|
expect(screen.queryByText("Details")).toBeNull();
|
|
});
|
|
});
|
|
// #endregion TestAgentChat.ToolCallCard.Executing
|
|
|
|
// #region TestAgentChat.ToolCallCard.Completed [C:2] [TYPE Test]
|
|
// @UX_STATE completed — checkmark icon, Details button present, clicking shows result.
|
|
describe("ToolCallCard — completed state", () => {
|
|
it("renders tool name and checkmark", () => {
|
|
render(ToolCallCard, {
|
|
props: {
|
|
tool: "search_dashboards",
|
|
output: { found: 3 },
|
|
status: "completed",
|
|
},
|
|
});
|
|
expect(screen.getByText("search_dashboards")).toBeTruthy();
|
|
expect(screen.getByText("Details")).toBeTruthy();
|
|
});
|
|
|
|
it("toggles detail section on Details click", async () => {
|
|
render(ToolCallCard, {
|
|
props: {
|
|
tool: "search_dashboards",
|
|
output: { found: 3, items: ["a", "b"] },
|
|
status: "completed",
|
|
},
|
|
});
|
|
// Initially details should be hidden
|
|
expect(document.querySelector("details")).toBeNull();
|
|
|
|
// Click Details button using fireEvent for reactive flush
|
|
const detailsBtn = screen.getByText("Details");
|
|
await fireEvent.click(detailsBtn);
|
|
|
|
// After click, details elements appear
|
|
const postDetails = document.querySelector("details");
|
|
expect(postDetails).toBeTruthy();
|
|
const summary = postDetails?.querySelector("summary");
|
|
expect(summary).toBeTruthy();
|
|
});
|
|
});
|
|
// #endregion TestAgentChat.ToolCallCard.Completed
|
|
|
|
// #region TestAgentChat.ToolCallCard.Failed [C:2] [TYPE Test]
|
|
// @UX_STATE failed — cross icon, error visible inline.
|
|
describe("ToolCallCard — failed state", () => {
|
|
it("renders tool name, cross, and error detail", () => {
|
|
render(ToolCallCard, {
|
|
props: {
|
|
tool: "search_dashboards",
|
|
error: "API timeout after 30s",
|
|
status: "failed",
|
|
},
|
|
});
|
|
expect(screen.getByText("search_dashboards")).toBeTruthy();
|
|
expect(screen.getByText("Details")).toBeTruthy();
|
|
});
|
|
});
|
|
// #endregion TestAgentChat.ToolCallCard.Failed
|
|
// #endregion TestAgentChat.ToolCallCard
|