Skip to main content
Glama
handlers.test.ts8.55 kB
import { ProjectsAPI } from '@/api/projects.js'; import { listProjects, createProject, updateProject, deleteProject } from '@/tools/projects/handlers.js'; import { PlaneInstance } from '@/config/plane-config.js'; import { describe, it, expect, beforeEach, vi } from 'vitest'; // Mock ProjectsAPI vi.mock('@/api/projects.js', () => ({ ProjectsAPI: vi.fn().mockImplementation((instance) => ({ instance, listProjects: vi.fn(), createProject: vi.fn(), updateProject: vi.fn(), deleteProject: vi.fn() })) })); describe('Project Tool Handlers', () => { let api: ReturnType<typeof vi.mocked<ProjectsAPI>>; const mockInstance: PlaneInstance = { name: 'test', baseUrl: 'https://test.plane.so', defaultWorkspace: 'default-workspace', apiKey: 'test-key' }; beforeEach(() => { api = new ProjectsAPI(mockInstance) as ReturnType<typeof vi.mocked<ProjectsAPI>>; }); describe('listProjects', () => { it('should list projects from default workspace', async () => { const mockProjects = [{ id: '123e4567-e89b-12d3-a456-426614174000', name: 'Test Project', identifier: 'TEST', description: null, network: 1, workspace: '123e4567-e89b-12d3-a456-426614174001', project_lead: null, default_assignee: null, is_member: true, member_role: 1, total_members: 1, total_cycles: 0, total_modules: 0, module_view: true, cycle_view: true, issue_views_view: true, page_view: true, inbox_view: true, created_at: '2024-01-25T00:00:00Z', updated_at: '2024-01-25T00:00:00Z', created_by: '123e4567-e89b-12d3-a456-426614174002', updated_by: '123e4567-e89b-12d3-a456-426614174002' }]; vi.mocked(api.listProjects).mockResolvedValue(mockProjects); const result = await listProjects(api, {}); expect(api.listProjects).toHaveBeenCalledWith('default-workspace', { include_archived: undefined }); expect(result.content[0].text).toBe(JSON.stringify(mockProjects, null, 2)); }); it('should list projects from specified workspace', async () => { const mockProjects = [{ id: '123e4567-e89b-12d3-a456-426614174000', name: 'Test Project', identifier: 'TEST', description: null, network: 1, workspace: '123e4567-e89b-12d3-a456-426614174001', project_lead: null, default_assignee: null, is_member: true, member_role: 1, total_members: 1, total_cycles: 0, total_modules: 0, module_view: true, cycle_view: true, issue_views_view: true, page_view: true, inbox_view: true, created_at: '2024-01-25T00:00:00Z', updated_at: '2024-01-25T00:00:00Z', created_by: '123e4567-e89b-12d3-a456-426614174002', updated_by: '123e4567-e89b-12d3-a456-426614174002' }]; vi.mocked(api.listProjects).mockResolvedValue(mockProjects); const result = await listProjects(api, { workspace_slug: 'custom-workspace' }); expect(api.listProjects).toHaveBeenCalledWith('custom-workspace', { include_archived: undefined }); expect(result.content[0].text).toBe(JSON.stringify(mockProjects, null, 2)); }); it('should handle errors gracefully', async () => { vi.mocked(api.listProjects).mockRejectedValue(new Error('API Error')); await expect(listProjects(api, {})) .rejects .toThrow('Failed to list projects: API Error'); }); }); describe('createProject', () => { it('should create a project in default workspace', async () => { const mockProject = { id: '123e4567-e89b-12d3-a456-426614174000', name: 'New Project', identifier: 'NEW', description: null, network: 1, workspace: '123e4567-e89b-12d3-a456-426614174001', project_lead: null, default_assignee: null, is_member: true, member_role: 1, total_members: 1, total_cycles: 0, total_modules: 0, module_view: true, cycle_view: true, issue_views_view: true, page_view: true, inbox_view: true, created_at: '2024-01-25T00:00:00Z', updated_at: '2024-01-25T00:00:00Z', created_by: '123e4567-e89b-12d3-a456-426614174002', updated_by: '123e4567-e89b-12d3-a456-426614174002' }; vi.mocked(api.createProject).mockResolvedValue(mockProject); const result = await createProject(api, { name: 'New Project', identifier: 'NEW' }); expect(api.createProject).toHaveBeenCalledWith('default-workspace', { name: 'New Project', identifier: 'NEW' }); expect(result.content[0].text).toBe(JSON.stringify(mockProject, null, 2)); }); it('should handle validation errors', async () => { await expect(createProject(api, {})) .rejects .toThrow(); }); }); describe('updateProject', () => { it('should update a project', async () => { const mockProject = { id: '123e4567-e89b-12d3-a456-426614174000', name: 'Updated Project', identifier: 'UPD', description: null, network: 1, workspace: '123e4567-e89b-12d3-a456-426614174001', project_lead: null, default_assignee: null, is_member: true, member_role: 1, total_members: 1, total_cycles: 0, total_modules: 0, module_view: true, cycle_view: true, issue_views_view: true, page_view: true, inbox_view: true, created_at: '2024-01-25T00:00:00Z', updated_at: '2024-01-25T00:00:00Z', created_by: '123e4567-e89b-12d3-a456-426614174002', updated_by: '123e4567-e89b-12d3-a456-426614174002' }; vi.mocked(api.updateProject).mockResolvedValue(mockProject); const result = await updateProject(api, { project_id: '1', name: 'Updated Project' }); expect(api.updateProject).toHaveBeenCalledWith('default-workspace', '1', { name: 'Updated Project' }); expect(result.content[0].text).toBe(JSON.stringify(mockProject, null, 2)); }); it('should handle missing project_id', async () => { await expect(updateProject(api, { name: 'Test' })) .rejects .toThrow(); }); }); describe('deleteProject', () => { it('should delete a project', async () => { vi.mocked(api.deleteProject).mockResolvedValue(undefined); const result = await deleteProject(api, { project_id: '1' }); expect(api.deleteProject).toHaveBeenCalledWith('default-workspace', '1'); expect(JSON.parse(result.content[0].text)).toEqual({ success: true, message: 'Project deleted successfully' }); }); it('should handle deletion errors', async () => { vi.mocked(api.deleteProject).mockRejectedValue(new Error('Not found')); await expect(deleteProject(api, { project_id: '1' })) .rejects .toThrow('Failed to delete project: Not found'); }); }); });

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/deus-h/claudeus-plane-mcp'

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