@iservu-inc/adf-cli
Version:
CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support
327 lines (261 loc) • 10.6 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const CursorGenerator = require('../lib/generators/cursor-generator');
const TEST_PROJECT_PATH = path.join(__dirname, 'test-project-cursor');
const TEST_SESSION_PATH = path.join(TEST_PROJECT_PATH, '.adf', 'sessions', 'test-session');
describe('CursorGenerator', () => {
beforeEach(async () => {
// Clean up test directories
await fs.remove(TEST_PROJECT_PATH);
await fs.ensureDir(TEST_PROJECT_PATH);
await fs.ensureDir(TEST_SESSION_PATH);
await fs.ensureDir(path.join(TEST_SESSION_PATH, 'outputs'));
});
afterEach(async () => {
// Clean up after tests
await fs.remove(TEST_PROJECT_PATH);
});
describe('PRP Framework', () => {
it('should generate Cursor configurations from PRP output', async () => {
// Create mock PRP output
const prpContent = `
Build a React dashboard that displays real-time analytics from PostgreSQL database.
This will help users make data-driven decisions and improve productivity.
- Frontend: React 18, TypeScript
- Backend: Node.js, Express
- Database: PostgreSQL
- src/components/Dashboard/
- src/api/analytics/
1. Fetch data from analytics API
2. Process and aggregate
3. Render charts
- Dashboard loads in <2s
- All charts render correctly
`;
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
prpContent,
'utf-8'
);
// Create metadata
await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
framework: 'rapid',
projectName: 'Test Analytics Dashboard'
});
// Generate Cursor configs
const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
const generated = await generator.generate();
// Verify .cursor/rules was created
const rulesPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
expect(await fs.pathExists(rulesPath)).toBe(true);
const rulesContent = await fs.readFile(rulesPath, 'utf-8');
expect(rulesContent).toContain('Test Analytics Dashboard');
expect(rulesContent).toContain('Cursor Rules');
expect(rulesContent).toContain('Project Goal');
expect(rulesContent).toContain('React dashboard');
expect(rulesContent).toContain('Tech Stack');
expect(rulesContent).toContain('Before Implementing Features');
expect(rulesContent).toContain('.adf/sessions/test-session/outputs/prp.md');
expect(rulesContent).toContain('Code Standards');
expect(rulesContent).toContain('What to Avoid');
// Verify .cursorrules deprecation notice was created
const legacyPath = path.join(TEST_PROJECT_PATH, '.cursorrules');
expect(await fs.pathExists(legacyPath)).toBe(true);
const legacyContent = await fs.readFile(legacyPath, 'utf-8');
expect(legacyContent).toContain('DEPRECATED');
expect(legacyContent).toContain('.cursor/rules');
expect(legacyContent).toContain('Migration');
// Verify generated structure
expect(generated.rules).toHaveLength(1);
expect(generated.legacy).toHaveLength(1);
});
});
describe('Balanced Framework', () => {
it('should generate Cursor configurations from Balanced outputs', async () => {
// Create mock outputs
const constitutionContent = `
1. User privacy is paramount
2. Performance over features
- No third-party analytics
- WCAG 2.1 AA compliance
`;
const specificationContent = `
A comprehensive user management system.
Microservices architecture with API gateway.
`;
const planContent = `
- React 18
- Node.js 20
- PostgreSQL 15
- Use TypeScript strict mode
- Follow Airbnb style guide
- Write tests first
- Document public APIs
`;
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'constitution.md'),
constitutionContent,
'utf-8'
);
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'specification.md'),
specificationContent,
'utf-8'
);
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'plan.md'),
planContent,
'utf-8'
);
await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
framework: 'balanced',
projectName: 'User Management System'
});
// Generate Cursor configs
const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'balanced');
await generator.generate();
// Verify .cursor/rules
const rulesPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
const rulesContent = await fs.readFile(rulesPath, 'utf-8');
expect(rulesContent).toContain('User Management System');
expect(rulesContent).toContain('Core Principles');
expect(rulesContent).toContain('User privacy is paramount');
expect(rulesContent).toContain('Constraints (Non-Negotiable)');
expect(rulesContent).toContain('WCAG 2.1 AA compliance');
expect(rulesContent).toContain('Microservices architecture');
expect(rulesContent).toContain('constitution.md');
expect(rulesContent).toContain('specification.md');
expect(rulesContent).toContain('plan.md');
expect(rulesContent).toContain('What You MUST NOT Do');
});
});
describe('BMAD Framework', () => {
it('should generate Cursor configurations from BMAD outputs', async () => {
// Create mock outputs
const prdContent = `
A complete e-commerce platform for small businesses.
- Enable online sales
- Provide analytics
- RESTful API
- Payment gateway integration
- Secure checkout flow
`;
const architectureContent = `
Modular monolith architecture with separate domains.
Clean architecture with domain-driven design.
- Order Management
- Inventory System
- Payment Processing
`;
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'prd.md'),
prdContent,
'utf-8'
);
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'architecture.md'),
architectureContent,
'utf-8'
);
await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
framework: 'comprehensive',
projectName: 'E-commerce Platform'
});
// Generate Cursor configs
const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'comprehensive');
await generator.generate();
// Verify .cursor/rules
const rulesPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
const rulesContent = await fs.readFile(rulesPath, 'utf-8');
expect(rulesContent).toContain('E-commerce Platform');
expect(rulesContent).toContain('Product Overview');
expect(rulesContent).toContain('e-commerce platform');
expect(rulesContent).toContain('Goals and Objectives');
expect(rulesContent).toContain('Enable online sales');
expect(rulesContent).toContain('System Architecture');
expect(rulesContent).toContain('Code Quality Standards');
expect(rulesContent).toContain('Security');
expect(rulesContent).toContain('Performance');
expect(rulesContent).toContain('prd.md');
expect(rulesContent).toContain('architecture.md');
expect(rulesContent).toContain('stories.md');
});
});
describe('Modern vs Legacy', () => {
it('should create modern .cursor/rules as primary config', async () => {
const prpContent = '# PRP\n\n## 1. Goal Definition\nTest project';
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
prpContent,
'utf-8'
);
const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
const generated = await generator.generate();
// Modern config should exist
const modernPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
expect(await fs.pathExists(modernPath)).toBe(true);
// Legacy should be deprecation notice
const legacyPath = path.join(TEST_PROJECT_PATH, '.cursorrules');
expect(await fs.pathExists(legacyPath)).toBe(true);
const legacyContent = await fs.readFile(legacyPath, 'utf-8');
expect(legacyContent).toContain('DEPRECATED');
});
});
describe('Template Variables', () => {
it('should replace session ID in paths', async () => {
const prpContent = '# PRP\n\n## 1. Goal Definition\nTest project';
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
prpContent,
'utf-8'
);
const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
await generator.generate();
const rulesContent = await fs.readFile(
path.join(TEST_PROJECT_PATH, '.cursor', 'rules'),
'utf-8'
);
// Should contain the actual session ID, not a template variable
expect(rulesContent).toContain('test-session');
expect(rulesContent).not.toContain('{SESSION_ID}');
});
it('should include ADF CLI version', async () => {
const prpContent = '# PRP\n\n## 1. Goal Definition\nTest';
await fs.writeFile(
path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
prpContent,
'utf-8'
);
const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
await generator.generate();
const rulesContent = await fs.readFile(
path.join(TEST_PROJECT_PATH, '.cursor', 'rules'),
'utf-8'
);
expect(rulesContent).toContain('Generated by');
expect(rulesContent).toContain('ADF CLI');
});
});
});