mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
test(ui): pin SectionHeader and ToolsSection behaviour before migration
This commit is contained in:
parent
9d069f21dc
commit
eb23dc2e81
2 changed files with 133 additions and 0 deletions
|
|
@ -0,0 +1,64 @@
|
|||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { SectionHeader } from "./SectionHeader";
|
||||
|
||||
describe("SectionHeader", () => {
|
||||
it("renders the input label with token, cost and turn metrics", () => {
|
||||
render(<SectionHeader type="input" tokens={1234} cost={0.000123} turnCount={3} onCopy={vi.fn()} />);
|
||||
|
||||
expect(screen.getByText("Input")).toBeInTheDocument();
|
||||
expect(screen.getByText("Tokens: 1,234")).toBeInTheDocument();
|
||||
expect(screen.getByText("Cost: $0.000123")).toBeInTheDocument();
|
||||
expect(screen.getByText("Turns: 3")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders the output label", () => {
|
||||
render(<SectionHeader type="output" onCopy={vi.fn()} />);
|
||||
|
||||
expect(screen.getByText("Output")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("omits metrics that were not provided", () => {
|
||||
render(<SectionHeader type="input" onCopy={vi.fn()} />);
|
||||
|
||||
expect(screen.queryByText(/^Tokens:/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/^Cost:/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/^Turns:/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("omits the turn count when there are no turns", () => {
|
||||
render(<SectionHeader type="input" turnCount={0} onCopy={vi.fn()} />);
|
||||
|
||||
expect(screen.queryByText(/^Turns:/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("copies without toggling the section", async () => {
|
||||
const onCopy = vi.fn();
|
||||
const onToggleCollapse = vi.fn();
|
||||
render(<SectionHeader type="input" onCopy={onCopy} onToggleCollapse={onToggleCollapse} />);
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: /copy/i }));
|
||||
|
||||
expect(onCopy).toHaveBeenCalledTimes(1);
|
||||
expect(onToggleCollapse).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("toggles the section when the header is clicked", async () => {
|
||||
const onToggleCollapse = vi.fn();
|
||||
render(<SectionHeader type="input" onCopy={vi.fn()} onToggleCollapse={onToggleCollapse} />);
|
||||
|
||||
await userEvent.click(screen.getByText("Input"));
|
||||
|
||||
expect(onToggleCollapse).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("stays inert when no toggle handler is given", async () => {
|
||||
const onCopy = vi.fn();
|
||||
render(<SectionHeader type="input" onCopy={onCopy} />);
|
||||
|
||||
await userEvent.click(screen.getByText("Input"));
|
||||
|
||||
expect(onCopy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -2,10 +2,46 @@
|
|||
* Core tests for Tools section
|
||||
*/
|
||||
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { parseToolsFromLog } from "./utils";
|
||||
import { ToolsSection } from "./ToolsSection";
|
||||
import { LogEntry } from "../columns";
|
||||
|
||||
const logWithTools = (toolNames: string[], calledName?: string): LogEntry => ({
|
||||
request_id: "render-1",
|
||||
api_key: "key",
|
||||
team_id: "team",
|
||||
model: "gpt-4",
|
||||
model_id: "gpt-4",
|
||||
call_type: "completion",
|
||||
spend: 0.01,
|
||||
total_tokens: 100,
|
||||
prompt_tokens: 50,
|
||||
completion_tokens: 50,
|
||||
startTime: "2024-01-01T00:00:00Z",
|
||||
endTime: "2024-01-01T00:00:01Z",
|
||||
cache_hit: "none",
|
||||
messages: JSON.stringify({
|
||||
model: "gpt-4",
|
||||
messages: [{ role: "user", content: "hi" }],
|
||||
tools: toolNames.map((name) => ({
|
||||
type: "function",
|
||||
function: { name, description: `${name} description`, parameters: { type: "object", properties: {} } },
|
||||
})),
|
||||
}),
|
||||
response: JSON.stringify({
|
||||
choices: [
|
||||
{
|
||||
message: calledName
|
||||
? { tool_calls: [{ id: "call_1", type: "function", function: { name: calledName, arguments: "{}" } }] }
|
||||
: { content: "done" },
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
describe("ToolsSection", () => {
|
||||
it("should parse tools from request and match with response tool calls", () => {
|
||||
const mockLog: LogEntry = {
|
||||
|
|
@ -115,3 +151,36 @@ describe("ToolsSection", () => {
|
|||
expect(tools).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ToolsSection rendering", () => {
|
||||
it("summarises how many tools were provided and called", () => {
|
||||
render(<ToolsSection log={logWithTools(["get_weather", "search_web"], "get_weather")} />);
|
||||
|
||||
expect(screen.getByText("Tools")).toBeInTheDocument();
|
||||
expect(screen.getByText("2 provided, 1 called")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("previews the first two tool names", () => {
|
||||
render(<ToolsSection log={logWithTools(["alpha", "beta", "gamma"])} />);
|
||||
|
||||
expect(screen.getByText(/alpha, beta/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders nothing when the log has no tools", () => {
|
||||
const { container } = render(<ToolsSection log={logWithTools([])} />);
|
||||
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it("reveals the tool list only after the section is expanded", async () => {
|
||||
render(<ToolsSection log={logWithTools(["get_weather", "search_web"], "get_weather")} />);
|
||||
|
||||
expect(screen.queryByText("called")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("not called")).not.toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByText("Tools"));
|
||||
|
||||
expect(await screen.findByText("called")).toBeInTheDocument();
|
||||
expect(screen.getByText("not called")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue