1- import { Text } from 'ink' ;
21import { render } from 'ink-testing-library' ;
32
4- interface MockSelectPromptProps {
5- highlightText : string ;
6- onChange : ( value : string ) => void ;
7- options : { label : string ; value : string } [ ] ;
8- }
9-
10- const { mockSelectPrompt } = vi . hoisted ( ( ) => ( {
11- mockSelectPrompt : vi . fn < ( props : MockSelectPromptProps ) => void > ( ) ,
12- } ) ) ;
13-
14- vi . mock ( '@/components/SelectPrompt' , ( ) => ( {
15- SelectPrompt : ( props : MockSelectPromptProps ) => {
16- mockSelectPrompt ( props ) ;
17- return (
18- < >
19- { props . options . map ( ( { label, value } ) => (
20- < Text key = { value } > { label } </ Text >
21- ) ) }
22- </ >
23- ) ;
24- } ,
25- } ) ) ;
3+ import { KEY } from '@/constants' ;
4+ import { time } from '@/utils' ;
265
276import { CommandMenu } from './CommandMenu' ;
287
298describe ( 'CommandMenu' , ( ) => {
30- beforeEach ( ( ) => {
31- mockSelectPrompt . mockReset ( ) ;
32- } ) ;
33-
349 it ( 'returns null when input does not start with a slash' , ( ) => {
3510 const onSubmit = vi . fn ( ) ;
3611 const { lastFrame } = render (
3712 < CommandMenu input = "hello" onSubmit = { onSubmit } /> ,
3813 ) ;
3914
4015 expect ( lastFrame ( ) ) . toBe ( '' ) ;
41- expect ( mockSelectPrompt ) . not . toHaveBeenCalled ( ) ;
4216 } ) ;
4317
4418 it ( 'returns null when no commands match the slash input' , ( ) => {
@@ -48,34 +22,35 @@ describe('CommandMenu', () => {
4822 ) ;
4923
5024 expect ( lastFrame ( ) ) . toBe ( '' ) ;
51- expect ( mockSelectPrompt ) . not . toHaveBeenCalled ( ) ;
5225 } ) ;
5326
54- it ( 'renders matching commands and forwards selection' , ( ) => {
27+ it ( 'renders matching commands and selects with Enter' , async ( ) => {
5528 const onSubmit = vi . fn ( ) ;
56- const { lastFrame } = render (
29+ const { lastFrame, stdin } = render (
5730 < CommandMenu input = "/m" onSubmit = { onSubmit } /> ,
5831 ) ;
5932
6033 expect ( lastFrame ( ) ) . toContain ( '/model - manage Ollama models' ) ;
6134 expect ( lastFrame ( ) ) . not . toContain ( '/clear - clear the current session' ) ;
62- expect ( mockSelectPrompt ) . toHaveBeenCalledTimes ( 1 ) ;
63-
64- const [ firstCall ] = mockSelectPrompt . mock . calls ;
65- expect ( firstCall ) . toBeDefined ( ) ;
66- const [ props ] = firstCall ;
67- expect ( props . highlightText ) . toBe ( '/m' ) ;
68- expect ( props . options ) . toEqual ( [
69- {
70- label : '/model - manage Ollama models' ,
71- value : '/model' ,
72- } ,
73- ] ) ;
74- const { onChange } = props ;
75- onChange ( '/model' ) ;
35+
36+ stdin . write ( KEY . ENTER ) ;
37+ await time . tick ( ) ;
38+
7639 expect ( onSubmit ) . toHaveBeenCalledWith ( '/model' ) ;
7740 } ) ;
7841
42+ it ( 'moves focus through slash commands before selecting' , async ( ) => {
43+ const onSubmit = vi . fn ( ) ;
44+ const { stdin } = render ( < CommandMenu input = "/" onSubmit = { onSubmit } /> ) ;
45+
46+ stdin . write ( KEY . DOWN ) ;
47+ await time . tick ( ) ;
48+ stdin . write ( KEY . ENTER ) ;
49+ await time . tick ( ) ;
50+
51+ expect ( onSubmit ) . toHaveBeenCalledWith ( '/session' ) ;
52+ } ) ;
53+
7954 it ( 'includes /search in matching command results' , ( ) => {
8055 const onSubmit = vi . fn ( ) ;
8156 const { lastFrame } = render (
0 commit comments