Files
proffesor-for-testing__agen…/tests/unit/init/config-preservation.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

244 lines
7.7 KiB
TypeScript

/**
* Test: Config Preservation on Reinstall
* Issue #206: Config overwritten on reinstall
*
* Verifies that user customizations in config.yaml are preserved
* when running `aqe init` again.
*/
import { describe, it, expect } from 'vitest';
import { VerificationPhase } from '../../../src/init/phases/12-verification.js';
describe('Config Preservation (Issue #206)', () => {
// Create instance to access private methods via any
const phase = new VerificationPhase() as any;
describe('parseYAML', () => {
it('should parse basic config YAML', () => {
const yaml = `
# Agentic QE v3 Configuration
version: "3.3.0"
project:
name: "test-project"
type: "single"
learning:
enabled: true
domains:
enabled:
- "test-generation"
- "coverage-analysis"
- "visual-accessibility"
disabled:
- "chaos-resilience"
`;
const result = phase.parseYAML(yaml);
expect(result).toBeDefined();
expect(result.version).toBe('3.3.0');
expect(result.project?.name).toBe('test-project');
expect(result.learning?.enabled).toBe(true);
expect(result.domains?.enabled).toContain('visual-accessibility');
expect(result.domains?.disabled).toContain('chaos-resilience');
});
it('should return [] not {} for empty array fields (Issue #244)', () => {
const yaml = `
domains:
enabled:
- "test-generation"
disabled:
workers:
enabled:
`;
const result = phase.parseYAML(yaml);
// disabled: with no items must be [] not {}
expect(Array.isArray(result.domains?.disabled)).toBe(true);
expect(result.domains?.disabled).toEqual([]);
// workers.enabled: with no items must be [] not {}
expect(Array.isArray(result.workers?.enabled)).toBe(true);
expect(result.workers?.enabled).toEqual([]);
// enabled with items should still work
expect(result.domains?.enabled).toContain('test-generation');
});
it('should parse numeric and boolean values correctly', () => {
const yaml = `
agents:
maxConcurrent: 10
defaultTimeout: 60000
workers:
daemonAutoStart: false
`;
const result = phase.parseYAML(yaml);
expect(result.agents?.maxConcurrent).toBe(10);
expect(result.agents?.defaultTimeout).toBe(60000);
expect(result.workers?.daemonAutoStart).toBe(false);
});
});
describe('mergeConfigs', () => {
const createBaseConfig = () => ({
version: '3.3.0',
project: { name: 'test', root: '/test', type: 'single' as const },
learning: {
enabled: true,
embeddingModel: 'transformer' as const,
hnswConfig: { M: 8, efConstruction: 100, efSearch: 50 },
qualityThreshold: 0.5,
promotionThreshold: 2,
pretrainedPatterns: true,
},
routing: { mode: 'ml' as const, confidenceThreshold: 0.7, feedbackEnabled: true },
workers: {
enabled: ['pattern-consolidator'],
intervals: {},
maxConcurrent: 2,
daemonAutoStart: true,
},
hooks: { claudeCode: true, preCommit: false, ciIntegration: false },
skills: { install: true, installV2: true, installV3: true, overwrite: false },
autoTuning: { enabled: true, parameters: [], evaluationPeriodMs: 3600000 },
domains: {
enabled: ['test-generation', 'coverage-analysis'],
disabled: [],
},
agents: { maxConcurrent: 5, defaultTimeout: 60000 },
});
it('should preserve custom enabled domains (Issue #206 - visual-accessibility)', () => {
const newConfig = createBaseConfig();
const existing = {
domains: {
enabled: ['test-generation', 'coverage-analysis', 'visual-accessibility'],
disabled: [],
},
};
const result = phase.mergeConfigs(newConfig, existing);
expect(result.domains.enabled).toContain('visual-accessibility');
expect(result.domains.enabled).toContain('test-generation');
expect(result.domains.enabled).toContain('coverage-analysis');
});
it('should add new default domains while preserving custom ones', () => {
const newConfig = createBaseConfig();
newConfig.domains.enabled = ['test-generation', 'coverage-analysis', 'NEW-DOMAIN'];
const existing = {
domains: {
enabled: ['test-generation', 'visual-accessibility'],
disabled: [],
},
};
const result = phase.mergeConfigs(newConfig, existing);
// Should have all: existing custom + new defaults
expect(result.domains.enabled).toContain('visual-accessibility'); // preserved custom
expect(result.domains.enabled).toContain('NEW-DOMAIN'); // added new default
expect(result.domains.enabled).toContain('test-generation'); // existing
});
it('should respect disabled domains when merging', () => {
const newConfig = createBaseConfig();
const existing = {
domains: {
enabled: ['test-generation', 'visual-accessibility'],
disabled: ['coverage-analysis'], // user explicitly disabled this
},
};
const result = phase.mergeConfigs(newConfig, existing);
expect(result.domains.enabled).not.toContain('coverage-analysis');
expect(result.domains.disabled).toContain('coverage-analysis');
});
it('should handle non-array disabled field without crashing (Issue #244)', () => {
const newConfig = createBaseConfig();
// Simulate the bug: parser returned {} for disabled
const existing = {
domains: {
enabled: ['test-generation'],
disabled: {} as unknown as string[],
},
};
// Should not throw TypeError: object is not iterable
const result = phase.mergeConfigs(newConfig, existing);
expect(result.domains.enabled).toContain('test-generation');
// disabled should remain as newConfig default since existing was invalid
expect(Array.isArray(result.domains.disabled)).toBe(true);
});
it('should preserve learning.enabled preference', () => {
const newConfig = createBaseConfig();
newConfig.learning.enabled = true;
const existing = {
learning: { enabled: false }, // user disabled learning
};
const result = phase.mergeConfigs(newConfig, existing);
expect(result.learning.enabled).toBe(false);
});
it('should preserve hooks preferences', () => {
const newConfig = createBaseConfig();
const existing = {
hooks: {
claudeCode: false, // user disabled
preCommit: true, // user enabled
},
};
const result = phase.mergeConfigs(newConfig, existing);
expect(result.hooks.claudeCode).toBe(false);
expect(result.hooks.preCommit).toBe(true);
});
it('should preserve agent limits', () => {
const newConfig = createBaseConfig();
const existing = {
agents: {
maxConcurrent: 20, // user increased
defaultTimeout: 120000, // user increased
},
};
const result = phase.mergeConfigs(newConfig, existing);
expect(result.agents.maxConcurrent).toBe(20);
expect(result.agents.defaultTimeout).toBe(120000);
});
it('should preserve worker preferences', () => {
const newConfig = createBaseConfig();
const existing = {
workers: {
enabled: ['pattern-consolidator', 'coverage-gap-scanner'],
daemonAutoStart: false,
},
};
const result = phase.mergeConfigs(newConfig, existing);
expect(result.workers.enabled).toContain('coverage-gap-scanner');
expect(result.workers.daemonAutoStart).toBe(false);
});
});
});