Skip to main content
Glama

mcp-github-project-manager

ProjectManagementService.test.ts.fixed8.81 kB
// filepath: /Users/vivek/grad-saas/mcp-github-project-manager/src/__tests__/unit/services/ProjectManagementService.test.ts import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { Issue, Milestone, Project, Sprint, CreateIssue } from "../../../domain/types"; import { ResourceStatus } from "../../../domain/resource-types"; import { GitHubIssueRepository } from "../../../infrastructure/github/repositories/GitHubIssueRepository"; import { GitHubMilestoneRepository } from "../../../infrastructure/github/repositories/GitHubMilestoneRepository"; import { GitHubProjectRepository } from "../../../infrastructure/github/repositories/GitHubProjectRepository"; import { GitHubSprintRepository } from "../../../infrastructure/github/repositories/GitHubSprintRepository"; import { ProjectManagementService } from "../../../services/ProjectManagementService"; // Mock repositories jest.mock( "../../../infrastructure/github/repositories/GitHubProjectRepository" ); jest.mock( "../../../infrastructure/github/repositories/GitHubIssueRepository" ); jest.mock( "../../../infrastructure/github/repositories/GitHubMilestoneRepository" ); jest.mock( "../../../infrastructure/github/repositories/GitHubSprintRepository" ); describe("ProjectManagementService", () => { let service: ProjectManagementService; let mockProjectRepo: jest.Mocked<GitHubProjectRepository>; let mockIssueRepo: jest.Mocked<GitHubIssueRepository>; let mockMilestoneRepo: jest.Mocked<GitHubMilestoneRepository>; let mockSprintRepo: jest.Mocked<GitHubSprintRepository>; beforeEach(() => { // Clear all mocks jest.clearAllMocks(); // Create service instance service = new ProjectManagementService( "test-owner", "test-repo", "test-token" ); // Get mock instances mockProjectRepo = GitHubProjectRepository.prototype as jest.Mocked<GitHubProjectRepository>; mockIssueRepo = GitHubIssueRepository.prototype as jest.Mocked<GitHubIssueRepository>; mockMilestoneRepo = GitHubMilestoneRepository.prototype as jest.Mocked<GitHubMilestoneRepository>; mockSprintRepo = GitHubSprintRepository.prototype as jest.Mocked<GitHubSprintRepository>; }); describe("createRoadmap", () => { it("should create a project with milestones and issues", async () => { // Arrange const roadmapData = { project: { title: "Q1 2024 Roadmap", description: "Product roadmap for Q1 2024", owner: "test-owner", visibility: "private" as const, }, milestones: [ { milestone: { title: "MVP Release", description: "Initial feature set", dueDate: "2024-03-31T00:00:00Z", }, issues: [ { title: "User Authentication", description: "Implement OAuth login", assignees: ["developer1"], labels: ["auth"], } as CreateIssue, ], }, ], }; // Mock repository responses const createdProject: Project = { ...roadmapData.project, id: "project-123", status: ResourceStatus.ACTIVE, fields: [], views: [], number: 1, url: "https://github.com/test-owner/projects/1", closed: false, createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z", }; const createdMilestone: Milestone = { ...roadmapData.milestones[0].milestone, id: "milestone-123", number: 1, status: ResourceStatus.ACTIVE, progress: { percent: 0, complete: 0, total: 1 }, url: "https://github.com/test-owner/test-repo/milestone/1", createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z", }; const createdIssue: Issue = { id: "issue-123", number: 1, title: "User Authentication", description: "Implement OAuth login", status: ResourceStatus.ACTIVE, assignees: ["developer1"], labels: ["auth"], milestoneId: "milestone-123", createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z", url: "https://github.com/test-owner/test-repo/issues/1", }; mockProjectRepo.create.mockResolvedValueOnce(createdProject); mockMilestoneRepo.create.mockResolvedValueOnce(createdMilestone); mockIssueRepo.create.mockResolvedValueOnce(createdIssue); // Act const result = await service.createRoadmap(roadmapData); // Assert expect(mockProjectRepo.create).toHaveBeenCalledWith(roadmapData.project); expect(mockMilestoneRepo.create).toHaveBeenCalledWith( roadmapData.milestones[0].milestone ); expect(mockIssueRepo.create).toHaveBeenCalledWith({ ...roadmapData.milestones[0].issues[0], milestoneId: "milestone-123", }); expect(result.project.id).toBe("project-123"); expect(result.milestones).toHaveLength(1); expect(result.milestones[0].milestone.id).toBe("milestone-123"); expect(result.milestones[0].issues).toHaveLength(1); expect(result.milestones[0].issues[0].id).toBe("issue-123"); }); it("should handle errors during roadmap creation", async () => { // Arrange const roadmapData = { project: { title: "Q1 2024 Roadmap", description: "Product roadmap for Q1 2024", owner: "test-owner", visibility: "private" as const, }, milestones: [], }; mockProjectRepo.create.mockRejectedValueOnce( new Error("Project creation failed") ); // Act & Assert await expect(service.createRoadmap(roadmapData)).rejects.toThrow( "Project creation failed" ); }); }); describe("planSprint", () => { it("should create a sprint and verify issues", async () => { // Arrange const sprintData = { sprint: { title: "Sprint 1", description: "First sprint", startDate: "2024-01-01T00:00:00Z", endDate: "2024-01-14T00:00:00Z", status: ResourceStatus.PLANNED, goals: ["Complete authentication features"], }, issueIds: ["issue-1", "issue-2"], }; const issue1: Issue = { id: "issue-1", number: 1, title: "Issue 1", description: "Test", status: ResourceStatus.ACTIVE, assignees: [], labels: [], createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z", url: "https://github.com/test-owner/test-repo/issues/1", }; const issue2: Issue = { id: "issue-2", number: 2, title: "Issue 2", description: "Test", status: ResourceStatus.ACTIVE, assignees: [], labels: [], createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z", url: "https://github.com/test-owner/test-repo/issues/2", }; mockIssueRepo.findById.mockImplementation((id) => { if (id === "issue-1") return Promise.resolve(issue1); if (id === "issue-2") return Promise.resolve(issue2); return Promise.resolve(null); }); const createdSprint: Sprint = { ...sprintData.sprint, id: "sprint-1", issues: sprintData.issueIds, createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z", url: "https://github.com/test-owner/test-repo/projects/sprint/1", }; mockSprintRepo.create.mockResolvedValueOnce(createdSprint); // Act const result = await service.planSprint(sprintData); // Assert expect(mockIssueRepo.findById).toHaveBeenCalledTimes(2); expect(mockSprintRepo.create).toHaveBeenCalledWith({ ...sprintData.sprint, issues: sprintData.issueIds, }); expect(result.id).toBe("sprint-1"); expect(result.issues).toEqual(sprintData.issueIds); }); it("should throw error if issue not found", async () => { // Arrange const sprintData = { sprint: { title: "Sprint 1", description: "First sprint", startDate: "2024-01-01T00:00:00Z", endDate: "2024-01-14T00:00:00Z", status: ResourceStatus.PLANNED, goals: ["Complete authentication features"], }, issueIds: ["non-existent-issue"], }; mockIssueRepo.findById.mockResolvedValueOnce(null); // Act & Assert await expect(service.planSprint(sprintData)).rejects.toThrow( /Issue #non-existent-issue not found/ ); }); }); });

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/kunwarVivek/mcp-github-project-manager'

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