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

200 lines (197 loc) 9.64 kB
"use strict"; /** * Unit tests for Components Discovery Tool */ Object.defineProperty(exports, "__esModule", { value: true }); const componentsDiscovery_1 = require("../tools/componentsDiscovery"); const gitlabClient_1 = require("../services/gitlabClient"); // Mock the GitLab client jest.mock('../services/gitlabClient', () => ({ fetchGitLabFileContentSafe: jest.fn(), GitLabError: class GitLabError extends Error { statusCode; url; constructor(message, statusCode, url) { super(message); this.statusCode = statusCode; this.url = url; this.name = 'GitLabError'; } } })); // Mock the config jest.mock('../config', () => ({ config: { urls: { mainLlms: 'https://gitlab.example.com/repo/-/raw/main/llms.txt' } } })); const gitlabClient_2 = require("../services/gitlabClient"); const mockFetchGitLabFileContentSafe = gitlabClient_2.fetchGitLabFileContentSafe; describe('Components Discovery Tool', () => { beforeEach(() => { jest.clearAllMocks(); jest.spyOn(console, 'log').mockImplementation(() => { }); jest.spyOn(console, 'error').mockImplementation(() => { }); }); afterEach(() => { jest.restoreAllMocks(); }); describe('parseLlmsContent', () => { it('should parse basic component list', () => { const content = `# Awesome Components component-a component-b guide/getting-started docs/readme.md`; const result = (0, componentsDiscovery_1.parseLlmsContent)(content); expect(result.title).toBe('Awesome Components'); expect(result.totalComponents).toBe(4); expect(result.components).toHaveLength(4); expect(result.components[0].name).toBe('component-a'); expect(result.components[1].name).toBe('component-b'); expect(result.components[2].name).toBe('guide/getting-started'); expect(result.components[2].type).toBe('guide'); expect(result.components[3].name).toBe('docs/readme.md'); expect(result.components[3].type).toBe('documentation'); }); it('should handle empty content', () => { const result = (0, componentsDiscovery_1.parseLlmsContent)(''); expect(result.totalComponents).toBe(0); expect(result.components).toHaveLength(0); }); it('should skip comments and headers', () => { const content = `# Title // This is a comment <!-- HTML comment --> component-a # Another header component-b`; const result = (0, componentsDiscovery_1.parseLlmsContent)(content); expect(result.totalComponents).toBe(2); expect(result.components[0].name).toBe('component-a'); expect(result.components[1].name).toBe('component-b'); }); it('should detect component types correctly', () => { const content = `button-component tutorial-guide documentation.md other-item`; const result = (0, componentsDiscovery_1.parseLlmsContent)(content); expect(result.components[0].type).toBe('component'); expect(result.components[1].type).toBe('guide'); expect(result.components[2].type).toBe('documentation'); expect(result.components[3].type).toBe('other'); }); it('should extract paths for file-like entries', () => { const content = `components/button.tsx guides/getting-started.md simple-name`; const result = (0, componentsDiscovery_1.parseLlmsContent)(content); expect(result.components[0].path).toBe('components/button.tsx'); expect(result.components[1].path).toBe('guides/getting-started.md'); expect(result.components[2].path).toBeUndefined(); }); }); describe('generateComponentsSummary', () => { it('should generate summary for components', () => { const parsed = { title: 'Test Components', totalComponents: 3, components: [ { name: 'button', type: 'component' }, { name: 'guide', type: 'guide' }, { name: 'docs', type: 'documentation' } ] }; const summary = (0, componentsDiscovery_1.generateComponentsSummary)(parsed); expect(summary).toContain('Test Components'); expect(summary).toContain('Total Components Found: 3'); expect(summary).toContain('component: 1 items'); expect(summary).toContain('guide: 1 items'); expect(summary).toContain('documentation: 1 items'); expect(summary).toContain('1. button (component)'); }); it('should handle empty component list', () => { const parsed = { totalComponents: 0, components: [] }; const summary = (0, componentsDiscovery_1.generateComponentsSummary)(parsed); expect(summary).toContain('Total Components Found: 0'); expect(summary).toContain('No components were found'); }); it('should truncate long component lists', () => { const components = Array.from({ length: 15 }, (_, i) => ({ name: `component-${i}`, type: 'component' })); const parsed = { totalComponents: 15, components }; const summary = (0, componentsDiscovery_1.generateComponentsSummary)(parsed); expect(summary).toContain('Total Components Found: 15'); expect(summary).toContain('... and 5 more components'); }); }); describe('componentsDiscoveryTool', () => { const mockContent = `# Awesome Components button-component input-component guide/getting-started`; it('should return raw content when format is raw', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockContent); const result = await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'raw' }); expect(result.content[0].text).toContain('Raw llms.txt Content'); expect(result.content[0].text).toContain(mockContent); expect(result.isError).toBeUndefined(); }); it('should return parsed content when format is parsed', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockContent); const result = await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'parsed' }); expect(result.content[0].text).toContain('Parsed Components Information'); expect(result.content[0].text).toContain('"totalComponents": 3'); expect(result.content[0].text).toContain('button-component'); expect(result.isError).toBeUndefined(); }); it('should return summary when format is summary', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockContent); const result = await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'summary' }); expect(result.content[0].text).toContain('Awesome Components'); expect(result.content[0].text).toContain('Total Components Found: 3'); expect(result.content[0].text).toContain('button-component'); expect(result.isError).toBeUndefined(); }); it('should default to parsed format when no format specified', async () => { mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockContent); const result = await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'parsed' }); expect(result.content[0].text).toContain('Components Discovery Results'); expect(result.content[0].text).toContain('"totalComponents": 3'); expect(result.isError).toBeUndefined(); }); it('should handle GitLab errors gracefully', async () => { const gitlabError = new gitlabClient_1.GitLabError('File not found', 404, 'https://example.com/file.txt'); mockFetchGitLabFileContentSafe.mockRejectedValueOnce(gitlabError); const result = await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'summary' }); 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 general errors gracefully', async () => { mockFetchGitLabFileContentSafe.mockRejectedValueOnce(new Error('Network error')); const result = await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'summary' }); expect(result.content[0].text).toContain('Error: Components Discovery Failed'); expect(result.content[0].text).toContain('Error: Network error'); expect(result.isError).toBe(true); }); it('should log the fetch URL', async () => { const consoleSpy = jest.spyOn(console, 'log'); mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockContent); await (0, componentsDiscovery_1.componentsDiscoveryTool)({ format: 'summary' }); expect(consoleSpy).toHaveBeenCalledWith('Fetching components list from: https://gitlab.example.com/repo/-/raw/main/llms.txt'); }); }); });