Skip to main content
Glama

SAP OData to MCP Server

by Raistlin82
ui-integration-test-suite.ts•24.3 kB
/** * Comprehensive Test Suite for UI Integration * Tests all UI tools, workflow integration, and suggestions */ import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { HierarchicalToolRegistry } from '../src/tools/hierarchical-tool-registry.js'; import { IntelligentToolRouter } from '../src/middleware/intelligent-tool-router.js'; import { SAPClient } from '../src/services/sap-client.js'; import { Logger } from '../src/utils/logger.js'; describe('šŸŽØ UI Integration Test Suite', () => { let mcpServer: McpServer; let toolRegistry: HierarchicalToolRegistry; let intelligentRouter: IntelligentToolRouter; let sapClient: SAPClient; let logger: Logger; beforeEach(() => { // Setup test environment mcpServer = new McpServer({ name: 'test-server', version: '1.0.0' }, {}); logger = new Logger({ level: 'debug', service: 'test' }); sapClient = new SAPClient({ baseUrl: 'https://test.sap.com', auth: { type: 'oauth2', clientId: 'test', clientSecret: 'test' } }, logger); toolRegistry = new HierarchicalToolRegistry(mcpServer, sapClient, logger); intelligentRouter = new IntelligentToolRouter(); }); describe('šŸ“‹ 1. Individual UI Tool Tests', () => { describe('ui-form-generator', () => { it('should create form with valid entity type', async () => { const args = { entityType: 'Customer', formType: 'create', fields: [ { name: 'CustomerID', label: 'ID Cliente', type: 'text', required: true }, { name: 'CompanyName', label: 'Ragione Sociale', type: 'text', required: true } ] }; const result = await testUITool('ui-form-generator', args); expect(result.content).toBeDefined(); expect(result.content[0].text).toContain('āœ… SAP Customer create form generated successfully'); expect(result.content[1].text).toContain('<!DOCTYPE html>'); expect(result.content[1].text).toContain('sap-form-container'); expect(result.content[1].text).toContain('CustomerID'); expect(result.content[1].text).toContain('CompanyName'); }); it('should handle all form types', async () => { const formTypes = ['create', 'edit', 'view']; for (const formType of formTypes) { const args = { entityType: 'Product', formType }; const result = await testUITool('ui-form-generator', args); expect(result.content[0].text).toContain(`āœ… SAP Product ${formType} form generated successfully`); expect(result.content[1].text).toContain(`${formType.charAt(0).toUpperCase() + formType.slice(1)} Form`); } }); }); describe('ui-data-grid', () => { it('should create data grid with custom columns', async () => { const args = { entityType: 'SalesOrder', columns: [ { label: 'Order ID', key: 'OrderID', type: 'text' }, { label: 'Customer', key: 'CustomerID', type: 'text' }, { label: 'Amount', key: 'TotalAmount', type: 'number' } ], features: { filtering: true, sorting: true, export: true, pagination: true } }; const result = await testUITool('ui-data-grid', args); expect(result.content[0].text).toContain('āœ… Interactive SalesOrder data grid generated with 3 columns'); expect(result.content[1].text).toContain('data-table'); expect(result.content[1].text).toContain('Order ID'); expect(result.content[1].text).toContain('exportData'); expect(result.content[1].text).toContain('filterTable'); }); it('should generate auto columns when none provided', async () => { const args = { entityType: 'Customer' }; const result = await testUITool('ui-data-grid', args); expect(result.content[0].text).toContain('āœ… Interactive Customer data grid generated with auto columns'); }); }); describe('ui-dashboard-composer', () => { it('should create dashboard with multiple widgets', async () => { const args = { dashboardTitle: 'Sales Performance Dashboard', widgets: [ { type: 'metric', title: 'Total Revenue', entityType: 'SalesOrder' }, { type: 'chart', title: 'Monthly Trends', entityType: 'SalesOrder' }, { type: 'gauge', title: 'Target Achievement', entityType: 'SalesOrder' } ], layout: 'grid' }; const result = await testUITool('ui-dashboard-composer', args); expect(result.content[0].text).toContain('āœ… "Sales Performance Dashboard" KPI dashboard created with 3 widgets and grid layout'); expect(result.content[1].text).toContain('Chart.js'); expect(result.content[1].text).toContain('Total Revenue'); expect(result.content[1].text).toContain('Monthly Trends'); expect(result.content[1].text).toContain('widget-grid'); }); }); describe('ui-workflow-builder', () => { it('should create workflow with approval steps', async () => { const args = { workflowName: 'Order Approval Process', steps: [ { name: 'Submit Order', type: 'form' }, { name: 'Manager Review', type: 'approval' }, { name: 'Finance Check', type: 'approval' }, { name: 'Final Notification', type: 'notification' } ], entityType: 'SalesOrder' }; const result = await testUITool('ui-workflow-builder', args); expect(result.content[0].text).toContain('āœ… "Order Approval Process" workflow created with 4 steps for SalesOrder entities'); expect(result.content[1].text).toContain('workflow-container'); expect(result.content[1].text).toContain('Submit Order'); expect(result.content[1].text).toContain('Manager Review'); expect(result.content[1].text).toContain('workflow-connector'); }); }); describe('ui-report-builder', () => { it('should create analytical report with drill-down', async () => { const args = { entityType: 'SalesOrder', reportType: 'analytical', dimensions: ['Region', 'Product'], measures: ['Revenue', 'Quantity', 'Profit'] }; const result = await testUITool('ui-report-builder', args); expect(result.content[0].text).toContain('āœ… analytical report for SalesOrder created with 2 dimensions and 3 measures'); expect(result.content[1].text).toContain('report-container'); expect(result.content[1].text).toContain('Revenue'); expect(result.content[1].text).toContain('trendChart'); expect(result.content[1].text).toContain('Chart.js'); }); }); }); describe('šŸ”„ 2. Workflow Integration Tests', () => { it('should suggest UI tools after execute-entity-operation (read)', async () => { const mockResponse = { data: { value: [ { CustomerID: '001', CompanyName: 'ACME Corp' }, { CustomerID: '002', CompanyName: 'Tech Solutions' } ] } }; const suggestions = generateUIToolSuggestions('read', 'Customer', mockResponse.data); expect(suggestions).toContain('šŸ“Š **Visualizzazione Dati (2 record trovati)**'); expect(suggestions).toContain('ui-data-grid'); expect(suggestions).toContain('ui-dashboard-composer'); expect(suggestions).toContain('ui-report-builder'); expect(suggestions).toContain('**Esempio uso:**'); }); it('should suggest UI tools after execute-entity-operation (create)', async () => { const mockResponse = { data: { CustomerID: '003', CompanyName: 'New Client' } }; const suggestions = generateUIToolSuggestions('create', 'Customer', mockResponse.data); expect(suggestions).toContain('āœ… **Customer creato con successo!**'); expect(suggestions).toContain('ui-form-generator'); expect(suggestions).toContain('ui-workflow-builder'); expect(suggestions).toContain('**Esempio form per creazione:**'); }); it('should suggest UI tools after entity schema discovery', async () => { const mockSchema = { entityName: 'Product', properties: [ { name: 'ProductID', type: 'Edm.String' }, { name: 'Price', type: 'Edm.Decimal' }, { name: 'Status', type: 'Edm.String' } ] }; const suggestions = generateEntityDiscoveryUIToolSuggestions('Product', mockSchema); expect(suggestions).toContain('šŸŽØ Strumenti UI Disponibili per Product'); expect(suggestions).toContain('### šŸ“ Gestione Dati'); expect(suggestions).toContain('### šŸ“Š Visualizzazione Tabellare'); expect(suggestions).toContain('### šŸ“ˆ Dashboard Analitico'); expect(suggestions).toContain('### šŸ”„ Workflow e Processi'); }); }); describe('🧠 3. Intelligent Router Tests', () => { it('should detect UI patterns in Italian', async () => { const testCases = [ { input: 'Crea una form per i clienti', expected: 'ui-form-generator' }, { input: 'Mostrami una tabella dei prodotti', expected: 'ui-data-grid' }, { input: 'Voglio un dashboard delle vendite', expected: 'ui-dashboard-composer' }, { input: 'Setup workflow approvazione', expected: 'ui-workflow-builder' }, { input: 'Genera un report sui ricavi', expected: 'ui-report-builder' } ]; for (const testCase of testCases) { const result = intelligentRouter.analyzeRequest(testCase.input); expect(result.suggestedTool).toBe(testCase.expected); } }); it('should detect UI patterns in English', async () => { const testCases = [ { input: 'Create a form for customers', expected: 'ui-form-generator' }, { input: 'Show me a table of products', expected: 'ui-data-grid' }, { input: 'I want a sales dashboard', expected: 'ui-dashboard-composer' }, { input: 'Build approval workflow', expected: 'ui-workflow-builder' }, { input: 'Generate revenue report', expected: 'ui-report-builder' } ]; for (const testCase of testCases) { const result = intelligentRouter.analyzeRequest(testCase.input); expect(result.suggestedTool).toBe(testCase.expected); } }); it('should suggest UI tools in workflow context', async () => { const testCases = [ { currentTool: 'execute-entity-operation', previousTools: ['search-sap-services', 'discover-service-entities'], userRequest: 'show me customer data in a table', expected: 'ui-data-grid' }, { currentTool: 'get-entity-schema', previousTools: [], userRequest: 'create form for this entity', expected: 'ui-form-generator' } ]; for (const testCase of testCases) { const suggestion = suggestUIToolForWorkflow( testCase.currentTool, testCase.previousTools, testCase.userRequest ); expect(suggestion).toBe(testCase.expected); } }); }); describe('šŸ” 4. Authentication & Authorization Tests', () => { it('should require authentication for UI tools', async () => { const uiTools = [ 'ui-form-generator', 'ui-data-grid', 'ui-dashboard-composer', 'ui-workflow-builder', 'ui-report-builder' ]; for (const toolName of uiTools) { try { await testUITool(toolName, { entityType: 'Test' }, { token: null }); fail(`${toolName} should require authentication`); } catch (error) { expect(error.message).toContain('Authentication required'); } } }); it('should validate scopes for UI tools', async () => { const scopeTests = [ { tool: 'ui-form-generator', requiredScope: 'ui.forms' }, { tool: 'ui-data-grid', requiredScope: 'ui.grids' }, { tool: 'ui-dashboard-composer', requiredScope: 'ui.dashboards' }, { tool: 'ui-workflow-builder', requiredScope: 'ui.workflows' }, { tool: 'ui-report-builder', requiredScope: 'ui.reports' } ]; for (const test of scopeTests) { try { await testUITool(test.tool, { entityType: 'Test' }, { token: 'valid-token', scopes: ['other.scope'] // Missing required scope }); fail(`${test.tool} should require ${test.requiredScope} scope`); } catch (error) { expect(error.message).toContain(`Insufficient permissions`); expect(error.message).toContain(test.requiredScope); } } }); }); describe('šŸ“Š 5. Error Handling Tests', () => { it('should handle invalid entity types gracefully', async () => { const result = await testUITool('ui-form-generator', { entityType: 'NonExistentEntity', formType: 'create' }); expect(result.content[0].text).toContain('āŒ Error generating form'); }); it('should handle malformed input parameters', async () => { const invalidInputs = [ { entityType: '', formType: 'create' }, { entityType: null, formType: 'create' }, { entityType: 'Customer' }, // Missing formType { columns: 'invalid' } // Wrong type for columns ]; for (const invalidInput of invalidInputs) { const result = await testUITool('ui-form-generator', invalidInput); expect(result.content[0].text).toContain('āŒ Error'); } }); it('should handle network/SAP connection errors', async () => { // Mock SAP client to throw connection error jest.spyOn(sapClient, 'request').mockRejectedValue(new Error('Connection failed')); const result = await testUITool('ui-data-grid', { entityType: 'Customer' }); expect(result.content[0].text).toContain('āŒ Error generating data grid'); }); }); describe('šŸ—ļø 6. TypeScript & Build Validation', () => { it('should have valid TypeScript compilation', async () => { const { execSync } = require('child_process'); try { execSync('npm run build', { cwd: process.cwd() }); expect(true).toBe(true); // Build succeeded } catch (error) { fail(`TypeScript compilation failed: ${error.message}`); } }); it('should have all UI tools registered', async () => { await toolRegistry.initialize(); const registeredTools = toolRegistry.getRegisteredTools(); const expectedUITools = [ 'ui-form-generator', 'ui-data-grid', 'ui-dashboard-composer', 'ui-workflow-builder', 'ui-report-builder' ]; for (const toolName of expectedUITools) { expect(registeredTools).toContain(toolName); } }); }); describe('šŸš€ 7. Performance Tests', () => { it('should generate UI tools within acceptable time limits', async () => { const performanceTests = [ { tool: 'ui-form-generator', maxTime: 1000 }, { tool: 'ui-data-grid', maxTime: 1500 }, { tool: 'ui-dashboard-composer', maxTime: 2000 }, { tool: 'ui-workflow-builder', maxTime: 1500 }, { tool: 'ui-report-builder', maxTime: 2000 } ]; for (const test of performanceTests) { const startTime = Date.now(); await testUITool(test.tool, { entityType: 'Performance' }); const executionTime = Date.now() - startTime; expect(executionTime).toBeLessThan(test.maxTime); } }); it('should handle concurrent UI tool requests', async () => { const concurrentRequests = Array.from({ length: 5 }, (_, i) => testUITool('ui-form-generator', { entityType: `ConcurrentTest${i}`, formType: 'create' }) ); const results = await Promise.all(concurrentRequests); expect(results).toHaveLength(5); results.forEach((result, index) => { expect(result.content[0].text).toContain(`āœ… SAP ConcurrentTest${index} create form generated successfully`); }); }); }); // Helper functions async function testUITool(toolName: string, args: any, context?: any): Promise<any> { // Mock implementation that simulates the UI tool execution // In a real test, this would call the actual tool registry const mockContext = context || { token: 'valid-test-token', scopes: ['ui.forms', 'ui.grids', 'ui.dashboards', 'ui.workflows', 'ui.reports'] }; // Simulate tool execution based on toolName switch (toolName) { case 'ui-form-generator': return mockFormGeneratorResponse(args); case 'ui-data-grid': return mockDataGridResponse(args); case 'ui-dashboard-composer': return mockDashboardResponse(args); case 'ui-workflow-builder': return mockWorkflowResponse(args); case 'ui-report-builder': return mockReportResponse(args); default: throw new Error(`Unknown tool: ${toolName}`); } } function mockFormGeneratorResponse(args: any) { if (!args.entityType) { return { content: [{ text: 'āŒ Error generating form: Missing entityType' }] }; } return { content: [ { text: `āœ… SAP ${args.entityType} ${args.formType || 'create'} form generated successfully with Fiori styling and validation.` }, { text: `<!DOCTYPE html><html><body><div class="sap-form-container"><h2>${args.entityType} Form</h2></div></body></html>` } ] }; } function mockDataGridResponse(args: any) { const columnCount = args.columns?.length || 'auto'; return { content: [ { text: `āœ… Interactive ${args.entityType} data grid generated with ${columnCount} columns and advanced features.` }, { text: `<!DOCTYPE html><html><body><table class="data-table"><thead><tr><th>Column</th></tr></thead></table><script>function exportData(){} function filterTable(){}</script></body></html>` } ] }; } function mockDashboardResponse(args: any) { return { content: [ { text: `āœ… "${args.dashboardTitle}" KPI dashboard created with ${args.widgets?.length || 0} widgets and ${args.layout || 'grid'} layout.` }, { text: `<!DOCTYPE html><html><head><script src="https://cdn.jsdelivr.net/npm/chart.js"></script></head><body><div class="widget-grid"></div></body></html>` } ] }; } function mockWorkflowResponse(args: any) { return { content: [ { text: `āœ… "${args.workflowName}" workflow created with ${args.steps?.length || 0} steps for ${args.entityType} entities.` }, { text: `<!DOCTYPE html><html><body><div class="workflow-container"><div class="workflow-connector"></div></body></html>` } ] }; } function mockReportResponse(args: any) { return { content: [ { text: `āœ… ${args.reportType} report for ${args.entityType} created with ${args.dimensions?.length || 0} dimensions and ${args.measures?.length || 0} measures.` }, { text: `<!DOCTYPE html><html><head><script src="https://cdn.jsdelivr.net/npm/chart.js"></script></head><body><div class="report-container"><canvas id="trendChart"></canvas></div></body></html>` } ] }; } function generateUIToolSuggestions(operation: string, entityName: string, responseData: any): string { // Mock implementation of suggestion generation switch (operation) { case 'read': const recordCount = responseData?.value?.length || 1; if (recordCount > 1) { return `šŸ“Š **Visualizzazione Dati (${recordCount} record trovati)**\n• ui-data-grid - Griglia interattiva\n• ui-dashboard-composer - Dashboard KPI\n• ui-report-builder - Report analitici\n\n**Esempio uso:**\nui-data-grid\n{"entityType": "${entityName}"}`; } break; case 'create': return `āœ… **${entityName} creato con successo!**\n\nšŸ› ļø **Prossimi Passi Consigliati:**\n• ui-form-generator - Genera form per future creazioni\n• ui-workflow-builder - Crea workflow di approvazione\n\n**Esempio form per creazione:**\nui-form-generator\n{"entityType": "${entityName}", "formType": "create"}`; } return ''; } function generateEntityDiscoveryUIToolSuggestions(entityName: string, schema: any): string { return `šŸŽØ Strumenti UI Disponibili per ${entityName}\n\n### šŸ“ Gestione Dati\n• ui-form-generator - Crea form per operazioni CRUD\n\n### šŸ“Š Visualizzazione Tabellare\n• ui-data-grid - Griglia interattiva\n\n### šŸ“ˆ Dashboard Analitico\n• ui-dashboard-composer - Dashboard KPI\n\n### šŸ”„ Workflow e Processi\n• ui-workflow-builder - Workflow per gestione stati`; } function suggestUIToolForWorkflow(currentTool: string, previousTools: string[], userRequest: string): string | undefined { const request = userRequest.toLowerCase(); if (request.includes('table') || request.includes('grid')) { return 'ui-data-grid'; } if (request.includes('form') || request.includes('create')) { return 'ui-form-generator'; } return undefined; } });

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/Raistlin82/btp-sap-odata-to-mcp-server-optimized'

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