import { loadConfig, validateConfig } from "../src/config"; import { AgentRailsConfig } from "../src/types"; import * as fs from "fs"; import * as path from "path"; describe("Config", () => { const testConfigDir = path.join(__dirname, "fixtures"); const validConfigPath = path.join(testConfigDir, "valid.config.js"); const invalidConfigPath = path.join(testConfigDir, "invalid.config.js"); beforeAll(() => { // Create fixtures directory if (!fs.existsSync(testConfigDir)) { fs.mkdirSync(testConfigDir, { recursive: true }); } // Create valid config fixture fs.writeFileSync( validConfigPath, ` module.exports = { llm: { provider: 'openai', apiKey: 'test-api-key', }, agent: async (input) => { return 'test response'; }, }; ` ); // Create invalid config fixture (missing agent) fs.writeFileSync( invalidConfigPath, ` module.exports = { llm: { provider: 'openai', apiKey: 'test-api-key', }, }; ` ); }); afterAll(() => { // Cleanup fixtures if (fs.existsSync(validConfigPath)) { fs.unlinkSync(validConfigPath); } if (fs.existsSync(invalidConfigPath)) { fs.unlinkSync(invalidConfigPath); } if (fs.existsSync(testConfigDir)) { fs.rmSync(testConfigDir, { recursive: true, force: true }); } }); describe("loadConfig", () => { it("should load a valid config file", async () => { const config = await loadConfig(validConfigPath); expect(config).toBeDefined(); expect(config.llm.apiKey).toBe("test-api-key"); expect(config.llm.provider).toBe("openai"); expect(typeof config.agent).toBe("function"); }); it("should set default values", async () => { const config = await loadConfig(validConfigPath); expect(config.testMatch).toEqual(["**/*.test.yaml", "**/*.test.yml"]); expect(config.timeout).toBe(30000); expect(config.llm.model).toBe("gpt-4-turbo-preview"); expect(config.llm.temperature).toBe(0.3); }); it("should throw error if config file not found", async () => { await expect(loadConfig("/nonexistent/path.js")).rejects.toThrow( "Failed to load config" ); }); it("should throw error if agent is missing", async () => { // Ensure fixtures directory exists and recreate invalid config if needed if (!fs.existsSync(testConfigDir)) { fs.mkdirSync(testConfigDir, { recursive: true }); } if (!fs.existsSync(invalidConfigPath)) { fs.writeFileSync( invalidConfigPath, ` module.exports = { llm: { provider: 'openai', apiKey: 'test-api-key', }, }; ` ); } await expect(loadConfig(invalidConfigPath)).rejects.toThrow( 'Config must include an "agent" function' ); }); it("should throw error if apiKey is missing", async () => { // Ensure fixtures directory exists if (!fs.existsSync(testConfigDir)) { fs.mkdirSync(testConfigDir, { recursive: true }); } const noApiKeyPath = path.join(testConfigDir, "no-api-key.config.js"); fs.writeFileSync( noApiKeyPath, ` module.exports = { llm: { provider: 'openai', }, agent: async (input) => 'test', }; ` ); await expect(loadConfig(noApiKeyPath)).rejects.toThrow( 'Config must include "llm.apiKey"' ); fs.unlinkSync(noApiKeyPath); }); }); describe("validateConfig", () => { it("should validate a correct config", () => { const config: AgentRailsConfig = { llm: { provider: "openai", apiKey: "test-key", }, agent: async (input: any) => "response", }; expect(() => validateConfig(config)).not.toThrow(); }); it("should throw if agent is not a function", () => { const config: any = { llm: { provider: "openai", apiKey: "test-key", }, agent: "not a function", }; expect(() => validateConfig(config)).toThrow( 'Config "agent" must be a function' ); }); it("should throw if apiKey is missing", () => { const config: any = { llm: { provider: "openai", }, agent: async (input: any) => "response", }; expect(() => validateConfig(config)).toThrow( 'Config "llm.apiKey" must be a non-empty string' ); }); }); });