import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { mkdtempSync, rmSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { loadConfig, saveConfig, mergeConfig, getConfigPath, DEFAULT_CONFIG } from '../../src/config/index.js'; let tempDir: string; beforeEach(() => { tempDir = mkdtempSync(join(tmpdir(), 'mcpctl-test-')); }); afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); }); describe('getConfigPath', () => { it('returns path within config dir', () => { const path = getConfigPath('/tmp/mcpctl'); expect(path).toBe('/tmp/mcpctl/config.json'); }); }); describe('loadConfig', () => { it('returns defaults when no config file exists', () => { const config = loadConfig({ configDir: tempDir }); expect(config).toEqual(DEFAULT_CONFIG); }); it('loads config from file', () => { saveConfig({ ...DEFAULT_CONFIG, daemonUrl: 'http://custom:5000' }, { configDir: tempDir }); const config = loadConfig({ configDir: tempDir }); expect(config.daemonUrl).toBe('http://custom:5000'); }); it('applies defaults for missing fields', () => { const { writeFileSync } = require('node:fs') as typeof import('node:fs'); writeFileSync(join(tempDir, 'config.json'), '{"daemonUrl":"http://x:1"}'); const config = loadConfig({ configDir: tempDir }); expect(config.daemonUrl).toBe('http://x:1'); expect(config.registries).toEqual(['official', 'glama', 'smithery']); }); }); describe('saveConfig', () => { it('creates config file', () => { saveConfig(DEFAULT_CONFIG, { configDir: tempDir }); expect(existsSync(join(tempDir, 'config.json'))).toBe(true); }); it('creates config directory if missing', () => { const nested = join(tempDir, 'nested', 'dir'); saveConfig(DEFAULT_CONFIG, { configDir: nested }); expect(existsSync(join(nested, 'config.json'))).toBe(true); }); it('round-trips configuration', () => { const custom = { ...DEFAULT_CONFIG, daemonUrl: 'http://custom:9000', registries: ['official' as const], outputFormat: 'json' as const, }; saveConfig(custom, { configDir: tempDir }); const loaded = loadConfig({ configDir: tempDir }); expect(loaded).toEqual(custom); }); }); describe('mergeConfig', () => { it('merges overrides into existing config', () => { saveConfig(DEFAULT_CONFIG, { configDir: tempDir }); const merged = mergeConfig({ daemonUrl: 'http://new:1234' }, { configDir: tempDir }); expect(merged.daemonUrl).toBe('http://new:1234'); expect(merged.registries).toEqual(DEFAULT_CONFIG.registries); }); it('works when no config file exists', () => { const merged = mergeConfig({ outputFormat: 'yaml' }, { configDir: tempDir }); expect(merged.outputFormat).toBe('yaml'); expect(merged.daemonUrl).toBe('http://localhost:3000'); }); });