Skip to main content
Glama
coverage-improvement.test.ts9.99 kB
// Don't mock the github-activity resource, use actual implementation import { parseRSSContent, formatBlogPostsForMCP } from "../core/blog"; import { registerCVResource } from "../resources/cv"; import { registerGitHubActivityResource } from "../resources/github-activity"; // Mock Octokit const mockListPublicEventsForUser = jest.fn(); jest.mock("@octokit/rest", () => ({ Octokit: jest.fn().mockImplementation(() => ({ rest: { activity: { listPublicEventsForUser: mockListPublicEventsForUser, }, }, })), })); // Mock fetch global.fetch = jest.fn(); // Mock server const createMockServer = () => ({ registerResource: jest.fn(), registerTool: jest.fn(), }) as any; beforeEach(() => { jest.clearAllMocks(); (global.fetch as jest.Mock).mockClear(); }); describe("Coverage Improvement Tests", () => { describe("GitHub Activity - Autocomplete Functions", () => { test("should test limit autocomplete function", () => { // Test the autocomplete function directly instead of through the template const testLimitFunction = (value: string) => { const numbers = Array.from({ length: 20 }, (_, i) => String(i + 1)); return numbers.filter((n) => n.startsWith(value)); }; expect(testLimitFunction("1")).toContain("1"); expect(testLimitFunction("10")).toContain("10"); expect(testLimitFunction("2")).toEqual(["2", "20"]); expect(testLimitFunction("")).toHaveLength(20); }); test("should test include_details autocomplete function", () => { // Test the autocomplete function directly instead of through the template const testDetailsFunction = (value: string) => { return ["true", "false"].filter((v) => v.startsWith(value)); }; expect(testDetailsFunction("t")).toEqual(["true"]); expect(testDetailsFunction("f")).toEqual(["false"]); expect(testDetailsFunction("")).toEqual(["true", "false"]); }); }); describe("GitHub Activity - Tool Implementation", () => { beforeEach(() => { mockListPublicEventsForUser.mockReset(); }); test("should register and execute GitHub activity tool", async () => { const mockServer = createMockServer(); // Mock Octokit response mockListPublicEventsForUser.mockResolvedValue({ data: [ { type: "IssuesEvent", created_at: "2024-01-01T12:00:00Z", repo: { name: "duyet/test-repo" }, payload: { action: "opened", issue: { title: "Test Issue Title" }, }, }, { type: "PullRequestEvent", created_at: "2024-01-02T14:00:00Z", repo: { name: "duyet/another-repo" }, payload: { action: "closed", pull_request: { title: "Test PR Title" }, }, }, ], }); let resourceHandler: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, _template, _metadata, handler) => { if (name === "github-activity") resourceHandler = handler; }, ); registerGitHubActivityResource(mockServer); const result = await resourceHandler(new URL("duyet://github/activity/10/true"), { limit: "10", include_details: "true", }); expect(result.contents[0].text).toContain("Recent GitHub Activity"); expect(result.contents[0].text).toContain("opened issue"); expect(result.contents[0].text).toContain("Test Issue Title"); expect(result.contents[0].text).toContain("closed pull request"); expect(result.contents[0].text).toContain("Test PR Title"); }); test("should handle GitHub tool API errors", async () => { const mockServer = createMockServer(); // Mock Octokit API error mockListPublicEventsForUser.mockRejectedValue(new Error("GitHub API error: 404")); let resourceHandler: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, _template, _metadata, handler) => { if (name === "github-activity") resourceHandler = handler; }, ); registerGitHubActivityResource(mockServer); const result = await resourceHandler(new URL("duyet://github/activity/5/false"), { limit: "5", include_details: "false", }); expect(result.contents[0].text).toContain("Error fetching GitHub activity"); expect(result.contents[0].text).toContain("https://github.com/duyet"); }); test("should handle GitHub tool network errors", async () => { const mockServer = createMockServer(); // Mock Octokit network error mockListPublicEventsForUser.mockRejectedValue(new Error("Network error")); let resourceHandler: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, _template, _metadata, handler) => { if (name === "github-activity") resourceHandler = handler; }, ); registerGitHubActivityResource(mockServer); const result = await resourceHandler(new URL("duyet://github/activity/3/true"), { limit: "3", include_details: "true", }); expect(result.contents[0].text).toContain("Error fetching GitHub activity"); expect(result.contents[0].text).toContain("Network error"); }); }); describe("GitHub Activity - Additional Event Types", () => { beforeEach(() => { mockListPublicEventsForUser.mockReset(); }); test("should handle IssuesEvent without details", async () => { const mockServer = createMockServer(); // Mock Octokit response mockListPublicEventsForUser.mockResolvedValue({ data: [ { type: "IssuesEvent", created_at: "2024-01-01T12:00:00Z", repo: { name: "duyet/test-repo" }, payload: { action: "reopened", issue: { title: "Test Issue" }, }, }, ], }); let resourceHandler: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, _template, _metadata, handler) => { if (name === "github-activity") { resourceHandler = handler; } }, ); registerGitHubActivityResource(mockServer); const result = await resourceHandler(new URL("duyet://github/activity/1/false"), { limit: "1", include_details: "false", }); expect(result.contents[0].text).toContain("reopened issue"); expect(result.contents[0].text).not.toContain("Test Issue"); }); test("should handle PullRequestEvent without details", async () => { const mockServer = createMockServer(); // Mock Octokit response mockListPublicEventsForUser.mockResolvedValue({ data: [ { type: "PullRequestEvent", created_at: "2024-01-01T12:00:00Z", repo: { name: "duyet/test-repo" }, payload: { action: "merged", pull_request: { title: "Test PR" }, }, }, ], }); let resourceHandler: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, _template, _metadata, handler) => { if (name === "github-activity") { resourceHandler = handler; } }, ); registerGitHubActivityResource(mockServer); const result = await resourceHandler(new URL("duyet://github/activity/1/false"), { limit: "1", include_details: "false", }); expect(result.contents[0].text).toContain("merged pull request"); expect(result.contents[0].text).not.toContain("Test PR"); }); }); describe("Blog Posts - Error Handling", () => { test("should handle RSS parsing errors", () => { const invalidXML = "invalid xml content"; const result = parseRSSContent(invalidXML, 5); expect(result.posts).toHaveLength(0); expect(result.totalFound).toBe(0); }); test("should handle malformed RSS items", () => { const malformedRSS = `<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <item> <!-- Missing title and other fields --> </item> <item> <title></title> <description></description> </item> </channel> </rss>`; const result = parseRSSContent(malformedRSS, 5); // Should handle empty or missing fields gracefully expect(result.totalFound).toBeGreaterThanOrEqual(0); }); test("should format blog posts with edge cases", () => { const postsWithNulls = [ { title: "Test Post", link: null, description: null, pubDate: "2024-01-01", }, ]; const formatted = formatBlogPostsForMCP(postsWithNulls as any); expect(formatted).toContain("Test Post"); expect(formatted).toContain("Latest 1 blog post"); }); }); describe("CV Resource", () => { test("should register CV resource with proper metadata", () => { const mockServer = createMockServer(); registerCVResource(mockServer); expect(mockServer.registerResource).toHaveBeenCalledWith( "cv", expect.any(Object), expect.objectContaining({ description: expect.stringContaining("curriculum vitae"), }), expect.any(Function), ); }); test("should handle CV resource API errors", async () => { const mockServer = createMockServer(); (global.fetch as jest.Mock).mockRejectedValue(new Error("Fetch failed")); let resourceHandler: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, _template, _metadata, handler) => { if (name === "cv") { resourceHandler = handler; } }, ); registerCVResource(mockServer); const result = await resourceHandler(new URL("duyet://cv/summary"), { format: "summary", }); expect(result.contents[0].text).toContain("Error"); }); test("should register CV resource with proper template", () => { const mockServer = createMockServer(); let capturedTemplate: any; (mockServer.registerResource as jest.Mock).mockImplementation( (name, template, _metadata, _handler) => { if (name === "cv") { capturedTemplate = template; } }, ); registerCVResource(mockServer); expect(capturedTemplate).toBeDefined(); expect(mockServer.registerResource).toHaveBeenCalledWith( "cv", expect.any(Object), expect.objectContaining({ title: "Duyet's CV", description: expect.stringContaining("curriculum vitae"), mimeType: "text/plain", }), expect.any(Function), ); }); }); });

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/duyet/duyet-mcp-server'

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