242 lines
10 KiB
JavaScript
242 lines
10 KiB
JavaScript
/**
|
|
* skill-integration.test.js - Integration tests for .agents skills
|
|
* Part of LCBP3-DMS Phase 3 enhancements
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { execSync } = require('child_process');
|
|
|
|
// Test configuration
|
|
const BASE_DIR = path.resolve(__dirname, '..');
|
|
const AGENTS_DIR = path.join(BASE_DIR, '.agents');
|
|
const SKILLS_DIR = path.join(AGENTS_DIR, 'skills');
|
|
const WORKFLOWS_DIR = path.join(BASE_DIR, '.windsurf', 'workflows');
|
|
|
|
// Test utilities
|
|
class SkillTestSuite {
|
|
constructor() {
|
|
this.results = {
|
|
passed: 0,
|
|
failed: 0,
|
|
errors: []
|
|
};
|
|
}
|
|
|
|
log(message, type = 'info') {
|
|
const colors = {
|
|
info: '\x1b[36m', // Cyan
|
|
pass: '\x1b[32m', // Green
|
|
fail: '\x1b[31m', // Red
|
|
warn: '\x1b[33m', // Yellow
|
|
reset: '\x1b[0m'
|
|
};
|
|
|
|
const color = colors[type] || colors.info;
|
|
console.log(`${color}${message}${colors.reset}`);
|
|
}
|
|
|
|
assert(condition, message) {
|
|
if (condition) {
|
|
this.log(` PASS: ${message}`, 'pass');
|
|
this.results.passed++;
|
|
return true;
|
|
} else {
|
|
this.log(` FAIL: ${message}`, 'fail');
|
|
this.results.failed++;
|
|
this.results.errors.push(message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
testDirectoryExists(dirPath, description) {
|
|
const exists = fs.existsSync(dirPath);
|
|
this.assert(exists, `${description} exists at ${dirPath}`);
|
|
return exists;
|
|
}
|
|
|
|
testFileExists(filePath, description) {
|
|
const exists = fs.existsSync(filePath);
|
|
this.assert(exists, `${description} exists at ${filePath}`);
|
|
return exists;
|
|
}
|
|
|
|
testFileContent(filePath, pattern, description) {
|
|
if (!fs.existsSync(filePath)) {
|
|
this.assert(false, `${description} - file not found: ${filePath}`);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
const matches = content.match(pattern);
|
|
this.assert(matches !== null, `${description} - pattern found in ${filePath}`);
|
|
return matches !== null;
|
|
} catch (error) {
|
|
this.assert(false, `${description} - error reading file: ${error.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
runScript(scriptPath, description) {
|
|
try {
|
|
const output = execSync(scriptPath, { encoding: 'utf8', cwd: BASE_DIR });
|
|
this.log(` SCRIPT: ${description} executed successfully`, 'pass');
|
|
return { success: true, output };
|
|
} catch (error) {
|
|
this.log(` SCRIPT: ${description} failed - ${error.message}`, 'fail');
|
|
this.results.failed++;
|
|
this.results.errors.push(`${description}: ${error.message}`);
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test suite implementation
|
|
const testSuite = new SkillTestSuite();
|
|
|
|
function runAllTests() {
|
|
testSuite.log('=== .agents Integration Test Suite ===', 'info');
|
|
testSuite.log(`Base directory: ${BASE_DIR}`, 'info');
|
|
testSuite.log(`Started: ${new Date().toISOString()}`, 'info');
|
|
testSuite.log('');
|
|
|
|
// Test 1: Directory Structure
|
|
testSuite.log('Test 1: Directory Structure', 'info');
|
|
testSuite.testDirectoryExists(AGENTS_DIR, '.agents directory');
|
|
testSuite.testDirectoryExists(SKILLS_DIR, 'skills directory');
|
|
testSuite.testDirectoryExists(WORKFLOWS_DIR, 'workflows directory');
|
|
testSuite.testDirectoryExists(path.join(AGENTS_DIR, 'scripts'), 'scripts directory');
|
|
testSuite.testDirectoryExists(path.join(AGENTS_DIR, 'rules'), 'rules directory');
|
|
testSuite.log('');
|
|
|
|
// Test 2: Core Files
|
|
testSuite.log('Test 2: Core Files', 'info');
|
|
testSuite.testFileExists(path.join(AGENTS_DIR, 'README.md'), 'README.md');
|
|
testSuite.testFileExists(path.join(SKILLS_DIR, 'VERSION'), 'skills VERSION file');
|
|
testSuite.testFileExists(path.join(SKILLS_DIR, 'skills.md'), 'skills.md documentation');
|
|
testSuite.log('');
|
|
|
|
// Test 3: Script Files
|
|
testSuite.log('Test 3: Validation Scripts', 'info');
|
|
testSuite.testFileExists(path.join(AGENTS_DIR, 'scripts', 'bash', 'validate-versions.sh'), 'bash validate-versions.sh');
|
|
testSuite.testFileExists(path.join(AGENTS_DIR, 'scripts', 'bash', 'audit-skills.sh'), 'bash audit-skills.sh');
|
|
testSuite.testFileExists(path.join(AGENTS_DIR, 'scripts', 'bash', 'sync-workflows.sh'), 'bash sync-workflows.sh');
|
|
testSuite.testFileExists(path.join(AGENTS_DIR, 'scripts', 'powershell', 'validate-versions.ps1'), 'powershell validate-versions.ps1');
|
|
testSuite.testFileExists(path.join(AGENTS_DIR, 'scripts', 'powershell', 'audit-skills.ps1'), 'powershell audit-skills.ps1');
|
|
testSuite.log('');
|
|
|
|
// Test 4: Version Consistency
|
|
testSuite.log('Test 4: Version Consistency', 'info');
|
|
testSuite.testFileContent(path.join(AGENTS_DIR, 'README.md'), /v1\.8\.6/, 'README.md version');
|
|
testSuite.testFileContent(path.join(SKILLS_DIR, 'VERSION'), /version: 1\.8\.6/, 'skills VERSION file');
|
|
testSuite.testFileContent(path.join(SKILLS_DIR, 'skills.md'), /v1\.8\.6/, 'skills.md version');
|
|
testSuite.testFileContent(path.join(AGENTS_DIR, 'rules', '00-project-context.md'), /v1\.8\.6/, 'project context version');
|
|
testSuite.log('');
|
|
|
|
// Test 5: Skills Structure
|
|
testSuite.log('Test 5: Skills Structure', 'info');
|
|
const skillDirs = fs.readdirSync(SKILLS_DIR).filter(item => {
|
|
const itemPath = path.join(SKILLS_DIR, item);
|
|
return fs.statSync(itemPath).isDirectory() && item.startsWith('speckit-') || item === 'nestjs-best-practices' || item === 'next-best-practices';
|
|
});
|
|
|
|
testSuite.assert(skillDirs.length >= 20, `Found at least 20 skill directories (found ${skillDirs.length})`);
|
|
|
|
// Test a few key skills
|
|
const keySkills = ['speckit-plan', 'speckit-implement', 'speckit-specify', 'speckit-validate'];
|
|
keySkills.forEach(skill => {
|
|
const skillPath = path.join(SKILLS_DIR, skill);
|
|
const skillMdPath = path.join(skillPath, 'SKILL.md');
|
|
testSuite.testDirectoryExists(skillPath, `${skill} directory`);
|
|
testSuite.testFileExists(skillMdPath, `${skill} SKILL.md`);
|
|
|
|
if (fs.existsSync(skillMdPath)) {
|
|
testSuite.testFileContent(skillMdPath, /^name:/, `${skill} has name field`);
|
|
testSuite.testFileContent(skillMdPath, /^description:/, `${skill} has description field`);
|
|
testSuite.testFileContent(skillMdPath, /^version:/, `${skill} has version field`);
|
|
testSuite.testFileContent(skillMdPath, /^## Role$/, `${skill} has Role section`);
|
|
testSuite.testFileContent(skillMdPath, /^## Task$/, `${skill} has Task section`);
|
|
}
|
|
});
|
|
testSuite.log('');
|
|
|
|
// Test 6: Workflows Structure
|
|
testSuite.log('Test 6: Workflows Structure', 'info');
|
|
const workflowFiles = fs.readdirSync(WORKFLOWS_DIR).filter(item => item.endsWith('.md'));
|
|
testSuite.assert(workflowFiles.length >= 20, `Found at least 20 workflow files (found ${workflowFiles.length})`);
|
|
|
|
// Test key workflows
|
|
const keyWorkflows = ['00-speckit.all.md', '02-speckit.specify.md', '04-speckit.plan.md', '07-speckit.implement.md'];
|
|
keyWorkflows.forEach(workflow => {
|
|
const workflowPath = path.join(WORKFLOWS_DIR, workflow);
|
|
testSuite.testFileExists(workflowPath, `${workflow} file`);
|
|
});
|
|
testSuite.log('');
|
|
|
|
// Test 7: Rules Structure
|
|
testSuite.log('Test 7: Rules Structure', 'info');
|
|
const rulesDir = path.join(AGENTS_DIR, 'rules');
|
|
const ruleFiles = fs.readdirSync(rulesDir).filter(item => item.endsWith('.md'));
|
|
testSuite.assert(ruleFiles.length >= 10, `Found at least 10 rule files (found ${ruleFiles.length})`);
|
|
|
|
// Test key rules
|
|
const keyRules = ['00-project-context.md', '01-adr-019-uuid.md', '02-security.md'];
|
|
keyRules.forEach(rule => {
|
|
const rulePath = path.join(rulesDir, rule);
|
|
testSuite.testFileExists(rulePath, `${rule} file`);
|
|
});
|
|
testSuite.log('');
|
|
|
|
// Test 8: Script Execution (if on Unix-like system)
|
|
if (process.platform !== 'win32') {
|
|
testSuite.log('Test 8: Script Execution', 'info');
|
|
|
|
// Test version validation script
|
|
const versionScript = path.join(AGENTS_DIR, 'scripts', 'bash', 'validate-versions.sh');
|
|
if (fs.existsSync(versionScript)) {
|
|
try {
|
|
// Make executable
|
|
fs.chmodSync(versionScript, '755');
|
|
testSuite.runScript(versionScript, 'Version validation script');
|
|
} catch (error) {
|
|
testSuite.log(` SKIP: Cannot execute version script - ${error.message}`, 'warn');
|
|
}
|
|
}
|
|
|
|
testSuite.log('');
|
|
}
|
|
|
|
// Test 9: Documentation Quality
|
|
testSuite.log('Test 9: Documentation Quality', 'info');
|
|
testSuite.testFileContent(path.join(AGENTS_DIR, 'README.md'), /## Troubleshooting/, 'README.md has troubleshooting section');
|
|
testSuite.testFileContent(path.join(SKILLS_DIR, 'skills.md'), /## Skill Dependency Matrix/, 'skills.md has dependency matrix');
|
|
testSuite.testFileContent(path.join(AGENTS_DIR, 'README.md'), /## Architecture/, 'README.md has architecture section');
|
|
testSuite.log('');
|
|
|
|
// Results Summary
|
|
testSuite.log('=== Test Results Summary ===', 'info');
|
|
testSuite.log(`Passed: ${testSuite.results.passed}`, 'pass');
|
|
testSuite.log(`Failed: ${testSuite.results.failed}`, testSuite.results.failed > 0 ? 'fail' : 'pass');
|
|
|
|
if (testSuite.results.errors.length > 0) {
|
|
testSuite.log('Errors:', 'fail');
|
|
testSuite.results.errors.forEach(error => {
|
|
testSuite.log(` - ${error}`, 'fail');
|
|
});
|
|
}
|
|
|
|
testSuite.log(`Completed: ${new Date().toISOString()}`, 'info');
|
|
|
|
return testSuite.results.failed === 0;
|
|
}
|
|
|
|
// Export for use in other modules
|
|
module.exports = { SkillTestSuite, runAllTests };
|
|
|
|
// Run tests if called directly
|
|
if (require.main === module) {
|
|
const success = runAllTests();
|
|
process.exit(success ? 0 : 1);
|
|
}
|