@iservu-inc/adf-cli
Version:
CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support
199 lines (158 loc) • 7.16 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const { SkipTracker, analyzeSkipPatterns } = require('../lib/learning/skip-tracker');
describe('Skip Tracker', () => {
const tempDir = path.join(__dirname, 'temp-skip-tracker-test');
beforeEach(async () => {
await fs.ensureDir(tempDir);
});
afterEach(async () => {
await fs.remove(tempDir);
});
describe('SkipTracker', () => {
test('should initialize with project metadata', () => {
const tracker = new SkipTracker(tempDir, {
projectType: 'cli-tool',
frameworks: ['commander'],
languages: ['JavaScript']
});
expect(tracker.projectPath).toBe(tempDir);
expect(tracker.sessionData.projectType).toBe('cli-tool');
expect(tracker.sessionData.frameworks).toContain('commander');
expect(tracker.sessionId).toBeTruthy();
});
test('should record skip events', () => {
const tracker = new SkipTracker(tempDir, { projectType: 'web-app' });
const question = {
id: 'q1',
text: 'What is your deployment strategy?',
category: 'deployment',
phase: 'architecture'
};
tracker.recordSkip(question, 'manual');
expect(tracker.sessionData.skips.length).toBe(1);
expect(tracker.sessionData.skips[0].questionId).toBe('q1');
expect(tracker.sessionData.skips[0].reason).toBe('manual');
expect(tracker.sessionData.skips[0].category).toBe('deployment');
});
test('should record answer events', () => {
const tracker = new SkipTracker(tempDir, { projectType: 'api-server' });
const question = {
id: 'q1',
text: 'What database will you use?',
category: 'backend'
};
tracker.recordAnswer(question, 'PostgreSQL with TypeORM', {
qualityScore: 85,
richness: 'comprehensive'
});
expect(tracker.sessionData.answers.length).toBe(1);
expect(tracker.sessionData.answers[0].questionId).toBe('q1');
expect(tracker.sessionData.answers[0].wordCount).toBe(3);
expect(tracker.sessionData.answers[0].qualityScore).toBe(85);
});
test('should track time spent on questions', async () => {
const tracker = new SkipTracker(tempDir, { projectType: 'web-app' });
const question = { id: 'q1', text: 'Test question' };
tracker.startQuestion('q1');
await new Promise(resolve => setTimeout(resolve, 100)); // Wait 100ms
const timeSpent = tracker.getTimeSpent('q1');
expect(timeSpent).toBeGreaterThan(0);
expect(timeSpent).toBeLessThan(1); // Should be fraction of a second
});
test('should record filtered questions in bulk', () => {
const tracker = new SkipTracker(tempDir, { projectType: 'cli-tool' });
const filteredQuestions = [
{ id: 'q1', text: 'Question 1', category: 'frontend' },
{ id: 'q2', text: 'Question 2', category: 'ui' }
];
tracker.recordFilteredQuestions(filteredQuestions);
expect(tracker.sessionData.skips.length).toBe(2);
expect(tracker.sessionData.skips.every(s => s.reason === 'filtered')).toBe(true);
});
test('should generate session summary', () => {
const tracker = new SkipTracker(tempDir, { projectType: 'web-app' });
tracker.recordSkip({ id: 'q1', text: 'Q1' }, 'manual');
tracker.recordSkip({ id: 'q2', text: 'Q2' }, 'filtered');
tracker.recordAnswer({ id: 'q3', text: 'Q3' }, 'Answer', {});
const summary = tracker.getSessionSummary();
expect(summary.totalSkips).toBe(2);
expect(summary.manualSkips).toBe(1);
expect(summary.filteredSkips).toBe(1);
expect(summary.totalAnswers).toBe(1);
});
test('should save session data', async () => {
const tracker = new SkipTracker(tempDir, { projectType: 'cli-tool' });
tracker.recordSkip({ id: 'q1', text: 'Test question' }, 'manual');
const result = await tracker.saveSession();
expect(result).toBe(true);
// Verify data was saved
const skipHistoryPath = path.join(tempDir, '.adf', 'learning', 'skip-history.json');
const exists = await fs.pathExists(skipHistoryPath);
expect(exists).toBe(true);
const data = await fs.readJSON(skipHistoryPath);
expect(data.sessions.length).toBe(1);
expect(data.sessions[0].skips.length).toBe(1);
});
});
describe('analyzeSkipPatterns', () => {
test('should return empty analysis for no history', async () => {
const analysis = await analyzeSkipPatterns(tempDir);
expect(analysis.totalSessions).toBe(0);
expect(analysis.totalSkips).toBe(0);
expect(analysis.mostSkippedQuestions).toEqual([]);
});
test('should analyze skip patterns from history', async () => {
// Create mock history
const history = {
version: '1.0',
sessions: [
{
sessionId: 's1',
skips: [
{ questionId: 'q1', text: 'Q1', category: 'deployment', reason: 'manual' },
{ questionId: 'q2', text: 'Q2', category: 'testing', reason: 'manual' }
]
},
{
sessionId: 's2',
skips: [
{ questionId: 'q1', text: 'Q1', category: 'deployment', reason: 'manual' },
{ questionId: 'q3', text: 'Q3', category: 'deployment', reason: 'filtered' }
]
}
]
};
await fs.ensureDir(path.join(tempDir, '.adf', 'learning'));
await fs.writeJSON(path.join(tempDir, '.adf', 'learning', 'skip-history.json'), history);
const analysis = await analyzeSkipPatterns(tempDir);
expect(analysis.totalSessions).toBe(2);
expect(analysis.manualSkips).toBe(3);
expect(analysis.filteredSkips).toBe(1);
expect(analysis.mostSkippedQuestions.length).toBeGreaterThan(0);
expect(analysis.mostSkippedQuestions[0].questionId).toBe('q1'); // Most skipped
expect(analysis.mostSkippedQuestions[0].count).toBe(2);
});
test('should identify most skipped categories', async () => {
const history = {
version: '1.0',
sessions: [
{
sessionId: 's1',
skips: [
{ questionId: 'q1', text: 'Q1', category: 'deployment', reason: 'manual' },
{ questionId: 'q2', text: 'Q2', category: 'deployment', reason: 'manual' },
{ questionId: 'q3', text: 'Q3', category: 'testing', reason: 'manual' }
]
}
]
};
await fs.ensureDir(path.join(tempDir, '.adf', 'learning'));
await fs.writeJSON(path.join(tempDir, '.adf', 'learning', 'skip-history.json'), history);
const analysis = await analyzeSkipPatterns(tempDir);
expect(analysis.mostSkippedCategories.length).toBeGreaterThan(0);
expect(analysis.mostSkippedCategories[0].category).toBe('deployment');
expect(analysis.mostSkippedCategories[0].count).toBe(2);
});
});
});