Skip to main content
Glama
tasks.integration.test.ts12.8 kB
import { describe, it, expect } from '@jest/globals'; import { executeToolWithRetry, generateTestTaskData, cleanupTestData, } from '../utils/test-helpers.ts'; import { entitySchemaValidator } from '../utils/schema-validator.ts'; import { ErrorTestUtils, createErrorTestCases } from '../utils/error-handling.ts'; import { TEST_CONFIG } from '../setup.ts'; describe('Task Tools Integration Tests', () => { const createdTasks: number[] = []; afterEach(async () => { // Clean up created tasks for (const taskId of createdTasks) { await cleanupTestData('task', taskId); } createdTasks.length = 0; }); describe('list-tasks', () => { it('should list all tasks', async () => { const result = await executeToolWithRetry('list-tasks', {}); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); // Validate schema for each task if (result.length > 0) { result.forEach((task: any) => { entitySchemaValidator.validateTask(task); }); } }); it('should list tasks with pagination', async () => { const result = await executeToolWithRetry('list-tasks', { page: 1, 'per-page': 10, }); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); expect(result.length).toBeLessThanOrEqual(10); }); it('should filter tasks by project', async () => { const result = await executeToolWithRetry('list-tasks', { project_id: 1, }); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); // Validate that all returned tasks have the expected project_id result.forEach((task: any) => { expect(task.project_id).toBe(1); }); }); it('should filter tasks by person', async () => { const result = await executeToolWithRetry('list-tasks', { people_id: 1, }); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); // Validate that all returned tasks have the expected people_id result.forEach((task: any) => { expect(task.people_id).toBe(1); }); }); it('should filter tasks by date range', async () => { const result = await executeToolWithRetry('list-tasks', { start_date: '2024-01-01', end_date: '2024-12-31', }); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); // Validate that all returned tasks fall within the date range result.forEach((task: any) => { if (task.start_date) { expect(task.start_date).toBeGreaterThanOrEqual('2024-01-01'); } if (task.end_date) { expect(task.end_date).toBeLessThanOrEqual('2024-12-31'); } }); }); }); describe('get-task', () => { it('should get a specific task by ID', async () => { // First, get a task ID from the list const tasks = await executeToolWithRetry('list-tasks', { 'per-page': 1 }); if (tasks.length === 0) { console.warn('No tasks found to test get-task'); return; } const taskId = tasks[0].task_id; const result = await executeToolWithRetry('get-task', { task_id: taskId, }); expect(result).toBeDefined(); expect(result.task_id).toBe(taskId); // Validate schema entitySchemaValidator.validateTask(result); }); it('should handle string task ID', async () => { const tasks = await executeToolWithRetry('list-tasks', { 'per-page': 1 }); if (tasks.length === 0) { console.warn('No tasks found to test get-task with string ID'); return; } const taskId = tasks[0].task_id.toString(); const result = await executeToolWithRetry('get-task', { task_id: taskId, }); expect(result).toBeDefined(); expect(result.task_id).toBe(parseInt(taskId)); }); }); describe('create-task', () => { it('should create a new task', async () => { if (!TEST_CONFIG.enableRealApiCalls) { console.warn('Skipping create-task test - real API calls disabled'); return; } const taskData = generateTestTaskData(); const result = await executeToolWithRetry('create-task', taskData); expect(result).toBeDefined(); expect(result.task_id).toBeDefined(); expect(result.name).toBe(taskData.name); expect(result.project_id).toBe(taskData.project_id); // Track for cleanup createdTasks.push(result.task_id); // Validate schema entitySchemaValidator.validateTask(result); }); it('should create task with all optional fields', async () => { const taskData = { project_id: 1, people_id: 1, name: 'Comprehensive Task', estimated_hours: 40, start_date: '2024-01-15', end_date: '2024-01-19', notes: 'Task with all fields', }; const result = await executeToolWithRetry('create-task', taskData); expect(result).toBeDefined(); expect(result.task_id).toBeDefined(); expect(result.people_id).toBe(taskData.people_id); // For real API, some fields might not be returned in create response if (process.env.TEST_REAL_API === 'true') { // Just verify the task was created and has required fields expect(result.task_id).toBeDefined(); expect(result.project_id).toBe(taskData.project_id); } else { expect(result.estimated_hours).toBe(taskData.estimated_hours); } // Track for cleanup createdTasks.push(result.task_id); }); }); describe('update-task', () => { it('should update an existing task', async () => { const taskData = generateTestTaskData({ project_id: 1, people_id: 1, name: 'Update Test Task', estimated_hours: 10, }); const created = await executeToolWithRetry('create-task', taskData); expect(created.task_id).toBeDefined(); const updatedName = `Updated ${taskData.name}`; const result = await executeToolWithRetry('update-task', { task_id: created.task_id, name: updatedName, estimated_hours: 20, }); expect(result).toBeDefined(); // For real API, we may need to fetch the updated task to verify changes if (process.env.TEST_REAL_API === 'true') { const updatedTask = await executeToolWithRetry('get-task', { task_id: created.task_id }); expect(updatedTask.task_id).toBe(created.task_id); expect(updatedTask.name).toBe(updatedName); expect(updatedTask.estimated_hours).toBe(20); } else { expect(result.task_id).toBe(created.task_id); expect(result.name).toBe(updatedName); expect(result.estimated_hours).toBe(20); } // Track for cleanup createdTasks.push(created.task_id); }); it('should update task with partial data', async () => { const taskData = generateTestTaskData({ project_id: 1, people_id: 1, name: 'Partial Update Test Task', estimated_hours: 15, }); const created = await executeToolWithRetry('create-task', taskData); expect(created.task_id).toBeDefined(); const result = await executeToolWithRetry('update-task', { task_id: created.task_id, estimated_hours: 30, }); expect(result).toBeDefined(); // For real API, we may need to fetch the updated task to verify changes if (process.env.TEST_REAL_API === 'true') { const updatedTask = await executeToolWithRetry('get-task', { task_id: created.task_id }); expect(updatedTask.task_id).toBe(created.task_id); expect(updatedTask.estimated_hours).toBe(30); expect(updatedTask.name).toBe(taskData.name); // Should remain unchanged } else { expect(result.task_id).toBe(created.task_id); expect(result.estimated_hours).toBe(30); expect(result.name).toBe(taskData.name); // Should remain unchanged } // Track for cleanup createdTasks.push(created.task_id); }); }); describe('delete-task', () => { it('should delete a task', async () => { if (!TEST_CONFIG.enableRealApiCalls) { console.warn('Skipping delete-task test - real API calls disabled'); return; } // First create a task const taskData = generateTestTaskData(); const created = await executeToolWithRetry('create-task', taskData); // Delete the task const result = await executeToolWithRetry('delete-task', { task_id: created.task_id, }); expect(result).toBeDefined(); expect(result.success).toBe(true); expect(result.message).toContain('deleted'); // Verify task is no longer accessible try { await executeToolWithRetry('get-task', { task_id: created.task_id, }); throw new Error('Task should have been deleted'); } catch (error) { // Expected - task should not be found expect(error).toBeDefined(); } }); }); describe('Error Handling', () => { const errorTestCases = createErrorTestCases('task'); errorTestCases.forEach(({ name, test }) => { it(name, async () => { const validParams = generateTestTaskData(); await test('get-task', validParams); }); }); it('should handle invalid task_id in get-task', async () => { await ErrorTestUtils.testNotFoundError( 'get-task', { task_id: 999999999, }, 'task' ); }); it('should handle invalid data in create-task', async () => { await ErrorTestUtils.testValidationError('create-task', { name: '', // Empty name project_id: 'invalid', // Invalid project ID }); }); it('should handle missing required fields in create-task', async () => { await ErrorTestUtils.testValidationError('create-task', { // Missing name and project_id hours: 8, }); }); it('should handle invalid date format in create-task', async () => { const invalidData = generateTestTaskData({ start_date: 'invalid-date', }); await ErrorTestUtils.testValidationError('create-task', invalidData, 'start_date'); }); it('should handle invalid project_id in create-task', async () => { const invalidData = generateTestTaskData({ project_id: 999999999, }); await ErrorTestUtils.testValidationError('create-task', invalidData, 'project_id'); }); }); describe('Performance Tests', () => { it('should handle concurrent requests', async () => { if (TEST_CONFIG.skipSlowTests) { console.warn('Skipping performance test - slow tests disabled'); return; } const requests = Array.from({ length: 5 }, () => executeToolWithRetry('list-tasks', { 'per-page': 5 }) ); const results = await Promise.all(requests); expect(results).toHaveLength(5); results.forEach((result) => { expect(Array.isArray(result)).toBe(true); }); }); }); describe('Data Validation', () => { it('should validate task data structure', async () => { const tasks = await executeToolWithRetry('list-tasks', { 'per-page': 5 }); tasks.forEach((task: any) => { expect(task).toBeDefined(); expect(task.task_id).toBeDefined(); expect(task.name).toBeDefined(); expect(typeof task.name).toBe('string'); expect(task.name.length).toBeGreaterThan(0); // Validate schema const validation = entitySchemaValidator.validateTask(task); expect(validation.isValid).toBe(true); }); }); it('should handle null values in task data', async () => { const tasks = await executeToolWithRetry('list-tasks', { 'per-page': 5 }); tasks.forEach((task: any) => { // These fields can be null according to the schema if (task.notes !== null) { expect(typeof task.notes).toBe('string'); } if (task.start_date !== null) { expect(typeof task.start_date).toBe('string'); } if (task.end_date !== null) { expect(typeof task.end_date).toBe('string'); } }); }); it('should validate task date ranges', async () => { const tasks = await executeToolWithRetry('list-tasks', { 'per-page': 10 }); tasks.forEach((task: any) => { if (task.start_date && task.end_date) { const startDate = new Date(task.start_date); const endDate = new Date(task.end_date); expect(startDate.getTime()).toBeLessThanOrEqual(endDate.getTime()); } }); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/asachs01/float-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server