UNPKG

@yeepay/awesome-components-mcp

Version:

MCP server providing access to awesome-components documentation and integration guides with dual-mode operation: direct fetch and GitLab MCP instruction generation

218 lines (174 loc) 7.7 kB
/** * Integration tests for Components Discovery MCP Tool * These tests verify the tool's behavior with mocked GitLab responses */ // Mock the GitLab client module const mockFetchGitLabFileContentSafe = jest.fn(); jest.mock('../../services/gitlabClient', () => ({ fetchGitLabFileContentSafe: mockFetchGitLabFileContentSafe, GitLabError: class GitLabError extends Error { constructor(message: string, public statusCode?: number, public url?: string) { super(message); this.name = 'GitLabError'; } } })); import { componentsDiscoveryTool } from '../../tools/componentsDiscovery'; // Mock the config jest.mock('../../config', () => ({ config: { urls: { gitlabBase: 'https://gitlab.example.com/repo/-/raw/main/', mainLlms: 'https://gitlab.example.com/repo/-/raw/main/llms.txt' }, auth: { gitlabToken: 'test-token' }, llmsTxtUrl: 'https://gitlab.example.com/repo/-/raw/main/llms.txt', llmsTxtProjectId: null, llmsTxtFile: null, gitlabMcpServerAddress: null, internalGitlabHost: null, internalGuidesProjectId: null } })); describe('Components Discovery Tool Integration Tests', () => { beforeEach(() => { jest.clearAllMocks(); jest.spyOn(console, 'log').mockImplementation(() => {}); jest.spyOn(console, 'error').mockImplementation(() => {}); }); afterEach(() => { jest.restoreAllMocks(); }); describe('Direct fetch mode (LLMS_TXT_URL configured)', () => { const mockLlmsContent = `# Awesome Components button-component input-component modal-component guide/getting-started docs/api-reference.md tutorial/basic-usage // This is a comment another-component`; it('should execute successfully and return JSON format', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockLlmsContent); const result = await componentsDiscoveryTool(); expect(result.content).toHaveLength(1); expect(result.content[0].type).toBe('text'); // Parse the JSON response const jsonData = JSON.parse(result.content[0].text); expect(jsonData).toHaveProperty('source'); expect(jsonData).toHaveProperty('totalComponents', 7); expect(jsonData).toHaveProperty('componentsByType'); expect(jsonData).toHaveProperty('components'); expect(jsonData.components).toHaveLength(7); expect(result.isError).toBeUndefined(); expect(mockFetchGitLabFileContentSafe).toHaveBeenCalledWith( 'https://gitlab.example.com/repo/-/raw/main/llms.txt' ); }); it('should categorize components correctly', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockLlmsContent); const result = await componentsDiscoveryTool(); const jsonData = JSON.parse(result.content[0].text); expect(jsonData.componentsByType).toEqual({ component: 4, guide: 1, documentation: 1, tutorial: 1 }); // Check specific components const buttonComponent = jsonData.components.find((c: any) => c.name === 'button-component'); expect(buttonComponent).toEqual({ name: 'button-component', type: 'component', path: 'button-component' }); const guideComponent = jsonData.components.find((c: any) => c.name === 'getting-started'); expect(guideComponent).toEqual({ name: 'getting-started', type: 'guide', path: 'guide/getting-started' }); expect(result.isError).toBeUndefined(); }); it('should handle empty content gracefully', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(''); const result = await componentsDiscoveryTool(); expect(result.content).toHaveLength(1); const jsonData = JSON.parse(result.content[0].text); expect(jsonData.totalComponents).toBe(0); expect(jsonData.components).toEqual([]); expect(jsonData.componentsByType).toEqual({}); expect(result.isError).toBeUndefined(); }); }); // Note: GitLab MCP instruction mode tests would require more complex mocking // For now, we'll test the direct fetch mode which is the current default describe('Error handling scenarios', () => { it('should handle GitLab errors gracefully', async () => { const { GitLabError } = require('../../services/gitlabClient'); const gitlabError = new GitLabError('File not found', 404, 'https://example.com/file.txt'); mockFetchGitLabFileContentSafe.mockRejectedValueOnce(gitlabError); const result = await componentsDiscoveryTool(); expect(result.content).toHaveLength(1); expect(result.content[0].text).toContain('Error: Components Discovery Failed'); expect(result.content[0].text).toContain('GitLab Error: File not found'); expect(result.content[0].text).toContain('**Status Code:** 404'); expect(result.isError).toBe(true); }); it('should handle network errors gracefully', async () => { mockFetchGitLabFileContentSafe.mockRejectedValueOnce(new Error('Network timeout')); const result = await componentsDiscoveryTool(); expect(result.content).toHaveLength(1); expect(result.content[0].text).toContain('Error: Components Discovery Failed'); expect(result.content[0].text).toContain('Error: Network timeout'); expect(result.isError).toBe(true); }); it('should handle unexpected errors gracefully', async () => { mockFetchGitLabFileContentSafe.mockRejectedValueOnce('Unexpected error type'); const result = await componentsDiscoveryTool(); expect(result.content).toHaveLength(1); expect(result.content[0].text).toContain('Error: Components Discovery Failed'); expect(result.content[0].text).toContain('Error: Unexpected error type'); expect(result.isError).toBe(true); }); }); describe('Tool behavior verification', () => { it('should log the correct URL being fetched', async () => { const consoleSpy = jest.spyOn(console, 'log'); mockFetchGitLabFileContentSafe.mockResolvedValueOnce('test content'); await componentsDiscoveryTool(); expect(consoleSpy).toHaveBeenCalledWith( 'Fetching components list from: https://gitlab.example.com/repo/-/raw/main/llms.txt' ); }); it('should call GitLab client with correct URL', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce('test content'); await componentsDiscoveryTool(); expect(mockFetchGitLabFileContentSafe).toHaveBeenCalledTimes(1); expect(mockFetchGitLabFileContentSafe).toHaveBeenCalledWith( 'https://gitlab.example.com/repo/-/raw/main/llms.txt' ); }); it('should return MCP-compliant response structure with valid JSON', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce('test content'); const result = await componentsDiscoveryTool(); // Verify MCP response structure expect(result).toHaveProperty('content'); expect(Array.isArray(result.content)).toBe(true); expect(result.content).toHaveLength(1); expect(result.content[0]).toHaveProperty('type', 'text'); expect(result.content[0]).toHaveProperty('text'); expect(typeof result.content[0].text).toBe('string'); // Verify the content is valid JSON expect(() => JSON.parse(result.content[0].text)).not.toThrow(); const jsonData = JSON.parse(result.content[0].text); expect(jsonData).toHaveProperty('source'); expect(jsonData).toHaveProperty('totalComponents'); expect(jsonData).toHaveProperty('componentsByType'); expect(jsonData).toHaveProperty('components'); }); }); });