@nestbox-ai/cli 1.0.18 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/test/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Test Suite Summary
2
+
3
+ This directory contains comprehensive unit tests for all CLI commands in the nestbox-ai-cli-tools project.
4
+
5
+ ## Test Files Created
6
+
7
+ - **auth.test.ts** - Tests for authentication commands (login, logout)
8
+ - **projects.test.ts** - Tests for project management commands (project use, project add, list)
9
+ - **compute.test.ts** - Tests for compute instance management commands (compute list, create, delete)
10
+ - **document.test.ts** - Tests for document management commands (doc and collection subcommands)
11
+ - **image.test.ts** - Tests for image management commands (image list)
12
+ - **agent.test.ts** - Tests for agent management commands (agent list, remove, deploy, generate, create)
13
+
14
+ ## What the Tests Cover
15
+
16
+ Each test file verifies:
17
+
18
+ 1. **Command Registration** - Ensures all commands and subcommands are properly registered
19
+ 2. **Command Structure** - Validates command names, descriptions, and hierarchy
20
+ 3. **Options and Arguments** - Checks that expected command-line options are available
21
+ 4. **Action Functions** - Verifies that action handlers are properly attached
22
+
23
+ ## Test Strategy
24
+
25
+ The tests focus on **command registration and structure validation** rather than execution logic. This approach:
26
+
27
+ - Ensures the CLI interface remains stable
28
+ - Validates command-line argument parsing
29
+ - Verifies help text and descriptions
30
+ - Doesn't require mocking complex external APIs
31
+ - Runs quickly and reliably
32
+
33
+ ## Running Tests
34
+
35
+ ```bash
36
+ # Run all tests
37
+ npm test
38
+
39
+ # Run tests with coverage
40
+ npm run coverage
41
+
42
+ # Run specific test file
43
+ npm test auth.test.ts
44
+ ```
45
+
46
+ ## Test Framework
47
+
48
+ - **Vitest** - Fast unit test runner with TypeScript support
49
+ - **Commander.js** - CLI framework being tested
50
+ - **Mock Strategy** - External dependencies are mocked to isolate command registration logic
51
+
52
+ All tests are passing and provide confidence that the CLI command structure is working correctly.
@@ -0,0 +1,140 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerAgentCommands } from '../src/commands/agent';
4
+
5
+ describe('Agent Commands', () => {
6
+ let program: Command;
7
+
8
+ beforeEach(() => {
9
+ program = new Command();
10
+ vi.clearAllMocks();
11
+ });
12
+
13
+ describe('registerAgentCommands', () => {
14
+ it('should register agent command group', () => {
15
+ registerAgentCommands(program);
16
+
17
+ const commands = program.commands;
18
+ const agentCommand = commands.find(cmd => cmd.name() === 'agent');
19
+
20
+ expect(agentCommand).toBeDefined();
21
+ expect(agentCommand?.description()).toBe('Manage Nestbox agents');
22
+ });
23
+
24
+ it('should register agent list subcommand', () => {
25
+ registerAgentCommands(program);
26
+
27
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
28
+ const subCommands = agentCommand?.commands || [];
29
+ const listCommand = subCommands.find(cmd => cmd.name() === 'list');
30
+
31
+ expect(listCommand).toBeDefined();
32
+ expect(listCommand?.description()).toBe('List all AI agents associated with the authenticated user');
33
+
34
+ // Check options
35
+ const options = listCommand?.options || [];
36
+ const projectOption = options.find(opt => opt.long === '--project');
37
+ expect(projectOption).toBeDefined();
38
+ expect(projectOption?.description).toBe('Project name (defaults to the current project)');
39
+ });
40
+
41
+ it('should register agent remove subcommand', () => {
42
+ registerAgentCommands(program);
43
+
44
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
45
+ const subCommands = agentCommand?.commands || [];
46
+ const removeCommand = subCommands.find(cmd => cmd.name() === 'remove');
47
+
48
+ expect(removeCommand).toBeDefined();
49
+ expect(removeCommand?.description()).toBe('Remove an AI agent');
50
+
51
+ // Check options
52
+ const options = removeCommand?.options || [];
53
+ const agentOption = options.find(opt => opt.long === '--agent');
54
+ const projectOption = options.find(opt => opt.long === '--project');
55
+
56
+ expect(agentOption).toBeDefined();
57
+ expect(projectOption).toBeDefined();
58
+ });
59
+
60
+ it('should register agent deploy subcommand', () => {
61
+ registerAgentCommands(program);
62
+
63
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
64
+ const subCommands = agentCommand?.commands || [];
65
+ const deployCommand = subCommands.find(cmd => cmd.name() === 'deploy');
66
+
67
+ expect(deployCommand).toBeDefined();
68
+ expect(deployCommand?.description()).toBe('Deploy an AI agent to the Nestbox platform');
69
+
70
+ // Check options
71
+ const options = deployCommand?.options || [];
72
+ const projectOption = options.find(opt => opt.long === '--project');
73
+ const agentOption = options.find(opt => opt.long === '--agent');
74
+ const instanceOption = options.find(opt => opt.long === '--instance');
75
+
76
+ expect(projectOption).toBeDefined();
77
+ expect(agentOption).toBeDefined();
78
+ expect(instanceOption).toBeDefined();
79
+ });
80
+
81
+ it('should register agent generate subcommand', () => {
82
+ registerAgentCommands(program);
83
+
84
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
85
+ const subCommands = agentCommand?.commands || [];
86
+ const generateCommand = subCommands.find(cmd => cmd.name() === 'generate');
87
+
88
+ expect(generateCommand).toBeDefined();
89
+ expect(generateCommand?.description()).toBe('Generate a new project from templates');
90
+
91
+ // Check that folder is an argument (it's in command name: "generate <folder>")
92
+ expect(generateCommand?.name()).toBe('generate');
93
+ });
94
+
95
+ it('should register agent create subcommand', () => {
96
+ registerAgentCommands(program);
97
+
98
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
99
+ const subCommands = agentCommand?.commands || [];
100
+ const createCommand = subCommands.find(cmd => cmd.name() === 'create');
101
+
102
+ expect(createCommand).toBeDefined();
103
+ expect(createCommand?.description()).toBe('Create multiple agents from a YAML configuration file');
104
+
105
+ // Check that it has optional arguments (in command name: "create [firstArg] [secondArg]")
106
+ expect(createCommand?.name()).toBe('create');
107
+
108
+ // Check options
109
+ const options = createCommand?.options || [];
110
+ const projectOption = options.find(opt => opt.long === '--project');
111
+
112
+ expect(projectOption).toBeDefined();
113
+ });
114
+
115
+ it('should have all expected agent subcommands', () => {
116
+ registerAgentCommands(program);
117
+
118
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
119
+ const subCommandNames = agentCommand?.commands.map(cmd => cmd.name()) || [];
120
+
121
+ expect(subCommandNames).toContain('list');
122
+ expect(subCommandNames).toContain('remove');
123
+ expect(subCommandNames).toContain('deploy');
124
+ expect(subCommandNames).toContain('generate');
125
+ expect(subCommandNames).toContain('create');
126
+ expect(subCommandNames).toHaveLength(5);
127
+ });
128
+
129
+ it('should have proper action functions for all subcommands', () => {
130
+ registerAgentCommands(program);
131
+
132
+ const agentCommand = program.commands.find(cmd => cmd.name() === 'agent');
133
+ const subCommands = agentCommand?.commands || [];
134
+
135
+ subCommands.forEach(cmd => {
136
+ expect(typeof cmd.action).toBe('function');
137
+ });
138
+ });
139
+ });
140
+ });
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerAuthCommands } from '../src/commands/auth';
4
+
5
+ describe('Auth Commands', () => {
6
+ let program: Command;
7
+
8
+ beforeEach(() => {
9
+ program = new Command();
10
+ vi.clearAllMocks();
11
+ });
12
+
13
+ describe('registerAuthCommands', () => {
14
+ it('should register login command with correct parameters', () => {
15
+ registerAuthCommands(program);
16
+
17
+ const commands = program.commands;
18
+ const loginCommand = commands.find(cmd => cmd.name() === 'login');
19
+
20
+ expect(loginCommand).toBeDefined();
21
+ expect(loginCommand?.description()).toBe('Login using Google SSO');
22
+
23
+ // Check if the command expects a domain argument (it's in the command name)
24
+ expect(loginCommand?.name()).toBe('login');
25
+ });
26
+
27
+ it('should register logout command with correct parameters', () => {
28
+ registerAuthCommands(program);
29
+
30
+ const commands = program.commands;
31
+ const logoutCommand = commands.find(cmd => cmd.name() === 'logout');
32
+
33
+ expect(logoutCommand).toBeDefined();
34
+ expect(logoutCommand?.description()).toBe('Logout from Nestbox platform');
35
+
36
+ // Check if the command has an optional domain argument (it's in the command name)
37
+ expect(logoutCommand?.name()).toBe('logout');
38
+ });
39
+
40
+ it('should register all expected auth commands', () => {
41
+ registerAuthCommands(program);
42
+
43
+ const commandNames = program.commands.map(cmd => cmd.name());
44
+ expect(commandNames).toContain('login');
45
+ expect(commandNames).toContain('logout');
46
+ expect(commandNames).toHaveLength(2);
47
+ });
48
+
49
+ it('should have proper command structure for login', () => {
50
+ registerAuthCommands(program);
51
+
52
+ const loginCommand = program.commands.find(cmd => cmd.name() === 'login');
53
+
54
+ // Verify command properties
55
+ expect(loginCommand?.name()).toBe('login');
56
+ expect(loginCommand?.description()).toBe('Login using Google SSO');
57
+ expect(typeof loginCommand?.action).toBe('function');
58
+ });
59
+
60
+ it('should have proper command structure for logout', () => {
61
+ registerAuthCommands(program);
62
+
63
+ const logoutCommand = program.commands.find(cmd => cmd.name() === 'logout');
64
+
65
+ // Verify command properties
66
+ expect(logoutCommand?.name()).toBe('logout');
67
+ expect(logoutCommand?.description()).toBe('Logout from Nestbox platform');
68
+ expect(typeof logoutCommand?.action).toBe('function');
69
+ });
70
+ });
71
+ });
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerComputeProgram } from '../src/commands/compute';
4
+
5
+ describe('Compute Commands', () => {
6
+ let program: Command;
7
+
8
+ beforeEach(() => {
9
+ program = new Command();
10
+ vi.clearAllMocks();
11
+ });
12
+
13
+ describe('registerComputeProgram', () => {
14
+ it('should register compute command group', () => {
15
+ registerComputeProgram(program);
16
+
17
+ const commands = program.commands;
18
+ const computeCommand = commands.find(cmd => cmd.name() === 'compute');
19
+
20
+ expect(computeCommand).toBeDefined();
21
+ expect(computeCommand?.description()).toBe('Manage Nestbox computes');
22
+ });
23
+
24
+ it('should register compute list subcommand', () => {
25
+ registerComputeProgram(program);
26
+
27
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
28
+ const subCommands = computeCommand?.commands || [];
29
+ const listCommand = subCommands.find(cmd => cmd.name() === 'list');
30
+
31
+ expect(listCommand).toBeDefined();
32
+ expect(listCommand?.description()).toBe('List all compute instances');
33
+
34
+ // Check options
35
+ const options = listCommand?.options || [];
36
+ const projectOption = options.find(opt => opt.long === '--project');
37
+ expect(projectOption).toBeDefined();
38
+ expect(projectOption?.description).toBe('Project ID or name (defaults to the current project)');
39
+ });
40
+
41
+ it('should register compute create subcommand', () => {
42
+ registerComputeProgram(program);
43
+
44
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
45
+ const subCommands = computeCommand?.commands || [];
46
+ const createCommand = subCommands.find(cmd => cmd.name() === 'create');
47
+
48
+ expect(createCommand).toBeDefined();
49
+ expect(createCommand?.description()).toBe('Create a new compute instance');
50
+
51
+ // Check options
52
+ const options = createCommand?.options || [];
53
+ const projectOption = options.find(opt => opt.long === '--project');
54
+ const imageOption = options.find(opt => opt.long === '--image');
55
+
56
+ expect(projectOption).toBeDefined();
57
+ expect(imageOption).toBeDefined();
58
+ });
59
+
60
+ it('should register compute delete subcommand', () => {
61
+ registerComputeProgram(program);
62
+
63
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
64
+ const subCommands = computeCommand?.commands || [];
65
+ const deleteCommand = subCommands.find(cmd => cmd.name() === 'delete');
66
+
67
+ expect(deleteCommand).toBeDefined();
68
+ expect(deleteCommand?.description()).toBe('Delete one or more compute instances');
69
+
70
+ // Check options
71
+ const options = deleteCommand?.options || [];
72
+ const projectOption = options.find(opt => opt.long === '--project');
73
+ const forceOption = options.find(opt => opt.long === '--force');
74
+
75
+ expect(projectOption).toBeDefined();
76
+ expect(forceOption).toBeDefined();
77
+ });
78
+
79
+ it('should have all expected compute subcommands', () => {
80
+ registerComputeProgram(program);
81
+
82
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
83
+ const subCommandNames = computeCommand?.commands.map(cmd => cmd.name()) || [];
84
+
85
+ expect(subCommandNames).toContain('list');
86
+ expect(subCommandNames).toContain('create');
87
+ expect(subCommandNames).toContain('delete');
88
+ expect(subCommandNames).toHaveLength(3);
89
+ });
90
+
91
+ it('should have proper action functions for all subcommands', () => {
92
+ registerComputeProgram(program);
93
+
94
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
95
+ const subCommands = computeCommand?.commands || [];
96
+
97
+ subCommands.forEach(cmd => {
98
+ expect(typeof cmd.action).toBe('function');
99
+ });
100
+ });
101
+
102
+ it('should register compute list command with correct structure', () => {
103
+ registerComputeProgram(program);
104
+
105
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
106
+ const listCommand = computeCommand?.commands.find(cmd => cmd.name() === 'list');
107
+
108
+ expect(listCommand?.name()).toBe('list');
109
+ expect(listCommand?.description()).toBe('List all compute instances');
110
+ expect(typeof listCommand?.action).toBe('function');
111
+ });
112
+
113
+ it('should register compute create command with correct structure', () => {
114
+ registerComputeProgram(program);
115
+
116
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
117
+ const createCommand = computeCommand?.commands.find(cmd => cmd.name() === 'create');
118
+
119
+ expect(createCommand?.name()).toBe('create');
120
+ expect(createCommand?.description()).toBe('Create a new compute instance');
121
+ expect(typeof createCommand?.action).toBe('function');
122
+ });
123
+
124
+ it('should register compute delete command with correct structure', () => {
125
+ registerComputeProgram(program);
126
+
127
+ const computeCommand = program.commands.find(cmd => cmd.name() === 'compute');
128
+ const deleteCommand = computeCommand?.commands.find(cmd => cmd.name() === 'delete');
129
+
130
+ expect(deleteCommand?.name()).toBe('delete');
131
+ expect(deleteCommand?.description()).toBe('Delete one or more compute instances');
132
+ expect(typeof deleteCommand?.action).toBe('function');
133
+ });
134
+ });
135
+ });
@@ -0,0 +1,217 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { Command } from 'commander';
3
+ import { registerDocumentCommands } from '../src/commands/document';
4
+
5
+ describe('Document Commands', () => {
6
+ let program: Command;
7
+
8
+ beforeEach(() => {
9
+ program = new Command();
10
+ vi.clearAllMocks();
11
+ });
12
+
13
+ describe('registerDocumentCommands', () => {
14
+ it('should register document command group', () => {
15
+ registerDocumentCommands(program);
16
+
17
+ const commands = program.commands;
18
+ const documentCommand = commands.find(cmd => cmd.name() === 'document');
19
+
20
+ expect(documentCommand).toBeDefined();
21
+ expect(documentCommand?.description()).toBe('Manage Nestbox documents');
22
+ });
23
+
24
+ it('should register doc subcommand group', () => {
25
+ registerDocumentCommands(program);
26
+
27
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
28
+ const subCommands = documentCommand?.commands || [];
29
+ const docCommand = subCommands.find(cmd => cmd.name() === 'doc');
30
+
31
+ expect(docCommand).toBeDefined();
32
+ expect(docCommand?.description()).toBe('Manage individual documents');
33
+ });
34
+
35
+ it('should register collection subcommand group', () => {
36
+ registerDocumentCommands(program);
37
+
38
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
39
+ const subCommands = documentCommand?.commands || [];
40
+ const collectionCommand = subCommands.find(cmd => cmd.name() === 'collection');
41
+
42
+ expect(collectionCommand).toBeDefined();
43
+ expect(collectionCommand?.description()).toBe('Manage document collections');
44
+ });
45
+
46
+ it('should register doc list subcommand', () => {
47
+ registerDocumentCommands(program);
48
+
49
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
50
+ const collectionCommand = documentCommand?.commands.find(cmd => cmd.name() === 'collection');
51
+ const collectionSubCommands = collectionCommand?.commands || [];
52
+ const listCommand = collectionSubCommands.find(cmd => cmd.name() === 'list');
53
+
54
+ expect(listCommand).toBeDefined();
55
+ expect(listCommand?.description()).toBe('List document collections for a specific instance');
56
+
57
+ // Check options
58
+ const options = listCommand?.options || [];
59
+ const instanceOption = options.find(opt => opt.long === '--instance');
60
+ const projectOption = options.find(opt => opt.long === '--project');
61
+
62
+ expect(instanceOption).toBeDefined();
63
+ expect(projectOption).toBeDefined();
64
+ });
65
+
66
+ it('should register doc create subcommand', () => {
67
+ registerDocumentCommands(program);
68
+
69
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
70
+ const collectionCommand = documentCommand?.commands.find(cmd => cmd.name() === 'collection');
71
+ const collectionSubCommands = collectionCommand?.commands || [];
72
+ const createCommand = collectionSubCommands.find(cmd => cmd.name() === 'create');
73
+
74
+ expect(createCommand).toBeDefined();
75
+ expect(createCommand?.description()).toBe('Create a new document collection for a specific instance');
76
+
77
+ // Check options
78
+ const options = createCommand?.options || [];
79
+ const instanceOption = options.find(opt => opt.long === '--instance');
80
+ const projectOption = options.find(opt => opt.long === '--project');
81
+
82
+ expect(instanceOption).toBeDefined();
83
+ expect(projectOption).toBeDefined();
84
+ });
85
+
86
+ it('should register doc get subcommand', () => {
87
+ registerDocumentCommands(program);
88
+
89
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
90
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
91
+ const docSubCommands = docCommand?.commands || [];
92
+ const getCommand = docSubCommands.find(cmd => cmd.name() === 'get');
93
+
94
+ expect(getCommand).toBeDefined();
95
+ expect(getCommand?.description()).toBe('Get a document from a collection');
96
+
97
+ // Arguments are part of the command definition, not in args array
98
+ expect(getCommand?.name()).toBe('get');
99
+ });
100
+
101
+ it('should register doc delete subcommand', () => {
102
+ registerDocumentCommands(program);
103
+
104
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
105
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
106
+ const docSubCommands = docCommand?.commands || [];
107
+ const deleteCommand = docSubCommands.find(cmd => cmd.name() === 'delete');
108
+
109
+ expect(deleteCommand).toBeDefined();
110
+ expect(deleteCommand?.description()).toBe('Delete a document from a collection');
111
+
112
+ // Arguments are part of the command definition, not in args array
113
+ expect(deleteCommand?.name()).toBe('delete');
114
+ });
115
+
116
+ it('should register doc update subcommand', () => {
117
+ registerDocumentCommands(program);
118
+
119
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
120
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
121
+ const docSubCommands = docCommand?.commands || [];
122
+ const updateCommand = docSubCommands.find(cmd => cmd.name() === 'update');
123
+
124
+ expect(updateCommand).toBeDefined();
125
+ expect(updateCommand?.description()).toBe('Update a document in a collection');
126
+
127
+ // Arguments are part of the command definition, not in args array
128
+ expect(updateCommand?.name()).toBe('update');
129
+ });
130
+
131
+ it('should register collection add subcommand', () => {
132
+ registerDocumentCommands(program);
133
+
134
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
135
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
136
+ const docSubCommands = docCommand?.commands || [];
137
+ const addCommand = docSubCommands.find(cmd => cmd.name() === 'add');
138
+
139
+ expect(addCommand).toBeDefined();
140
+ expect(addCommand?.description()).toBe('Add a new document to a collection');
141
+
142
+ // Check options
143
+ const options = addCommand?.options || [];
144
+ const instanceOption = options.find(opt => opt.long === '--instance');
145
+ const collectionOption = options.find(opt => opt.long === '--collection');
146
+
147
+ expect(instanceOption).toBeDefined();
148
+ expect(collectionOption).toBeDefined();
149
+ });
150
+
151
+ it('should register collection search subcommand', () => {
152
+ registerDocumentCommands(program);
153
+
154
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
155
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
156
+ const docSubCommands = docCommand?.commands || [];
157
+ const searchCommand = docSubCommands.find(cmd => cmd.name() === 'search');
158
+
159
+ expect(searchCommand).toBeDefined();
160
+ expect(searchCommand?.description()).toBe('Search for documents in a collection');
161
+
162
+ // Check arguments and options
163
+ expect(searchCommand?.name()).toBe('search');
164
+ });
165
+
166
+ it('should have all expected doc subcommands', () => {
167
+ registerDocumentCommands(program);
168
+
169
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
170
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
171
+ const docSubCommandNames = docCommand?.commands.map(cmd => cmd.name()) || [];
172
+
173
+ expect(docSubCommandNames).toContain('add');
174
+ expect(docSubCommandNames).toContain('get');
175
+ expect(docSubCommandNames).toContain('delete');
176
+ expect(docSubCommandNames).toContain('update');
177
+ expect(docSubCommandNames).toContain('upload-file');
178
+ expect(docSubCommandNames).toContain('search');
179
+ expect(docSubCommandNames).toHaveLength(6);
180
+ });
181
+
182
+ it('should have all expected collection subcommands', () => {
183
+ registerDocumentCommands(program);
184
+
185
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
186
+ const collectionCommand = documentCommand?.commands.find(cmd => cmd.name() === 'collection');
187
+ const collectionSubCommandNames = collectionCommand?.commands.map(cmd => cmd.name()) || [];
188
+
189
+ expect(collectionSubCommandNames).toContain('list');
190
+ expect(collectionSubCommandNames).toContain('create');
191
+ expect(collectionSubCommandNames).toContain('get');
192
+ expect(collectionSubCommandNames).toContain('delete');
193
+ expect(collectionSubCommandNames).toContain('update');
194
+ expect(collectionSubCommandNames).toHaveLength(5);
195
+ });
196
+
197
+ it('should have proper action functions for all subcommands', () => {
198
+ registerDocumentCommands(program);
199
+
200
+ const documentCommand = program.commands.find(cmd => cmd.name() === 'document');
201
+ const docCommand = documentCommand?.commands.find(cmd => cmd.name() === 'doc');
202
+ const collectionCommand = documentCommand?.commands.find(cmd => cmd.name() === 'collection');
203
+
204
+ // Check doc subcommands
205
+ const docSubCommands = docCommand?.commands || [];
206
+ docSubCommands.forEach(cmd => {
207
+ expect(typeof cmd.action).toBe('function');
208
+ });
209
+
210
+ // Check collection subcommands
211
+ const collectionSubCommands = collectionCommand?.commands || [];
212
+ collectionSubCommands.forEach(cmd => {
213
+ expect(typeof cmd.action).toBe('function');
214
+ });
215
+ });
216
+ });
217
+ });