Files
proffesor-for-testing__agen…/tests/unit/init/init-wizard.test.ts
Profa 2253d05618 feat: flatten project structure — archive v2, promote v3 to root
Remove the nested v3/ subdirectory by moving all active source code,
tests, configs, and assets directly to the project root. Archive v2/
(dead code, 847MB) to v2-archive.tar.gz.

Key changes:
- Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/
- Move v3/tsconfig.json, v3/vitest.config.ts to root
- Merge v3/package.json into root package.json (ESM, scripts, deps, exports)
- Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/
- Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes
- Fix all init installer path resolution (3-level-up → 2-level-up)
- Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe"
- Update settings.json ADR/DDD directories to docs/implementation/
- Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks)
- Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces
- Update 15 guidance shards: v3/src/ → src/ path references
- Fix sync interfaces: remove v3/ and v2/ path references
- Fix test path calculations (process.cwd() + '..' no longer needed)
- Fix flaky perf test threshold (500ms → 1000ms for CI environments)
- Fix complexity-analyzer test to match ADR-051 keyword-based eligibility

Build passes, 17,901 tests pass, CLI and MCP bundles verified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:35:41 +00:00

910 lines
30 KiB
TypeScript

/**
* Init Wizard and Orchestrator Tests
* ADR-025: Enhanced Init with Self-Configuration
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import {
InitOrchestrator,
createInitOrchestrator,
quickInit,
formatInitResult,
} from '../../../src/init/init-wizard.js';
import type { InitResult, PretrainedLibrary } from '../../../src/init/types.js';
// Mock fs module for project analyzer and init wizard
vi.mock('fs', async () => {
const actual = await vi.importActual('fs');
return {
...actual,
existsSync: vi.fn().mockReturnValue(false),
readFileSync: vi.fn().mockReturnValue('{}'),
statSync: vi.fn().mockReturnValue({ isDirectory: () => false, isFile: () => true }),
readdirSync: vi.fn().mockReturnValue([]),
mkdirSync: vi.fn(),
writeFileSync: vi.fn(),
};
});
// Mock better-sqlite3 for persistence database initialization
// Now uses ESM dynamic import in production code
vi.mock('better-sqlite3', () => {
const mockStatement = {
get: vi.fn().mockReturnValue({ name: 'kv_store' }),
run: vi.fn(),
all: vi.fn().mockReturnValue([]),
bind: vi.fn().mockReturnThis(),
};
const mockDb = {
pragma: vi.fn(),
exec: vi.fn(),
prepare: vi.fn().mockReturnValue(mockStatement),
close: vi.fn(),
transaction: vi.fn((fn: () => void) => fn),
};
// Use a proper function (not arrow) so it can be used as a constructor with `new`
function MockDatabase() {
return mockDb;
}
// ESM default export format
return { default: MockDatabase };
});
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
const mockExistsSync = existsSync as ReturnType<typeof vi.fn>;
const mockReadFileSync = readFileSync as ReturnType<typeof vi.fn>;
const mockMkdirSync = mkdirSync as ReturnType<typeof vi.fn>;
const mockWriteFileSync = writeFileSync as ReturnType<typeof vi.fn>;
describe('InitOrchestrator', () => {
const testProjectRoot = '/test/project';
beforeEach(() => {
vi.clearAllMocks();
mockExistsSync.mockReturnValue(false);
mockReadFileSync.mockImplementation((path: string) => {
if (path.includes('package.json')) {
return JSON.stringify({ name: 'test-project' });
}
return '';
});
// Reset write mocks - they should succeed by default
mockMkdirSync.mockReturnValue(undefined);
mockWriteFileSync.mockReturnValue(undefined);
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('createInitOrchestrator', () => {
it('should create an init orchestrator', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
});
expect(orchestrator).toBeInstanceOf(InitOrchestrator);
});
it('should create orchestrator with auto mode', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
expect(orchestrator).toBeInstanceOf(InitOrchestrator);
});
it('should create orchestrator with minimal config', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
minimal: true,
});
expect(orchestrator).toBeInstanceOf(InitOrchestrator);
});
});
describe('getWizardSteps', () => {
it('should return wizard steps', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
});
const steps = orchestrator.getWizardSteps();
expect(Array.isArray(steps)).toBe(true);
expect(steps.length).toBeGreaterThan(0);
});
it('should have welcome step first', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
});
const steps = orchestrator.getWizardSteps();
expect(steps[0].id).toBe('welcome');
expect(steps[0].type).toBe('info');
});
it('should include project-type step', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
});
const steps = orchestrator.getWizardSteps();
const projectTypeStep = steps.find((s) => s.id === 'project-type');
expect(projectTypeStep).toBeDefined();
expect(projectTypeStep?.type).toBe('choice');
expect(projectTypeStep?.options?.length).toBeGreaterThan(0);
});
it('should include learning-mode step', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
});
const steps = orchestrator.getWizardSteps();
const learningStep = steps.find((s) => s.id === 'learning-mode');
expect(learningStep).toBeDefined();
expect(learningStep?.type).toBe('choice');
});
it('should include confirm steps', () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
});
const steps = orchestrator.getWizardSteps();
const confirmSteps = steps.filter((s) => s.type === 'confirm');
expect(confirmSteps.length).toBeGreaterThan(0);
});
});
describe('initialize', () => {
it('should complete initialization in auto mode', async () => {
mockExistsSync.mockImplementation((path: string) => {
return path.includes('package.json');
});
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
expect(result.success).toBe(true);
expect(result.config).toBeDefined();
expect(result.steps.length).toBeGreaterThan(0);
expect(result.totalDurationMs).toBeGreaterThanOrEqual(0);
expect(result.timestamp).toBeInstanceOf(Date);
});
it('should record all step results', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
expect(result.steps.length).toBeGreaterThan(0);
for (const step of result.steps) {
expect(step.step).toBeDefined();
expect(step.status).toMatch(/success|error/);
expect(step.message).toBeDefined();
expect(step.durationMs).toBeGreaterThanOrEqual(0);
}
});
it('should populate summary', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
expect(result.summary.projectAnalyzed).toBe(true);
expect(result.summary.configGenerated).toBe(true);
expect(typeof result.summary.patternsLoaded).toBe('number');
expect(typeof result.summary.skillsInstalled).toBe('number');
expect(typeof result.summary.agentsInstalled).toBe('number');
expect(typeof result.summary.hooksConfigured).toBe('boolean');
expect(typeof result.summary.mcpConfigured).toBe('boolean');
expect(typeof result.summary.claudeMdGenerated).toBe('boolean');
expect(typeof result.summary.workersStarted).toBe('number');
});
it('should apply wizard answers', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
wizardAnswers: {
'project-type': 'monorepo',
'learning-mode': 'basic',
'load-patterns': false,
hooks: false,
workers: false,
},
});
const result = await orchestrator.initialize();
expect(result.success).toBe(true);
expect(result.config.project.type).toBe('monorepo');
expect(result.config.learning.embeddingModel).toBe('hash');
expect(result.config.learning.pretrainedPatterns).toBe(false);
expect(result.config.hooks.claudeCode).toBe(false);
expect(result.config.workers.daemonAutoStart).toBe(false);
});
it('should handle disabled learning mode', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
wizardAnswers: {
'learning-mode': 'disabled',
},
});
const result = await orchestrator.initialize();
expect(result.success).toBe(true);
expect(result.config.learning.enabled).toBe(false);
});
it('should load pretrained patterns when provided', async () => {
// Create realistic pretrained library with actual patterns grouped by domain
const testPatterns = Array.from({ length: 50 }, (_, i) => ({
id: `pattern-${i}`,
domain: i < 25 ? 'test-generation' : 'test-execution',
type: 'unit',
content: 'describe("test", () => { it("should work", () => {}) })',
metadata: {
language: 'typescript',
framework: 'vitest',
confidence: 0.9,
usageCount: 10,
successRate: 0.95,
},
}));
const pretrainedLibrary: PretrainedLibrary = {
version: '1.0.0',
exportedFrom: 'test-suite',
exportDate: new Date().toISOString(),
patterns: testPatterns,
statistics: {
totalPatterns: 50,
byDomain: {
'test-generation': 25,
'test-execution': 25,
},
byLanguage: { typescript: 50 },
averageConfidence: 0.9,
},
};
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
pretrainedLibrary,
});
const result = await orchestrator.initialize();
expect(result.success).toBe(true);
expect(result.summary.patternsLoaded).toBe(50);
});
it('should skip patterns when requested', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
skipPatterns: true,
});
const result = await orchestrator.initialize();
expect(result.success).toBe(true);
expect(result.summary.patternsLoaded).toBe(0);
});
it('should start workers based on config', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
expect(result.success).toBe(true);
// Workers started should match enabled workers count
expect(result.summary.workersStarted).toBeGreaterThanOrEqual(0);
});
});
describe('quickInit', () => {
it('should perform quick initialization', async () => {
mockExistsSync.mockImplementation((path: string) => {
return path.includes('package.json');
});
const result = await quickInit(testProjectRoot);
expect(result.success).toBe(true);
expect(result.config).toBeDefined();
expect(result.steps.length).toBeGreaterThan(0);
});
it('should use auto mode', async () => {
const result = await quickInit(testProjectRoot);
expect(result.success).toBe(true);
// Auto mode generates config based on analysis
expect(result.config.project.name).toBeDefined();
});
});
describe('formatInitResult', () => {
it('should format successful result', () => {
const result: InitResult = {
success: true,
config: {
version: '3.0.0',
project: {
name: 'test-project',
root: '/test/project',
type: 'single',
},
learning: {
enabled: true,
embeddingModel: 'transformer',
hnswConfig: { M: 16, efConstruction: 200, efSearch: 100 },
qualityThreshold: 0.7,
promotionThreshold: 3,
pretrainedPatterns: true,
},
routing: {
mode: 'hybrid',
confidenceThreshold: 0.7,
fallbackEnabled: true,
},
workers: {
enabled: ['pattern-consolidator'],
intervals: {},
maxConcurrent: 4,
daemonAutoStart: true,
},
hooks: {
claudeCode: true,
preCommit: false,
ciIntegration: false,
},
autoTuning: {
enabled: true,
parameters: [],
evaluationPeriodMs: 60000,
},
domains: {
enabled: ['test-generation'],
disabled: [],
},
agents: {
maxConcurrent: 8,
defaultTimeout: 60000,
},
},
steps: [
{ step: 'Project Analysis', status: 'success', message: 'Done', durationMs: 50 },
{ step: 'Configuration Generation', status: 'success', message: 'Done', durationMs: 10 },
],
summary: {
projectAnalyzed: true,
configGenerated: true,
patternsLoaded: 100,
skillsInstalled: 64,
agentsInstalled: 59,
hooksConfigured: true,
mcpConfigured: true,
claudeMdGenerated: true,
workersStarted: 2,
},
totalDurationMs: 200,
timestamp: new Date(),
};
const formatted = formatInitResult(result);
expect(formatted).toContain('AQE v3 Initialization');
expect(formatted).toContain('test-project');
expect(formatted).toContain('single');
expect(formatted).toContain('100'); // patterns loaded
expect(formatted).toContain('59'); // agents installed
expect(formatted).toContain('MCP Server'); // MCP configured
expect(formatted).toContain('initialized');
});
it('should format failed result', () => {
const result: InitResult = {
success: false,
config: {
version: '3.0.0',
project: {
name: 'unknown',
root: '/test/project',
type: 'single',
},
learning: {
enabled: true,
embeddingModel: 'hash',
hnswConfig: { M: 16, efConstruction: 200, efSearch: 100 },
qualityThreshold: 0.7,
promotionThreshold: 3,
pretrainedPatterns: true,
},
routing: {
mode: 'rules',
confidenceThreshold: 0.7,
fallbackEnabled: true,
},
workers: {
enabled: [],
intervals: {},
maxConcurrent: 4,
daemonAutoStart: false,
},
hooks: {
claudeCode: false,
preCommit: false,
ciIntegration: false,
},
autoTuning: {
enabled: false,
parameters: [],
evaluationPeriodMs: 60000,
},
domains: {
enabled: [],
disabled: [],
},
agents: {
maxConcurrent: 5,
defaultTimeout: 60000,
},
},
steps: [
{ step: 'Project Analysis', status: 'error', message: 'Failed to read', durationMs: 10 },
],
summary: {
projectAnalyzed: false,
configGenerated: false,
patternsLoaded: 0,
skillsInstalled: 0,
agentsInstalled: 0,
hooksConfigured: false,
mcpConfigured: false,
claudeMdGenerated: false,
workersStarted: 0,
},
totalDurationMs: 50,
timestamp: new Date(),
};
const formatted = formatInitResult(result);
expect(formatted).toContain('AQE v3 Initialization');
expect(formatted).toContain('failed');
});
it('should include step timing', () => {
const result: InitResult = {
success: true,
config: {
version: '3.0.0',
project: { name: 'test', root: '/test', type: 'single' },
learning: {
enabled: true,
embeddingModel: 'hash',
hnswConfig: { M: 16, efConstruction: 200, efSearch: 100 },
qualityThreshold: 0.7,
promotionThreshold: 3,
pretrainedPatterns: true,
},
routing: { mode: 'rules', confidenceThreshold: 0.7, fallbackEnabled: true },
workers: { enabled: [], intervals: {}, maxConcurrent: 4, daemonAutoStart: false },
hooks: { claudeCode: false, preCommit: false, ciIntegration: false },
autoTuning: { enabled: false, parameters: [], evaluationPeriodMs: 60000 },
domains: { enabled: [], disabled: [] },
agents: { maxConcurrent: 5, defaultTimeout: 60000 },
},
steps: [
{ step: 'Step 1', status: 'success', message: 'Done', durationMs: 123 },
],
summary: {
projectAnalyzed: true,
configGenerated: true,
patternsLoaded: 0,
skillsInstalled: 0,
agentsInstalled: 0,
hooksConfigured: false,
mcpConfigured: false,
claudeMdGenerated: false,
workersStarted: 0,
},
totalDurationMs: 123,
timestamp: new Date(),
};
const formatted = formatInitResult(result);
expect(formatted).toContain('123ms');
});
});
describe('Error Handling', () => {
it('should handle analysis errors gracefully', async () => {
mockExistsSync.mockImplementation(() => {
throw new Error('Permission denied');
});
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
expect(result.success).toBe(false);
expect(result.steps.some((s) => s.status === 'error')).toBe(true);
});
it('should include error message in failed steps', async () => {
mockExistsSync.mockImplementation(() => {
throw new Error('Test error message');
});
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
expect(result.success).toBe(false);
const errorStep = result.steps.find((s) => s.status === 'error');
expect(errorStep?.message).toContain('Test error message');
});
});
describe('Real Implementation File Operations', () => {
it('should create .agentic-qe directory and config.yaml', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
// Verify mkdirSync was called for .agentic-qe
expect(mockMkdirSync).toHaveBeenCalled();
const mkdirCalls = mockMkdirSync.mock.calls;
const configDirCall = mkdirCalls.find((call) =>
(call[0] as string).includes('.agentic-qe')
);
expect(configDirCall).toBeDefined();
// Verify writeFileSync was called for config.yaml
expect(mockWriteFileSync).toHaveBeenCalled();
const writeCalls = mockWriteFileSync.mock.calls;
const configYamlCall = writeCalls.find((call) =>
(call[0] as string).includes('config.yaml')
);
expect(configYamlCall).toBeDefined();
expect(configYamlCall![1]).toContain('version: "3.0.0"');
expect(configYamlCall![1]).toContain('project:');
});
it('should create .claude/settings.json with hooks', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
// Verify writeFileSync was called for settings.json
const writeCalls = mockWriteFileSync.mock.calls;
const settingsCall = writeCalls.find((call) =>
(call[0] as string).includes('settings.json')
);
expect(settingsCall).toBeDefined();
// Parse and verify the settings content
const settingsContent = JSON.parse(settingsCall![1] as string);
expect(settingsContent.hooks).toBeDefined();
expect(settingsContent.hooks.PreToolUse).toBeDefined();
expect(settingsContent.hooks.PostToolUse).toBeDefined();
expect(settingsContent.hooks.SessionStart).toBeDefined();
expect(settingsContent.hooks.Stop).toBeDefined(); // Claude Code uses 'Stop' for session end
expect(settingsContent.aqe).toBeDefined();
expect(settingsContent.aqe.hooksConfigured).toBe(true);
});
it('should create learning system directories and config', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
// Verify data and hnsw directories created
const mkdirCalls = mockMkdirSync.mock.calls;
const dataDirCall = mkdirCalls.find((call) =>
(call[0] as string).includes('data')
);
expect(dataDirCall).toBeDefined();
const hnswDirCall = mkdirCalls.find((call) =>
(call[0] as string).includes('hnsw')
);
expect(hnswDirCall).toBeDefined();
// Verify learning-config.json written
const writeCalls = mockWriteFileSync.mock.calls;
const learningConfigCall = writeCalls.find((call) =>
(call[0] as string).includes('learning-config.json')
);
expect(learningConfigCall).toBeDefined();
const learningConfig = JSON.parse(learningConfigCall![1] as string);
expect(learningConfig.embeddingModel).toBeDefined();
expect(learningConfig.hnswConfig).toBeDefined();
expect(learningConfig.databasePath).toContain('memory.db');
});
it('should create worker registry and configs', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
// Verify workers directory created
const mkdirCalls = mockMkdirSync.mock.calls;
const workersDirCall = mkdirCalls.find((call) =>
(call[0] as string).includes('workers')
);
expect(workersDirCall).toBeDefined();
// Verify registry.json written
const writeCalls = mockWriteFileSync.mock.calls;
const registryCall = writeCalls.find((call) =>
(call[0] as string).includes('registry.json')
);
expect(registryCall).toBeDefined();
const registry = JSON.parse(registryCall![1] as string);
expect(registry.version).toBe('3.0.0');
expect(registry.workers).toBeDefined();
expect(registry.maxConcurrent).toBeDefined();
});
it('should write pretrained patterns to domain directories', async () => {
const testPatterns = [
{
id: 'p1',
domain: 'test-generation',
type: 'unit',
content: 'test pattern 1',
metadata: { confidence: 0.9, usageCount: 5, successRate: 0.95 },
},
{
id: 'p2',
domain: 'test-generation',
type: 'integration',
content: 'test pattern 2',
metadata: { confidence: 0.85, usageCount: 3, successRate: 0.9 },
},
];
const pretrainedLibrary: PretrainedLibrary = {
version: '1.0.0',
exportedFrom: 'test-suite',
exportDate: new Date().toISOString(),
patterns: testPatterns,
statistics: {
totalPatterns: 2,
byDomain: { 'test-generation': 2 },
byLanguage: {},
averageConfidence: 0.875,
},
};
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
pretrainedLibrary,
});
await orchestrator.initialize();
// Verify pattern directory created for the domain
const mkdirCalls = mockMkdirSync.mock.calls;
const patternDirCall = mkdirCalls.find((call) =>
(call[0] as string).includes('patterns/test-generation')
);
expect(patternDirCall).toBeDefined();
// Verify patterns.json written
const writeCalls = mockWriteFileSync.mock.calls;
const patternsCall = writeCalls.find((call) =>
(call[0] as string).includes('patterns.json')
);
expect(patternsCall).toBeDefined();
const patterns = JSON.parse(patternsCall![1] as string);
expect(patterns).toHaveLength(2);
expect(patterns[0].id).toBe('p1');
});
it('should not write hooks when claudeCode is disabled', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
wizardAnswers: {
hooks: false,
},
});
await orchestrator.initialize();
// Verify settings.json was NOT written
const writeCalls = mockWriteFileSync.mock.calls;
const settingsCall = writeCalls.find((call) =>
(call[0] as string).includes('settings.json')
);
expect(settingsCall).toBeUndefined();
});
it('should not write worker configs when daemonAutoStart is disabled', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
wizardAnswers: {
workers: false,
},
});
await orchestrator.initialize();
// Verify registry.json was NOT written
const writeCalls = mockWriteFileSync.mock.calls;
const registryCall = writeCalls.find((call) =>
(call[0] as string).includes('registry.json')
);
expect(registryCall).toBeUndefined();
});
it('should create CLAUDE.md with AQE v3 section', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
// Verify CLAUDE.md was written
const writeCalls = mockWriteFileSync.mock.calls;
const claudeMdCall = writeCalls.find((call) =>
(call[0] as string).includes('CLAUDE.md')
);
expect(claudeMdCall).toBeDefined();
// Verify content includes expected sections
const content = claudeMdCall![1] as string;
expect(content).toContain('Agentic QE v3');
expect(content).toContain('MCP Server');
expect(content).toContain('12 DDD Domains');
expect(content).toContain('V3 QE Agents');
expect(content).toContain('Data Storage');
expect(content).toContain('memory.db');
});
it('should append to existing CLAUDE.md with backup', async () => {
// Simulate existing CLAUDE.md
mockExistsSync.mockImplementation((path: string) => {
if (path.includes('CLAUDE.md') && !path.includes('.backup')) return true;
if (path.includes('package.json')) return true;
return false;
});
mockReadFileSync.mockImplementation((path: string) => {
if (path.includes('CLAUDE.md')) {
return '# Existing CLAUDE.md\n\nSome existing content here.';
}
if (path.includes('package.json')) {
return JSON.stringify({ name: 'test-project' });
}
return '';
});
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
const writeCalls = mockWriteFileSync.mock.calls;
// Verify backup was created
const backupCall = writeCalls.find((call) =>
(call[0] as string).includes('CLAUDE.md.backup')
);
expect(backupCall).toBeDefined();
expect(backupCall![1]).toBe('# Existing CLAUDE.md\n\nSome existing content here.');
// Verify CLAUDE.md was appended to
const claudeMdCall = writeCalls.find((call) =>
(call[0] as string).includes('CLAUDE.md') && !(call[0] as string).includes('.backup')
);
expect(claudeMdCall).toBeDefined();
const content = claudeMdCall![1] as string;
// Should contain existing content
expect(content).toContain('# Existing CLAUDE.md');
expect(content).toContain('Some existing content');
// Should contain AQE section
expect(content).toContain('Agentic QE v3');
});
it('should not duplicate AQE section in CLAUDE.md', async () => {
// Simulate existing CLAUDE.md that already has AQE section
mockExistsSync.mockImplementation((path: string) => {
if (path.includes('CLAUDE.md')) return true;
if (path.includes('package.json')) return true;
return false;
});
mockReadFileSync.mockImplementation((path: string) => {
if (path.includes('CLAUDE.md')) {
return '# Existing CLAUDE.md\n\n## Agentic QE v3\n\nAlready has section.';
}
if (path.includes('package.json')) {
return JSON.stringify({ name: 'test-project' });
}
return '';
});
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
const result = await orchestrator.initialize();
// Should still succeed - just won't duplicate
expect(result.summary.claudeMdGenerated).toBe(true);
});
it('should create .claude/mcp.json with AQE v3 server', async () => {
const orchestrator = createInitOrchestrator({
projectRoot: testProjectRoot,
autoMode: true,
});
await orchestrator.initialize();
// Verify mcp.json was written
const writeCalls = mockWriteFileSync.mock.calls;
const mcpCall = writeCalls.find((call) =>
(call[0] as string).includes('mcp.json')
);
expect(mcpCall).toBeDefined();
// Verify content
const mcpConfig = JSON.parse(mcpCall![1] as string);
expect(mcpConfig.mcpServers).toBeDefined();
expect(mcpConfig.mcpServers['agentic-qe']).toBeDefined();
expect(mcpConfig.mcpServers['agentic-qe'].command).toBe('npx');
expect(mcpConfig.mcpServers['agentic-qe'].args).toEqual(['@anthropics/agentic-qe', 'mcp', 'start']);
});
});
});