import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { mkdtempSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { createConfigCommand } from '../../src/commands/config.js'; import { loadConfig, saveConfig, DEFAULT_CONFIG } from '../../src/config/index.js'; let tempDir: string; let output: string[]; function log(...args: string[]) { output.push(args.join(' ')); } beforeEach(() => { tempDir = mkdtempSync(join(tmpdir(), 'mcpctl-config-test-')); output = []; }); afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); }); function makeCommand() { return createConfigCommand({ configDeps: { configDir: tempDir }, log, }); } describe('config view', () => { it('outputs default config as JSON', async () => { const cmd = makeCommand(); await cmd.parseAsync(['view'], { from: 'user' }); expect(output).toHaveLength(1); const parsed = JSON.parse(output[0]) as Record; expect(parsed['daemonUrl']).toBe('http://localhost:3000'); }); it('outputs config as YAML with --output yaml', async () => { const cmd = makeCommand(); await cmd.parseAsync(['view', '-o', 'yaml'], { from: 'user' }); expect(output[0]).toContain('daemonUrl:'); }); }); describe('config set', () => { it('sets a string value', async () => { const cmd = makeCommand(); await cmd.parseAsync(['set', 'daemonUrl', 'http://new:9000'], { from: 'user' }); expect(output[0]).toContain('daemonUrl'); const config = loadConfig({ configDir: tempDir }); expect(config.daemonUrl).toBe('http://new:9000'); }); it('sets cacheTTLMs as integer', async () => { const cmd = makeCommand(); await cmd.parseAsync(['set', 'cacheTTLMs', '60000'], { from: 'user' }); const config = loadConfig({ configDir: tempDir }); expect(config.cacheTTLMs).toBe(60000); }); it('sets registries as comma-separated list', async () => { const cmd = makeCommand(); await cmd.parseAsync(['set', 'registries', 'official,glama'], { from: 'user' }); const config = loadConfig({ configDir: tempDir }); expect(config.registries).toEqual(['official', 'glama']); }); it('sets outputFormat', async () => { const cmd = makeCommand(); await cmd.parseAsync(['set', 'outputFormat', 'json'], { from: 'user' }); const config = loadConfig({ configDir: tempDir }); expect(config.outputFormat).toBe('json'); }); }); describe('config path', () => { it('shows config file path', async () => { const cmd = makeCommand(); await cmd.parseAsync(['path'], { from: 'user' }); expect(output[0]).toContain(tempDir); expect(output[0]).toContain('config.json'); }); }); describe('config reset', () => { it('resets to defaults', async () => { // First set a custom value saveConfig({ ...DEFAULT_CONFIG, daemonUrl: 'http://custom' }, { configDir: tempDir }); const cmd = makeCommand(); await cmd.parseAsync(['reset'], { from: 'user' }); expect(output[0]).toContain('reset'); const config = loadConfig({ configDir: tempDir }); expect(config.daemonUrl).toBe(DEFAULT_CONFIG.daemonUrl); }); });