mcp-think-tank
Version:
Structured thinking and knowledge management tool for Model Context Protocol
161 lines (160 loc) • 4.96 kB
JavaScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { TaskStorage } from '../src/tasks/storage.js';
import { v4 as uuidv4 } from 'uuid';
// Mock the dependencies
vi.mock('fs', () => ({
default: {
existsSync: vi.fn(() => false),
writeFileSync: vi.fn(),
readFileSync: vi.fn(),
appendFileSync: vi.fn(),
createWriteStream: vi.fn(() => ({
write: vi.fn(),
end: vi.fn(),
on: vi.fn((event, callback) => callback())
})),
renameSync: vi.fn()
}
}));
vi.mock('../src/utils/fs.js', () => ({
createDirectory: vi.fn()
}));
vi.mock('../src/utils/logger.js', () => ({
logger: {
info: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
warn: vi.fn()
}
}));
vi.mock('fastmcp', () => ({
FastMCP: class {
constructor() {
this.addTool = vi.fn();
this.callTool = vi.fn();
this.start = vi.fn();
}
}
}));
TaskStorage.prototype.clearAllTasks = function () {
this.tasks.clear();
};
describe('Task Management', () => {
let taskStorage;
beforeEach(() => {
vi.resetAllMocks();
// Create a new instance for each test
taskStorage = new TaskStorage();
// Use the public helper to clear tasks
taskStorage.clearAllTasks();
});
afterEach(() => {
vi.useRealTimers();
vi.restoreAllMocks();
});
it('should create a new task', () => {
const task = {
id: uuidv4(),
description: 'Test task',
status: 'todo',
priority: 'medium'
};
const result = taskStorage.addTask(task);
expect(result).toEqual(task);
expect(taskStorage.getAllTasks()).toContain(task);
});
it('should update an existing task', () => {
const task = {
id: uuidv4(),
description: 'Test task',
status: 'todo',
priority: 'medium'
};
taskStorage.addTask(task);
const updatedTask = taskStorage.updateTask(task.id, {
description: 'Updated task',
priority: 'high'
});
expect(updatedTask).toEqual({
...task,
description: 'Updated task',
priority: 'high'
});
});
it('should return null when updating a non-existent task', () => {
const result = taskStorage.updateTask('non-existent-id', {
description: 'This should fail'
});
expect(result).toBeNull();
});
it('should delete a task', () => {
const task = {
id: uuidv4(),
description: 'Task to delete',
status: 'todo',
priority: 'low'
};
taskStorage.addTask(task);
const deleteResult = taskStorage.deleteTask(task.id);
expect(deleteResult).toBe(true);
expect(taskStorage.getAllTasks()).not.toContain(task);
});
it('should filter tasks by status', () => {
const todoTask = {
id: uuidv4(),
description: 'Todo task',
status: 'todo',
priority: 'medium'
};
const doneTask = {
id: uuidv4(),
description: 'Done task',
status: 'done',
priority: 'medium'
};
taskStorage.addTask(todoTask);
taskStorage.addTask(doneTask);
const todoTasks = taskStorage.getTasksBy({ status: 'todo' });
expect(todoTasks).toHaveLength(1);
expect(todoTasks[0]).toEqual(todoTask);
const doneTasks = taskStorage.getTasksBy({ status: 'done' });
expect(doneTasks).toHaveLength(1);
expect(doneTasks[0]).toEqual(doneTask);
});
it('should filter tasks by priority', () => {
const highTask = {
id: uuidv4(),
description: 'High priority task',
status: 'todo',
priority: 'high'
};
const lowTask = {
id: uuidv4(),
description: 'Low priority task',
status: 'todo',
priority: 'low'
};
taskStorage.addTask(highTask);
taskStorage.addTask(lowTask);
const highTasks = taskStorage.getTasksBy({ priority: 'high' });
expect(highTasks).toHaveLength(1);
expect(highTasks[0]).toEqual(highTask);
});
it('should debounce save operations', () => {
vi.useFakeTimers();
const task = {
id: uuidv4(),
description: 'Test task',
status: 'todo',
priority: 'medium'
};
taskStorage.addTask(task);
taskStorage.save();
// Timer should be set but not executed yet
expect(vi.getTimerCount()).toBe(1);
// Fast-forward time
vi.advanceTimersByTime(5000);
// Timer should have executed
expect(vi.getTimerCount()).toBe(0);
});
});