194 lines
6.6 KiB
TypeScript
194 lines
6.6 KiB
TypeScript
/**
|
|
* V3 Task Hooks Tests
|
|
*
|
|
* Tests for pre-task and post-task hook functionality.
|
|
*
|
|
* @module v3/shared/hooks/__tests__/task-hooks.test
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import {
|
|
createHookRegistry,
|
|
createTaskHooksManager,
|
|
TaskHooksManager,
|
|
HookRegistry,
|
|
HookEvent,
|
|
} from '../../src/hooks/index.js';
|
|
|
|
describe('TaskHooksManager', () => {
|
|
let registry: HookRegistry;
|
|
let taskManager: TaskHooksManager;
|
|
|
|
beforeEach(() => {
|
|
registry = createHookRegistry();
|
|
taskManager = createTaskHooksManager(registry);
|
|
});
|
|
|
|
describe('pre-task hook', () => {
|
|
it('should register pre-task hook on creation', () => {
|
|
const hooks = registry.getHandlers(HookEvent.PreTaskExecute);
|
|
expect(hooks.length).toBeGreaterThan(0);
|
|
expect(hooks.some(h => h.name === 'task-hooks:pre-task')).toBe(true);
|
|
});
|
|
|
|
it('should analyze task and suggest agents for coding task', async () => {
|
|
const result = await taskManager.executePreTask(
|
|
'task-123',
|
|
'Implement user authentication feature'
|
|
);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.suggestedAgents).toBeDefined();
|
|
expect(result.suggestedAgents!.length).toBeGreaterThan(0);
|
|
expect(result.suggestedAgents![0].type).toBe('coder');
|
|
expect(result.suggestedAgents![0].confidence).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should suggest security-architect for security tasks', async () => {
|
|
const result = await taskManager.executePreTask(
|
|
'task-456',
|
|
'Fix security vulnerability in authentication'
|
|
);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.suggestedAgents).toBeDefined();
|
|
const securityAgent = result.suggestedAgents!.find(a => a.type === 'security-architect');
|
|
expect(securityAgent).toBeDefined();
|
|
});
|
|
|
|
it('should suggest tester for test-related tasks', async () => {
|
|
const result = await taskManager.executePreTask(
|
|
'task-789',
|
|
'Write unit tests for user service'
|
|
);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.suggestedAgents).toBeDefined();
|
|
const testerAgent = result.suggestedAgents!.find(a => a.type === 'tester');
|
|
expect(testerAgent).toBeDefined();
|
|
});
|
|
|
|
it('should estimate complexity based on task description', async () => {
|
|
// Simple task
|
|
const simpleResult = await taskManager.executePreTask(
|
|
'task-simple',
|
|
'Fix typo in readme'
|
|
);
|
|
expect(simpleResult.complexity).toBe('low');
|
|
|
|
// Complex task
|
|
const complexResult = await taskManager.executePreTask(
|
|
'task-complex',
|
|
'Refactor and redesign the entire authentication system with multiple OAuth providers'
|
|
);
|
|
expect(complexResult.complexity).toBe('high');
|
|
});
|
|
|
|
it('should detect risks in task description', async () => {
|
|
const result = await taskManager.executePreTask(
|
|
'task-risky',
|
|
'Delete old data from production database'
|
|
);
|
|
|
|
expect(result.risks).toBeDefined();
|
|
expect(result.risks!.length).toBeGreaterThan(0);
|
|
expect(result.risks!.some(r => r.includes('production'))).toBe(true);
|
|
});
|
|
|
|
it('should track active tasks', async () => {
|
|
await taskManager.executePreTask('task-1', 'Task 1');
|
|
await taskManager.executePreTask('task-2', 'Task 2');
|
|
|
|
const activeTasks = taskManager.getActiveTasks();
|
|
expect(activeTasks.size).toBe(2);
|
|
expect(activeTasks.has('task-1')).toBe(true);
|
|
expect(activeTasks.has('task-2')).toBe(true);
|
|
});
|
|
|
|
it('should provide recommendations for high complexity tasks', async () => {
|
|
const result = await taskManager.executePreTask(
|
|
'task-high-complexity',
|
|
'Implement complex distributed system with multiple services'
|
|
);
|
|
|
|
expect(result.recommendations).toBeDefined();
|
|
expect(result.recommendations!.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('post-task hook', () => {
|
|
it('should register post-task hook on creation', () => {
|
|
const hooks = registry.getHandlers(HookEvent.PostTaskExecute);
|
|
expect(hooks.length).toBeGreaterThan(0);
|
|
expect(hooks.some(h => h.name === 'task-hooks:post-task')).toBe(true);
|
|
});
|
|
|
|
it('should record successful task outcome', async () => {
|
|
// First start the task
|
|
await taskManager.executePreTask('task-success', 'Test task');
|
|
|
|
// Then complete it
|
|
const result = await taskManager.executePostTask('task-success', true);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.outcome).toBeDefined();
|
|
expect(result.outcome!.success).toBe(true);
|
|
expect(result.outcome!.duration).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
it('should record failed task outcome', async () => {
|
|
await taskManager.executePreTask('task-failed', 'Test task');
|
|
|
|
const result = await taskManager.executePostTask('task-failed', false, {
|
|
error: 'Test failed due to timeout',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.outcome).toBeDefined();
|
|
expect(result.outcome!.success).toBe(false);
|
|
});
|
|
|
|
it('should create learning trajectory', async () => {
|
|
await taskManager.executePreTask('task-learn', 'Test task');
|
|
const result = await taskManager.executePostTask('task-learn', true);
|
|
|
|
expect(result.trajectoryId).toBeDefined();
|
|
expect(result.trajectoryId).toContain('trajectory-');
|
|
});
|
|
|
|
it('should track learning updates', async () => {
|
|
await taskManager.executePreTask('task-updates', 'Test task');
|
|
const result = await taskManager.executePostTask('task-updates', true);
|
|
|
|
expect(result.learningUpdates).toBeDefined();
|
|
expect(result.learningUpdates!.trajectoriesRecorded).toBe(1);
|
|
});
|
|
|
|
it('should remove task from active tasks after completion', async () => {
|
|
await taskManager.executePreTask('task-cleanup', 'Test task');
|
|
expect(taskManager.getActiveTasks().has('task-cleanup')).toBe(true);
|
|
|
|
await taskManager.executePostTask('task-cleanup', true);
|
|
expect(taskManager.getActiveTasks().has('task-cleanup')).toBe(false);
|
|
});
|
|
|
|
it('should handle post-task without pre-task gracefully', async () => {
|
|
const result = await taskManager.executePostTask('task-no-pre', true);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.outcome).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('clearActiveTasks', () => {
|
|
it('should clear all active tasks', async () => {
|
|
await taskManager.executePreTask('task-1', 'Task 1');
|
|
await taskManager.executePreTask('task-2', 'Task 2');
|
|
expect(taskManager.getActiveTasks().size).toBe(2);
|
|
|
|
taskManager.clearActiveTasks();
|
|
expect(taskManager.getActiveTasks().size).toBe(0);
|
|
});
|
|
});
|
|
});
|