UNPKG

@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
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 = `# Product Requirement Prompt (PRP) ## 1. Goal Definition Build a React dashboard that displays real-time analytics from PostgreSQL database. ## 2. Business Justification This will help users make data-driven decisions and improve productivity. ## 3. Contextual Intelligence ### Technology Stack - Frontend: React 18, TypeScript - Backend: Node.js, Express - Database: PostgreSQL ## 4. Implementation Blueprint ### File Structure - src/components/Dashboard/ - src/api/analytics/ ### Core Logic 1. Fetch data from analytics API 2. Process and aggregate 3. Render charts ## 5. Validation ### Success Criteria - 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 = `# Constitution ## Core Principles 1. User privacy is paramount 2. Performance over features ## Constraints - No third-party analytics - WCAG 2.1 AA compliance `; const specificationContent = `# Specification ## Overview A comprehensive user management system. ## Architecture Microservices architecture with API gateway. `; const planContent = `# Technical Plan ## Technology Stack - React 18 - Node.js 20 - PostgreSQL 15 ## Code Style - Use TypeScript strict mode - Follow Airbnb style guide ## Coding Standards - 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 = `# Product Requirements Document ## Executive Summary A complete e-commerce platform for small businesses. ## Goals and Objectives - Enable online sales - Provide analytics ## Technical Requirements - RESTful API - Payment gateway integration - Secure checkout flow `; const architectureContent = `# System Architecture ## System Overview Modular monolith architecture with separate domains. ## Architecture Overview Clean architecture with domain-driven design. ## Components - 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'); }); }); });