@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
222 lines (184 loc) • 6.94 kB
text/typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import { ConfigManager } from '../config-manager.js';
import { AtlasConfig } from '../types.js';
describe('ConfigManager', () => {
let tempDir: string;
let configManager: ConfigManager;
beforeEach(async () => {
// Create a temporary directory for testing
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'atlas-test-'));
process.chdir(tempDir);
});
afterEach(async () => {
// Clean up
process.chdir('/');
await fs.rm(tempDir, { recursive: true, force: true });
});
describe('Configuration Loading', () => {
it('should use default config when no config file exists', async () => {
configManager = new ConfigManager();
await configManager.load();
const config = configManager.get();
expect(config.projectMode).toBe('new');
expect(config.features?.tddEnforcement).toBe('strict');
expect(config.storage?.mode).toBe('local');
});
it('should load config from atlas.config.json', async () => {
const customConfig: Partial<AtlasConfig> = {
projectMode: 'existing',
projectName: 'test-project',
features: {
tddEnforcement: 'advisory',
},
};
await fs.writeFile(
path.join(tempDir, 'atlas.config.json'),
JSON.stringify(customConfig)
);
configManager = new ConfigManager();
await configManager.load();
const config = configManager.get();
expect(config.projectMode).toBe('existing');
expect(config.projectName).toBe('test-project');
expect(config.features?.tddEnforcement).toBe('advisory');
});
it('should merge custom config with defaults', async () => {
const customConfig: Partial<AtlasConfig> = {
projectMode: 'multi-repo',
};
await fs.writeFile(
path.join(tempDir, 'atlas.config.json'),
JSON.stringify(customConfig)
);
configManager = new ConfigManager();
await configManager.load();
const config = configManager.get();
expect(config.projectMode).toBe('multi-repo');
expect(config.features?.tddEnforcement).toBe('strict'); // Default value
});
});
describe('Project Detection', () => {
it('should detect a new project', async () => {
configManager = new ConfigManager();
const detection = await configManager.detectProject();
expect(detection.hasGit).toBe(false);
expect(detection.hasPackageJson).toBe(false);
expect(detection.suggestedMode).toBe('new');
});
it('should detect an existing Node.js project', async () => {
// Create git directory
await fs.mkdir(path.join(tempDir, '.git'));
// Create package.json
await fs.writeFile(
path.join(tempDir, 'package.json'),
JSON.stringify({
name: 'test-project',
devDependencies: {
jest: '^29.0.0',
},
})
);
configManager = new ConfigManager();
const detection = await configManager.detectProject();
expect(detection.hasGit).toBe(true);
expect(detection.hasPackageJson).toBe(true);
expect(detection.hasTests).toBe(true);
expect(detection.testFramework).toBe('jest');
expect(detection.suggestedMode).toBe('existing');
});
it('should detect a multi-repo project', async () => {
// Create multiple subdirectories with package.json files
await fs.mkdir(path.join(tempDir, 'frontend'));
await fs.mkdir(path.join(tempDir, 'backend'));
await fs.writeFile(
path.join(tempDir, 'frontend', 'package.json'),
JSON.stringify({ name: 'frontend' })
);
await fs.writeFile(
path.join(tempDir, 'backend', 'package.json'),
JSON.stringify({ name: 'backend' })
);
configManager = new ConfigManager();
const detection = await configManager.detectProject();
expect(detection.suggestedMode).toBe('multi-repo');
});
});
describe('Storage Path Resolution', () => {
it('should use local storage by default', async () => {
configManager = new ConfigManager();
await configManager.load();
const storagePath = configManager.getDataPath();
expect(storagePath).toContain('.atlas');
expect(storagePath.endsWith('.atlas')).toBe(true);
});
it('should use home directory storage when configured', async () => {
configManager = new ConfigManager();
configManager.set({
projectName: 'test-project',
storage: {
mode: 'home',
isolation: 'project',
},
});
const storagePath = configManager.getDataPath();
expect(storagePath).toBe(
path.join(os.homedir(), '.atlas', 'projects', 'test-project')
);
});
it('should use custom storage path when configured', async () => {
const customPath = '/custom/storage/path';
configManager = new ConfigManager();
configManager.set({
storage: {
mode: 'custom',
path: customPath,
},
});
const storagePath = configManager.getDataPath();
expect(storagePath).toBe(customPath);
});
});
describe('Module Management', () => {
it('should enable all modules by default', async () => {
configManager = new ConfigManager();
await configManager.load();
expect(configManager.isModuleEnabled('kanban')).toBe(true);
expect(configManager.isModuleEnabled('development')).toBe(true);
expect(configManager.isModuleEnabled('documentation')).toBe(true);
});
it('should respect module configuration', async () => {
configManager = new ConfigManager();
configManager.set({
integration: {
modules: {
kanban: true,
development: false,
documentation: true,
},
},
});
expect(configManager.isModuleEnabled('kanban')).toBe(true);
expect(configManager.isModuleEnabled('development')).toBe(false);
expect(configManager.isModuleEnabled('documentation')).toBe(true);
});
});
describe('Configuration Persistence', () => {
it('should save configuration to file', async () => {
configManager = new ConfigManager();
configManager.set({
projectMode: 'existing',
projectName: 'saved-project',
});
await configManager.save();
// Verify file was created
const savedConfig = JSON.parse(
await fs.readFile(path.join(tempDir, 'atlas.config.json'), 'utf-8')
);
expect(savedConfig.projectMode).toBe('existing');
expect(savedConfig.projectName).toBe('saved-project');
});
});
});