import 'reflect-metadata'; import { container } from 'tsyringe'; import { TaskClassifierService } from '../../../src/services/nlp/classifiers/task-classifier.service'; import { OpenAIService } from '../../../src/services/ai/openai.service'; // Mock OpenAIService jest.mock('../../../src/services/ai/openai.service'); describe('TaskClassifierService', () => { let service: TaskClassifierService; let mockOpenAIService: jest.Mocked; beforeEach(() => { jest.clearAllMocks(); container.clearInstances(); // Create mock OpenAI service mockOpenAIService = { complete: jest.fn(), } as any; // Register mock with container container.registerInstance(OpenAIService, mockOpenAIService); // Create service service = container.resolve(TaskClassifierService); }); describe('classify', () => { it('should classify task type correctly', async () => { // Arrange const text = 'Add new user registration feature with email verification'; const entities = { title: 'User registration feature', description: 'Implement user registration with email verification', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'feature', subType: 'authentication', confidence: 0.9, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('feature'); expect(result.subType).toBe('authentication'); expect(result.confidence).toBeGreaterThan(0.8); }); it('should classify bug reports', async () => { // Arrange const text = 'Fix the login button not working on mobile devices'; const entities = { title: 'Fix login button on mobile', priority: 'high', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'bug', severity: 'high', affectedArea: 'authentication', confidence: 0.95, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('bug'); expect(result.severity).toBe('high'); expect(result.affectedArea).toBe('authentication'); }); it('should classify improvements', async () => { // Arrange const text = 'Optimize database queries to improve page load time'; const entities = { title: 'Optimize database queries', description: 'Performance improvement', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'improvement', category: 'performance', impact: 'medium', confidence: 0.85, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('improvement'); expect(result.category).toBe('performance'); expect(result.impact).toBe('medium'); }); it('should detect priority from context', async () => { // Arrange const text = 'URGENT: Critical security patch needed ASAP'; const entities = { title: 'Security patch', priority: 'critical', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'security', priority: 'critical', urgency: 'immediate', confidence: 0.98, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.priority).toBe('critical'); expect(result.urgency).toBe('immediate'); expect(result.confidence).toBeGreaterThan(0.95); }); it('should analyze sentiment for urgency', async () => { // Arrange const text = 'This is blocking the entire team! We need this fixed NOW!'; const entities = { title: 'Blocking issue', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'blocker', sentiment: 'negative', urgency: 'critical', emotionalTone: 'frustrated', confidence: 0.92, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.urgency).toBe('critical'); expect(result.sentiment).toBe('negative'); expect(result.emotionalTone).toBe('frustrated'); }); it('should estimate complexity', async () => { // Arrange const text = 'Refactor the entire authentication system to use OAuth 2.0 with multiple providers'; const entities = { title: 'Refactor authentication system', estimatedHours: 40, }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'refactoring', complexity: 'high', estimatedEffort: 'large', riskLevel: 'medium', confidence: 0.8, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.complexity).toBe('high'); expect(result.estimatedEffort).toBe('large'); expect(result.riskLevel).toBe('medium'); }); it('should identify technical areas', async () => { // Arrange const text = 'Update React components to use TypeScript and add unit tests'; const entities = { title: 'Update React components', tags: ['frontend', 'testing'], }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'technical-debt', technicalAreas: ['frontend', 'typescript', 'testing'], frameworks: ['react'], confidence: 0.88, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.technicalAreas).toContain('frontend'); expect(result.technicalAreas).toContain('typescript'); expect(result.frameworks).toContain('react'); }); it('should classify documentation tasks', async () => { // Arrange const text = 'Write API documentation for the new endpoints'; const entities = { title: 'API documentation', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'documentation', documentationType: 'api', priority: 'medium', confidence: 0.9, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('documentation'); expect(result.documentationType).toBe('api'); }); it('should handle multi-language classification', async () => { // Arrange const text = 'Corregir el error en el sistema de pagos'; // Spanish const entities = { title: 'Error sistema de pagos', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'bug', affectedArea: 'payments', language: 'es', confidence: 0.85, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classifyTask(text, entities, 'es'); // Assert expect(result.taskType).toBe('bug'); expect(result.affectedArea).toBe('payments'); expect(result.language).toBe('es'); }); it('should provide confidence scores', async () => { // Arrange const text = 'Maybe look into improving something'; const entities = { title: 'Improvement task', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'improvement', confidence: 0.4, uncertaintyReason: 'vague description', }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.confidence).toBeLessThan(0.5); expect(result.uncertaintyReason).toBe('vague description'); }); it('should handle classification errors', async () => { // Arrange const text = 'Test task'; const entities = { title: 'Test' }; mockOpenAIService.complete.mockRejectedValue(new Error('Classification failed')); // Act & Assert await expect(service.classify({ text, entities, language: 'en' })).rejects.toThrow('Classification failed'); }); it('should classify research tasks', async () => { // Arrange const text = 'Research and evaluate different caching strategies for the API'; const entities = { title: 'Research caching strategies', }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'research', researchArea: 'performance', deliverables: ['evaluation report', 'recommendations'], confidence: 0.87, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('research'); expect(result.researchArea).toBe('performance'); expect(result.deliverables).toContain('evaluation report'); }); }); describe('pattern-based classification', () => { it('should detect bug patterns', async () => { // Arrange const text = 'BUG: Application crashes when user clicks submit'; const entities = { title: 'Application crash' }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'bug', patternMatch: true, confidence: 0.99, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('bug'); expect(result.patternMatch).toBe(true); expect(result.confidence).toBeGreaterThan(0.95); }); it('should detect feature patterns', async () => { // Arrange const text = 'FEATURE REQUEST: Add dark mode to the application'; const entities = { title: 'Add dark mode' }; mockOpenAIService.complete.mockResolvedValue({ content: JSON.stringify({ taskType: 'feature', requestType: 'enhancement', patternMatch: true, confidence: 0.95, }), usage: { totalTokens: 100 }, }); // Act const result = await service.classify({ text, entities, language: 'en' }); // Assert expect(result.taskType).toBe('feature'); expect(result.requestType).toBe('enhancement'); expect(result.patternMatch).toBe(true); }); }); });