kitstore-cli 1.0.0 → 1.0.2
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/default-config.json +1 -0
- package/dist/config.js +20 -4
- package/package.json +5 -1
- package/.env.test +0 -4
- package/.eslintrc.js +0 -29
- package/e2e/install.e2e.test.ts +0 -237
- package/e2e/integration.e2e.test.ts +0 -346
- package/e2e/login.e2e.test.ts +0 -188
- package/jest.config.js +0 -24
- package/openapitools.json +0 -7
- package/src/__tests__/commands/init.test.ts +0 -52
- package/src/__tests__/commands/install.test.ts +0 -449
- package/src/__tests__/commands/list.test.ts +0 -164
- package/src/__tests__/commands/login.test.ts +0 -293
- package/src/__tests__/commands/rule-check.test.ts +0 -52
- package/src/__tests__/commands/search.test.ts +0 -168
- package/src/__tests__/commands/upload.test.ts +0 -404
- package/src/__tests__/config.test.ts +0 -181
- package/src/__tests__/setup.ts +0 -11
- package/src/api/client.ts +0 -20
- package/src/api/generated/.openapi-generator/FILES +0 -17
- package/src/api/generated/.openapi-generator/VERSION +0 -1
- package/src/api/generated/.openapi-generator-ignore +0 -23
- package/src/api/generated/api.ts +0 -1171
- package/src/api/generated/base.ts +0 -62
- package/src/api/generated/common.ts +0 -113
- package/src/api/generated/configuration.ts +0 -121
- package/src/api/generated/docs/AuthApi.md +0 -158
- package/src/api/generated/docs/AuthResponseDto.md +0 -22
- package/src/api/generated/docs/AuthUserDto.md +0 -24
- package/src/api/generated/docs/HealthApi.md +0 -183
- package/src/api/generated/docs/LoginDto.md +0 -22
- package/src/api/generated/docs/RegisterDto.md +0 -24
- package/src/api/generated/docs/RuleAuthorDto.md +0 -22
- package/src/api/generated/docs/RuleResponseDto.md +0 -36
- package/src/api/generated/docs/RulesApi.md +0 -289
- package/src/api/generated/git_push.sh +0 -57
- package/src/api/generated/index.ts +0 -18
- package/src/commands/init.ts +0 -46
- package/src/commands/install.ts +0 -129
- package/src/commands/list.ts +0 -71
- package/src/commands/login.ts +0 -65
- package/src/commands/rule-check.ts +0 -49
- package/src/commands/search.ts +0 -66
- package/src/commands/upload.ts +0 -117
- package/src/config.ts +0 -66
- package/src/index.ts +0 -79
- package/test-cli-config.js +0 -118
- package/tsconfig.json +0 -24
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
import { loginCommand } from '../../commands/login';
|
|
2
|
-
import * as config from '../../config';
|
|
3
|
-
import * as apiClient from '../../api/client';
|
|
4
|
-
import axios from 'axios';
|
|
5
|
-
import inquirer from 'inquirer';
|
|
6
|
-
|
|
7
|
-
// Mock dependencies
|
|
8
|
-
jest.mock('../../config', () => ({
|
|
9
|
-
getConfig: jest.fn(),
|
|
10
|
-
saveConfig: jest.fn(),
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
jest.mock('../../api/client', () => ({
|
|
14
|
-
createApi: jest.fn(),
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
jest.mock('axios');
|
|
18
|
-
jest.mock('inquirer', () => ({
|
|
19
|
-
prompt: jest.fn(),
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
const mockInquirer = require('inquirer');
|
|
23
|
-
|
|
24
|
-
// TC-UNIT-CLI-001 to TC-UNIT-CLI-002
|
|
25
|
-
describe('Login Command', () => {
|
|
26
|
-
const mockGetConfig = config.getConfig as jest.MockedFunction<typeof config.getConfig>;
|
|
27
|
-
const mockSaveConfig = config.saveConfig as jest.MockedFunction<typeof config.saveConfig>;
|
|
28
|
-
const mockCreateApi = apiClient.createApi as jest.MockedFunction<typeof apiClient.createApi>;
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
jest.clearAllMocks();
|
|
32
|
-
(axios.isAxiosError as unknown as jest.Mock).mockImplementation((err: any) => err?.isAxiosError === true);
|
|
33
|
-
jest.spyOn(console, 'log').mockImplementation();
|
|
34
|
-
jest.spyOn(console, 'error').mockImplementation();
|
|
35
|
-
jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
|
|
36
|
-
throw new Error(`Process exit with code ${code}`);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
afterEach(() => {
|
|
41
|
-
jest.restoreAllMocks();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// TC-UNIT-CLI-001: Login command (success)
|
|
45
|
-
describe('login success', () => {
|
|
46
|
-
it('should login successfully and save token', async () => {
|
|
47
|
-
const mockAuthApi = {
|
|
48
|
-
authControllerLogin: jest.fn().mockResolvedValue({
|
|
49
|
-
data: {
|
|
50
|
-
token: 'test-token-123',
|
|
51
|
-
user: {
|
|
52
|
-
id: 'user-id',
|
|
53
|
-
username: 'testuser',
|
|
54
|
-
email: 'test@example.com',
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
}),
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
mockGetConfig.mockResolvedValue({
|
|
61
|
-
server: 'http://localhost:3000',
|
|
62
|
-
token: undefined,
|
|
63
|
-
user: undefined,
|
|
64
|
-
lastLogin: undefined,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
mockCreateApi.mockResolvedValue({
|
|
68
|
-
authApi: mockAuthApi,
|
|
69
|
-
rulesApi: {} as any,
|
|
70
|
-
} as any);
|
|
71
|
-
|
|
72
|
-
await loginCommand({
|
|
73
|
-
email: 'test@example.com',
|
|
74
|
-
password: 'Password123!',
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
|
|
78
|
-
expect(mockAuthApi.authControllerLogin).toHaveBeenCalledWith({
|
|
79
|
-
email: 'test@example.com',
|
|
80
|
-
password: 'Password123!',
|
|
81
|
-
});
|
|
82
|
-
expect(mockSaveConfig).toHaveBeenCalledWith({
|
|
83
|
-
token: 'test-token-123',
|
|
84
|
-
server: 'http://localhost:3000',
|
|
85
|
-
user: {
|
|
86
|
-
id: 'user-id',
|
|
87
|
-
username: 'testuser',
|
|
88
|
-
email: 'test@example.com',
|
|
89
|
-
},
|
|
90
|
-
lastLogin: expect.any(String),
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// TC-UNIT-CLI-002: Login command (failure)
|
|
96
|
-
describe('login failure', () => {
|
|
97
|
-
it('should handle 401 error', async () => {
|
|
98
|
-
const axiosError = {
|
|
99
|
-
isAxiosError: true,
|
|
100
|
-
response: {
|
|
101
|
-
status: 401,
|
|
102
|
-
data: { error: 'Invalid credentials' },
|
|
103
|
-
},
|
|
104
|
-
message: 'Request failed with status code 401',
|
|
105
|
-
} as any;
|
|
106
|
-
|
|
107
|
-
const mockAuthApi = {
|
|
108
|
-
authControllerLogin: jest.fn().mockRejectedValue(axiosError),
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
mockGetConfig.mockResolvedValue({
|
|
112
|
-
server: 'http://localhost:3000',
|
|
113
|
-
token: undefined,
|
|
114
|
-
user: undefined,
|
|
115
|
-
lastLogin: undefined,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
mockCreateApi.mockResolvedValue({
|
|
119
|
-
authApi: mockAuthApi,
|
|
120
|
-
rulesApi: {} as any,
|
|
121
|
-
} as any);
|
|
122
|
-
|
|
123
|
-
await expect(
|
|
124
|
-
loginCommand({
|
|
125
|
-
email: 'test@example.com',
|
|
126
|
-
password: 'WrongPassword',
|
|
127
|
-
}),
|
|
128
|
-
).rejects.toThrow();
|
|
129
|
-
|
|
130
|
-
expect(mockSaveConfig).not.toHaveBeenCalled();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// TC-UNIT-CLI-003: Interactive login prompts
|
|
134
|
-
it('should prompt for email and password when not provided', async () => {
|
|
135
|
-
mockInquirer.prompt
|
|
136
|
-
.mockResolvedValueOnce({ email: 'prompted@example.com' })
|
|
137
|
-
.mockResolvedValueOnce({ password: 'promptedpassword' });
|
|
138
|
-
|
|
139
|
-
const mockAuthApi = {
|
|
140
|
-
authControllerLogin: jest.fn().mockResolvedValue({
|
|
141
|
-
data: {
|
|
142
|
-
token: 'test-token-123',
|
|
143
|
-
user: {
|
|
144
|
-
id: 'user-id',
|
|
145
|
-
username: 'testuser',
|
|
146
|
-
email: 'prompted@example.com',
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
}),
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
mockGetConfig.mockResolvedValue({
|
|
153
|
-
server: 'http://localhost:3000',
|
|
154
|
-
token: undefined,
|
|
155
|
-
user: undefined,
|
|
156
|
-
lastLogin: undefined,
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
mockCreateApi.mockResolvedValue({
|
|
160
|
-
authApi: mockAuthApi,
|
|
161
|
-
rulesApi: {} as any,
|
|
162
|
-
} as any);
|
|
163
|
-
|
|
164
|
-
await loginCommand({});
|
|
165
|
-
|
|
166
|
-
expect(mockInquirer.prompt).toHaveBeenCalledTimes(2);
|
|
167
|
-
expect(mockInquirer.prompt).toHaveBeenNthCalledWith(1, [
|
|
168
|
-
{ type: 'input', name: 'email', message: 'Email:' }
|
|
169
|
-
]);
|
|
170
|
-
expect(mockInquirer.prompt).toHaveBeenNthCalledWith(2, [
|
|
171
|
-
{ type: 'password', name: 'password', message: 'Password:' }
|
|
172
|
-
]);
|
|
173
|
-
expect(mockAuthApi.authControllerLogin).toHaveBeenCalledWith({
|
|
174
|
-
email: 'prompted@example.com',
|
|
175
|
-
password: 'promptedpassword',
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// TC-UNIT-CLI-004: Empty credentials after prompts
|
|
180
|
-
it('should exit with error when email/password are empty after prompts', async () => {
|
|
181
|
-
mockInquirer.prompt
|
|
182
|
-
.mockResolvedValueOnce({ email: '' })
|
|
183
|
-
.mockResolvedValueOnce({ password: '' });
|
|
184
|
-
|
|
185
|
-
mockGetConfig.mockResolvedValue({
|
|
186
|
-
server: 'http://localhost:3000',
|
|
187
|
-
token: undefined,
|
|
188
|
-
user: undefined,
|
|
189
|
-
lastLogin: undefined,
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
await expect(loginCommand({})).rejects.toThrow('Process exit with code 1');
|
|
193
|
-
expect(console.error).toHaveBeenCalledWith('❌ Login failed: Email and password are required');
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// TC-UNIT-CLI-005: Login response without token
|
|
197
|
-
it('should handle login response without token', async () => {
|
|
198
|
-
const mockAuthApi = {
|
|
199
|
-
authControllerLogin: jest.fn().mockResolvedValue({
|
|
200
|
-
data: {
|
|
201
|
-
user: {
|
|
202
|
-
id: 'user-id',
|
|
203
|
-
username: 'testuser',
|
|
204
|
-
email: 'test@example.com',
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
}),
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
mockGetConfig.mockResolvedValue({
|
|
211
|
-
server: 'http://localhost:3000',
|
|
212
|
-
token: undefined,
|
|
213
|
-
user: undefined,
|
|
214
|
-
lastLogin: undefined,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
mockCreateApi.mockResolvedValue({
|
|
218
|
-
authApi: mockAuthApi,
|
|
219
|
-
rulesApi: {} as any,
|
|
220
|
-
} as any);
|
|
221
|
-
|
|
222
|
-
await expect(loginCommand({ email: 'test@example.com', password: 'password123' }))
|
|
223
|
-
.rejects.toThrow('Process exit with code 1');
|
|
224
|
-
|
|
225
|
-
expect(console.error).toHaveBeenCalledWith('❌ Login failed');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
// TC-UNIT-CLI-006: Other axios errors
|
|
229
|
-
it('should handle other axios errors', async () => {
|
|
230
|
-
const axiosError = {
|
|
231
|
-
isAxiosError: true,
|
|
232
|
-
response: {
|
|
233
|
-
status: 500,
|
|
234
|
-
data: { error: 'Internal server error' },
|
|
235
|
-
},
|
|
236
|
-
message: 'Request failed with status code 500',
|
|
237
|
-
} as any;
|
|
238
|
-
|
|
239
|
-
const mockAuthApi = {
|
|
240
|
-
authControllerLogin: jest.fn().mockRejectedValue(axiosError),
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
mockGetConfig.mockResolvedValue({
|
|
244
|
-
server: 'http://localhost:3000',
|
|
245
|
-
token: undefined,
|
|
246
|
-
user: undefined,
|
|
247
|
-
lastLogin: undefined,
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
mockCreateApi.mockResolvedValue({
|
|
251
|
-
authApi: mockAuthApi,
|
|
252
|
-
rulesApi: {} as any,
|
|
253
|
-
} as any);
|
|
254
|
-
|
|
255
|
-
await expect(
|
|
256
|
-
loginCommand({
|
|
257
|
-
email: 'test@example.com',
|
|
258
|
-
password: 'Password123!',
|
|
259
|
-
}),
|
|
260
|
-
).rejects.toThrow('Process exit with code 1');
|
|
261
|
-
|
|
262
|
-
expect(console.error).toHaveBeenCalledWith('❌ Login failed: Internal server error');
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// TC-UNIT-CLI-007: Non-axios errors
|
|
266
|
-
it('should handle non-axios errors', async () => {
|
|
267
|
-
const mockAuthApi = {
|
|
268
|
-
authControllerLogin: jest.fn().mockRejectedValue(new Error('Network error')),
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
mockGetConfig.mockResolvedValue({
|
|
272
|
-
server: 'http://localhost:3000',
|
|
273
|
-
token: undefined,
|
|
274
|
-
user: undefined,
|
|
275
|
-
lastLogin: undefined,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
mockCreateApi.mockResolvedValue({
|
|
279
|
-
authApi: mockAuthApi,
|
|
280
|
-
rulesApi: {} as any,
|
|
281
|
-
} as any);
|
|
282
|
-
|
|
283
|
-
await expect(
|
|
284
|
-
loginCommand({
|
|
285
|
-
email: 'test@example.com',
|
|
286
|
-
password: 'Password123!',
|
|
287
|
-
}),
|
|
288
|
-
).rejects.toThrow('Process exit with code 1');
|
|
289
|
-
|
|
290
|
-
expect(console.error).toHaveBeenCalledWith('❌ Login failed: Network error');
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
});
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { ruleCheckCommand } from '../../commands/rule-check';
|
|
2
|
-
import * as fs from 'fs-extra';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
|
|
5
|
-
jest.mock('fs-extra');
|
|
6
|
-
|
|
7
|
-
describe('Rule Check Command', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
jest.clearAllMocks();
|
|
10
|
-
jest.spyOn(console, 'log').mockImplementation();
|
|
11
|
-
jest.spyOn(console, 'error').mockImplementation();
|
|
12
|
-
jest.spyOn(console, 'warn').mockImplementation();
|
|
13
|
-
jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
|
|
14
|
-
throw new Error(`Process exit with code ${code}`);
|
|
15
|
-
}) as any;
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should pass for a valid rule file', async () => {
|
|
19
|
-
(fs.pathExists as unknown as jest.Mock).mockResolvedValue(true);
|
|
20
|
-
(fs.readFile as unknown as jest.Mock).mockResolvedValue('@requirement TC-UNIT-001\nValid rule content');
|
|
21
|
-
|
|
22
|
-
await ruleCheckCommand('valid-rule.md');
|
|
23
|
-
|
|
24
|
-
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Rule validation passed!'));
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should exit if file not found', async () => {
|
|
28
|
-
(fs.pathExists as unknown as jest.Mock).mockResolvedValue(false);
|
|
29
|
-
|
|
30
|
-
await expect(ruleCheckCommand('non-existent.md')).rejects.toThrow('Process exit with code 1');
|
|
31
|
-
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('File not found'));
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should warn about missing @requirement tag', async () => {
|
|
35
|
-
(fs.pathExists as unknown as jest.Mock).mockResolvedValue(true);
|
|
36
|
-
(fs.readFile as unknown as jest.Mock).mockResolvedValue('Rule without requirement tag');
|
|
37
|
-
|
|
38
|
-
await ruleCheckCommand('no-tag.md');
|
|
39
|
-
|
|
40
|
-
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('Warning: Missing @requirement tag'));
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should error if file is empty', async () => {
|
|
44
|
-
(fs.pathExists as unknown as jest.Mock).mockResolvedValue(true);
|
|
45
|
-
(fs.readFile as unknown as jest.Mock).mockResolvedValue('');
|
|
46
|
-
|
|
47
|
-
await ruleCheckCommand('empty.md');
|
|
48
|
-
|
|
49
|
-
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Error: File is empty'));
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { searchCommand } from '../../commands/search';
|
|
2
|
-
import * as config from '../../config';
|
|
3
|
-
|
|
4
|
-
// Mock dependencies
|
|
5
|
-
jest.mock('../../config', () => ({
|
|
6
|
-
getConfig: jest.fn(),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
jest.mock('../../api/client', () => ({
|
|
10
|
-
createApi: jest.fn(),
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
describe('Search Command', () => {
|
|
14
|
-
const mockGetConfig = config.getConfig as jest.MockedFunction<typeof config.getConfig>;
|
|
15
|
-
const mockCreateApi = require('../../api/client').createApi as jest.MockedFunction<any>;
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
jest.clearAllMocks();
|
|
19
|
-
jest.spyOn(console, 'log').mockImplementation();
|
|
20
|
-
jest.spyOn(console, 'error').mockImplementation();
|
|
21
|
-
// Re-establish process.exit mock for each test
|
|
22
|
-
jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
|
|
23
|
-
throw new Error(`Process exit with code ${code}`);
|
|
24
|
-
}) as any;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
afterEach(() => {
|
|
28
|
-
jest.restoreAllMocks();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('search success', () => {
|
|
32
|
-
it('should search rules by query', async () => {
|
|
33
|
-
mockGetConfig.mockResolvedValue({
|
|
34
|
-
server: 'http://localhost:3000',
|
|
35
|
-
token: 'test-token',
|
|
36
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
37
|
-
lastLogin: new Date().toISOString(),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const mockRulesApi = {
|
|
41
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
42
|
-
data: [
|
|
43
|
-
{
|
|
44
|
-
id: 'rule-1',
|
|
45
|
-
name: 'Authentication Rule',
|
|
46
|
-
tag: 'auth',
|
|
47
|
-
type: 'rule',
|
|
48
|
-
description: 'Handles user authentication',
|
|
49
|
-
version: '1.0.0',
|
|
50
|
-
author: { username: 'user1' },
|
|
51
|
-
createdAt: '2024-01-01T00:00:00.000Z',
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
}),
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
58
|
-
|
|
59
|
-
await searchCommand('auth', {});
|
|
60
|
-
|
|
61
|
-
expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
|
|
62
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({
|
|
63
|
-
name: 'auth',
|
|
64
|
-
});
|
|
65
|
-
expect(console.log).toHaveBeenCalledWith('🔍 Search results for "auth":');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should apply additional filters with search query', async () => {
|
|
69
|
-
mockGetConfig.mockResolvedValue({
|
|
70
|
-
server: 'http://localhost:3000',
|
|
71
|
-
token: 'test-token',
|
|
72
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
73
|
-
lastLogin: new Date().toISOString(),
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const mockRulesApi = {
|
|
77
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
78
|
-
data: [
|
|
79
|
-
{
|
|
80
|
-
id: 'rule-1',
|
|
81
|
-
name: 'Validation Rule',
|
|
82
|
-
tag: 'validation',
|
|
83
|
-
type: 'rule',
|
|
84
|
-
description: 'Input validation rule',
|
|
85
|
-
version: '1.0.0',
|
|
86
|
-
author: { username: 'user1' },
|
|
87
|
-
createdAt: '2024-01-01T00:00:00.000Z',
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
}),
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
94
|
-
|
|
95
|
-
await searchCommand('validation', { type: 'rule', limit: '5' });
|
|
96
|
-
|
|
97
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({
|
|
98
|
-
name: 'validation',
|
|
99
|
-
type: 'rule',
|
|
100
|
-
limit: 5,
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should handle no search results', async () => {
|
|
105
|
-
mockGetConfig.mockResolvedValue({
|
|
106
|
-
server: 'http://localhost:3000',
|
|
107
|
-
token: 'test-token',
|
|
108
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
109
|
-
lastLogin: new Date().toISOString(),
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const mockRulesApi = {
|
|
113
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
114
|
-
data: [],
|
|
115
|
-
}),
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
119
|
-
|
|
120
|
-
await searchCommand('nonexistent', {});
|
|
121
|
-
|
|
122
|
-
expect(console.log).toHaveBeenCalledWith('🔍 No rules or commands found matching "nonexistent".');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe('search failure', () => {
|
|
127
|
-
it('should exit with error when not logged in', async () => {
|
|
128
|
-
mockGetConfig.mockResolvedValue({
|
|
129
|
-
server: 'http://localhost:3000',
|
|
130
|
-
token: undefined,
|
|
131
|
-
user: undefined,
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
await expect(searchCommand('test', {})).rejects.toThrow('Process exit with code 1');
|
|
135
|
-
expect(console.error).toHaveBeenCalledWith('❌ Not logged in. Please run `kitstore login` first.');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('should validate query parameter', async () => {
|
|
139
|
-
mockGetConfig.mockResolvedValue({
|
|
140
|
-
server: 'http://localhost:3000',
|
|
141
|
-
token: 'test-token',
|
|
142
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
143
|
-
lastLogin: new Date().toISOString(),
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
await expect(searchCommand('', {})).rejects.toThrow('Process exit with code 1');
|
|
147
|
-
expect(console.error).toHaveBeenCalledWith('❌ Search query is required.');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should handle API errors gracefully', async () => {
|
|
151
|
-
mockGetConfig.mockResolvedValue({
|
|
152
|
-
server: 'http://localhost:3000',
|
|
153
|
-
token: 'test-token',
|
|
154
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
155
|
-
lastLogin: new Date().toISOString(),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const mockRulesApi = {
|
|
159
|
-
rulesControllerFindAll: jest.fn().mockRejectedValue(new Error('API Error')),
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
163
|
-
|
|
164
|
-
await expect(searchCommand('test', {})).rejects.toThrow('Process exit with code 1');
|
|
165
|
-
expect(console.error).toHaveBeenCalledWith('❌ Search failed:', expect.any(Error));
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
});
|