GitHubProjectManager.test.ts.fixed•5.43 kB
// filepath: /Users/vivek/grad-saas/mcp-github-project-manager/src/__tests__/integration/GitHubProjectManager.test.ts
import {
afterEach,
beforeEach,
describe,
expect,
it,
jest,
} from "@jest/globals";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import nock from "nock";
import { mockData } from "../setup";
// Define types for our test responses
interface RoadmapResponse {
project: typeof mockData.project;
milestones: Array<{
milestone: typeof mockData.milestone;
issues: (typeof mockData.issue)[];
}>;
}
interface SprintResponse {
id: string;
title: string;
startDate: string;
endDate: string;
status: string;
goals: string[];
issues: string[];
}
interface ToolResponse {
content: Array<{
type: "text";
text: string;
}>;
}
describe("GitHub Project Manager Integration", () => {
const originalEnv = process.env;
let server: Server;
beforeEach(() => {
process.env = {
...originalEnv,
GITHUB_TOKEN: "test-token",
GITHUB_OWNER: "test-owner",
GITHUB_REPO: "test-repo",
};
nock.disableNetConnect();
// Create server instance
server = new Server(
{ name: "test-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
});
afterEach(() => {
process.env = originalEnv;
nock.cleanAll();
jest.clearAllMocks();
});
describe("create_roadmap tool", () => {
it("should create a complete roadmap with project, milestones, and issues", async () => {
// Mock GitHub API responses
const scope = nock("https://api.github.com")
// Project creation (GraphQL)
.post("/graphql")
.reply(200, {
createProjectV2: {
projectV2: mockData.project,
},
})
// Milestone creation (GraphQL)
.post("/graphql")
.reply(200, {
createMilestone: {
milestone: mockData.milestone,
},
})
// Issue creation (GraphQL)
.post("/graphql")
.reply(200, {
createIssue: {
issue: mockData.issue,
},
});
// Create mock response
const mockResponse: RoadmapResponse = {
project: mockData.project,
milestones: [
{
milestone: mockData.milestone,
issues: [mockData.issue],
},
],
};
// Set up tool handler
const handler = async () => ({
content: [
{
type: "text" as const,
text: JSON.stringify(mockResponse),
},
],
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name !== "create_roadmap") {
throw new Error("Unknown tool");
}
return handler();
});
// Test the tool handler
const response = await handler();
// Verify the response
expect(response.content).toHaveLength(1);
const result = JSON.parse(response.content[0].text) as RoadmapResponse;
expect(result.project.id).toBeDefined();
expect(result.milestones).toHaveLength(1);
expect(result.milestones[0].issues).toHaveLength(1);
// Verify all API calls were made
expect(scope.isDone()).toBe(true);
});
});
describe("plan_sprint tool", () => {
it("should create a sprint and verify issues exist", async () => {
// Mock GitHub API responses
const scope = nock("https://api.github.com")
// Issue verification (GraphQL)
.post("/graphql")
.reply(200, {
repository: {
issue: mockData.issue
}
})
// Sprint creation (GraphQL)
.post("/graphql")
.reply(200, {
createProjectV2Field: {
projectV2Field: {
id: "field-1",
name: "Sprint",
},
},
createProjectV2IterationFieldIteration: {
iteration: {
id: "sprint-1",
title: "Sprint 1",
startDate: "2024-01-01T00:00:00Z",
duration: 2,
},
},
});
// Create mock response
const mockResponse: SprintResponse = {
id: "sprint-1",
title: "Sprint 1",
startDate: "2024-01-01T00:00:00Z",
endDate: "2024-01-14T23:59:59Z",
status: "planned",
goals: ["Complete authentication features"],
issues: ["issue-123"],
};
// Set up tool handler
const handler = async () => ({
content: [
{
type: "text" as const,
text: JSON.stringify(mockResponse),
},
],
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name !== "plan_sprint") {
throw new Error("Unknown tool");
}
return handler();
});
// Test the tool handler
const response = await handler();
// Verify the response
expect(response.content).toHaveLength(1);
const result = JSON.parse(response.content[0].text) as SprintResponse;
expect(result.id).toBe("sprint-1");
expect(result.issues).toContain("issue-123");
// Verify all API calls were made
expect(scope.isDone()).toBe(true);
});
});
});