kitstore-cli 1.0.0 → 1.0.1
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/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,449 +0,0 @@
|
|
|
1
|
-
import { installCommand } from '../../commands/install';
|
|
2
|
-
import * as config from '../../config';
|
|
3
|
-
import * as apiClient from '../../api/client';
|
|
4
|
-
import axios from 'axios';
|
|
5
|
-
import * as fs from 'fs-extra';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import inquirer from 'inquirer';
|
|
8
|
-
|
|
9
|
-
// Mock dependencies
|
|
10
|
-
jest.mock('../../config', () => ({
|
|
11
|
-
getConfig: jest.fn(),
|
|
12
|
-
getInstallPaths: jest.fn(),
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
jest.mock('../../api/client', () => ({
|
|
16
|
-
createApi: jest.fn(),
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
jest.mock('axios');
|
|
20
|
-
jest.mock('fs-extra', () => ({
|
|
21
|
-
pathExists: jest.fn(),
|
|
22
|
-
ensureDir: jest.fn(),
|
|
23
|
-
writeFile: jest.fn(),
|
|
24
|
-
createReadStream: jest.fn(),
|
|
25
|
-
}));
|
|
26
|
-
jest.mock('inquirer', () => ({
|
|
27
|
-
prompt: jest.fn(),
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
// TC-UNIT-CLI-003: Install command (success)
|
|
31
|
-
describe('Install Command', () => {
|
|
32
|
-
const mockGetConfig = config.getConfig as jest.MockedFunction<typeof config.getConfig>;
|
|
33
|
-
const mockGetInstallPaths = config.getInstallPaths as jest.MockedFunction<typeof config.getInstallPaths>;
|
|
34
|
-
const mockCreateApi = apiClient.createApi as jest.MockedFunction<typeof apiClient.createApi>;
|
|
35
|
-
const mockAxiosGet = axios.get as jest.MockedFunction<typeof axios.get>;
|
|
36
|
-
const mockFsEnsureDir = fs.ensureDir as jest.MockedFunction<any>;
|
|
37
|
-
const mockFsPathExists = fs.pathExists as jest.MockedFunction<any>;
|
|
38
|
-
const mockFsWriteFile = fs.writeFile as jest.MockedFunction<any>;
|
|
39
|
-
|
|
40
|
-
beforeEach(() => {
|
|
41
|
-
jest.clearAllMocks();
|
|
42
|
-
jest.spyOn(console, 'log').mockImplementation();
|
|
43
|
-
jest.spyOn(console, 'error').mockImplementation();
|
|
44
|
-
// Re-establish process.exit mock for each test
|
|
45
|
-
jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
|
|
46
|
-
throw new Error(`Process exit with code ${code}`);
|
|
47
|
-
}) as any;
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
afterEach(() => {
|
|
51
|
-
jest.restoreAllMocks();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should install rule successfully', async () => {
|
|
55
|
-
mockGetConfig.mockResolvedValue({
|
|
56
|
-
server: 'http://localhost:3000',
|
|
57
|
-
token: 'test-token',
|
|
58
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
59
|
-
lastLogin: new Date().toISOString(),
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
mockGetInstallPaths.mockReturnValue({
|
|
63
|
-
rules: '/path/to/rules',
|
|
64
|
-
commands: '/path/to/commands',
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const mockRulesApi = {
|
|
68
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
69
|
-
data: [
|
|
70
|
-
{
|
|
71
|
-
id: 'rule-id-1',
|
|
72
|
-
name: 'Test Rule',
|
|
73
|
-
tag: 'test',
|
|
74
|
-
type: 'rule',
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
}),
|
|
78
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
79
|
-
data: {
|
|
80
|
-
downloadUrl: 'https://signed-url.com/file',
|
|
81
|
-
},
|
|
82
|
-
}),
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
mockCreateApi.mockResolvedValue({
|
|
86
|
-
authApi: {} as any,
|
|
87
|
-
rulesApi: mockRulesApi as any,
|
|
88
|
-
} as any);
|
|
89
|
-
|
|
90
|
-
mockAxiosGet.mockResolvedValue({
|
|
91
|
-
data: 'rule content',
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
mockFsPathExists.mockResolvedValue(false);
|
|
95
|
-
mockFsEnsureDir.mockResolvedValue(undefined);
|
|
96
|
-
mockFsWriteFile.mockResolvedValue(undefined);
|
|
97
|
-
|
|
98
|
-
// Mock inquirer when multiple rules exist
|
|
99
|
-
const mockInquirer = require('inquirer');
|
|
100
|
-
mockInquirer.prompt = jest.fn().mockResolvedValue({ rule: 'rule-id-1' });
|
|
101
|
-
|
|
102
|
-
await installCommand({
|
|
103
|
-
tag: 'test',
|
|
104
|
-
type: 'rule',
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalled();
|
|
108
|
-
expect(mockRulesApi.rulesControllerGetDownloadUrl).toHaveBeenCalledWith('rule-id-1');
|
|
109
|
-
expect(mockAxiosGet).toHaveBeenCalledWith('https://signed-url.com/file', {
|
|
110
|
-
responseType: 'text',
|
|
111
|
-
});
|
|
112
|
-
expect(mockFsWriteFile).toHaveBeenCalled();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// TC-UNIT-CLI-026: Install with tag filtering
|
|
116
|
-
it('should filter rules by tag', async () => {
|
|
117
|
-
mockGetConfig.mockResolvedValue({
|
|
118
|
-
server: 'http://localhost:3000',
|
|
119
|
-
token: 'test-token',
|
|
120
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
121
|
-
lastLogin: new Date().toISOString(),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
mockGetInstallPaths.mockReturnValue({
|
|
125
|
-
rules: '/path/to/rules',
|
|
126
|
-
commands: '/path/to/commands',
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
const mockRulesApi = {
|
|
130
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
131
|
-
data: [
|
|
132
|
-
{
|
|
133
|
-
id: 'rule-id-1',
|
|
134
|
-
name: 'Test Rule',
|
|
135
|
-
tag: 'test',
|
|
136
|
-
type: 'rule',
|
|
137
|
-
version: '1.0.0',
|
|
138
|
-
author: { username: 'testuser' },
|
|
139
|
-
description: 'A test rule',
|
|
140
|
-
},
|
|
141
|
-
],
|
|
142
|
-
}),
|
|
143
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
144
|
-
data: { downloadUrl: 'https://signed-url.com/file' },
|
|
145
|
-
}),
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
mockCreateApi.mockResolvedValue({
|
|
149
|
-
authApi: {} as any,
|
|
150
|
-
rulesApi: mockRulesApi as any,
|
|
151
|
-
} as any);
|
|
152
|
-
|
|
153
|
-
mockAxiosGet.mockResolvedValue({ data: 'rule content' });
|
|
154
|
-
mockFsPathExists.mockResolvedValue(false);
|
|
155
|
-
mockFsEnsureDir.mockResolvedValue(undefined);
|
|
156
|
-
mockFsWriteFile.mockResolvedValue(undefined);
|
|
157
|
-
|
|
158
|
-
await installCommand({ tag: 'test' });
|
|
159
|
-
|
|
160
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({ tag: 'test' });
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// TC-UNIT-CLI-027: Install with type filtering
|
|
164
|
-
it('should filter rules by type', async () => {
|
|
165
|
-
mockGetConfig.mockResolvedValue({
|
|
166
|
-
server: 'http://localhost:3000',
|
|
167
|
-
token: 'test-token',
|
|
168
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
169
|
-
lastLogin: new Date().toISOString(),
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
mockGetInstallPaths.mockReturnValue({
|
|
173
|
-
rules: '/path/to/rules',
|
|
174
|
-
commands: '/path/to/commands',
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const mockRulesApi = {
|
|
178
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
179
|
-
data: [
|
|
180
|
-
{
|
|
181
|
-
id: 'rule-id-1',
|
|
182
|
-
name: 'Test Rule',
|
|
183
|
-
tag: 'test',
|
|
184
|
-
type: 'rule',
|
|
185
|
-
version: '1.0.0',
|
|
186
|
-
author: { username: 'testuser' },
|
|
187
|
-
},
|
|
188
|
-
],
|
|
189
|
-
}),
|
|
190
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
191
|
-
data: { downloadUrl: 'https://signed-url.com/file' },
|
|
192
|
-
}),
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
mockCreateApi.mockResolvedValue({
|
|
196
|
-
authApi: {} as any,
|
|
197
|
-
rulesApi: mockRulesApi as any,
|
|
198
|
-
} as any);
|
|
199
|
-
|
|
200
|
-
mockAxiosGet.mockResolvedValue({ data: 'rule content' });
|
|
201
|
-
mockFsPathExists.mockResolvedValue(false);
|
|
202
|
-
mockFsEnsureDir.mockResolvedValue(undefined);
|
|
203
|
-
mockFsWriteFile.mockResolvedValue(undefined);
|
|
204
|
-
|
|
205
|
-
await installCommand({ type: 'rule' });
|
|
206
|
-
|
|
207
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({ type: 'rule' });
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
// TC-UNIT-CLI-028: Install with file download failure
|
|
211
|
-
it('should handle file download failure', async () => {
|
|
212
|
-
mockGetConfig.mockResolvedValue({
|
|
213
|
-
server: 'http://localhost:3000',
|
|
214
|
-
token: 'test-token',
|
|
215
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
216
|
-
lastLogin: new Date().toISOString(),
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
mockGetInstallPaths.mockReturnValue({
|
|
220
|
-
rules: '/path/to/rules',
|
|
221
|
-
commands: '/path/to/commands',
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const mockRulesApi = {
|
|
225
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
226
|
-
data: [
|
|
227
|
-
{
|
|
228
|
-
id: 'rule-id-1',
|
|
229
|
-
name: 'Test Rule',
|
|
230
|
-
tag: 'test',
|
|
231
|
-
type: 'rule',
|
|
232
|
-
version: '1.0.0',
|
|
233
|
-
author: { username: 'testuser' },
|
|
234
|
-
},
|
|
235
|
-
],
|
|
236
|
-
}),
|
|
237
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
238
|
-
data: { downloadUrl: 'https://signed-url.com/file' },
|
|
239
|
-
}),
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
mockCreateApi.mockResolvedValue({
|
|
243
|
-
authApi: {} as any,
|
|
244
|
-
rulesApi: mockRulesApi as any,
|
|
245
|
-
} as any);
|
|
246
|
-
|
|
247
|
-
// Mock axios download failure
|
|
248
|
-
mockAxiosGet.mockRejectedValue(new Error('Download failed'));
|
|
249
|
-
mockFsPathExists.mockResolvedValue(false);
|
|
250
|
-
|
|
251
|
-
await expect(installCommand({})).rejects.toThrow('Process exit with code 1');
|
|
252
|
-
|
|
253
|
-
expect(mockAxiosGet).toHaveBeenCalledWith('https://signed-url.com/file', {
|
|
254
|
-
responseType: 'text',
|
|
255
|
-
});
|
|
256
|
-
expect(console.error).toHaveBeenCalledWith('❌ Failed to download rule:', 'Download failed');
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
// TC-UNIT-CLI-029: Install with directory permission issues
|
|
260
|
-
it('should handle directory creation permission issues', async () => {
|
|
261
|
-
mockGetConfig.mockResolvedValue({
|
|
262
|
-
server: 'http://localhost:3000',
|
|
263
|
-
token: 'test-token',
|
|
264
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
265
|
-
lastLogin: new Date().toISOString(),
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
mockGetInstallPaths.mockReturnValue({
|
|
269
|
-
rules: '/path/to/rules',
|
|
270
|
-
commands: '/path/to/commands',
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const mockRulesApi = {
|
|
274
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
275
|
-
data: [
|
|
276
|
-
{
|
|
277
|
-
id: 'rule-id-1',
|
|
278
|
-
name: 'Test Rule',
|
|
279
|
-
tag: 'test',
|
|
280
|
-
type: 'rule',
|
|
281
|
-
version: '1.0.0',
|
|
282
|
-
author: { username: 'testuser' },
|
|
283
|
-
},
|
|
284
|
-
],
|
|
285
|
-
}),
|
|
286
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
287
|
-
data: { downloadUrl: 'https://signed-url.com/file' },
|
|
288
|
-
}),
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
mockCreateApi.mockResolvedValue({
|
|
292
|
-
authApi: {} as any,
|
|
293
|
-
rulesApi: mockRulesApi as any,
|
|
294
|
-
} as any);
|
|
295
|
-
|
|
296
|
-
mockAxiosGet.mockResolvedValue({ data: 'rule content' });
|
|
297
|
-
mockFsPathExists.mockResolvedValue(false);
|
|
298
|
-
mockFsEnsureDir.mockRejectedValue(new Error('Permission denied'));
|
|
299
|
-
mockFsWriteFile.mockResolvedValue(undefined);
|
|
300
|
-
|
|
301
|
-
await expect(installCommand({})).rejects.toThrow('Process exit with code 1');
|
|
302
|
-
|
|
303
|
-
expect(mockFsEnsureDir).toHaveBeenCalledWith('/path/to/rules');
|
|
304
|
-
expect(console.error).toHaveBeenCalledWith('❌ Failed to create installation directory:', 'Permission denied');
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// TC-UNIT-CLI-030: Install with force overwrite
|
|
308
|
-
it('should handle force overwrite option', async () => {
|
|
309
|
-
mockGetConfig.mockResolvedValue({
|
|
310
|
-
server: 'http://localhost:3000',
|
|
311
|
-
token: 'test-token',
|
|
312
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
313
|
-
lastLogin: new Date().toISOString(),
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
mockGetInstallPaths.mockReturnValue({
|
|
317
|
-
rules: '/path/to/rules',
|
|
318
|
-
commands: '/path/to/commands',
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
const mockRulesApi = {
|
|
322
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
323
|
-
data: [
|
|
324
|
-
{
|
|
325
|
-
id: 'rule-id-1',
|
|
326
|
-
name: 'Test Rule',
|
|
327
|
-
tag: 'test',
|
|
328
|
-
type: 'rule',
|
|
329
|
-
version: '1.0.0',
|
|
330
|
-
author: { username: 'testuser' },
|
|
331
|
-
},
|
|
332
|
-
],
|
|
333
|
-
}),
|
|
334
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
335
|
-
data: { downloadUrl: 'https://signed-url.com/file' },
|
|
336
|
-
}),
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
mockCreateApi.mockResolvedValue({
|
|
340
|
-
authApi: {} as any,
|
|
341
|
-
rulesApi: mockRulesApi as any,
|
|
342
|
-
} as any);
|
|
343
|
-
|
|
344
|
-
mockAxiosGet.mockResolvedValue({ data: 'rule content' });
|
|
345
|
-
mockFsPathExists.mockResolvedValue(true); // File already exists
|
|
346
|
-
mockFsEnsureDir.mockResolvedValue(undefined);
|
|
347
|
-
mockFsWriteFile.mockResolvedValue(undefined);
|
|
348
|
-
|
|
349
|
-
await installCommand({ force: true });
|
|
350
|
-
|
|
351
|
-
expect(mockFsWriteFile).toHaveBeenCalledWith(path.join('/path/to/rules', 'rule-id-1'), 'rule content');
|
|
352
|
-
expect(console.log).toHaveBeenCalledWith('✅ Successfully installed rule: Test Rule');
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
// TC-UNIT-CLI-031: Install with no rules found
|
|
356
|
-
it('should handle no rules found', async () => {
|
|
357
|
-
mockGetConfig.mockResolvedValue({
|
|
358
|
-
server: 'http://localhost:3000',
|
|
359
|
-
token: 'test-token',
|
|
360
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
361
|
-
lastLogin: new Date().toISOString(),
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
const mockRulesApi = {
|
|
365
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
366
|
-
data: [],
|
|
367
|
-
}),
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
mockCreateApi.mockResolvedValue({
|
|
371
|
-
authApi: {} as any,
|
|
372
|
-
rulesApi: mockRulesApi as any,
|
|
373
|
-
} as any);
|
|
374
|
-
|
|
375
|
-
await installCommand({});
|
|
376
|
-
|
|
377
|
-
expect(console.log).toHaveBeenCalledWith('📭 No rules found matching the criteria.');
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
// TC-UNIT-CLI-032: Install with multiple rules (interactive selection)
|
|
381
|
-
it('should handle multiple rules with interactive selection', async () => {
|
|
382
|
-
const mockInquirer = require('inquirer');
|
|
383
|
-
mockInquirer.prompt = jest.fn().mockResolvedValue({ rule: 'rule-id-2' });
|
|
384
|
-
|
|
385
|
-
mockGetConfig.mockResolvedValue({
|
|
386
|
-
server: 'http://localhost:3000',
|
|
387
|
-
token: 'test-token',
|
|
388
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
389
|
-
lastLogin: new Date().toISOString(),
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
mockGetInstallPaths.mockReturnValue({
|
|
393
|
-
rules: '/path/to/rules',
|
|
394
|
-
commands: '/path/to/commands',
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
const mockRulesApi = {
|
|
398
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
399
|
-
data: [
|
|
400
|
-
{
|
|
401
|
-
id: 'rule-id-1',
|
|
402
|
-
name: 'Test Rule 1',
|
|
403
|
-
tag: 'test',
|
|
404
|
-
type: 'rule',
|
|
405
|
-
version: '1.0.0',
|
|
406
|
-
author: { username: 'testuser' },
|
|
407
|
-
},
|
|
408
|
-
{
|
|
409
|
-
id: 'rule-id-2',
|
|
410
|
-
name: 'Test Rule 2',
|
|
411
|
-
tag: 'test',
|
|
412
|
-
type: 'rule',
|
|
413
|
-
version: '1.0.0',
|
|
414
|
-
author: { username: 'testuser' },
|
|
415
|
-
},
|
|
416
|
-
],
|
|
417
|
-
}),
|
|
418
|
-
rulesControllerGetDownloadUrl: jest.fn().mockResolvedValue({
|
|
419
|
-
data: { downloadUrl: 'https://signed-url.com/file' },
|
|
420
|
-
}),
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
mockCreateApi.mockResolvedValue({
|
|
424
|
-
authApi: {} as any,
|
|
425
|
-
rulesApi: mockRulesApi as any,
|
|
426
|
-
} as any);
|
|
427
|
-
|
|
428
|
-
mockAxiosGet.mockResolvedValue({ data: 'rule content' });
|
|
429
|
-
mockFsPathExists.mockResolvedValue(false);
|
|
430
|
-
mockFsEnsureDir.mockResolvedValue(undefined);
|
|
431
|
-
mockFsWriteFile.mockResolvedValue(undefined);
|
|
432
|
-
|
|
433
|
-
await installCommand({});
|
|
434
|
-
|
|
435
|
-
expect(mockInquirer.prompt).toHaveBeenCalledWith([
|
|
436
|
-
{
|
|
437
|
-
type: 'list',
|
|
438
|
-
name: 'rule',
|
|
439
|
-
message: 'Select a rule to install:',
|
|
440
|
-
choices: [
|
|
441
|
-
{ name: 'Test Rule 1 (rule-id-1)', value: 'rule-id-1' },
|
|
442
|
-
{ name: 'Test Rule 2 (rule-id-2)', value: 'rule-id-2' },
|
|
443
|
-
],
|
|
444
|
-
},
|
|
445
|
-
]);
|
|
446
|
-
expect(mockRulesApi.rulesControllerGetDownloadUrl).toHaveBeenCalledWith('rule-id-2');
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { listCommand } from '../../commands/list';
|
|
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('List 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('list success', () => {
|
|
32
|
-
it('should list all rules when no filters provided', 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: 'Test Rule 1',
|
|
46
|
-
tag: 'test',
|
|
47
|
-
type: 'rule',
|
|
48
|
-
description: 'First test rule',
|
|
49
|
-
version: '1.0.0',
|
|
50
|
-
author: { username: 'user1' },
|
|
51
|
-
createdAt: '2024-01-01T00:00:00.000Z',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
id: 'rule-2',
|
|
55
|
-
name: 'Test Rule 2',
|
|
56
|
-
tag: 'util',
|
|
57
|
-
type: 'command',
|
|
58
|
-
description: 'Second test rule',
|
|
59
|
-
version: '2.0.0',
|
|
60
|
-
author: { username: 'user2' },
|
|
61
|
-
createdAt: '2024-01-02T00:00:00.000Z',
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
}),
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
68
|
-
|
|
69
|
-
await listCommand({});
|
|
70
|
-
|
|
71
|
-
expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
|
|
72
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({});
|
|
73
|
-
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('📋 Found 2 rules/commands:'));
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should apply filters when provided', async () => {
|
|
77
|
-
mockGetConfig.mockResolvedValue({
|
|
78
|
-
server: 'http://localhost:3000',
|
|
79
|
-
token: 'test-token',
|
|
80
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
81
|
-
lastLogin: new Date().toISOString(),
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const mockRulesApi = {
|
|
85
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
86
|
-
data: [
|
|
87
|
-
{
|
|
88
|
-
id: 'rule-1',
|
|
89
|
-
name: 'Filtered Rule',
|
|
90
|
-
tag: 'test',
|
|
91
|
-
type: 'rule',
|
|
92
|
-
description: 'Filtered test rule',
|
|
93
|
-
version: '1.0.0',
|
|
94
|
-
author: { username: 'user1' },
|
|
95
|
-
createdAt: '2024-01-01T00:00:00.000Z',
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
}),
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
102
|
-
|
|
103
|
-
await listCommand({ type: 'rule', tag: 'test', limit: '10' });
|
|
104
|
-
|
|
105
|
-
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({
|
|
106
|
-
type: 'rule',
|
|
107
|
-
tag: 'test',
|
|
108
|
-
limit: 10,
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should handle empty results', async () => {
|
|
113
|
-
mockGetConfig.mockResolvedValue({
|
|
114
|
-
server: 'http://localhost:3000',
|
|
115
|
-
token: 'test-token',
|
|
116
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
117
|
-
lastLogin: new Date().toISOString(),
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const mockRulesApi = {
|
|
121
|
-
rulesControllerFindAll: jest.fn().mockResolvedValue({
|
|
122
|
-
data: [],
|
|
123
|
-
}),
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
127
|
-
|
|
128
|
-
await listCommand({});
|
|
129
|
-
|
|
130
|
-
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('📭 No rules or commands found.'));
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe('list failure', () => {
|
|
135
|
-
it('should exit with error when not logged in', async () => {
|
|
136
|
-
mockGetConfig.mockResolvedValue({
|
|
137
|
-
server: 'http://localhost:3000',
|
|
138
|
-
token: undefined,
|
|
139
|
-
user: undefined,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
await expect(listCommand({})).rejects.toThrow('Process exit with code 1');
|
|
143
|
-
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('❌ Not logged in. Please run `kitstore login` first.'));
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('should handle API errors gracefully', async () => {
|
|
147
|
-
mockGetConfig.mockResolvedValue({
|
|
148
|
-
server: 'http://localhost:3000',
|
|
149
|
-
token: 'test-token',
|
|
150
|
-
user: { id: 'user-id', username: 'testuser' },
|
|
151
|
-
lastLogin: new Date().toISOString(),
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
const mockRulesApi = {
|
|
155
|
-
rulesControllerFindAll: jest.fn().mockRejectedValue(new Error('API Error')),
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
159
|
-
|
|
160
|
-
await expect(listCommand({})).rejects.toThrow('Process exit with code 1');
|
|
161
|
-
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('❌ Failed to list rules:'));
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|