Files
ai-terminal-assistant/packages/core/tests/unit/agent/config-loader.test.ts
T
kurihada eb80b2c9e6 fix(core): 修复测试用例以匹配最新实现
- todo-manager.test: 修复空日期字符串导致的 Invalid time value 错误
- config-loader.test: 更新测试以匹配简化后的配置加载逻辑
- mcp/config.test: 修复配置路径匹配问题
- task.test/task-extended.test: 添加缺失的 agentEventEmitter mock
- presets/index.test: 更新预设 Agent 数量和 maxSteps 测试
- agent.test: 添加缺失的 mock 函数并修正模式切换测试
- 删除过时的 session/manager.test 和 storage.test (使用已废弃的 API)
2025-12-16 22:33:46 +08:00

281 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
loadAgentConfig,
saveAgentConfig,
getConfigTemplate,
} from '../../../src/agent/config-loader.js';
import type { AgentConfigFile } from '../../../src/agent/types.js';
// Mock fs
vi.mock('fs', () => ({
existsSync: vi.fn(),
promises: {
readFile: vi.fn(),
writeFile: vi.fn(),
mkdir: vi.fn(),
},
}));
// Mock js-yaml
vi.mock('js-yaml', () => ({
load: vi.fn((content: string) => JSON.parse(content)),
dump: vi.fn((obj: unknown) => JSON.stringify(obj, null, 2)),
}));
import * as fs from 'fs';
describe('loadAgentConfig - 加载 Agent 配置', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('无配置文件时返回 null', async () => {
vi.mocked(fs.existsSync).mockReturnValue(false);
const config = await loadAgentConfig('/test/project');
expect(config).toBeNull();
});
it('加载 JSON 配置文件', async () => {
const mockConfig: AgentConfigFile = {
defaults: {
maxSteps: 20,
},
agents: {
'custom-agent': {
description: '自定义 Agent',
mode: 'subagent',
prompt: '你是助手',
},
},
};
vi.mocked(fs.existsSync).mockImplementation((path: unknown) =>
String(path).endsWith('.json')
);
vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify(mockConfig));
const config = await loadAgentConfig('/test/project');
expect(config).not.toBeNull();
expect(config?.defaults?.maxSteps).toBe(20);
expect(config?.agents?.['custom-agent']).toBeDefined();
});
it('加载 YAML 配置文件(现在只支持 JSON,此测试确认行为)', async () => {
// 实现已改为只支持 JSON,这里测试当找不到 JSON 文件时返回 null
vi.mocked(fs.existsSync).mockReturnValue(false);
const config = await loadAgentConfig('/test/project');
expect(config).toBeNull();
});
it('无效配置格式返回 null', async () => {
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.promises.readFile).mockResolvedValue('invalid json');
// 会在解析时失败
const config = await loadAgentConfig('/test/project');
// 取决于实现,可能是 null 或抛出错误后 null
expect(config).toBeNull();
});
it('配置搜索顺序(现在只搜索全局配置目录)', async () => {
// 实现已改为只从全局配置目录加载
const calls: string[] = [];
vi.mocked(fs.existsSync).mockImplementation((path: unknown) => {
calls.push(String(path));
return false;
});
await loadAgentConfig('/test/project');
// 只搜索一个路径(全局配置目录的 agents.json
expect(calls.length).toBe(1);
expect(calls[0]).toContain('agents.json');
});
});
describe('saveAgentConfig - 保存 Agent 配置', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(fs.existsSync).mockReturnValue(false);
});
it('保存 JSON 格式配置', async () => {
const config: AgentConfigFile = {
defaults: {
maxSteps: 10,
},
agents: {},
};
await saveAgentConfig('/test/project', config, 'json');
expect(fs.promises.mkdir).toHaveBeenCalled();
expect(fs.promises.writeFile).toHaveBeenCalledWith(
expect.stringContaining('agents.json'),
expect.any(String),
'utf-8'
);
});
it('保存 YAML 格式配置(现在只支持 JSON', async () => {
const config: AgentConfigFile = {
defaults: {
maxSteps: 10,
},
agents: {},
};
// 即使传入 yaml 格式,也会保存为 JSON
await saveAgentConfig('/test/project', config, 'yaml');
expect(fs.promises.writeFile).toHaveBeenCalledWith(
expect.stringContaining('agents.json'),
expect.any(String),
'utf-8'
);
});
it('创建配置目录如果不存在', async () => {
vi.mocked(fs.existsSync).mockReturnValue(false);
await saveAgentConfig('/test/project', { agents: {} }, 'json');
expect(fs.promises.mkdir).toHaveBeenCalledWith(
expect.any(String),
{ recursive: true }
);
});
it('目录已存在时不重复创建', async () => {
vi.mocked(fs.existsSync).mockReturnValue(true);
await saveAgentConfig('/test/project', { agents: {} }, 'json');
expect(fs.promises.mkdir).not.toHaveBeenCalled();
});
});
describe('getConfigTemplate - 获取配置模板', () => {
it('返回有效的配置模板', () => {
const template = getConfigTemplate();
expect(template).toBeDefined();
expect(template.defaults).toBeDefined();
expect(template.agents).toBeDefined();
});
it('模板包含默认配置', () => {
const template = getConfigTemplate();
expect(template.defaults?.maxSteps).toBeDefined();
expect(template.defaults?.model).toBeDefined();
});
it('模板包含示例 Agent', () => {
const template = getConfigTemplate();
expect(template.agents).toBeDefined();
expect(Object.keys(template.agents || {}).length).toBeGreaterThan(0);
});
it('示例 Agent 包含必要字段', () => {
const template = getConfigTemplate();
const agents = template.agents || {};
const firstAgent = Object.values(agents)[0];
expect(firstAgent).toBeDefined();
expect(firstAgent.description).toBeDefined();
expect(firstAgent.mode).toBeDefined();
});
it('模板包含权限配置示例', () => {
const template = getConfigTemplate();
expect(template.defaults?.permission).toBeDefined();
expect(template.defaults?.permission?.bash).toBeDefined();
});
});
describe('配置验证', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('空对象是有效配置', async () => {
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify({}));
const config = await loadAgentConfig('/test/project');
expect(config).not.toBeNull();
});
it('只有 defaults 的配置有效', async () => {
const mockConfig = {
defaults: {
maxSteps: 10,
},
};
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify(mockConfig));
const config = await loadAgentConfig('/test/project');
expect(config).not.toBeNull();
expect(config?.defaults?.maxSteps).toBe(10);
});
it('只有 agents 的配置有效', async () => {
const mockConfig = {
agents: {
'test-agent': {
description: 'Test',
mode: 'subagent',
},
},
};
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify(mockConfig));
const config = await loadAgentConfig('/test/project');
expect(config).not.toBeNull();
expect(config?.agents?.['test-agent']).toBeDefined();
});
it('defaults 为非对象时配置无效', async () => {
const mockConfig = {
defaults: 'invalid',
};
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify(mockConfig));
const config = await loadAgentConfig('/test/project');
// 应该返回 null(无效配置)
expect(config).toBeNull();
});
it('agents 为非对象时配置无效', async () => {
const mockConfig = {
agents: 'invalid',
};
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify(mockConfig));
const config = await loadAgentConfig('/test/project');
expect(config).toBeNull();
});
});