kitstore-cli 1.0.39 → 1.0.41
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/__tests__/commands/install.test.js +15 -8
- package/dist/__tests__/commands/list.test.js +14 -6
- package/dist/__tests__/commands/login.test.js +18 -10
- package/dist/__tests__/commands/search.test.js +15 -7
- package/dist/__tests__/commands/upload.test.js +21 -12
- package/dist/__tests__/config.test.js +70 -12
- package/dist/commands/login.js +35 -6
- package/package.json +1 -1
|
@@ -42,6 +42,13 @@ const apiClient = __importStar(require("../../api/client"));
|
|
|
42
42
|
const axios_1 = __importDefault(require("axios"));
|
|
43
43
|
const fs = __importStar(require("fs-extra"));
|
|
44
44
|
const path = __importStar(require("path"));
|
|
45
|
+
const fs_1 = require("fs");
|
|
46
|
+
// Load default-config server URL for unit tests (use Node.js fs, not fs-extra which is mocked)
|
|
47
|
+
const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
|
|
48
|
+
const defaultConfig = (0, fs_1.existsSync)(defaultConfigPath)
|
|
49
|
+
? JSON.parse((0, fs_1.readFileSync)(defaultConfigPath, 'utf8'))
|
|
50
|
+
: { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
|
|
51
|
+
const DEFAULT_SERVER_URL = defaultConfig.server;
|
|
45
52
|
// Mock dependencies
|
|
46
53
|
jest.mock('../../config', () => ({
|
|
47
54
|
getConfig: jest.fn(),
|
|
@@ -83,7 +90,7 @@ describe('Install Command', () => {
|
|
|
83
90
|
});
|
|
84
91
|
it('should install rule successfully', async () => {
|
|
85
92
|
mockGetConfig.mockResolvedValue({
|
|
86
|
-
server:
|
|
93
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
87
94
|
token: 'test-token',
|
|
88
95
|
user: { id: 'user-id', username: 'testuser' },
|
|
89
96
|
lastLogin: new Date().toISOString(),
|
|
@@ -136,7 +143,7 @@ describe('Install Command', () => {
|
|
|
136
143
|
// TC-UNIT-CLI-026: Install with tag filtering
|
|
137
144
|
it('should filter rules by tag', async () => {
|
|
138
145
|
mockGetConfig.mockResolvedValue({
|
|
139
|
-
server:
|
|
146
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
140
147
|
token: 'test-token',
|
|
141
148
|
user: { id: 'user-id', username: 'testuser' },
|
|
142
149
|
lastLogin: new Date().toISOString(),
|
|
@@ -183,7 +190,7 @@ describe('Install Command', () => {
|
|
|
183
190
|
// TC-UNIT-CLI-027: Install with type filtering
|
|
184
191
|
it('should filter rules by type', async () => {
|
|
185
192
|
mockGetConfig.mockResolvedValue({
|
|
186
|
-
server:
|
|
193
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
187
194
|
token: 'test-token',
|
|
188
195
|
user: { id: 'user-id', username: 'testuser' },
|
|
189
196
|
lastLogin: new Date().toISOString(),
|
|
@@ -229,7 +236,7 @@ describe('Install Command', () => {
|
|
|
229
236
|
// TC-UNIT-CLI-028: Install with file download failure
|
|
230
237
|
it('should handle file download failure', async () => {
|
|
231
238
|
mockGetConfig.mockResolvedValue({
|
|
232
|
-
server:
|
|
239
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
233
240
|
token: 'test-token',
|
|
234
241
|
user: { id: 'user-id', username: 'testuser' },
|
|
235
242
|
lastLogin: new Date().toISOString(),
|
|
@@ -271,7 +278,7 @@ describe('Install Command', () => {
|
|
|
271
278
|
// TC-UNIT-CLI-029: Install with directory permission issues
|
|
272
279
|
it('should handle directory creation permission issues', async () => {
|
|
273
280
|
mockGetConfig.mockResolvedValue({
|
|
274
|
-
server:
|
|
281
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
275
282
|
token: 'test-token',
|
|
276
283
|
user: { id: 'user-id', username: 'testuser' },
|
|
277
284
|
lastLogin: new Date().toISOString(),
|
|
@@ -312,7 +319,7 @@ describe('Install Command', () => {
|
|
|
312
319
|
// TC-UNIT-CLI-030: Install with force overwrite
|
|
313
320
|
it('should handle force overwrite option', async () => {
|
|
314
321
|
mockGetConfig.mockResolvedValue({
|
|
315
|
-
server:
|
|
322
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
316
323
|
token: 'test-token',
|
|
317
324
|
user: { id: 'user-id', username: 'testuser' },
|
|
318
325
|
lastLogin: new Date().toISOString(),
|
|
@@ -353,7 +360,7 @@ describe('Install Command', () => {
|
|
|
353
360
|
// TC-UNIT-CLI-031: Install with no rules found
|
|
354
361
|
it('should handle no rules found', async () => {
|
|
355
362
|
mockGetConfig.mockResolvedValue({
|
|
356
|
-
server:
|
|
363
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
357
364
|
token: 'test-token',
|
|
358
365
|
user: { id: 'user-id', username: 'testuser' },
|
|
359
366
|
lastLogin: new Date().toISOString(),
|
|
@@ -375,7 +382,7 @@ describe('Install Command', () => {
|
|
|
375
382
|
const mockInquirer = require('inquirer');
|
|
376
383
|
mockInquirer.prompt = jest.fn().mockResolvedValue({ rule: 'rule-id-2' });
|
|
377
384
|
mockGetConfig.mockResolvedValue({
|
|
378
|
-
server:
|
|
385
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
379
386
|
token: 'test-token',
|
|
380
387
|
user: { id: 'user-id', username: 'testuser' },
|
|
381
388
|
lastLogin: new Date().toISOString(),
|
|
@@ -35,6 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const list_1 = require("../../commands/list");
|
|
37
37
|
const config = __importStar(require("../../config"));
|
|
38
|
+
const fs = __importStar(require("fs-extra"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
// Load default-config server URL for unit tests
|
|
41
|
+
const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
|
|
42
|
+
const defaultConfig = fs.existsSync(defaultConfigPath)
|
|
43
|
+
? JSON.parse(fs.readFileSync(defaultConfigPath, 'utf8'))
|
|
44
|
+
: { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
|
|
45
|
+
const DEFAULT_SERVER_URL = defaultConfig.server;
|
|
38
46
|
// Mock dependencies
|
|
39
47
|
jest.mock('../../config', () => ({
|
|
40
48
|
getConfig: jest.fn(),
|
|
@@ -60,7 +68,7 @@ describe('List Command', () => {
|
|
|
60
68
|
describe('list success', () => {
|
|
61
69
|
it('should list all rules when no filters provided', async () => {
|
|
62
70
|
mockGetConfig.mockResolvedValue({
|
|
63
|
-
server:
|
|
71
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
64
72
|
token: 'test-token',
|
|
65
73
|
user: { id: 'user-id', username: 'testuser' },
|
|
66
74
|
lastLogin: new Date().toISOString(),
|
|
@@ -93,7 +101,7 @@ describe('List Command', () => {
|
|
|
93
101
|
};
|
|
94
102
|
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
95
103
|
await (0, list_1.listCommand)({});
|
|
96
|
-
expect(mockCreateApi).toHaveBeenCalledWith({ server:
|
|
104
|
+
expect(mockCreateApi).toHaveBeenCalledWith({ server: DEFAULT_SERVER_URL });
|
|
97
105
|
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith(undefined, // page
|
|
98
106
|
undefined, // limit
|
|
99
107
|
undefined, // tag
|
|
@@ -105,7 +113,7 @@ describe('List Command', () => {
|
|
|
105
113
|
});
|
|
106
114
|
it('should apply filters when provided', async () => {
|
|
107
115
|
mockGetConfig.mockResolvedValue({
|
|
108
|
-
server:
|
|
116
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
109
117
|
token: 'test-token',
|
|
110
118
|
user: { id: 'user-id', username: 'testuser' },
|
|
111
119
|
lastLogin: new Date().toISOString(),
|
|
@@ -138,7 +146,7 @@ describe('List Command', () => {
|
|
|
138
146
|
});
|
|
139
147
|
it('should handle empty results', async () => {
|
|
140
148
|
mockGetConfig.mockResolvedValue({
|
|
141
|
-
server:
|
|
149
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
142
150
|
token: 'test-token',
|
|
143
151
|
user: { id: 'user-id', username: 'testuser' },
|
|
144
152
|
lastLogin: new Date().toISOString(),
|
|
@@ -156,7 +164,7 @@ describe('List Command', () => {
|
|
|
156
164
|
describe('list failure', () => {
|
|
157
165
|
it('should exit with error when not logged in', async () => {
|
|
158
166
|
mockGetConfig.mockResolvedValue({
|
|
159
|
-
server:
|
|
167
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
160
168
|
token: undefined,
|
|
161
169
|
user: undefined,
|
|
162
170
|
});
|
|
@@ -165,7 +173,7 @@ describe('List Command', () => {
|
|
|
165
173
|
});
|
|
166
174
|
it('should handle API errors gracefully', async () => {
|
|
167
175
|
mockGetConfig.mockResolvedValue({
|
|
168
|
-
server:
|
|
176
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
169
177
|
token: 'test-token',
|
|
170
178
|
user: { id: 'user-id', username: 'testuser' },
|
|
171
179
|
lastLogin: new Date().toISOString(),
|
|
@@ -40,6 +40,14 @@ const login_1 = require("../../commands/login");
|
|
|
40
40
|
const config = __importStar(require("../../config"));
|
|
41
41
|
const apiClient = __importStar(require("../../api/client"));
|
|
42
42
|
const axios_1 = __importDefault(require("axios"));
|
|
43
|
+
const fs = __importStar(require("fs-extra"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
// Load default-config server URL for unit tests
|
|
46
|
+
const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
|
|
47
|
+
const defaultConfig = fs.existsSync(defaultConfigPath)
|
|
48
|
+
? JSON.parse(fs.readFileSync(defaultConfigPath, 'utf8'))
|
|
49
|
+
: { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
|
|
50
|
+
const DEFAULT_SERVER_URL = defaultConfig.server;
|
|
43
51
|
// Mock dependencies
|
|
44
52
|
jest.mock('../../config', () => ({
|
|
45
53
|
getConfig: jest.fn(),
|
|
@@ -86,7 +94,7 @@ describe('Login Command', () => {
|
|
|
86
94
|
}),
|
|
87
95
|
};
|
|
88
96
|
mockGetConfig.mockResolvedValue({
|
|
89
|
-
server:
|
|
97
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
90
98
|
token: undefined,
|
|
91
99
|
user: undefined,
|
|
92
100
|
lastLogin: undefined,
|
|
@@ -99,14 +107,14 @@ describe('Login Command', () => {
|
|
|
99
107
|
email: 'test@example.com',
|
|
100
108
|
password: 'Password123!',
|
|
101
109
|
});
|
|
102
|
-
expect(mockCreateApi).toHaveBeenCalledWith({ server:
|
|
110
|
+
expect(mockCreateApi).toHaveBeenCalledWith({ server: DEFAULT_SERVER_URL });
|
|
103
111
|
expect(mockAuthApi.authControllerLogin).toHaveBeenCalledWith({
|
|
104
112
|
email: 'test@example.com',
|
|
105
113
|
password: 'Password123!',
|
|
106
114
|
});
|
|
107
115
|
expect(mockSaveConfig).toHaveBeenCalledWith({
|
|
108
116
|
token: 'test-token-123',
|
|
109
|
-
server:
|
|
117
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
110
118
|
user: {
|
|
111
119
|
id: 'user-id',
|
|
112
120
|
username: 'testuser',
|
|
@@ -137,7 +145,7 @@ describe('Login Command', () => {
|
|
|
137
145
|
authControllerLogin: jest.fn().mockRejectedValue(axiosError),
|
|
138
146
|
};
|
|
139
147
|
mockGetConfig.mockResolvedValue({
|
|
140
|
-
server:
|
|
148
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
141
149
|
token: undefined,
|
|
142
150
|
user: undefined,
|
|
143
151
|
lastLogin: undefined,
|
|
@@ -151,7 +159,7 @@ describe('Login Command', () => {
|
|
|
151
159
|
password: 'WrongPassword',
|
|
152
160
|
})).rejects.toThrow();
|
|
153
161
|
expect(mockSaveConfig).not.toHaveBeenCalled();
|
|
154
|
-
expect(console.error).toHaveBeenCalledWith('❌ Login failed: Invalid
|
|
162
|
+
expect(console.error).toHaveBeenCalledWith('❌ Login failed: Invalid email or password');
|
|
155
163
|
});
|
|
156
164
|
// TC-UNIT-CLI-003: Interactive login prompts
|
|
157
165
|
it('should prompt for email and password when not provided', async () => {
|
|
@@ -171,7 +179,7 @@ describe('Login Command', () => {
|
|
|
171
179
|
}),
|
|
172
180
|
};
|
|
173
181
|
mockGetConfig.mockResolvedValue({
|
|
174
|
-
server:
|
|
182
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
175
183
|
token: undefined,
|
|
176
184
|
user: undefined,
|
|
177
185
|
lastLogin: undefined,
|
|
@@ -199,7 +207,7 @@ describe('Login Command', () => {
|
|
|
199
207
|
.mockResolvedValueOnce({ email: '' })
|
|
200
208
|
.mockResolvedValueOnce({ password: '' });
|
|
201
209
|
mockGetConfig.mockResolvedValue({
|
|
202
|
-
server:
|
|
210
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
203
211
|
token: undefined,
|
|
204
212
|
user: undefined,
|
|
205
213
|
lastLogin: undefined,
|
|
@@ -221,7 +229,7 @@ describe('Login Command', () => {
|
|
|
221
229
|
}),
|
|
222
230
|
};
|
|
223
231
|
mockGetConfig.mockResolvedValue({
|
|
224
|
-
server:
|
|
232
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
225
233
|
token: undefined,
|
|
226
234
|
user: undefined,
|
|
227
235
|
lastLogin: undefined,
|
|
@@ -254,7 +262,7 @@ describe('Login Command', () => {
|
|
|
254
262
|
authControllerLogin: jest.fn().mockRejectedValue(axiosError),
|
|
255
263
|
};
|
|
256
264
|
mockGetConfig.mockResolvedValue({
|
|
257
|
-
server:
|
|
265
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
258
266
|
token: undefined,
|
|
259
267
|
user: undefined,
|
|
260
268
|
lastLogin: undefined,
|
|
@@ -275,7 +283,7 @@ describe('Login Command', () => {
|
|
|
275
283
|
authControllerLogin: jest.fn().mockRejectedValue(new Error('Network error')),
|
|
276
284
|
};
|
|
277
285
|
mockGetConfig.mockResolvedValue({
|
|
278
|
-
server:
|
|
286
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
279
287
|
token: undefined,
|
|
280
288
|
user: undefined,
|
|
281
289
|
lastLogin: undefined,
|
|
@@ -35,6 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const search_1 = require("../../commands/search");
|
|
37
37
|
const config = __importStar(require("../../config"));
|
|
38
|
+
const fs = __importStar(require("fs-extra"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
// Load default-config server URL for unit tests
|
|
41
|
+
const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
|
|
42
|
+
const defaultConfig = fs.existsSync(defaultConfigPath)
|
|
43
|
+
? JSON.parse(fs.readFileSync(defaultConfigPath, 'utf8'))
|
|
44
|
+
: { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
|
|
45
|
+
const DEFAULT_SERVER_URL = defaultConfig.server;
|
|
38
46
|
// Mock dependencies
|
|
39
47
|
jest.mock('../../config', () => ({
|
|
40
48
|
getConfig: jest.fn(),
|
|
@@ -60,7 +68,7 @@ describe('Search Command', () => {
|
|
|
60
68
|
describe('search success', () => {
|
|
61
69
|
it('should search rules by query', async () => {
|
|
62
70
|
mockGetConfig.mockResolvedValue({
|
|
63
|
-
server:
|
|
71
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
64
72
|
token: 'test-token',
|
|
65
73
|
user: { id: 'user-id', username: 'testuser' },
|
|
66
74
|
lastLogin: new Date().toISOString(),
|
|
@@ -83,7 +91,7 @@ describe('Search Command', () => {
|
|
|
83
91
|
};
|
|
84
92
|
mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
|
|
85
93
|
await (0, search_1.searchCommand)('auth', {});
|
|
86
|
-
expect(mockCreateApi).toHaveBeenCalledWith({ server:
|
|
94
|
+
expect(mockCreateApi).toHaveBeenCalledWith({ server: DEFAULT_SERVER_URL });
|
|
87
95
|
expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith(undefined, // page
|
|
88
96
|
undefined, // limit
|
|
89
97
|
undefined, // tag
|
|
@@ -95,7 +103,7 @@ describe('Search Command', () => {
|
|
|
95
103
|
});
|
|
96
104
|
it('should apply additional filters with search query', async () => {
|
|
97
105
|
mockGetConfig.mockResolvedValue({
|
|
98
|
-
server:
|
|
106
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
99
107
|
token: 'test-token',
|
|
100
108
|
user: { id: 'user-id', username: 'testuser' },
|
|
101
109
|
lastLogin: new Date().toISOString(),
|
|
@@ -128,7 +136,7 @@ describe('Search Command', () => {
|
|
|
128
136
|
});
|
|
129
137
|
it('should handle no search results', async () => {
|
|
130
138
|
mockGetConfig.mockResolvedValue({
|
|
131
|
-
server:
|
|
139
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
132
140
|
token: 'test-token',
|
|
133
141
|
user: { id: 'user-id', username: 'testuser' },
|
|
134
142
|
lastLogin: new Date().toISOString(),
|
|
@@ -146,7 +154,7 @@ describe('Search Command', () => {
|
|
|
146
154
|
describe('search failure', () => {
|
|
147
155
|
it('should exit with error when not logged in', async () => {
|
|
148
156
|
mockGetConfig.mockResolvedValue({
|
|
149
|
-
server:
|
|
157
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
150
158
|
token: undefined,
|
|
151
159
|
user: undefined,
|
|
152
160
|
});
|
|
@@ -155,7 +163,7 @@ describe('Search Command', () => {
|
|
|
155
163
|
});
|
|
156
164
|
it('should validate query parameter', async () => {
|
|
157
165
|
mockGetConfig.mockResolvedValue({
|
|
158
|
-
server:
|
|
166
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
159
167
|
token: 'test-token',
|
|
160
168
|
user: { id: 'user-id', username: 'testuser' },
|
|
161
169
|
lastLogin: new Date().toISOString(),
|
|
@@ -165,7 +173,7 @@ describe('Search Command', () => {
|
|
|
165
173
|
});
|
|
166
174
|
it('should handle API errors gracefully', async () => {
|
|
167
175
|
mockGetConfig.mockResolvedValue({
|
|
168
|
-
server:
|
|
176
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
169
177
|
token: 'test-token',
|
|
170
178
|
user: { id: 'user-id', username: 'testuser' },
|
|
171
179
|
lastLogin: new Date().toISOString(),
|
|
@@ -41,6 +41,14 @@ const config = __importStar(require("../../config"));
|
|
|
41
41
|
const axios_1 = __importDefault(require("axios"));
|
|
42
42
|
const fs = __importStar(require("fs-extra"));
|
|
43
43
|
const form_data_1 = __importDefault(require("form-data"));
|
|
44
|
+
const fs_1 = require("fs");
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
// Load default-config server URL for unit tests (use Node.js fs, not fs-extra which is mocked)
|
|
47
|
+
const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
|
|
48
|
+
const defaultConfig = (0, fs_1.existsSync)(defaultConfigPath)
|
|
49
|
+
? JSON.parse((0, fs_1.readFileSync)(defaultConfigPath, 'utf8'))
|
|
50
|
+
: { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
|
|
51
|
+
const DEFAULT_SERVER_URL = defaultConfig.server;
|
|
44
52
|
// Mock dependencies
|
|
45
53
|
jest.mock('../../config', () => ({
|
|
46
54
|
getConfig: jest.fn(),
|
|
@@ -89,7 +97,7 @@ describe('Upload Command', () => {
|
|
|
89
97
|
describe('upload success', () => {
|
|
90
98
|
it('should upload file successfully', async () => {
|
|
91
99
|
mockGetConfig.mockResolvedValue({
|
|
92
|
-
server:
|
|
100
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
93
101
|
token: 'test-token',
|
|
94
102
|
user: { id: 'user-id', username: 'testuser' },
|
|
95
103
|
lastLogin: new Date().toISOString(),
|
|
@@ -118,7 +126,8 @@ describe('Upload Command', () => {
|
|
|
118
126
|
description: 'Test description',
|
|
119
127
|
});
|
|
120
128
|
expect(mockFsPathExists).toHaveBeenCalledWith('./test.md');
|
|
121
|
-
expect(mockAxiosPost).toHaveBeenCalledWith(
|
|
129
|
+
expect(mockAxiosPost).toHaveBeenCalledWith(`${DEFAULT_SERVER_URL}/api/rules`, // Use default-config server URL
|
|
130
|
+
expect.any(Object), expect.objectContaining({
|
|
122
131
|
headers: expect.objectContaining({
|
|
123
132
|
Authorization: 'Bearer test-token',
|
|
124
133
|
}),
|
|
@@ -129,7 +138,7 @@ describe('Upload Command', () => {
|
|
|
129
138
|
describe('upload failure', () => {
|
|
130
139
|
it('should handle file not found error', async () => {
|
|
131
140
|
mockGetConfig.mockResolvedValue({
|
|
132
|
-
server:
|
|
141
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
133
142
|
token: 'test-token',
|
|
134
143
|
user: { id: 'user-id', username: 'testuser' },
|
|
135
144
|
lastLogin: new Date().toISOString(),
|
|
@@ -145,7 +154,7 @@ describe('Upload Command', () => {
|
|
|
145
154
|
// TC-UNIT-CLI-033: Upload with file size validation
|
|
146
155
|
it('should validate file size limits', async () => {
|
|
147
156
|
mockGetConfig.mockResolvedValue({
|
|
148
|
-
server:
|
|
157
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
149
158
|
token: 'test-token',
|
|
150
159
|
user: { id: 'user-id', username: 'testuser' },
|
|
151
160
|
lastLogin: new Date().toISOString(),
|
|
@@ -164,7 +173,7 @@ describe('Upload Command', () => {
|
|
|
164
173
|
// TC-UNIT-CLI-034: Upload with file type validation
|
|
165
174
|
it('should validate file type', async () => {
|
|
166
175
|
mockGetConfig.mockResolvedValue({
|
|
167
|
-
server:
|
|
176
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
168
177
|
token: 'test-token',
|
|
169
178
|
user: { id: 'user-id', username: 'testuser' },
|
|
170
179
|
lastLogin: new Date().toISOString(),
|
|
@@ -182,7 +191,7 @@ describe('Upload Command', () => {
|
|
|
182
191
|
// TC-UNIT-CLI-035: Upload with API failure
|
|
183
192
|
it.skip('should handle API upload failure', async () => {
|
|
184
193
|
mockGetConfig.mockResolvedValue({
|
|
185
|
-
server:
|
|
194
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
186
195
|
token: 'test-token',
|
|
187
196
|
user: { id: 'user-id', username: 'testuser' },
|
|
188
197
|
lastLogin: new Date().toISOString(),
|
|
@@ -206,7 +215,7 @@ describe('Upload Command', () => {
|
|
|
206
215
|
// TC-UNIT-CLI-036: Upload with authentication error
|
|
207
216
|
it.skip('should handle authentication errors', async () => {
|
|
208
217
|
mockGetConfig.mockResolvedValue({
|
|
209
|
-
server:
|
|
218
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
210
219
|
token: 'invalid-token',
|
|
211
220
|
user: { id: 'user-id', username: 'testuser' },
|
|
212
221
|
lastLogin: new Date().toISOString(),
|
|
@@ -230,7 +239,7 @@ describe('Upload Command', () => {
|
|
|
230
239
|
// TC-UNIT-CLI-037: Upload with network error
|
|
231
240
|
it.skip('should handle network errors', async () => {
|
|
232
241
|
mockGetConfig.mockResolvedValue({
|
|
233
|
-
server:
|
|
242
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
234
243
|
token: 'test-token',
|
|
235
244
|
user: { id: 'user-id', username: 'testuser' },
|
|
236
245
|
lastLogin: new Date().toISOString(),
|
|
@@ -249,7 +258,7 @@ describe('Upload Command', () => {
|
|
|
249
258
|
// TC-UNIT-CLI-038: Upload with metadata extraction
|
|
250
259
|
it.skip('should extract and send metadata correctly', async () => {
|
|
251
260
|
mockGetConfig.mockResolvedValue({
|
|
252
|
-
server:
|
|
261
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
253
262
|
token: 'test-token',
|
|
254
263
|
user: { id: 'user-id', username: 'testuser' },
|
|
255
264
|
lastLogin: new Date().toISOString(),
|
|
@@ -289,7 +298,7 @@ describe('Upload Command', () => {
|
|
|
289
298
|
// TC-UNIT-CLI-039: Upload with default version
|
|
290
299
|
it.skip('should use default version when not specified', async () => {
|
|
291
300
|
mockGetConfig.mockResolvedValue({
|
|
292
|
-
server:
|
|
301
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
293
302
|
token: 'test-token',
|
|
294
303
|
user: { id: 'user-id', username: 'testuser' },
|
|
295
304
|
lastLogin: new Date().toISOString(),
|
|
@@ -315,7 +324,7 @@ describe('Upload Command', () => {
|
|
|
315
324
|
// TC-UNIT-CLI-040: Upload with missing required parameters
|
|
316
325
|
it.skip('should validate required parameters', async () => {
|
|
317
326
|
mockGetConfig.mockResolvedValue({
|
|
318
|
-
server:
|
|
327
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
319
328
|
token: 'test-token',
|
|
320
329
|
user: { id: 'user-id', username: 'testuser' },
|
|
321
330
|
lastLogin: new Date().toISOString(),
|
|
@@ -333,7 +342,7 @@ describe('Upload Command', () => {
|
|
|
333
342
|
// TC-UNIT-CLI-041: Upload command success with all parameters
|
|
334
343
|
it.skip('should handle successful upload with all parameters', async () => {
|
|
335
344
|
mockGetConfig.mockResolvedValue({
|
|
336
|
-
server:
|
|
345
|
+
server: DEFAULT_SERVER_URL, // Use default-config server URL
|
|
337
346
|
token: 'test-token',
|
|
338
347
|
user: { id: 'user-id', username: 'testuser' },
|
|
339
348
|
lastLogin: new Date().toISOString(),
|
|
@@ -35,6 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const globals_1 = require("@jest/globals");
|
|
37
37
|
const config_1 = require("../config");
|
|
38
|
+
const fs_1 = require("fs");
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
// Load default-config server URL for unit tests (use Node.js fs, not fs-extra which is mocked)
|
|
41
|
+
const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
|
|
42
|
+
const defaultConfig = (0, fs_1.existsSync)(defaultConfigPath)
|
|
43
|
+
? JSON.parse((0, fs_1.readFileSync)(defaultConfigPath, 'utf8'))
|
|
44
|
+
: { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
|
|
45
|
+
const DEFAULT_SERVER_URL = defaultConfig.server;
|
|
38
46
|
// Mock dependencies
|
|
39
47
|
globals_1.jest.mock('fs-extra');
|
|
40
48
|
globals_1.jest.mock('os', () => ({
|
|
@@ -42,7 +50,6 @@ globals_1.jest.mock('os', () => ({
|
|
|
42
50
|
}));
|
|
43
51
|
const fs = __importStar(require("fs-extra"));
|
|
44
52
|
const os = __importStar(require("os"));
|
|
45
|
-
const path = __importStar(require("path"));
|
|
46
53
|
describe('Config', () => {
|
|
47
54
|
const mockHomeDir = 'C:\\Users\\trieu';
|
|
48
55
|
const mockConfigDir = path.join(mockHomeDir, '.kitstore');
|
|
@@ -64,10 +71,23 @@ describe('Config', () => {
|
|
|
64
71
|
describe('getConfig', () => {
|
|
65
72
|
it('should return default config when config file does not exist', async () => {
|
|
66
73
|
// @ts-ignore
|
|
67
|
-
fs.pathExists.
|
|
74
|
+
fs.pathExists.mockImplementation((filePath) => {
|
|
75
|
+
// Return true for default-config.json path, false for config.json
|
|
76
|
+
if (filePath.includes('default-config.json')) {
|
|
77
|
+
return Promise.resolve(true);
|
|
78
|
+
}
|
|
79
|
+
return Promise.resolve(false);
|
|
80
|
+
});
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
fs.readJson.mockImplementation((filePath) => {
|
|
83
|
+
if (filePath.includes('default-config.json')) {
|
|
84
|
+
return Promise.resolve({ server: DEFAULT_SERVER_URL });
|
|
85
|
+
}
|
|
86
|
+
return Promise.reject(new Error('File not found'));
|
|
87
|
+
});
|
|
68
88
|
const result = await (0, config_1.getConfig)();
|
|
69
89
|
expect(result).toEqual({
|
|
70
|
-
server:
|
|
90
|
+
server: DEFAULT_SERVER_URL // Use default-config server URL
|
|
71
91
|
});
|
|
72
92
|
expect(fs.ensureDir).toHaveBeenCalledWith(mockConfigDir);
|
|
73
93
|
expect(fs.pathExists).toHaveBeenCalledWith(mockConfigFile);
|
|
@@ -79,9 +99,20 @@ describe('Config', () => {
|
|
|
79
99
|
user: { id: '123', username: 'testuser' }
|
|
80
100
|
};
|
|
81
101
|
// @ts-ignore
|
|
82
|
-
fs.pathExists.
|
|
102
|
+
fs.pathExists.mockImplementation((filePath) => {
|
|
103
|
+
// Return true for config.json, false for default-config.json (file config takes precedence)
|
|
104
|
+
if (filePath === mockConfigFile) {
|
|
105
|
+
return Promise.resolve(true);
|
|
106
|
+
}
|
|
107
|
+
return Promise.resolve(false);
|
|
108
|
+
});
|
|
83
109
|
// @ts-ignore
|
|
84
|
-
fs.readJson.
|
|
110
|
+
fs.readJson.mockImplementation((filePath) => {
|
|
111
|
+
if (filePath === mockConfigFile) {
|
|
112
|
+
return Promise.resolve(fileConfig);
|
|
113
|
+
}
|
|
114
|
+
return Promise.reject(new Error('File not found'));
|
|
115
|
+
});
|
|
85
116
|
const result = await (0, config_1.getConfig)();
|
|
86
117
|
expect(result).toEqual({
|
|
87
118
|
server: 'https://api.example.com', // From file
|
|
@@ -92,20 +123,47 @@ describe('Config', () => {
|
|
|
92
123
|
});
|
|
93
124
|
it('should handle file read errors gracefully', async () => {
|
|
94
125
|
// @ts-ignore
|
|
95
|
-
fs.pathExists.
|
|
126
|
+
fs.pathExists.mockImplementation((filePath) => {
|
|
127
|
+
// Return true for default-config.json path, true for config.json (exists but read fails)
|
|
128
|
+
if (filePath.includes('default-config.json')) {
|
|
129
|
+
return Promise.resolve(true);
|
|
130
|
+
}
|
|
131
|
+
return Promise.resolve(true); // config.json exists
|
|
132
|
+
});
|
|
96
133
|
// @ts-ignore
|
|
97
|
-
fs.readJson.
|
|
134
|
+
fs.readJson.mockImplementation((filePath) => {
|
|
135
|
+
if (filePath.includes('default-config.json')) {
|
|
136
|
+
return Promise.resolve({ server: DEFAULT_SERVER_URL });
|
|
137
|
+
}
|
|
138
|
+
// config.json read fails
|
|
139
|
+
return Promise.reject(new Error('Read failed'));
|
|
140
|
+
});
|
|
98
141
|
const result = await (0, config_1.getConfig)();
|
|
99
142
|
expect(result).toEqual({
|
|
100
|
-
server:
|
|
143
|
+
server: DEFAULT_SERVER_URL // Use default-config server URL
|
|
101
144
|
});
|
|
102
145
|
});
|
|
103
146
|
it('should handle ensureDir errors gracefully', async () => {
|
|
104
147
|
// @ts-ignore
|
|
105
148
|
fs.ensureDir.mockRejectedValue(new Error('Permission denied'));
|
|
149
|
+
// @ts-ignore
|
|
150
|
+
fs.pathExists.mockImplementation((filePath) => {
|
|
151
|
+
// Return true for default-config.json path
|
|
152
|
+
if (filePath.includes('default-config.json')) {
|
|
153
|
+
return Promise.resolve(true);
|
|
154
|
+
}
|
|
155
|
+
return Promise.resolve(false);
|
|
156
|
+
});
|
|
157
|
+
// @ts-ignore
|
|
158
|
+
fs.readJson.mockImplementation((filePath) => {
|
|
159
|
+
if (filePath.includes('default-config.json')) {
|
|
160
|
+
return Promise.resolve({ server: DEFAULT_SERVER_URL });
|
|
161
|
+
}
|
|
162
|
+
return Promise.reject(new Error('File not found'));
|
|
163
|
+
});
|
|
106
164
|
const result = await (0, config_1.getConfig)();
|
|
107
165
|
expect(result).toEqual({
|
|
108
|
-
server:
|
|
166
|
+
server: DEFAULT_SERVER_URL // Use default-config server URL
|
|
109
167
|
});
|
|
110
168
|
});
|
|
111
169
|
});
|
|
@@ -121,7 +179,7 @@ describe('Config', () => {
|
|
|
121
179
|
expect(fs.writeJson).toHaveBeenCalledWith(mockConfigFile, config, { spaces: 2 });
|
|
122
180
|
});
|
|
123
181
|
it('should handle write errors', async () => {
|
|
124
|
-
const config = { server:
|
|
182
|
+
const config = { server: DEFAULT_SERVER_URL }; // Use default-config server URL
|
|
125
183
|
// @ts-ignore
|
|
126
184
|
fs.writeJson.mockRejectedValue(new Error('Write failed'));
|
|
127
185
|
await expect((0, config_1.saveConfig)(config)).rejects.toThrow('Write failed');
|
|
@@ -168,9 +226,9 @@ describe('Config', () => {
|
|
|
168
226
|
});
|
|
169
227
|
it('should allow optional properties', () => {
|
|
170
228
|
const minimalConfig = {
|
|
171
|
-
server:
|
|
229
|
+
server: DEFAULT_SERVER_URL // Use default-config server URL
|
|
172
230
|
};
|
|
173
|
-
expect(minimalConfig.server).toBe(
|
|
231
|
+
expect(minimalConfig.server).toBe(DEFAULT_SERVER_URL); // Use default-config server URL
|
|
174
232
|
expect(minimalConfig.token).toBeUndefined();
|
|
175
233
|
expect(minimalConfig.user).toBeUndefined();
|
|
176
234
|
expect(minimalConfig.lastLogin).toBeUndefined();
|
package/dist/commands/login.js
CHANGED
|
@@ -12,9 +12,9 @@ const client_1 = require("../api/client");
|
|
|
12
12
|
* @requirement TC-UNIT-CLI-001, TC-UNIT-CLI-002, TC-E2E-CLI-001
|
|
13
13
|
*/
|
|
14
14
|
async function loginCommand(options) {
|
|
15
|
+
const config = await (0, config_1.getConfig)();
|
|
16
|
+
const server = options.server || config.server;
|
|
15
17
|
try {
|
|
16
|
-
const config = await (0, config_1.getConfig)();
|
|
17
|
-
const server = options.server || config.server;
|
|
18
18
|
let email = options.email;
|
|
19
19
|
let password = options.password;
|
|
20
20
|
if (!email) {
|
|
@@ -52,15 +52,44 @@ async function loginCommand(options) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
catch (err) {
|
|
55
|
+
let errorMessage = 'Unknown error';
|
|
55
56
|
if (axios_1.default.isAxiosError(err)) {
|
|
56
|
-
|
|
57
|
+
// Handle Axios errors (network, HTTP errors)
|
|
58
|
+
const status = err.response?.status;
|
|
59
|
+
const message = err.response?.data?.message?.message ||
|
|
60
|
+
err.response?.data?.message ||
|
|
61
|
+
err.message;
|
|
62
|
+
if (status === 401) {
|
|
63
|
+
errorMessage = 'Invalid email or password';
|
|
64
|
+
}
|
|
65
|
+
else if (status === 429) {
|
|
66
|
+
errorMessage = 'Rate limit exceeded. Please try again later';
|
|
67
|
+
}
|
|
68
|
+
else if (err.code === 'ECONNREFUSED') {
|
|
69
|
+
errorMessage = `Cannot connect to server at ${err.config?.url || server}. Is the server running?`;
|
|
70
|
+
}
|
|
71
|
+
else if (err.code === 'ENOTFOUND') {
|
|
72
|
+
errorMessage = `Server not found: ${err.config?.url || server}. Check your server URL.`;
|
|
73
|
+
}
|
|
74
|
+
else if (err.code === 'ETIMEDOUT' || err.code === 'ECONNABORTED') {
|
|
75
|
+
errorMessage = `Connection timeout. Server at ${err.config?.url || server} did not respond in time.`;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
errorMessage = message || `HTTP ${status || 'error'}`;
|
|
79
|
+
}
|
|
57
80
|
}
|
|
58
81
|
else if (err instanceof Error) {
|
|
59
|
-
|
|
82
|
+
errorMessage = err.message;
|
|
60
83
|
}
|
|
61
|
-
else {
|
|
62
|
-
|
|
84
|
+
else if (typeof err === 'string') {
|
|
85
|
+
errorMessage = err;
|
|
86
|
+
}
|
|
87
|
+
else if (err && typeof err === 'object') {
|
|
88
|
+
// Try to extract meaningful information from object
|
|
89
|
+
const errObj = err;
|
|
90
|
+
errorMessage = errObj.message || errObj.error || errObj.toString() || 'Unknown error occurred';
|
|
63
91
|
}
|
|
92
|
+
console.error(`❌ Login failed: ${errorMessage}`);
|
|
64
93
|
process.exit(1);
|
|
65
94
|
}
|
|
66
95
|
}
|