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
This commit is contained in:
Imanol Maiztegui
2026-04-30 14:50:11 +02:00
parent 236fa2dd88
commit a3ed2bb37f
@@ -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 <button onClick={() => setCount(count() + 1)}>{count()}</button>\n}\n",
after:
"import { createSignal } from 'solid-js'\n\nexport function Counter() {\n const [count, setCount] = createSignal(1)\n return <button onClick={() => setCount(count() + 1)}>{count()}</button>\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 (
<DataProvider data={props.data ?? mockData} directory="/project">
<DataProvider data={props.data ?? mockData} directory="/project" onOpenDiff={props.onOpenDiff}>
<DiffComponentProvider component={Diff}>
<CodeComponentProvider component={Code}>
<FileComponentProvider component={File}>
@@ -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: () => (
<AllProviders data={mockDataEdit} onOpenDiff={() => {}}>
<style>{`[data-slot="edit-trigger-actions"] { opacity: 1 !important; }`}</style>
<AssistantParts messages={[mockAssistantMessage]} />
</AllProviders>
),
}
// --- All 5 tool hint error types in a single screenshot ---
const hintErrors: ToolPart[] = [