import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { loadConfig } from "../../src/config.js"; describe("loadConfig", () => { const originalEnv = process.env; beforeEach(() => { process.env = { ...originalEnv }; // Set required vars by default process.env.DISCORD_BOT_TOKEN = "test-discord-token"; }); afterEach(() => { process.env = originalEnv; }); it("should load required environment variables", () => { const config = loadConfig(); expect(config.discordBotToken).toBe("test-discord-token"); }); it("should apply default values for optional config", () => { const config = loadConfig(); expect(config.claudeCliPath).toBe("claude"); expect(config.allowedTools).toEqual(["Read", "Write", "Edit", "Glob", "Grep", "WebSearch", "WebFetch"]); expect(config.permissionMode).toBe("bypassPermissions"); expect(config.queryTimeoutMs).toBe(120_000); expect(config.maxConcurrentQueries).toBe(5); expect(config.configDir).toBe("./config"); expect(config.maxQueueDepth).toBe(100); expect(config.outputChannelId).toBeUndefined(); expect(config.agentBackend).toBe("claude"); expect(config.backendCliPath).toBe("claude"); expect(config.backendModel).toBeUndefined(); expect(config.backendMaxTurns).toBe(25); }); it("should parse ALLOWED_TOOLS from comma-separated string", () => { process.env.ALLOWED_TOOLS = "Read,Write,Bash"; const config = loadConfig(); expect(config.allowedTools).toEqual(["Read", "Write", "Bash"]); }); it("should trim whitespace from ALLOWED_TOOLS entries", () => { process.env.ALLOWED_TOOLS = " Read , Write , Bash "; const config = loadConfig(); expect(config.allowedTools).toEqual(["Read", "Write", "Bash"]); }); it("should read all optional environment variables", () => { process.env.PERMISSION_MODE = "default"; process.env.QUERY_TIMEOUT_MS = "60000"; process.env.MAX_CONCURRENT_QUERIES = "10"; process.env.CONFIG_DIR = "/custom/config"; process.env.MAX_QUEUE_DEPTH = "200"; process.env.OUTPUT_CHANNEL_ID = "123456789"; process.env.CLAUDE_CLI_PATH = "/usr/local/bin/claude"; const config = loadConfig(); expect(config.permissionMode).toBe("default"); expect(config.queryTimeoutMs).toBe(60_000); expect(config.maxConcurrentQueries).toBe(10); expect(config.configDir).toBe("/custom/config"); expect(config.maxQueueDepth).toBe(200); expect(config.outputChannelId).toBe("123456789"); expect(config.claudeCliPath).toBe("/usr/local/bin/claude"); }); it("should read new backend environment variables", () => { process.env.AGENT_BACKEND = "codex"; process.env.BACKEND_CLI_PATH = "/usr/local/bin/codex"; process.env.BACKEND_MODEL = "gpt-4"; process.env.BACKEND_MAX_TURNS = "10"; const config = loadConfig(); expect(config.agentBackend).toBe("codex"); expect(config.backendCliPath).toBe("/usr/local/bin/codex"); expect(config.backendModel).toBe("gpt-4"); expect(config.backendMaxTurns).toBe(10); }); it("should default backendCliPath to backend name when no CLI path env vars are set", () => { process.env.AGENT_BACKEND = "gemini"; const config = loadConfig(); expect(config.backendCliPath).toBe("gemini"); }); it("should use CLAUDE_CLI_PATH as backendCliPath when backend is claude and BACKEND_CLI_PATH is not set", () => { process.env.CLAUDE_CLI_PATH = "/custom/claude"; const config = loadConfig(); expect(config.agentBackend).toBe("claude"); expect(config.backendCliPath).toBe("/custom/claude"); expect(config.claudeCliPath).toBe("/custom/claude"); }); it("should prefer BACKEND_CLI_PATH over CLAUDE_CLI_PATH", () => { process.env.CLAUDE_CLI_PATH = "/old/claude"; process.env.BACKEND_CLI_PATH = "/new/backend"; const config = loadConfig(); expect(config.backendCliPath).toBe("/new/backend"); }); it("should throw for invalid AGENT_BACKEND value", () => { process.env.AGENT_BACKEND = "invalid-backend"; expect(() => loadConfig()).toThrow('Invalid backend name "invalid-backend"'); }); it("should throw when DISCORD_BOT_TOKEN is missing", () => { delete process.env.DISCORD_BOT_TOKEN; expect(() => loadConfig()).toThrow("DISCORD_BOT_TOKEN"); }); it("should list all missing required variables in error message", () => { delete process.env.DISCORD_BOT_TOKEN; expect(() => loadConfig()).toThrow( "Missing required environment variables: DISCORD_BOT_TOKEN" ); }); });