/** * @fileoverview Comprehensive test suite for all public MCP tools * Runs all public tool tests and provides coverage reporting */ import { describe, test, expect, beforeAll, afterAll } from '@jest/globals'; import { mockFactory } from '../mocks/mockFactory.js'; describe('Public Tools Integration Tests', () => { let mockEnv; let toolGenerator; beforeAll(async () => { // Setup comprehensive mock environment mockEnv = mockFactory.createMockEnvironment({ authTypes: ['public'], enableHttpMocks: true, enableAuthMocks: true, enableHealthcareMocks: true }); toolGenerator = mockEnv.toolGenerator; // Setup all public endpoint mocks setupPublicEndpointMocks(); }); afterAll(() => { mockFactory.resetAllMocks(); }); /** * Setup mock responses for all public endpoints */ function setupPublicEndpointMocks() { // Login endpoints const loginEndpoints = [ { method: 'POST', path: '/api/login' }, { method: 'POST', path: '/api/frontend/login' }, { method: 'POST', path: '/api/admin/login' }, { method: 'POST', path: '/api/login-partner-api' }, { method: 'POST', path: '/api/affiliate-login-api' }, { method: 'POST', path: '/api/network/login' }, { method: 'POST', path: '/api/patient/login' }, { method: 'POST', path: '/api/patient-login-api' }, { method: 'POST', path: '/api/login-patient' } ]; loginEndpoints.forEach(endpoint => { mockFactory.httpMocks.mockRequest(endpoint.method, endpoint.path, { status: 200, data: { success: true, token: `mock_token_${Date.now()}`, user: { id: 'user_123', email: 'test@example.com' } } }); }); // Registration endpoints const registrationEndpoints = [ { method: 'POST', path: '/emr-api/provider-register' }, { method: 'POST', path: '/api/register-patients' }, { method: 'POST', path: '/api/register-patient' }, { method: 'POST', path: '/api/affiliate-register-api' }, { method: 'POST', path: '/api/partner-register-api' }, { method: 'POST', path: '/api/network/register' }, { method: 'POST', path: '/api/emr/provider/register' }, { method: 'POST', path: '/api/patient/register-patient' } ]; registrationEndpoints.forEach(endpoint => { mockFactory.httpMocks.mockRequest(endpoint.method, endpoint.path, { status: 201, data: { success: true, user: { id: 'new_user_123', email: 'newuser@example.com' }, message: 'Registration successful' } }); }); // Password management endpoints const passwordEndpoints = [ { method: 'POST', path: '/api/forgot-password' }, { method: 'POST', path: '/api/frontend/forgot-password' }, { method: 'POST', path: '/api/emr/provider/forgot-password' }, { method: 'POST', path: '/api/password-reset' }, { method: 'POST', path: '/api/frontend/reset-password' }, { method: 'POST', path: '/api/emr/provider/reset-password' }, { method: 'POST', path: '/api/set-password' }, { method: 'POST', path: '/api/emr/set-password' }, { method: 'POST', path: '/api/affiliate/set-password' }, { method: 'POST', path: '/api/reset-password' } ]; passwordEndpoints.forEach(endpoint => { mockFactory.httpMocks.mockRequest(endpoint.method, endpoint.path, { status: 200, data: { success: true, message: 'Password operation successful' } }); }); // Data access endpoints mockFactory.httpMocks.mockRequest('POST', '/api/check-email', { status: 200, data: { available: true, email: 'test@example.com' } }); mockFactory.httpMocks.mockRequest('POST', '/api/check-user', { status: 200, data: { exists: true, userType: 'provider' } }); // Appointment endpoints mockFactory.httpMocks.mockRequest('POST', '/api/patient/available-slots/2025-07-15', { status: 200, data: { date: '2025-07-15', availableSlots: [ { time: '09:00', duration: 30, providerId: 'provider_123' } ] } }); mockFactory.httpMocks.mockRequest('POST', '/api/patient-book-appointment', { status: 201, data: { success: true, appointment: { id: 'appointment_123', status: 'scheduled' } } }); // Verification endpoints mockFactory.httpMocks.mockRequest('POST', '/api/public-manage-verify-email', { status: 200, data: { success: true, verified: true } }); mockFactory.httpMocks.mockRequest('POST', '/api/public-manage-resend-verification', { status: 200, data: { success: true, message: 'Verification email sent' } }); } describe('Public Tools Coverage Test', () => { test('should have all 77 public tools available', async () => { const allTools = toolGenerator.generateAllTools(); const publicTools = allTools.filter(tool => tool.name.startsWith('public_')); // Verify we have the expected number of public tools expect(publicTools.length).toBeGreaterThanOrEqual(70); // Allow for some variance // Verify tool naming convention publicTools.forEach(tool => { expect(tool.name).toMatch(/^public_[a-zA-Z]+_[a-zA-Z]+/); expect(tool.description).toBeDefined(); expect(tool.inputSchema).toBeDefined(); }); }); test('should categorize public tools correctly', async () => { const allTools = toolGenerator.generateAllTools(); const publicTools = allTools.filter(tool => tool.name.startsWith('public_')); const categories = { login: [], registration: [], password: [], verification: [], data: [], appointment: [], other: [] }; publicTools.forEach(tool => { if (tool.name.includes('login') || tool.name.includes('Login')) { categories.login.push(tool); } else if (tool.name.includes('register') || tool.name.includes('Register')) { categories.registration.push(tool); } else if (tool.name.includes('password') || tool.name.includes('Password') || tool.name.includes('setPassword')) { categories.password.push(tool); } else if (tool.name.includes('verify') || tool.name.includes('Verify') || tool.name.includes('verification')) { categories.verification.push(tool); } else if (tool.name.includes('check') || tool.name.includes('Check') || tool.name.includes('get')) { categories.data.push(tool); } else if (tool.name.includes('appointment') || tool.name.includes('Appointment') || tool.name.includes('slot')) { categories.appointment.push(tool); } else { categories.other.push(tool); } }); // Verify we have tools in each major category expect(categories.login.length).toBeGreaterThan(5); expect(categories.registration.length).toBeGreaterThan(5); expect(categories.password.length).toBeGreaterThan(5); console.log('Public Tools Distribution:'); Object.entries(categories).forEach(([category, tools]) => { console.log(` ${category}: ${tools.length} tools`); }); }); }); describe('Public Tools Parameter Validation', () => { test('should validate required parameters for login tools', async () => { const loginTools = [ 'public_create_login', 'public_create_frontendlogin', 'public_create_adminlogin' ]; for (const toolName of loginTools) { const tool = toolGenerator.getTool(toolName); if (tool) { expect(tool.inputSchema.required).toBeDefined(); expect(tool.inputSchema.required.length).toBeGreaterThan(0); } } }); test('should validate required parameters for registration tools', async () => { const registrationTools = [ 'public_create_emrApiproviderRegister', 'public_create_registerPatient', 'public_create_affiliateRegisterApi' ]; for (const toolName of registrationTools) { const tool = toolGenerator.getTool(toolName); if (tool) { expect(tool.inputSchema.required).toBeDefined(); expect(tool.inputSchema.required.length).toBeGreaterThan(1); } } }); }); describe('Public Tools Error Handling', () => { test('should handle network errors gracefully', async () => { // Mock network error for all endpoints mockFactory.httpMocks.setDefaultResponse('POST', null); mockFactory.httpMocks.setDefaultResponse('GET', null); const testTool = 'public_create_login'; const parameters = { username: 'test', password: 'test' }; // Should handle network errors without crashing await expect(toolGenerator.executeTool(testTool, parameters)) .rejects.toThrow(); }); test('should handle malformed responses', async () => { // Mock malformed response mockFactory.httpMocks.mockRequest('POST', '/api/login', { status: 200, data: 'invalid json response' }); const testTool = 'public_create_login'; const parameters = { username: 'test', password: 'test' }; await expect(toolGenerator.executeTool(testTool, parameters)) .rejects.toThrow(); }); }); describe('Public Tools Security Tests', () => { test('should not expose sensitive information in logs', async () => { const testTool = 'public_create_login'; const parameters = { username: 'testuser', password: 'supersecretpassword123!' }; await toolGenerator.executeTool(testTool, parameters); // Check request history doesn't contain password const history = mockFactory.httpMocks.getRequestHistory(); const loginRequest = history.find(req => req.url === '/api/login'); if (loginRequest) { const requestString = JSON.stringify(loginRequest); expect(requestString).not.toContain('supersecretpassword123!'); } }); test('should validate input sanitization', async () => { const testTool = 'public_create_checkEmail'; const maliciousEmail = '@test.com'; await expect(toolGenerator.executeTool(testTool, { email: maliciousEmail })) .rejects.toThrow(); }); }); describe('Public Tools Performance Tests', () => { test('should complete tool execution within reasonable time', async () => { const testTool = 'public_create_checkEmail'; const parameters = { email: 'test@example.com' }; const startTime = Date.now(); await toolGenerator.executeTool(testTool, parameters); const endTime = Date.now(); const executionTime = endTime - startTime; expect(executionTime).toBeLessThan(5000); // Should complete within 5 seconds }); test('should handle concurrent tool executions', async () => { const testTool = 'public_create_checkEmail'; const promises = []; // Execute 10 concurrent requests for (let i = 0; i < 10; i++) { const parameters = { email: `test${i}@example.com` }; promises.push(toolGenerator.executeTool(testTool, parameters)); } const results = await Promise.allSettled(promises); // All requests should complete (either fulfilled or rejected) expect(results.length).toBe(10); results.forEach(result => { expect(['fulfilled', 'rejected']).toContain(result.status); }); }); }); describe('Public Tools Integration', () => { test('should maintain consistent response format across tools', async () => { const testTools = [ { name: 'public_create_login', params: { username: 'test', password: 'test' } }, { name: 'public_create_checkEmail', params: { email: 'test@example.com' } }, { name: 'public_create_forgotPassword', params: { email: 'test@example.com' } } ]; for (const { name, params } of testTools) { const result = await toolGenerator.executeTool(name, params); // All tools should return consistent structure expect(result).toHaveProperty('success'); expect(result).toHaveProperty('data'); expect(typeof result.success).toBe('boolean'); } }); }); });