UNPKG

ruch

Version:

Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance. Create maintainable, scalable applications with domain-driven design and integrated AI tooling.

183 lines (143 loc) 6.7 kB
import { describe, it, beforeEach, expect, vi } from 'vitest'; import { generateAiGuide } from '../../src/commands/guide-ai'; import type { Logger } from '../../src/services/console-logger'; // Mock fs-extra vi.mock('fs-extra', () => ({ default: { readdir: vi.fn().mockResolvedValue([]), stat: vi.fn().mockResolvedValue({ isDirectory: () => true }), writeFile: vi.fn().mockResolvedValue(undefined), ensureDir: vi.fn().mockResolvedValue(undefined), }, readdir: vi.fn().mockResolvedValue([]), stat: vi.fn().mockResolvedValue({ isDirectory: () => true }), writeFile: vi.fn().mockResolvedValue(undefined), ensureDir: vi.fn().mockResolvedValue(undefined), })); // Mock console.warn const mockConsoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {}); // Mock process.cwd vi.spyOn(process, 'cwd').mockReturnValue('/test/project'); describe('guide-ai command', () => { let mockLogger: Logger; beforeEach(() => { vi.clearAllMocks(); // Create fresh mock logger for each test mockLogger = { info: vi.fn(), success: vi.fn(), warning: vi.fn(), error: vi.fn(), log: vi.fn(), }; }); describe('basic functionality', () => { it('should generate guide files successfully', async () => { await generateAiGuide(mockLogger, []); expect(mockLogger.info).toHaveBeenCalledWith('🤖 Generating AI tools guide...'); expect(mockLogger.success).toHaveBeenCalledWith('🎉 AI tools guide generated successfully!'); }); it('should handle domain analysis', async () => { const fs = await import('fs-extra'); vi.mocked(fs.readdir).mockResolvedValueOnce(['user', 'product'] as any); await generateAiGuide(mockLogger, []); // Vérifier que l'analyse de la structure a été loggée expect(mockLogger.info).toHaveBeenCalledWith('📊 Analyzing project structure...'); }); it('should handle missing domains folder gracefully', async () => { const fs = await import('fs-extra'); vi.mocked(fs.readdir).mockRejectedValueOnce(new Error('ENOENT')); await generateAiGuide(mockLogger, []); // Vérifier que le processus continue malgré l'erreur expect(mockLogger.success).toHaveBeenCalledWith('🎉 AI tools guide generated successfully!'); }); }); describe('tool configurations', () => { it('should generate Cursor configuration', async () => { await generateAiGuide(mockLogger, ['cursor']); expect(mockLogger.info).toHaveBeenCalledWith( '🔧 Generating configurations for AI tools: cursor...' ); expect(mockLogger.success).toHaveBeenCalledWith( '✅ Tool configurations generated for: cursor' ); }); it('should generate multiple tool configurations', async () => { await generateAiGuide(mockLogger, ['cursor', 'copilot']); expect(mockLogger.info).toHaveBeenCalledWith( '🔧 Generating configurations for AI tools: cursor, copilot...' ); expect(mockLogger.success).toHaveBeenCalledWith( '✅ Tool configurations generated for: cursor, copilot' ); }); it('should warn about unknown tools', async () => { await generateAiGuide(mockLogger, ['unknown-tool']); expect(mockConsoleWarn).toHaveBeenCalledWith( expect.stringContaining('Warning: Unknown tool "unknown-tool"') ); }); it('should accept all supported tools', async () => { await generateAiGuide(mockLogger, ['cursor', 'copilot', 'windsurf', 'juni']); expect(mockLogger.success).toHaveBeenCalledWith( '✅ Tool configurations generated for: cursor, copilot, windsurf, juni' ); }); }); describe('domain guides generation', () => { it('should complete successfully even with domain analysis', async () => { const fs = await import('fs-extra'); vi.mocked(fs.readdir).mockResolvedValueOnce(['user', 'product'] as any); await generateAiGuide(mockLogger, []); // Vérifier que le processus s'est terminé avec succès expect(mockLogger.success).toHaveBeenCalledWith('🎉 AI tools guide generated successfully!'); }); it('should skip domain guides when no domains exist', async () => { const fs = await import('fs-extra'); vi.mocked(fs.readdir).mockResolvedValueOnce([] as any); await generateAiGuide(mockLogger, []); // Pas de guides de domaines générés car aucun domaine détecté expect(mockLogger.success).toHaveBeenCalledWith('🎉 AI tools guide generated successfully!'); }); }); describe('file writing', () => { it('should write configuration files', async () => { await generateAiGuide(mockLogger, []); // Vérifier que le processus de génération s'est bien déroulé expect(mockLogger.info).toHaveBeenCalledWith('📝 Generating configuration file...'); expect(mockLogger.success).toHaveBeenCalledWith('✅ ruch-guide.json generated'); }); it('should write global guide file', async () => { await generateAiGuide(mockLogger, []); // Vérifier que le guide global a été généré expect(mockLogger.info).toHaveBeenCalledWith('📚 Generating global guide...'); expect(mockLogger.success).toHaveBeenCalledWith('✅ GUIDE.md generated'); }); it('should handle tool configurations', async () => { await generateAiGuide(mockLogger, ['copilot', 'juni']); // Vérifier que les configurations d'outils ont été traitées expect(mockLogger.info).toHaveBeenCalledWith( expect.stringContaining('Generating configurations for AI tools') ); expect(mockLogger.success).toHaveBeenCalledWith( expect.stringContaining('Tool configurations generated for') ); }); }); describe('error handling', () => { it('should handle errors gracefully in most cases', async () => { const fs = await import('fs-extra'); vi.mocked(fs.readdir).mockRejectedValueOnce(new Error('ENOENT')); await generateAiGuide(mockLogger, []); // Le processus doit continuer malgré l'erreur de lecture des domaines expect(mockLogger.success).toHaveBeenCalledWith('🎉 AI tools guide generated successfully!'); }); it('should handle domain analysis errors gracefully', async () => { const fs = await import('fs-extra'); vi.mocked(fs.readdir).mockResolvedValueOnce(['user'] as any); vi.mocked(fs.stat).mockRejectedValueOnce(new Error('Stat error')); await generateAiGuide(mockLogger, []); expect(mockLogger.success).toHaveBeenCalledWith('🎉 AI tools guide generated successfully!'); }); }); });