|
9 | 9 | import { mkdtempSync } from 'node:fs'; |
10 | 10 | import { tmpdir } from 'node:os'; |
11 | 11 | import { join } from 'node:path'; |
| 12 | +import { Command } from 'commander'; |
12 | 13 | import { beforeEach, describe, expect, it, vi } from 'vitest'; |
13 | | -import { CLIError } from '../lib/errors.js'; |
| 14 | +import { ApiError, CLIError } from '../lib/errors.js'; |
14 | 15 | import { writeProfile } from '../lib/credentials.js'; |
15 | 16 | import type { DoctorDeps, DoctorReport } from './doctor.js'; |
16 | 17 | import { createDoctorCommand, runDoctor } from './doctor.js'; |
@@ -56,6 +57,14 @@ function healthyDeps(credentialsPath: string, extra: Partial<DoctorDeps> = {}): |
56 | 57 | }; |
57 | 58 | } |
58 | 59 |
|
| 60 | +function makeDoctorProgram(deps: DoctorDeps = {}): Command { |
| 61 | + const program = new Command(); |
| 62 | + program.exitOverride(); |
| 63 | + program.option('--output <mode>', 'output', 'text'); |
| 64 | + program.addCommand(createDoctorCommand(deps)); |
| 65 | + return program; |
| 66 | +} |
| 67 | + |
59 | 68 | let credentialsPath: string; |
60 | 69 |
|
61 | 70 | beforeEach(() => { |
@@ -271,4 +280,36 @@ describe('createDoctorCommand wiring', () => { |
271 | 280 | it('--help describes the diagnostic', () => { |
272 | 281 | expect(createDoctorCommand().helpInformation()).toContain('Diagnose'); |
273 | 282 | }); |
| 283 | + |
| 284 | + it('rejects invalid --output with the shared VALIDATION_ERROR', async () => { |
| 285 | + const rejection = await makeDoctorProgram() |
| 286 | + .parseAsync(['node', 'ts', '--output', 'yaml', 'doctor']) |
| 287 | + .catch((error: unknown) => error); |
| 288 | + expect(rejection).toBeInstanceOf(ApiError); |
| 289 | + expect(rejection).toMatchObject({ |
| 290 | + code: 'VALIDATION_ERROR', |
| 291 | + exitCode: 5, |
| 292 | + nextAction: 'Flag `--output` is invalid: must be one of: json, text.', |
| 293 | + }); |
| 294 | + }); |
| 295 | + |
| 296 | + it('accepts valid --output modes through command wiring', async () => { |
| 297 | + writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath }); |
| 298 | + for (const mode of ['text', 'json'] as const) { |
| 299 | + const { capture, deps } = makeCapture(); |
| 300 | + await makeDoctorProgram({ ...healthyDeps(credentialsPath), ...deps }).parseAsync([ |
| 301 | + 'node', |
| 302 | + 'ts', |
| 303 | + '--output', |
| 304 | + mode, |
| 305 | + 'doctor', |
| 306 | + ]); |
| 307 | + const raw = capture.stdout.join(''); |
| 308 | + if (mode === 'json') { |
| 309 | + expect((JSON.parse(raw) as DoctorReport).failures).toBe(0); |
| 310 | + } else { |
| 311 | + expect(raw).toContain('All checks passed.'); |
| 312 | + } |
| 313 | + } |
| 314 | + }); |
274 | 315 | }); |
0 commit comments