task-master-neo-sdlc
Version:
Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.
249 lines (204 loc) • 6.4 kB
JavaScript
import { KnowledgeGraph } from '../knowledge-graph.js';
describe('KnowledgeGraph', () => {
let graph;
beforeEach(() => {
graph = new KnowledgeGraph();
});
describe('addNode', () => {
it('should add a node with timestamp', () => {
const node = {
id: 'test-1',
type: 'task',
data: { title: 'Test Task' }
};
graph.addNode(node);
const result = graph.nodes.get('test-1');
expect(result).toBeDefined();
expect(result.type).toBe('task');
expect(result.created).toBeDefined();
expect(result.updated).toBeDefined();
});
it('should throw error for duplicate node id', () => {
const node = { id: 'test-1', type: 'task' };
graph.addNode(node);
expect(() => graph.addNode(node)).toThrow('Node already exists');
});
});
describe('addEdge', () => {
beforeEach(() => {
graph.addNode({ id: 'node1', type: 'task' });
graph.addNode({ id: 'node2', type: 'agent' });
});
it('should add edge between nodes', () => {
const edge = {
from: 'node1',
to: 'node2',
type: 'assigned'
};
graph.addEdge(edge);
const result = graph.edges.get('node1:assigned:node2');
expect(result).toBeDefined();
expect(result.type).toBe('assigned');
expect(result.created).toBeDefined();
});
it('should throw error for invalid node references', () => {
const edge = {
from: 'node1',
to: 'invalid',
type: 'assigned'
};
expect(() => graph.addEdge(edge)).toThrow('Invalid node reference');
});
});
describe('updateContext', () => {
it('should create or update node with context', async () => {
const context = {
id: 'workflow-1',
type: 'workflow',
status: 'active',
metrics: { progress: 0.5 }
};
await graph.updateContext(context);
const node = graph.nodes.get('workflow-1');
expect(node).toBeDefined();
expect(node.data.status).toBe('active');
expect(node.data.metrics.progress).toBe(0.5);
expect(node.updated).toBeDefined();
});
it('should update cache on context change', async () => {
const context = {
id: 'agent-1',
type: 'agent',
status: 'idle'
};
await graph.updateContext(context);
expect(graph.contextCache.get('agent-1')).toBeDefined();
await graph.updateContext({
...context,
status: 'active'
});
const cached = graph.contextCache.get('agent-1');
expect(cached.status).toBe('active');
});
});
describe('getContext', () => {
beforeEach(async () => {
await graph.updateContext({
id: 'task-1',
type: 'task',
status: 'pending'
});
await graph.updateContext({
id: 'agent-1',
type: 'agent',
capabilities: ['testing']
});
graph.addEdge({
from: 'task-1',
to: 'agent-1',
type: 'assigned'
});
});
it('should return node context with connected nodes', async () => {
const context = await graph.getContext('task-1');
expect(context.id).toBe('task-1');
expect(context.type).toBe('task');
expect(context.connected).toBeDefined();
expect(context.connected.assigned).toContainEqual(
expect.objectContaining({ id: 'agent-1' })
);
});
it('should use cache when available', async () => {
const firstCall = await graph.getContext('task-1');
const secondCall = await graph.getContext('task-1');
expect(secondCall).toEqual(firstCall);
expect(graph.contextCache.has('task-1')).toBe(true);
});
});
describe('findNodes', () => {
beforeEach(async () => {
await graph.updateContext({
id: 'task-1',
type: 'task',
priority: 'high'
});
await graph.updateContext({
id: 'task-2',
type: 'task',
priority: 'medium'
});
});
it('should find nodes by type and criteria', () => {
const results = graph.findNodes('task', node =>
node.data.priority === 'high'
);
expect(results).toHaveLength(1);
expect(results[0].id).toBe('task-1');
});
it('should return empty array when no matches', () => {
const results = graph.findNodes('task', node =>
node.data.priority === 'low'
);
expect(results).toHaveLength(0);
});
});
describe('validateContext', () => {
it('should validate required fields by type', () => {
const context = {
id: 'workflow-1',
type: 'workflow'
};
const result = graph.validateContext(context);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Missing required field: status');
});
it('should validate field types', () => {
const context = {
id: 'metrics-1',
type: 'metrics',
values: 'invalid' // Should be array
};
const result = graph.validateContext(context);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Invalid field type: values');
});
});
describe('analyzeContext', () => {
beforeEach(async () => {
await graph.updateContext({
id: 'agent-1',
type: 'agent',
metrics: {
tasksCompleted: 10,
successRate: 0.9
}
});
for (let i = 1; i <= 3; i++) {
await graph.updateContext({
id: `task-${i}`,
type: 'task',
status: 'completed'
});
graph.addEdge({
from: `task-${i}`,
to: 'agent-1',
type: 'completed_by'
});
}
});
it('should analyze node relationships and metrics', async () => {
const analysis = await graph.analyzeContext('agent-1');
expect(analysis.metrics).toBeDefined();
expect(analysis.relationships).toBeDefined();
expect(analysis.recommendations).toBeDefined();
expect(analysis.metrics.taskCount).toBe(3);
expect(analysis.relationships.completed_by).toHaveLength(3);
});
it('should provide type-specific insights', async () => {
const analysis = await graph.analyzeContext('agent-1');
expect(analysis.insights).toContain(
expect.stringContaining('success rate')
);
});
});
});