directus-task-management/tests/services/nlp/task-classifier.service.tes...

380 lines
11 KiB
TypeScript

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<OpenAIService>;
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);
});
});
});