@@ -175,36 +175,40 @@ describe('ExpandTextDialog', () => {
175175 expect ( screen . getByRole ( 'button' , { name : 'Save' } ) ) . toBeInTheDocument ( )
176176 expect ( screen . getByRole ( 'button' , { name : 'Cancel' } ) ) . toBeInTheDocument ( )
177177 } )
178+
179+ it ( 'should not show Edit/Source toggle in code mode' , ( ) => {
180+ render ( < ExpandTextDialog open = { true } value = '' inputType = 'code' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
181+
182+ expect ( screen . queryByRole ( 'button' , { name : 'Edit' } ) ) . not . toBeInTheDocument ( )
183+ expect ( screen . queryByRole ( 'button' , { name : 'Source' } ) ) . not . toBeInTheDocument ( )
184+ } )
178185 } )
179186
180187 // --- Rich text mode ---
181188
182189 describe ( 'inputType="string" (richtext)' , ( ) => {
183- it ( 'should render the TipTap editor instead of a TextField' , async ( ) => {
184- render (
185- < ExpandTextDialog open = { true } value = '<p>Hello</p>' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
186- )
190+ it ( 'should render the TipTap editor instead of a TextField in Edit mode' , async ( ) => {
191+ render ( < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
187192
188193 // RichTextEditor renders data-testid='rich-text-editor' which wraps tiptap
189194 expect ( await screen . findByTestId ( 'rich-text-editor' ) ) . toBeInTheDocument ( )
190195 expect ( screen . getByTestId ( 'tiptap-editor-content' ) ) . toBeInTheDocument ( )
191196
192197 // Plain TextField should NOT be present
193198 expect ( screen . queryByTestId ( 'expand-content-input' ) ) . not . toBeInTheDocument ( )
199+ expect ( screen . queryByTestId ( 'source-input' ) ) . not . toBeInTheDocument ( )
194200 } )
195201
196202 it ( 'should render plain TextField for non-string, non-code input types' , ( ) => {
197- render ( < ExpandTextDialog open = { true } value = 'Hello ' inputType = 'number' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
203+ render ( < ExpandTextDialog open = { true } value = '42 ' inputType = 'number' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
198204
199205 expect ( screen . getByTestId ( 'expand-content-input' ) ) . toBeInTheDocument ( )
200206 expect ( screen . queryByTestId ( 'rich-text-editor' ) ) . not . toBeInTheDocument ( )
201207 expect ( screen . queryByTestId ( 'code-input' ) ) . not . toBeInTheDocument ( )
202208 } )
203209
204210 it ( 'should still show Save and Cancel buttons in richtext mode' , ( ) => {
205- render (
206- < ExpandTextDialog open = { true } value = '<p>Hello</p>' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
207- )
211+ render ( < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
208212
209213 expect ( screen . getByRole ( 'button' , { name : 'Save' } ) ) . toBeInTheDocument ( )
210214 expect ( screen . getByRole ( 'button' , { name : 'Cancel' } ) ) . toBeInTheDocument ( )
@@ -214,7 +218,7 @@ describe('ExpandTextDialog', () => {
214218 render (
215219 < ExpandTextDialog
216220 open = { true }
217- value = '<p> Hello</p> '
221+ value = 'Hello'
218222 inputType = 'string'
219223 disabled = { true }
220224 onConfirm = { mockOnConfirm }
@@ -241,14 +245,204 @@ describe('ExpandTextDialog', () => {
241245 } )
242246
243247 it ( 'should call onCancel when Cancel is clicked in richtext mode' , ( ) => {
244- render (
245- < ExpandTextDialog open = { true } value = '<p>Hello</p>' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
246- )
248+ render ( < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
247249
248250 fireEvent . click ( screen . getByRole ( 'button' , { name : 'Cancel' } ) )
249251
250252 expect ( mockOnCancel ) . toHaveBeenCalled ( )
251253 expect ( mockOnConfirm ) . not . toHaveBeenCalled ( )
252254 } )
255+
256+ // --- Edit/Source toggle ---
257+
258+ it ( 'should show Edit and Source toggle buttons in richtext mode' , ( ) => {
259+ render ( < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
260+
261+ expect ( screen . getByRole ( 'button' , { name : 'Edit' } ) ) . toBeInTheDocument ( )
262+ expect ( screen . getByRole ( 'button' , { name : 'Source' } ) ) . toBeInTheDocument ( )
263+ } )
264+
265+ it ( 'should not show Edit/Source toggle for non-string input types' , ( ) => {
266+ render ( < ExpandTextDialog open = { true } value = '42' inputType = 'number' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
267+
268+ expect ( screen . queryByRole ( 'button' , { name : 'Edit' } ) ) . not . toBeInTheDocument ( )
269+ expect ( screen . queryByRole ( 'button' , { name : 'Source' } ) ) . not . toBeInTheDocument ( )
270+ } )
271+
272+ it ( 'should not change mode when the active toggle button is clicked again' , ( ) => {
273+ render (
274+ < ExpandTextDialog open = { true } value = '## My heading' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
275+ )
276+
277+ // Already in Edit mode — clicking Edit again should keep the rich-text editor visible
278+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Edit' } ) )
279+ expect ( screen . getByTestId ( 'rich-text-editor' ) ) . toBeInTheDocument ( )
280+ expect ( screen . queryByTestId ( 'source-input' ) ) . not . toBeInTheDocument ( )
281+ } )
282+
283+ it ( 'should switch to Source mode showing a raw text field when Source is clicked' , ( ) => {
284+ render (
285+ < ExpandTextDialog open = { true } value = '## My heading' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
286+ )
287+
288+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
289+
290+ // Source mode renders a monospace TextField with data-testid='source-input'
291+ expect ( screen . getByTestId ( 'source-input' ) ) . toBeInTheDocument ( )
292+
293+ // TipTap editor should be unmounted
294+ expect ( screen . queryByTestId ( 'rich-text-editor' ) ) . not . toBeInTheDocument ( )
295+ } )
296+
297+ it ( 'should show the current markdown value in Source mode' , ( ) => {
298+ render (
299+ < ExpandTextDialog open = { true } value = '## My heading' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
300+ )
301+
302+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
303+
304+ const sourceTextarea = screen . getByTestId ( 'source-input' ) . querySelector ( 'textarea' ) !
305+ expect ( sourceTextarea ) . toHaveValue ( '## My heading' )
306+ } )
307+
308+ it ( 'should switch back to Edit mode when Edit is clicked from Source' , ( ) => {
309+ render ( < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
310+
311+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
312+ expect ( screen . getByTestId ( 'source-input' ) ) . toBeInTheDocument ( )
313+
314+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Edit' } ) )
315+ expect ( screen . getByTestId ( 'rich-text-editor' ) ) . toBeInTheDocument ( )
316+ expect ( screen . queryByTestId ( 'source-input' ) ) . not . toBeInTheDocument ( )
317+ } )
318+
319+ it ( 'should save edits made in Source mode when Save is clicked' , ( ) => {
320+ render (
321+ < ExpandTextDialog open = { true } value = '## My heading' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
322+ )
323+
324+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
325+
326+ const sourceTextarea = screen . getByTestId ( 'source-input' ) . querySelector ( 'textarea' ) !
327+ fireEvent . change ( sourceTextarea , { target : { value : '## Updated heading' } } )
328+
329+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Save' } ) )
330+
331+ expect ( mockOnConfirm ) . toHaveBeenCalledWith ( '## Updated heading' )
332+ } )
333+
334+ it ( 'should disable the toggle buttons when disabled' , ( ) => {
335+ render (
336+ < ExpandTextDialog
337+ open = { true }
338+ value = 'Hello'
339+ inputType = 'string'
340+ disabled = { true }
341+ onConfirm = { mockOnConfirm }
342+ onCancel = { mockOnCancel }
343+ />
344+ )
345+
346+ expect ( screen . getByRole ( 'button' , { name : 'Edit' } ) ) . toBeDisabled ( )
347+ expect ( screen . getByRole ( 'button' , { name : 'Source' } ) ) . toBeDisabled ( )
348+ } )
349+
350+ it ( 'should reset to Edit mode when the dialog is reopened' , ( ) => {
351+ const { rerender } = render (
352+ < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } />
353+ )
354+
355+ // Switch to Source mode
356+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
357+ expect ( screen . getByTestId ( 'source-input' ) ) . toBeInTheDocument ( )
358+
359+ // Close dialog
360+ rerender ( < ExpandTextDialog open = { false } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
361+
362+ // Reopen — should be back in Edit mode
363+ rerender ( < ExpandTextDialog open = { true } value = 'Hello' inputType = 'string' onConfirm = { mockOnConfirm } onCancel = { mockOnCancel } /> )
364+
365+ expect ( screen . getByTestId ( 'rich-text-editor' ) ) . toBeInTheDocument ( )
366+ expect ( screen . queryByTestId ( 'source-input' ) ) . not . toBeInTheDocument ( )
367+ } )
368+ } )
369+
370+ // --- With suggestionItems (VariableInput mode) ---
371+
372+ describe ( 'inputType="string" with suggestionItems' , ( ) => {
373+ const mockSuggestionItems = [ { id : 'question' , label : 'question' , description : "User's question" , category : 'Chat Context' } ]
374+
375+ it ( 'should render VariableInput instead of RichTextEditor in Edit mode when suggestionItems provided' , ( ) => {
376+ render (
377+ < ExpandTextDialog
378+ open = { true }
379+ value = 'Hello'
380+ inputType = 'string'
381+ suggestionItems = { mockSuggestionItems }
382+ onConfirm = { mockOnConfirm }
383+ onCancel = { mockOnCancel }
384+ />
385+ )
386+
387+ expect ( screen . getByTestId ( 'variable-input' ) ) . toBeInTheDocument ( )
388+ expect ( screen . queryByTestId ( 'rich-text-editor' ) ) . not . toBeInTheDocument ( )
389+ } )
390+
391+ it ( 'should switch to Source mode and back to VariableInput when suggestionItems provided' , ( ) => {
392+ render (
393+ < ExpandTextDialog
394+ open = { true }
395+ value = 'Hello {{question}}'
396+ inputType = 'string'
397+ suggestionItems = { mockSuggestionItems }
398+ onConfirm = { mockOnConfirm }
399+ onCancel = { mockOnCancel }
400+ />
401+ )
402+
403+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
404+ expect ( screen . getByTestId ( 'source-input' ) ) . toBeInTheDocument ( )
405+ expect ( screen . queryByTestId ( 'variable-input' ) ) . not . toBeInTheDocument ( )
406+
407+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Edit' } ) )
408+ expect ( screen . getByTestId ( 'variable-input' ) ) . toBeInTheDocument ( )
409+ expect ( screen . queryByTestId ( 'source-input' ) ) . not . toBeInTheDocument ( )
410+ } )
411+
412+ it ( 'should still show Edit/Source toggle when suggestionItems provided' , ( ) => {
413+ render (
414+ < ExpandTextDialog
415+ open = { true }
416+ value = ''
417+ inputType = 'string'
418+ suggestionItems = { mockSuggestionItems }
419+ onConfirm = { mockOnConfirm }
420+ onCancel = { mockOnCancel }
421+ />
422+ )
423+
424+ expect ( screen . getByRole ( 'button' , { name : 'Edit' } ) ) . toBeInTheDocument ( )
425+ expect ( screen . getByRole ( 'button' , { name : 'Source' } ) ) . toBeInTheDocument ( )
426+ } )
427+
428+ it ( 'should save edits made in Source mode when suggestionItems provided' , ( ) => {
429+ render (
430+ < ExpandTextDialog
431+ open = { true }
432+ value = 'Hello {{question}}'
433+ inputType = 'string'
434+ suggestionItems = { mockSuggestionItems }
435+ onConfirm = { mockOnConfirm }
436+ onCancel = { mockOnCancel }
437+ />
438+ )
439+
440+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Source' } ) )
441+ const sourceTextarea = screen . getByTestId ( 'source-input' ) . querySelector ( 'textarea' ) !
442+ fireEvent . change ( sourceTextarea , { target : { value : 'Updated {{question}}' } } )
443+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Save' } ) )
444+
445+ expect ( mockOnConfirm ) . toHaveBeenCalledWith ( 'Updated {{question}}' )
446+ } )
253447 } )
254448} )
0 commit comments