11/**
2- * Unit tests for Composer component
2+ * Unit tests for InputPrompt component
33 *
44 * Tests cover:
55 * - handleSend functionality
1111import React from "react" ;
1212import { render , screen , fireEvent } from "@testing-library/react" ;
1313import { describe , it , expect , vi , beforeEach } from "vitest" ;
14- import Composer , { type ComposerProps } from "./Composer " ;
14+ import InputPrompt , { type InputPromptProps } from "./InputPrompt " ;
1515import type { SkillInfo } from "@/webview/types" ;
1616
1717// Mock dependencies
@@ -83,6 +83,19 @@ vi.mock("@/webview/components/ui/popover", () => ({
8383 PopoverContent : vi . fn ( ( { children } ) => < div data-testid = "popover-content" > { children } </ div > ) ,
8484} ) ) ;
8585
86+ vi . mock ( "@/webview/components/PromptAttachments" , ( ) => ( {
87+ PromptAttachments : vi . fn ( ( { attachments } ) => (
88+ < div data-testid = "prompt-attachments" > { attachments . length } attachments</ div >
89+ ) ) ,
90+ usePromptAttachments : vi . fn ( ( ) => ( {
91+ attachments : [ ] ,
92+ handlePaste : vi . fn ( ) ,
93+ removeAttachment : vi . fn ( ) ,
94+ clearAttachments : vi . fn ( ) ,
95+ getImageUrls : vi . fn ( ( ) => [ ] ) ,
96+ } ) ) ,
97+ } ) ) ;
98+
8699vi . mock ( "@/webview/lib/utils" , ( ) => ( {
87100 cn : vi . fn ( ( ...args : unknown [ ] ) => args . filter ( Boolean ) . join ( " " ) ) ,
88101} ) ) ;
@@ -115,7 +128,7 @@ const mockOnSendPrompt =
115128const mockOnInterrupt = vi . fn < ( ) => void > ( ) ;
116129const mockOnSelectSkills = vi . fn < ( skills : SkillInfo [ ] ) => void > ( ) ;
117130
118- const defaultProps : ComposerProps = {
131+ const defaultProps : InputPromptProps = {
119132 loading : false ,
120133 selectedSkills : [ ] as SkillInfo [ ] ,
121134 availableSkills : [ ] as SkillInfo [ ] ,
@@ -136,37 +149,37 @@ const defaultProps: ComposerProps = {
136149 onSelectSkills : mockOnSelectSkills ,
137150} ;
138151
139- describe ( "Composer " , ( ) => {
152+ describe ( "InputPrompt " , ( ) => {
140153 beforeEach ( ( ) => {
141154 vi . clearAllMocks ( ) ;
142155 } ) ;
143156
144157 describe ( "handleSend" , ( ) => {
145158 it ( "calls onSendPrompt when sending a message" , async ( ) => {
146- render ( < Composer { ...defaultProps } /> ) ;
159+ render ( < InputPrompt { ...defaultProps } /> ) ;
147160 const textarea = screen . getByRole ( "textbox" ) ;
148161 fireEvent . change ( textarea , { target : { value : "Hello" } } ) ;
149162 fireEvent . keyDown ( textarea , { key : "Enter" } ) ;
150163 expect ( mockOnSendPrompt ) . toHaveBeenCalledWith ( "Hello" , [ ] , [ ] , undefined ) ;
151164 } ) ;
152165
153166 it ( "does not send empty message" , ( ) => {
154- render ( < Composer { ...defaultProps } /> ) ;
167+ render ( < InputPrompt { ...defaultProps } /> ) ;
155168 const textarea = screen . getByRole ( "textbox" ) ;
156169 fireEvent . keyDown ( textarea , { key : "Enter" } ) ;
157170 expect ( mockOnSendPrompt ) . not . toHaveBeenCalled ( ) ;
158171 } ) ;
159172
160173 it ( "trims whitespace before sending" , async ( ) => {
161- render ( < Composer { ...defaultProps } /> ) ;
174+ render ( < InputPrompt { ...defaultProps } /> ) ;
162175 const textarea = screen . getByRole ( "textbox" ) ;
163176 fireEvent . change ( textarea , { target : { value : " Hello " } } ) ;
164177 fireEvent . keyDown ( textarea , { key : "Enter" } ) ;
165178 expect ( mockOnSendPrompt ) . toHaveBeenCalledWith ( "Hello" , [ ] , [ ] , undefined ) ;
166179 } ) ;
167180
168181 it ( "does not send while loading" , ( ) => {
169- render ( < Composer { ...defaultProps } loading = { true } /> ) ;
182+ render ( < InputPrompt { ...defaultProps } loading = { true } /> ) ;
170183 const textarea = screen . getByRole ( "textbox" ) ;
171184 fireEvent . change ( textarea , { target : { value : "Hello" } } ) ;
172185 fireEvent . keyDown ( textarea , { key : "Enter" } ) ;
@@ -176,15 +189,15 @@ describe("Composer", () => {
176189
177190 describe ( "Keyboard navigation" , ( ) => {
178191 it ( "does not send on Shift+Enter" , ( ) => {
179- render ( < Composer { ...defaultProps } /> ) ;
192+ render ( < InputPrompt { ...defaultProps } /> ) ;
180193 const textarea = screen . getByRole ( "textbox" ) ;
181194 fireEvent . change ( textarea , { target : { value : "Hello" } } ) ;
182195 fireEvent . keyDown ( textarea , { key : "Enter" , shiftKey : true } ) ;
183196 expect ( mockOnSendPrompt ) . not . toHaveBeenCalled ( ) ;
184197 } ) ;
185198
186199 it ( "does not send on other keys" , ( ) => {
187- render ( < Composer { ...defaultProps } /> ) ;
200+ render ( < InputPrompt { ...defaultProps } /> ) ;
188201 const textarea = screen . getByRole ( "textbox" ) ;
189202 fireEvent . change ( textarea , { target : { value : "Hello" } } ) ;
190203 fireEvent . keyDown ( textarea , { key : "A" } ) ;
@@ -194,12 +207,12 @@ describe("Composer", () => {
194207
195208 describe ( "Loading state" , ( ) => {
196209 it ( "renders interrupt button when loading" , ( ) => {
197- render ( < Composer { ...defaultProps } loading = { true } /> ) ;
210+ render ( < InputPrompt { ...defaultProps } loading = { true } /> ) ;
198211 expect ( screen . getByTestId ( "input-group-button" ) ) . toBeInTheDocument ( ) ;
199212 } ) ;
200213
201214 it ( "calls onInterrupt when interrupt button clicked" , ( ) => {
202- render ( < Composer { ...defaultProps } loading = { true } /> ) ;
215+ render ( < InputPrompt { ...defaultProps } loading = { true } /> ) ;
203216 const button = screen . getByTestId ( "input-group-button" ) ;
204217 fireEvent . click ( button ) ;
205218 expect ( mockOnInterrupt ) . toHaveBeenCalled ( ) ;
@@ -208,35 +221,38 @@ describe("Composer", () => {
208221
209222 describe ( "Skills" , ( ) => {
210223 it ( "renders skills panel" , ( ) => {
211- render ( < Composer { ...defaultProps } /> ) ;
224+ render ( < InputPrompt { ...defaultProps } /> ) ;
212225 expect ( screen . getByTestId ( "skills-panel" ) ) . toBeInTheDocument ( ) ;
213226 } ) ;
214227
215228 it ( "passes selectedSkills to onSelectSkills" , ( ) => {
216229 const skills = [ { id : "skill1" , name : "TestSkill" } ] ;
217- render ( < Composer { ...defaultProps } availableSkills = { skills } /> ) ;
230+ render ( < InputPrompt { ...defaultProps } availableSkills = { skills } /> ) ;
218231 // Skills panel should be rendered with skills
219232 expect ( screen . getByTestId ( "skills-panel" ) ) . toBeInTheDocument ( ) ;
220233 } ) ;
221234 } ) ;
222235
223236 describe ( "Context meter" , ( ) => {
224237 it ( "renders context meter" , ( ) => {
225- render ( < Composer { ...defaultProps } /> ) ;
238+ render ( < InputPrompt { ...defaultProps } /> ) ;
226239 expect ( screen . getByTestId ( "context-meter" ) ) . toBeInTheDocument ( ) ;
227240 } ) ;
228241 } ) ;
229242
230243 describe ( "Hover card" , ( ) => {
231244 it ( "renders hover card when activeEditor is null" , ( ) => {
232- render ( < Composer { ...defaultProps } /> ) ;
245+ render ( < InputPrompt { ...defaultProps } /> ) ;
233246 // HoverCard may or may not be rendered based on activeEditor
234247 expect ( screen . getByTestId ( "field-group" ) ) . toBeInTheDocument ( ) ;
235248 } ) ;
236249
237250 it ( "renders hover card when activeEditor is provided" , ( ) => {
238251 render (
239- < Composer { ...defaultProps } activeEditor = { { fileName : "test.ts" , languageId : "typescript" , lineCount : 100 } } />
252+ < InputPrompt
253+ { ...defaultProps }
254+ activeEditor = { { fileName : "test.ts" , languageId : "typescript" , lineCount : 100 } }
255+ />
240256 ) ;
241257 expect ( screen . getByTestId ( "hover-card" ) ) . toBeInTheDocument ( ) ;
242258 } ) ;
0 commit comments