bbk-cli 1.1.2 → 1.2.0
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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/README.md +113 -132
- package/dist/cli/wrapper.d.ts +0 -1
- package/dist/cli/wrapper.d.ts.map +1 -1
- package/dist/cli/wrapper.js +19 -54
- package/dist/cli/wrapper.js.map +1 -1
- package/dist/commands/helpers.js +1 -1
- package/dist/commands/runner.d.ts.map +1 -1
- package/dist/commands/runner.js +22 -18
- package/dist/commands/runner.js.map +1 -1
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +37 -52
- package/dist/config/constants.js.map +1 -1
- package/dist/utils/arg-parser.d.ts.map +1 -1
- package/dist/utils/arg-parser.js +23 -8
- package/dist/utils/arg-parser.js.map +1 -1
- package/dist/utils/bitbucket-client.d.ts +24 -37
- package/dist/utils/bitbucket-client.d.ts.map +1 -1
- package/dist/utils/bitbucket-client.js +38 -52
- package/dist/utils/bitbucket-client.js.map +1 -1
- package/dist/utils/bitbucket-utils.d.ts +48 -68
- package/dist/utils/bitbucket-utils.d.ts.map +1 -1
- package/dist/utils/bitbucket-utils.js +100 -125
- package/dist/utils/bitbucket-utils.js.map +1 -1
- package/dist/utils/config-loader.d.ts +10 -29
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +277 -51
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -3
- package/tests/integration/cli-integration.test.ts +96 -217
- package/tests/unit/cli/wrapper.test.ts +28 -137
- package/tests/unit/commands/runner.test.ts +69 -197
- package/tests/unit/utils/arg-parser.test.ts +53 -4
- package/tests/unit/utils/config-loader.test.ts +441 -106
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
|
|
6
|
-
// Mock the Bitbucket API functions
|
|
6
|
+
// Mock the Bitbucket API functions - must be at top level but without external references
|
|
7
7
|
vi.mock('../../src/utils/bitbucket-client.js', () => ({
|
|
8
8
|
listRepositories: vi.fn(),
|
|
9
9
|
getRepository: vi.fn(),
|
|
@@ -21,52 +21,37 @@ vi.mock('../../src/utils/bitbucket-client.js', () => ({
|
|
|
21
21
|
clearClients: vi.fn(),
|
|
22
22
|
}));
|
|
23
23
|
|
|
24
|
-
// Mock helper functions
|
|
25
|
-
vi.mock('../../src/commands/helpers.js',
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
printCommandDetail: vi.fn(actual.printCommandDetail),
|
|
31
|
-
getCurrentVersion: vi.fn(() => '0.0.0'),
|
|
32
|
-
};
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Mock config-loader to spy on loadConfig
|
|
36
|
-
vi.mock('../../src/utils/config-loader.js', async () => {
|
|
37
|
-
const actual = await vi.importActual('../../src/utils/config-loader.js');
|
|
38
|
-
return {
|
|
39
|
-
...actual,
|
|
40
|
-
loadConfig: vi.fn(actual.loadConfig),
|
|
41
|
-
};
|
|
42
|
-
});
|
|
24
|
+
// Mock helper functions
|
|
25
|
+
vi.mock('../../src/commands/helpers.js', () => ({
|
|
26
|
+
printAvailableCommands: vi.fn(),
|
|
27
|
+
printCommandDetail: vi.fn(),
|
|
28
|
+
getCurrentVersion: vi.fn(() => '0.0.0'),
|
|
29
|
+
}));
|
|
43
30
|
|
|
44
31
|
// Integration tests that test the entire flow through multiple modules
|
|
45
32
|
|
|
46
33
|
describe('CLI Integration', () => {
|
|
47
|
-
let
|
|
34
|
+
let testConfigDir: string;
|
|
35
|
+
let homedirSpy: vi.SpyInstance;
|
|
48
36
|
let configPath: string;
|
|
49
37
|
|
|
50
38
|
beforeEach(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
# Test Config`;
|
|
39
|
+
testConfigDir = fs.mkdtempSync(path.join(os.tmpdir(), 'bbk-cli-integration-'));
|
|
40
|
+
|
|
41
|
+
// Spy on os.homedir() to return test directory (works on all platforms)
|
|
42
|
+
homedirSpy = vi.spyOn(os, 'homedir').mockReturnValue(testConfigDir);
|
|
43
|
+
|
|
44
|
+
configPath = path.join(testConfigDir, '.bbkcli');
|
|
45
|
+
|
|
46
|
+
// Write valid INI config
|
|
47
|
+
const configContent = `[auth]
|
|
48
|
+
email=test@test.com
|
|
49
|
+
api_token=test_token_123
|
|
50
|
+
|
|
51
|
+
[defaults]
|
|
52
|
+
workspace=testworkspace
|
|
53
|
+
format=json
|
|
54
|
+
`;
|
|
70
55
|
fs.writeFileSync(configPath, configContent);
|
|
71
56
|
|
|
72
57
|
// Clear all mocks before each test
|
|
@@ -74,59 +59,49 @@ defaultFormat: json
|
|
|
74
59
|
});
|
|
75
60
|
|
|
76
61
|
afterEach(() => {
|
|
77
|
-
fs.rmSync(
|
|
62
|
+
fs.rmSync(testConfigDir, { recursive: true, force: true });
|
|
63
|
+
|
|
64
|
+
// Restore original os.homedir()
|
|
65
|
+
homedirSpy.mockRestore();
|
|
78
66
|
});
|
|
79
67
|
|
|
80
68
|
describe('Config Loading Integration', () => {
|
|
81
69
|
it('should load and parse configuration file', async () => {
|
|
82
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
83
|
-
|
|
84
70
|
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
85
|
-
const config = await loadConfig(
|
|
71
|
+
const config = await loadConfig();
|
|
86
72
|
|
|
87
73
|
expect(config).toBeDefined();
|
|
88
|
-
expect(config.
|
|
89
|
-
expect(config.
|
|
90
|
-
expect(config.
|
|
91
|
-
expect(config.profiles.cloud.apiToken).toBe('test_token_123');
|
|
92
|
-
expect(config.defaultProfile).toBe('cloud');
|
|
74
|
+
expect(config.email).toBe('test@test.com');
|
|
75
|
+
expect(config.apiToken).toBe('test_token_123');
|
|
76
|
+
expect(config.defaultWorkspace).toBe('testworkspace');
|
|
93
77
|
expect(config.defaultFormat).toBe('json');
|
|
94
78
|
});
|
|
95
79
|
|
|
96
|
-
it('should
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
expect(config.profiles.cloud).toBeDefined();
|
|
102
|
-
expect(config.profiles.staging).toBeDefined();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('should validate required profile fields', async () => {
|
|
106
|
-
const invalidConfig = `---
|
|
107
|
-
profiles:
|
|
108
|
-
incomplete:
|
|
109
|
-
email: test@test.com
|
|
110
|
-
# Missing apiToken
|
|
111
|
-
---
|
|
80
|
+
it('should load config without optional fields', async () => {
|
|
81
|
+
// Write minimal config
|
|
82
|
+
const minimalConfig = `[auth]
|
|
83
|
+
email=minimal@test.com
|
|
84
|
+
api_token=minimal_token
|
|
112
85
|
`;
|
|
113
|
-
fs.writeFileSync(configPath,
|
|
86
|
+
fs.writeFileSync(configPath, minimalConfig);
|
|
114
87
|
|
|
115
88
|
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
89
|
+
const config = await loadConfig();
|
|
116
90
|
|
|
117
|
-
expect(
|
|
91
|
+
expect(config.email).toBe('minimal@test.com');
|
|
92
|
+
expect(config.apiToken).toBe('minimal_token');
|
|
93
|
+
expect(config.defaultWorkspace).toBeUndefined();
|
|
94
|
+
expect(config.defaultFormat).toBe('json'); // Default format
|
|
118
95
|
});
|
|
119
96
|
});
|
|
120
97
|
|
|
121
98
|
describe('Command Runner Integration', () => {
|
|
122
99
|
it('should parse command line arguments and execute', async () => {
|
|
123
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
124
|
-
|
|
125
100
|
const { parseArguments } = await import('../../src/utils/arg-parser.js');
|
|
126
101
|
const { listRepositories } = await import('../../src/utils/bitbucket-client.js');
|
|
127
102
|
|
|
128
103
|
// Mock the Bitbucket API call
|
|
129
|
-
listRepositories.mockResolvedValue({
|
|
104
|
+
vi.mocked(listRepositories).mockResolvedValue({
|
|
130
105
|
success: true,
|
|
131
106
|
result: JSON.stringify({ repositories: [{ slug: 'my-repo', name: 'My Repository' }] }),
|
|
132
107
|
});
|
|
@@ -212,105 +187,22 @@ profiles:
|
|
|
212
187
|
});
|
|
213
188
|
});
|
|
214
189
|
|
|
215
|
-
describe('Bitbucket API Integration', () => {
|
|
216
|
-
it('should initialize Bitbucket client with profile', async () => {
|
|
217
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
218
|
-
|
|
219
|
-
const { getBitbucketClientOptions } = await import('../../src/utils/config-loader.js');
|
|
220
|
-
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
221
|
-
|
|
222
|
-
const config = await loadConfig(testDir);
|
|
223
|
-
const options = getBitbucketClientOptions(config, 'cloud');
|
|
224
|
-
|
|
225
|
-
expect(options.auth).toBeDefined();
|
|
226
|
-
expect(options.auth?.email).toBe('test@test.com');
|
|
227
|
-
expect(options.auth?.apiToken).toBe('test_token_123');
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('should handle different profiles', async () => {
|
|
231
|
-
const { getBitbucketClientOptions } = await import('../../src/utils/config-loader.js');
|
|
232
|
-
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
233
|
-
|
|
234
|
-
const config = await loadConfig(testDir);
|
|
235
|
-
const cloudOptions = getBitbucketClientOptions(config, 'cloud');
|
|
236
|
-
const stagingOptions = getBitbucketClientOptions(config, 'staging');
|
|
237
|
-
|
|
238
|
-
expect(cloudOptions.auth?.email).toBe('test@test.com');
|
|
239
|
-
expect(stagingOptions.auth?.email).toBe('staging@test.com');
|
|
240
|
-
expect(cloudOptions).not.toEqual(stagingOptions);
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
describe('Command Help Integration', () => {
|
|
245
|
-
it('should display all available commands', async () => {
|
|
246
|
-
const { printAvailableCommands } = await import('../../src/commands/helpers.js');
|
|
247
|
-
const { COMMANDS } = await import('../../src/config/constants.js');
|
|
248
|
-
|
|
249
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
250
|
-
|
|
251
|
-
printAvailableCommands();
|
|
252
|
-
|
|
253
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('\nAvailable commands:');
|
|
254
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining(`1. ${COMMANDS[0]}`));
|
|
255
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining(`10. ${COMMANDS[9]}`));
|
|
256
|
-
|
|
257
|
-
consoleLogSpy.mockRestore();
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it('should display detailed help for each command', async () => {
|
|
261
|
-
const { printCommandDetail } = await import('../../src/commands/helpers.js');
|
|
262
|
-
const { COMMANDS, COMMANDS_INFO } = await import('../../src/config/constants.js');
|
|
263
|
-
|
|
264
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
265
|
-
|
|
266
|
-
COMMANDS.forEach((command, index) => {
|
|
267
|
-
consoleLogSpy.mockClear();
|
|
268
|
-
printCommandDetail(command);
|
|
269
|
-
|
|
270
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining(command));
|
|
271
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining(COMMANDS_INFO[index]));
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
consoleLogSpy.mockRestore();
|
|
275
|
-
});
|
|
276
|
-
});
|
|
277
|
-
|
|
278
190
|
describe('CLI Wrapper Integration', () => {
|
|
279
191
|
it('should initialize CLI with config', async () => {
|
|
280
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
281
|
-
|
|
282
192
|
const { wrapper } = await import('../../src/cli/wrapper.js');
|
|
283
|
-
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
284
|
-
|
|
285
|
-
const cli = new wrapper();
|
|
286
|
-
|
|
287
|
-
await cli.connect();
|
|
288
|
-
|
|
289
|
-
expect(loadConfig).toHaveBeenCalledWith(testDir);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it('should handle profile switching', async () => {
|
|
293
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
294
193
|
|
|
295
|
-
const { wrapper } = await import('../../src/cli/wrapper.js');
|
|
296
194
|
const cli = new wrapper();
|
|
297
195
|
|
|
298
196
|
await cli.connect();
|
|
299
197
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('Switched to profile: staging');
|
|
307
|
-
|
|
308
|
-
consoleLogSpy.mockRestore();
|
|
198
|
+
// Config should be loaded
|
|
199
|
+
// @ts-expect-error - accessing private property for testing
|
|
200
|
+
expect(cli.config).toBeDefined();
|
|
201
|
+
// @ts-expect-error - accessing private property for testing
|
|
202
|
+
expect(cli.config?.email).toBe('test@test.com');
|
|
309
203
|
});
|
|
310
204
|
|
|
311
205
|
it('should handle format switching', async () => {
|
|
312
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
313
|
-
|
|
314
206
|
const { wrapper } = await import('../../src/cli/wrapper.js');
|
|
315
207
|
const cli = new wrapper();
|
|
316
208
|
|
|
@@ -328,61 +220,26 @@ profiles:
|
|
|
328
220
|
});
|
|
329
221
|
|
|
330
222
|
describe('Error Handling Integration', () => {
|
|
331
|
-
it('should handle missing config file', async () => {
|
|
332
|
-
fs.rmSync(configPath);
|
|
333
|
-
|
|
334
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
335
|
-
|
|
336
|
-
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
337
|
-
|
|
338
|
-
expect(() => loadConfig(testDir)).toThrow('Configuration file not found');
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it('should handle invalid config format', async () => {
|
|
342
|
-
const invalidConfig = `# Invalid Config
|
|
343
|
-
|
|
344
|
-
This is just markdown without frontmatter
|
|
345
|
-
`;
|
|
346
|
-
fs.writeFileSync(configPath, invalidConfig);
|
|
347
|
-
|
|
348
|
-
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
349
|
-
|
|
350
|
-
expect(() => loadConfig(testDir)).toThrow('Invalid configuration file format');
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
it('should handle missing profile', async () => {
|
|
354
|
-
const { getBitbucketClientOptions } = await import('../../src/utils/config-loader.js');
|
|
355
|
-
const { loadConfig } = await import('../../src/utils/config-loader.js');
|
|
356
|
-
|
|
357
|
-
const config = await loadConfig(testDir);
|
|
358
|
-
|
|
359
|
-
expect(() => getBitbucketClientOptions(config, 'nonexistent')).toThrow('Profile "nonexistent" not found');
|
|
360
|
-
});
|
|
361
|
-
|
|
362
223
|
it('should handle invalid email format', async () => {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
apiToken: token
|
|
368
|
-
---
|
|
224
|
+
// Write config with invalid email
|
|
225
|
+
const invalidConfig = `[auth]
|
|
226
|
+
email=invalid-email
|
|
227
|
+
api_token=test_token
|
|
369
228
|
`;
|
|
370
229
|
fs.writeFileSync(configPath, invalidConfig);
|
|
371
230
|
|
|
372
|
-
const { loadConfig } = await import('../../src/utils/
|
|
231
|
+
const { loadConfig } = await import('../../src/utils/index.js');
|
|
373
232
|
|
|
374
|
-
expect(() => loadConfig(
|
|
233
|
+
expect(() => loadConfig()).toThrow(/Invalid email/);
|
|
375
234
|
});
|
|
376
235
|
});
|
|
377
236
|
|
|
378
237
|
describe('End-to-End Workflows', () => {
|
|
379
238
|
it('should execute list-repositories workflow', async () => {
|
|
380
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
381
|
-
|
|
382
239
|
const { runCommand } = await import('../../src/commands/runner.js');
|
|
383
240
|
const { listRepositories } = await import('../../src/utils/bitbucket-client.js');
|
|
384
241
|
|
|
385
|
-
listRepositories.mockResolvedValue({
|
|
242
|
+
vi.mocked(listRepositories).mockResolvedValue({
|
|
386
243
|
success: true,
|
|
387
244
|
result: JSON.stringify({
|
|
388
245
|
repositories: [
|
|
@@ -403,7 +260,7 @@ profiles:
|
|
|
403
260
|
// Expected
|
|
404
261
|
}
|
|
405
262
|
|
|
406
|
-
expect(listRepositories).toHaveBeenCalledWith('
|
|
263
|
+
expect(listRepositories).toHaveBeenCalledWith('test-workspace', 'json');
|
|
407
264
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('docs-repo'));
|
|
408
265
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Engineering'));
|
|
409
266
|
|
|
@@ -412,12 +269,10 @@ profiles:
|
|
|
412
269
|
});
|
|
413
270
|
|
|
414
271
|
it('should execute create-issue workflow', async () => {
|
|
415
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
416
|
-
|
|
417
272
|
const { runCommand } = await import('../../src/commands/runner.js');
|
|
418
273
|
const { createIssue } = await import('../../src/utils/bitbucket-client.js');
|
|
419
274
|
|
|
420
|
-
createIssue.mockResolvedValue({
|
|
275
|
+
vi.mocked(createIssue).mockResolvedValue({
|
|
421
276
|
success: true,
|
|
422
277
|
result: JSON.stringify({
|
|
423
278
|
id: '12345',
|
|
@@ -447,7 +302,6 @@ profiles:
|
|
|
447
302
|
}
|
|
448
303
|
|
|
449
304
|
expect(createIssue).toHaveBeenCalledWith(
|
|
450
|
-
'cloud',
|
|
451
305
|
'test-workspace',
|
|
452
306
|
'my-repo',
|
|
453
307
|
'New Issue',
|
|
@@ -463,12 +317,10 @@ profiles:
|
|
|
463
317
|
});
|
|
464
318
|
|
|
465
319
|
it('should execute get-user workflow', async () => {
|
|
466
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
467
|
-
|
|
468
320
|
const { runCommand } = await import('../../src/commands/runner.js');
|
|
469
321
|
const { getUser } = await import('../../src/utils/bitbucket-client.js');
|
|
470
322
|
|
|
471
|
-
getUser.mockResolvedValue({
|
|
323
|
+
vi.mocked(getUser).mockResolvedValue({
|
|
472
324
|
success: true,
|
|
473
325
|
result: JSON.stringify({
|
|
474
326
|
uuid: '{5b10a2844c20165700ede21g}',
|
|
@@ -488,7 +340,7 @@ profiles:
|
|
|
488
340
|
// Expected
|
|
489
341
|
}
|
|
490
342
|
|
|
491
|
-
expect(getUser).toHaveBeenCalledWith('
|
|
343
|
+
expect(getUser).toHaveBeenCalledWith('5b10a2844c20165700ede21g', 'json');
|
|
492
344
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('John Doe'));
|
|
493
345
|
|
|
494
346
|
exitSpy.mockRestore();
|
|
@@ -496,14 +348,12 @@ profiles:
|
|
|
496
348
|
});
|
|
497
349
|
|
|
498
350
|
it('should execute test-connection workflow', async () => {
|
|
499
|
-
process.env.CLAUDE_PROJECT_ROOT = testDir;
|
|
500
|
-
|
|
501
351
|
const { runCommand } = await import('../../src/commands/runner.js');
|
|
502
352
|
const { testConnection } = await import('../../src/utils/bitbucket-client.js');
|
|
503
353
|
|
|
504
|
-
testConnection.mockResolvedValue({
|
|
354
|
+
vi.mocked(testConnection).mockResolvedValue({
|
|
505
355
|
success: true,
|
|
506
|
-
result: 'Connection successful!\n\
|
|
356
|
+
result: 'Connection successful!\n\nLogged in as: John Doe (johndoe)',
|
|
507
357
|
});
|
|
508
358
|
|
|
509
359
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
@@ -517,7 +367,7 @@ profiles:
|
|
|
517
367
|
// Expected
|
|
518
368
|
}
|
|
519
369
|
|
|
520
|
-
expect(testConnection).
|
|
370
|
+
expect(testConnection).toHaveBeenCalled();
|
|
521
371
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Connection successful'));
|
|
522
372
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('John Doe'));
|
|
523
373
|
|
|
@@ -525,4 +375,33 @@ profiles:
|
|
|
525
375
|
consoleLogSpy.mockRestore();
|
|
526
376
|
});
|
|
527
377
|
});
|
|
378
|
+
|
|
379
|
+
describe('Default Workspace Resolution', () => {
|
|
380
|
+
it('should override default workspace when specified', async () => {
|
|
381
|
+
const { runCommand } = await import('../../src/commands/runner.js');
|
|
382
|
+
const { listRepositories } = await import('../../src/utils/bitbucket-client.js');
|
|
383
|
+
|
|
384
|
+
vi.mocked(listRepositories).mockResolvedValue({
|
|
385
|
+
success: true,
|
|
386
|
+
result: JSON.stringify({ repositories: [] }),
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
390
|
+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
|
|
391
|
+
throw new Error('process.exit called');
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
try {
|
|
395
|
+
await runCommand('list-repositories', '{"workspace":"custom-workspace"}', null);
|
|
396
|
+
} catch {
|
|
397
|
+
// Expected
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Should use the specified workspace, not the default
|
|
401
|
+
expect(listRepositories).toHaveBeenCalledWith('custom-workspace', 'json');
|
|
402
|
+
|
|
403
|
+
exitSpy.mockRestore();
|
|
404
|
+
consoleLogSpy.mockRestore();
|
|
405
|
+
});
|
|
406
|
+
});
|
|
528
407
|
});
|