1+ import test from 'ava' ;
2+ import React from 'react' ;
3+ import { render } from 'ink-testing-library' ;
4+ import { LSP , lspCommand } from './lsp' ;
5+ import { getLSPManager , type LSPInitResult } from '../lsp/lsp-manager' ;
6+ import { ThemeContext } from '../hooks/useTheme' ;
7+ import { themes } from '../config/themes' ;
8+
9+ console . log ( `\nlsp-command.spec.tsx` ) ;
10+
11+ // Mock ThemeProvider for testing
12+ const MockThemeProvider = ( { children} : { children : React . ReactNode } ) => {
13+ const mockTheme = {
14+ currentTheme : 'tokyo-night' as const ,
15+ colors : themes [ 'tokyo-night' ] . colors ,
16+ setCurrentTheme : ( ) => { } ,
17+ } ;
18+ return (
19+ < ThemeContext . Provider value = { mockTheme } > { children } </ ThemeContext . Provider >
20+ ) ;
21+ } ;
22+
23+ // Mock LSP manager status
24+ const mockLSPStatus = {
25+ initialized : true ,
26+ servers : [
27+ {
28+ name : 'typescript-language-server' ,
29+ ready : true ,
30+ languages : [ 'ts' , 'js' , 'tsx' , 'jsx' ] ,
31+ } ,
32+ {
33+ name : 'gopls' ,
34+ ready : true ,
35+ languages : [ 'go' ] ,
36+ } ,
37+ {
38+ name : 'rust-analyzer' ,
39+ ready : false ,
40+ languages : [ 'rs' ] ,
41+ } ,
42+ ] ,
43+ } ;
44+
45+ // ============================================================================
46+ // Tests for LSP Command Display
47+ // ============================================================================
48+
49+ test ( 'LSP command: shows no servers when none connected' , t => {
50+ const emptyStatus = {
51+ initialized : false ,
52+ servers : [ ] ,
53+ } ;
54+
55+ const { lastFrame} = render (
56+ < MockThemeProvider >
57+ < LSP status = { emptyStatus } />
58+ </ MockThemeProvider > ,
59+ ) ;
60+
61+ const output = lastFrame ( ) ;
62+ t . truthy ( output ) ;
63+ t . regex ( output ! , / N o L S P s e r v e r s c o n n e c t e d / ) ;
64+ t . regex ( output ! , / a g e n t s \. c o n f i g \. j s o n / ) ;
65+ t . regex ( output ! , / L S P s e r v e r s w i l l a u t o - d i s c o v e r b a s e d o n y o u r p r o j e c t f i l e s / ) ;
66+ } ) ;
67+
68+ test ( 'LSP command: displays server status correctly' , t => {
69+ const { lastFrame} = render (
70+ < MockThemeProvider >
71+ < LSP status = { mockLSPStatus } />
72+ </ MockThemeProvider > ,
73+ ) ;
74+
75+ const output = lastFrame ( ) ;
76+ t . truthy ( output ) ;
77+
78+ // Should show connected servers count
79+ t . regex ( output ! , / C o n n e c t e d L S P S e r v e r s \( 3 \) : / ) ;
80+
81+ // Should show server names
82+ t . regex ( output ! , / t y p e s c r i p t - l a n g u a g e - s e r v e r / ) ;
83+ t . regex ( output ! , / g o p l s / ) ;
84+ t . regex ( output ! , / r u s t - a n a l y z e r / ) ;
85+
86+ // Should show status icons
87+ t . regex ( output ! , / 🟢 / ) ; // Ready servers
88+ t . regex ( output ! , / 🔴 / ) ; // Initializing server
89+
90+ // Should show status text
91+ t . regex ( output ! , / \( R e a d y \) / ) ;
92+ t . regex ( output ! , / \( I n i t i a l i z i n g \) / ) ;
93+ } ) ;
94+
95+ test ( 'LSP command: displays associated languages correctly' , t => {
96+ const { lastFrame} = render (
97+ < MockThemeProvider >
98+ < LSP status = { mockLSPStatus } />
99+ </ MockThemeProvider > ,
100+ ) ;
101+
102+ const output = lastFrame ( ) ;
103+ t . truthy ( output ) ;
104+
105+ // Should show languages for each server
106+ t . regex ( output ! , / L a n g u a g e s : t s , j s , t s x , j s x / ) ;
107+ t . regex ( output ! , / L a n g u a g e s : g o / ) ;
108+ t . regex ( output ! , / L a n g u a g e s : r s / ) ;
109+ } ) ;
110+
111+ test ( 'LSP command: handles single language correctly' , t => {
112+ const singleLangStatus = {
113+ initialized : true ,
114+ servers : [
115+ {
116+ name : 'single-lang-server' ,
117+ ready : true ,
118+ languages : [ 'python' ] ,
119+ } ,
120+ ] ,
121+ } ;
122+
123+ const { lastFrame} = render (
124+ < MockThemeProvider >
125+ < LSP status = { singleLangStatus } />
126+ </ MockThemeProvider > ,
127+ ) ;
128+
129+ const output = lastFrame ( ) ;
130+ t . truthy ( output ) ;
131+ t . regex ( output ! , / L a n g u a g e s : p y t h o n / ) ;
132+ } ) ;
133+
134+ test ( 'LSP command: handles multiple languages correctly' , t => {
135+ const multiLangStatus = {
136+ initialized : true ,
137+ servers : [
138+ {
139+ name : 'multi-lang-server' ,
140+ ready : true ,
141+ languages : [ 'js' , 'ts' , 'jsx' , 'tsx' , 'vue' ] ,
142+ } ,
143+ ] ,
144+ } ;
145+
146+ const { lastFrame} = render (
147+ < MockThemeProvider >
148+ < LSP status = { multiLangStatus } />
149+ </ MockThemeProvider > ,
150+ ) ;
151+
152+ const output = lastFrame ( ) ;
153+ t . truthy ( output ) ;
154+ t . regex ( output ! , / L a n g u a g e s : j s , t s , j s x , t s x , v u e / ) ;
155+ } ) ;
156+
157+ test ( 'LSP command: shows correct status icons' , t => {
158+ const testCases = [
159+ { ready : true , expectedIcon : '🟢' } ,
160+ { ready : false , expectedIcon : '🔴' } ,
161+ ] ;
162+
163+ for ( const testCase of testCases ) {
164+ const status = {
165+ initialized : true ,
166+ servers : [
167+ {
168+ name : 'test-server' ,
169+ ready : testCase . ready ,
170+ languages : [ 'test' ] ,
171+ } ,
172+ ] ,
173+ } ;
174+
175+ const { lastFrame} = render (
176+ < MockThemeProvider >
177+ < LSP status = { status } />
178+ </ MockThemeProvider > ,
179+ ) ;
180+
181+ const output = lastFrame ( ) ;
182+ t . truthy ( output ) ;
183+ t . regex (
184+ output ! ,
185+ new RegExp ( testCase . expectedIcon ) ,
186+ `Should show ${ testCase . expectedIcon } for ready=${ testCase . ready } ` ,
187+ ) ;
188+ }
189+ } ) ;
190+
191+ test ( 'LSP command: shows correct status text' , t => {
192+ const testCases = [
193+ { ready : true , expectedText : 'Ready' } ,
194+ { ready : false , expectedText : 'Initializing' } ,
195+ ] ;
196+
197+ for ( const testCase of testCases ) {
198+ const status = {
199+ initialized : true ,
200+ servers : [
201+ {
202+ name : 'test-server' ,
203+ ready : testCase . ready ,
204+ languages : [ 'test' ] ,
205+ } ,
206+ ] ,
207+ } ;
208+
209+ const { lastFrame} = render (
210+ < MockThemeProvider >
211+ < LSP status = { status } />
212+ </ MockThemeProvider > ,
213+ ) ;
214+
215+ const output = lastFrame ( ) ;
216+ t . truthy ( output ) ;
217+ t . regex (
218+ output ! ,
219+ new RegExp ( `\\(${ testCase . expectedText } \\)` ) ,
220+ `Should show (${ testCase . expectedText } ) for ready=${ testCase . ready } ` ,
221+ ) ;
222+ }
223+ } ) ;
224+
225+ // ============================================================================
226+ // Command Handler Tests
227+ // ============================================================================
228+
229+ test ( 'lspCommand has correct name' , t => {
230+ t . is ( lspCommand . name , 'lsp' ) ;
231+ } ) ;
232+
233+ test ( 'lspCommand has description' , t => {
234+ t . truthy ( lspCommand . description ) ;
235+ t . is ( typeof lspCommand . description , 'string' ) ;
236+ t . true ( lspCommand . description . length > 0 ) ;
237+ } ) ;
238+
239+ test ( 'lspCommand handler is a function' , t => {
240+ t . is ( typeof lspCommand . handler , 'function' ) ;
241+ } ) ;
242+
243+ test ( 'lspCommand handler returns valid React element' , async t => {
244+ // Mock the LSP manager to return our test status
245+ const originalGetLSPManager = getLSPManager ;
246+ const mockLSPManager = {
247+ getStatus : ( ) => mockLSPStatus ,
248+ } ;
249+ // Since we can't directly mock the singleton function, we'll just call the handler
250+ // which will use the actual LSP manager (but it will return an element regardless)
251+ const mockMessages : any [ ] = [ ] ;
252+ const mockMetadata : any = {
253+ provider : 'test' ,
254+ model : 'test' ,
255+ tokens : 0 ,
256+ getMessageTokens : ( ) => 0 ,
257+ } ;
258+
259+ const result = await lspCommand . handler ( [ ] , mockMessages , mockMetadata ) ;
260+
261+ t . truthy ( result ) ;
262+ t . true ( React . isValidElement ( result ) ) ;
263+ } ) ;
264+
265+ test ( 'lspCommand handler returns React element when no servers connected' , async t => {
266+ const mockMessages : any [ ] = [ ] ;
267+ const mockMetadata : any = {
268+ provider : 'test' ,
269+ model : 'test' ,
270+ tokens : 0 ,
271+ getMessageTokens : ( ) => 0 ,
272+ } ;
273+
274+ const result = await lspCommand . handler ( [ ] , mockMessages , mockMetadata ) ;
275+
276+ t . truthy ( result ) ;
277+ t . true ( React . isValidElement ( result ) ) ;
278+ } ) ;
0 commit comments