@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/.github/workflows/generate-client.yml +34 -6
- package/dist/commands/agent.js +23 -7
- package/dist/commands/agent.js.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/agent.d.ts +0 -1
- package/dist/utils/agent.js +0 -48
- package/dist/utils/agent.js.map +1 -1
- package/package.json +2 -1
- package/src/commands/agent.ts +26 -8
- package/src/index.ts +9 -2
- package/src/utils/agent.ts +0 -57
- package/test/README.md +52 -0
- package/test/agent.test.ts +140 -0
- package/test/auth.test.ts +71 -0
- package/test/compute.test.ts +135 -0
- package/test/document.test.ts +217 -0
- package/test/image.test.ts +107 -0
- package/test/mocks.ts +122 -0
- package/test/projects.test.ts +108 -0
- package/test/setup.ts +121 -0
- package/tsconfig.json +3 -1
- package/vitest.config.d.ts +2 -0
- package/vitest.config.js +23 -0
- package/vitest.config.js.map +1 -0
- package/vitest.config.ts +21 -0
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
|
+
});
|