44 * SPDX-License-Identifier: Apache-2.0
55 */
66
7- import { describe , it , expect , vi , beforeEach } from 'vitest' ;
7+ import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest' ;
8+ import { Storage , type Config } from '@google/gemini-cli-core' ;
89import { commandsCommand } from './commandsCommand.js' ;
910import { MessageType } from '../types.js' ;
1011import { createMockCommandContext } from '../../test-utils/mockCommandContext.js' ;
1112import type { CommandContext } from './types.js' ;
13+ import { FileCommandLoader } from '../../services/FileCommandLoader.js' ;
14+
15+ vi . mock ( '../../services/FileCommandLoader.js' ) ;
16+
17+ vi . mock ( '@google/gemini-cli-core' , async ( ) => {
18+ const actual = await vi . importActual <
19+ typeof import ( '@google/gemini-cli-core' )
20+ > ( '@google/gemini-cli-core' ) ;
21+ return {
22+ ...actual ,
23+ Storage : class extends actual . Storage {
24+ static override getUserCommandsDir ( ) {
25+ return '/mock/user/commands' ;
26+ }
27+ override getProjectCommandsDir ( ) {
28+ return '/mock/project/commands' ;
29+ }
30+ } ,
31+ } ;
32+ } ) ;
1233
1334describe ( 'commandsCommand' , ( ) => {
1435 let context : CommandContext ;
@@ -18,10 +39,27 @@ describe('commandsCommand', () => {
1839 context = createMockCommandContext ( {
1940 ui : {
2041 reloadCommands : vi . fn ( ) ,
42+ addItem : vi . fn ( ) ,
43+ } ,
44+ services : {
45+ agentContext : {
46+ getProjectRoot : vi . fn ( ) . mockReturnValue ( '/mock/project' ) ,
47+ getFolderTrust : vi . fn ( ) . mockReturnValue ( false ) ,
48+ isTrustedFolder : vi . fn ( ) . mockReturnValue ( false ) ,
49+ getExtensions : vi . fn ( ) . mockReturnValue ( [
50+ { name : 'ext1' , path : '/mock/ext1' , isActive : true } ,
51+ { name : 'ext2' , path : '/mock/ext2' , isActive : false } ,
52+ ] ) ,
53+ storage : new Storage ( '/mock/project' ) ,
54+ } as unknown as Config ,
2155 } ,
2256 } ) ;
2357 } ) ;
2458
59+ afterEach ( ( ) => {
60+ vi . restoreAllMocks ( ) ;
61+ } ) ;
62+
2563 describe ( 'default action' , ( ) => {
2664 it ( 'should return an info message prompting subcommand usage' , async ( ) => {
2765 const result = await commandsCommand . action ! ( context , '' ) ;
@@ -30,7 +68,70 @@ describe('commandsCommand', () => {
3068 type : 'message' ,
3169 messageType : 'info' ,
3270 content :
33- 'Use "/commands reload" to reload custom command definitions from .toml files.' ,
71+ 'Use "/commands list" to view available .toml files, or "/commands reload" to reload custom command definitions.' ,
72+ } ) ;
73+ } ) ;
74+ } ) ;
75+
76+ describe ( 'list' , ( ) => {
77+ it ( 'should list .toml files from available sources' , async ( ) => {
78+ vi . mocked (
79+ FileCommandLoader . prototype . listAvailableFiles ,
80+ ) . mockResolvedValue ( [
81+ {
82+ displayName : 'User' ,
83+ path : '/mock/user/commands' ,
84+ files : [ 'user1.toml' ] ,
85+ } ,
86+ {
87+ displayName : 'Project' ,
88+ path : '/mock/project/commands' ,
89+ files : [ 'proj1.toml' ] ,
90+ } ,
91+ {
92+ displayName : 'Extension: ext1' ,
93+ path : '/mock/ext1/commands' ,
94+ files : [ 'ext1.toml' ] ,
95+ } ,
96+ ] ) ;
97+
98+ const listCmd = commandsCommand . subCommands ! . find (
99+ ( s ) => s . name === 'list' ,
100+ ) ! ;
101+
102+ await listCmd . action ! ( context , '' ) ;
103+
104+ expect ( context . ui . addItem ) . toHaveBeenCalledWith (
105+ expect . objectContaining ( {
106+ type : MessageType . INFO ,
107+ text : expect . any ( String ) ,
108+ } ) ,
109+ expect . any ( Number ) ,
110+ ) ;
111+
112+ // Snapshot the text content
113+ const addItemCall = vi . mocked ( context . ui . addItem ) . mock . calls [ 0 ] [ 0 ] ;
114+
115+ expect ( ( addItemCall as { text : string } ) . text ) . toMatchSnapshot ( ) ;
116+ } ) ;
117+
118+ it ( 'should show "No custom command files found" message if no .toml files exist' , async ( ) => {
119+ vi . mocked (
120+ FileCommandLoader . prototype . listAvailableFiles ,
121+ ) . mockResolvedValue ( [ ] ) ;
122+
123+ const listCmd = commandsCommand . subCommands ! . find (
124+ ( s ) => s . name === 'list' ,
125+ ) ! ;
126+
127+ const result = await listCmd . action ! ( context , '' ) ;
128+
129+ expect ( result ) . toEqual ( {
130+ type : 'message' ,
131+ messageType : 'info' ,
132+ content : expect . stringContaining (
133+ 'No custom command files (.toml) found.' ,
134+ ) ,
34135 } ) ;
35136 } ) ;
36137 } ) ;
0 commit comments