From a3ed2bb37fdd868a558b854c3ccb9b1636f2db3b Mon Sep 17 00:00:00 2001 From: Imanol Maiztegui Date: Thu, 30 Apr 2026 14:50:11 +0200 Subject: [PATCH] test(kilo-ui): add storybook story for edit tool diff viewer button Introduce `WithEditToolOpenDiffAction` story and supporting `editCompletedPart` fixture with full filediff metadata to exercise the `canOpenDiff()` code path. Force-reveal the hover-only action slot via a scoped style override so visual regression snapshots capture the icon-button layout. - Add completed edit tool part with before/after file content - Wire `onOpenDiff` prop through `AllProviders` into `DataProvider` - Create dedicated `mockDataEdit` dataset for the new story --- .../src/stories/message-part.stories.tsx | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/packages/kilo-ui/src/stories/message-part.stories.tsx b/packages/kilo-ui/src/stories/message-part.stories.tsx index e67fe32b441..8c256487b12 100644 --- a/packages/kilo-ui/src/stories/message-part.stories.tsx +++ b/packages/kilo-ui/src/stories/message-part.stories.tsx @@ -163,6 +163,39 @@ const errorToolPart: ToolPart = { }, } +// Completed edit tool with full filediff metadata — exercises canOpenDiff() +// so the "Open in Diff Viewer" icon button renders in the trigger. +const editCompletedPart: ToolPart = { + id: "part-tool-edit-done", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-edit-done", + tool: "edit", + state: { + status: "completed", + input: { + filePath: "src/counter.tsx", + oldString: "const [count, setCount] = createSignal(0)", + newString: "const [count, setCount] = createSignal(1)", + }, + output: "File edited successfully", + title: "Edit file", + metadata: { + filediff: { + file: "src/counter.tsx", + before: + "import { createSignal } from 'solid-js'\n\nexport function Counter() {\n const [count, setCount] = createSignal(0)\n return \n}\n", + after: + "import { createSignal } from 'solid-js'\n\nexport function Counter() {\n const [count, setCount] = createSignal(1)\n return \n}\n", + additions: 1, + deletions: 1, + }, + }, + time: { start: now - 4000, end: now - 3500 }, + }, +} + // --- Reasoning part --- const reasoningPart: ReasoningPart = { @@ -208,10 +241,12 @@ const mockDataReasoning = createMockData([reasoningPart, textPart]) const mockDataBash = createMockData([bashCompleted]) // Three context-group tools — exercises ContextToolGroupHeader collapse path const mockDataContextGroup = createMockData([completedToolPart, grepCompleted, globCompleted, textPart]) +// Completed edit tool with filediff — exercises the "Open in Diff Viewer" button path +const mockDataEdit = createMockData([editCompletedPart]) -function AllProviders(props: { children: any; data?: MockData }) { +function AllProviders(props: { children: any; data?: MockData; onOpenDiff?: () => void }) { return ( - + @@ -354,6 +389,25 @@ export const WithContextGroup: Story = { ), } +// --- Completed edit tool with filediff → "Open in Diff Viewer" icon visible --- +// +// CSS :hover cannot be triggered reliably from Storybook `play` functions, +// so the action slot is force-revealed via a scoped style override. This +// captures the layout with the icon present so the visual regression +// suite catches any regression in: +// - the `:has()` parent-grow rule on basic-tool-tool-info +// - the `margin-left: auto` pushing the action to the right +// - the icon-button ghost variant in the tool-trigger row +export const WithEditToolOpenDiffAction: Story = { + name: "WithEditTool (open-diff action visible)", + render: () => ( + {}}> + + + + ), +} + // --- All 5 tool hint error types in a single screenshot --- const hintErrors: ToolPart[] = [