#!/usr/bin/env node /** * @fileoverview Test runner for Laravel Healthcare MCP Server * Validates configuration, authentication, and basic functionality */ import { ConfigManager } from "../src/config/ConfigManager.js"; import { AuthManager } from "../src/auth/AuthManager.js"; import { ApiClient } from "../src/proxy/ApiClient.js"; import { ToolGenerator } from "../src/tools/ToolGenerator.js"; import { logger } from "../src/utils/logger.js"; import { AUTH_TYPES } from "../src/config/endpoints.js"; /** * Test runner class */ class TestRunner { constructor() { this.tests = []; this.results = { passed: 0, failed: 0, skipped: 0, total: 0, }; } /** * Add a test * @param {string} name - Test name * @param {Function} testFn - Test function * @param {boolean} skip - Skip this test */ addTest(name, testFn, skip = false) { this.tests.push({ name, testFn, skip }); } /** * Run all tests */ async runTests() { console.log("๐Ÿงช Laravel Healthcare MCP Server Test Suite\n"); for (const test of this.tests) { this.results.total++; if (test.skip) { console.log(`โญ๏ธ SKIP: ${test.name}`); this.results.skipped++; continue; } try { console.log(`๐Ÿ”„ Running: ${test.name}`); await test.testFn(); console.log(`โœ… PASS: ${test.name}\n`); this.results.passed++; } catch (error) { console.log(`โŒ FAIL: ${test.name}`); console.log(` Error: ${error.message}\n`); this.results.failed++; } } this.printSummary(); } /** * Print test summary */ printSummary() { console.log("๐Ÿ“Š Test Results Summary"); console.log("========================"); console.log(`Total Tests: ${this.results.total}`); console.log(`Passed: ${this.results.passed}`); console.log(`Failed: ${this.results.failed}`); console.log(`Skipped: ${this.results.skipped}`); const successRate = this.results.total > 0 ? ((this.results.passed / this.results.total) * 100).toFixed(1) : 0; console.log(`Success Rate: ${successRate}%`); if (this.results.failed > 0) { console.log( "\nโŒ Some tests failed. Check the output above for details." ); process.exit(1); } else { console.log("\nโœ… All tests passed!"); } } } /** * Configuration tests */ async function testConfiguration() { const config = new ConfigManager(); // Test required configuration if (!config.get("LARAVEL_API_BASE_URL")) { throw new Error("LARAVEL_API_BASE_URL is required"); } // Test URL format try { new URL(config.get("LARAVEL_API_BASE_URL")); } catch (error) { throw new Error("LARAVEL_API_BASE_URL must be a valid URL"); } // Test numeric values const numericConfigs = [ "LARAVEL_API_TIMEOUT", "LARAVEL_API_RETRY_ATTEMPTS", "TOKEN_CACHE_DURATION", ]; numericConfigs.forEach((key) => { const value = config.get(key); if (value !== undefined && (isNaN(value) || value < 0)) { throw new Error(`${key} must be a positive number`); } }); console.log(" โœ“ Configuration validation passed"); } /** * Authentication manager tests */ async function testAuthManager() { const config = new ConfigManager(); const authManager = new AuthManager(null, config.getAll(true)); // Test cache functionality const stats = authManager.getCacheStats(); if (!stats || typeof stats !== "object") { throw new Error("Auth manager cache stats not available"); } // Test credential loading const credentials = authManager.credentials; if (!credentials || typeof credentials !== "object") { throw new Error("Auth manager credentials not loaded"); } // Check if at least one auth type is configured const configuredAuthTypes = Object.values(AUTH_TYPES).filter((authType) => { if (authType === AUTH_TYPES.PUBLIC) return false; const creds = credentials[authType]; return creds && creds.username && creds.password; }); if (configuredAuthTypes.length === 0) { throw new Error("At least one authentication type must be configured"); } console.log( ` โœ“ Auth manager initialized with ${configuredAuthTypes.length} auth types` ); } /** * API client tests */ async function testApiClient() { const config = new ConfigManager(); const authManager = new AuthManager(null, config.getAll(true)); const apiClient = new ApiClient(config.getAll(), authManager); // Test health status const health = apiClient.getHealthStatus(); if (!health || !health.baseURL) { throw new Error("API client health status not available"); } // Test configuration if (health.baseURL !== config.get("LARAVEL_API_BASE_URL")) { throw new Error("API client base URL mismatch"); } console.log(" โœ“ API client initialized successfully"); } /** * Tool generator tests */ async function testToolGenerator() { const config = new ConfigManager(); const authManager = new AuthManager(null, config.getAll(true)); const apiClient = new ApiClient(config.getAll(), authManager); const toolGenerator = new ToolGenerator(apiClient); // Generate tools const tools = toolGenerator.generateAllTools(); if (!Array.isArray(tools) || tools.length === 0) { throw new Error("Tool generator did not generate any tools"); } // Test tool structure const firstTool = tools[0]; const requiredFields = ["name", "description", "inputSchema"]; requiredFields.forEach((field) => { if (!firstTool[field]) { throw new Error(`Tool missing required field: ${field}`); } }); // Test tool retrieval const toolByName = toolGenerator.getTool(firstTool.name); if (!toolByName) { throw new Error("Tool retrieval by name failed"); } console.log(` โœ“ Tool generator created ${tools.length} tools`); } /** * Endpoint registry tests */ async function testEndpointRegistry() { const { PUBLIC_ENDPOINTS, AUTH_TYPES, ENDPOINT_CATEGORIES } = await import( "../src/config/endpoints.js" ); // Test public endpoints if (!Array.isArray(PUBLIC_ENDPOINTS) || PUBLIC_ENDPOINTS.length === 0) { throw new Error("No public endpoints defined"); } // Test endpoint structure const firstEndpoint = PUBLIC_ENDPOINTS[0]; const requiredFields = [ "path", "method", "controller", "category", "description", ]; requiredFields.forEach((field) => { if (!firstEndpoint[field]) { throw new Error(`Endpoint missing required field: ${field}`); } }); // Test auth types const authTypeValues = Object.values(AUTH_TYPES); if (authTypeValues.length < 8) { throw new Error("Not all authentication types defined"); } // Test categories const categoryValues = Object.values(ENDPOINT_CATEGORIES); if (categoryValues.length === 0) { throw new Error("No endpoint categories defined"); } console.log( ` โœ“ Endpoint registry has ${PUBLIC_ENDPOINTS.length} public endpoints` ); } /** * Environment variable tests */ async function testEnvironmentVariables() { const requiredEnvVars = ["LARAVEL_API_BASE_URL"]; const missingVars = []; requiredEnvVars.forEach((varName) => { if (!process.env[varName]) { missingVars.push(varName); } }); if (missingVars.length > 0) { throw new Error( `Missing required environment variables: ${missingVars.join(", ")}` ); } // Check for at least one auth configuration const authTypes = [ "ADMIN", "AGENT", "PATIENT", "PRACTITIONER", "AFFILIATE", "PARTNER", "NETWORK", "DOCTOR", "PROVIDER", ]; const configuredAuth = authTypes.filter((authType) => { return ( process.env[`${authType}_USERNAME`] && process.env[`${authType}_PASSWORD`] ); }); if (configuredAuth.length === 0) { console.log(" โš ๏ธ Warning: No authentication credentials configured"); } console.log( ` โœ“ Environment variables validated (${configuredAuth.length} auth types configured)` ); } /** * Network connectivity tests */ async function testNetworkConnectivity() { const config = new ConfigManager(); const baseUrl = config.get("LARAVEL_API_BASE_URL"); try { // Simple connectivity test using fetch const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); const response = await fetch(baseUrl, { method: "HEAD", signal: controller.signal, }); clearTimeout(timeoutId); console.log( ` โœ“ Network connectivity to ${baseUrl} successful (${response.status})` ); } catch (error) { if (error.name === "AbortError") { throw new Error(`Network timeout connecting to ${baseUrl}`); } throw new Error(`Network connectivity failed: ${error.message}`); } } /** * Main test execution */ async function main() { const runner = new TestRunner(); // Add tests runner.addTest("Environment Variables", testEnvironmentVariables); runner.addTest("Configuration Loading", testConfiguration); runner.addTest("Endpoint Registry", testEndpointRegistry); runner.addTest("Authentication Manager", testAuthManager); runner.addTest("API Client", testApiClient); runner.addTest("Tool Generator", testToolGenerator); runner.addTest( "Network Connectivity", testNetworkConnectivity, !process.env.LARAVEL_API_BASE_URL ); // Run tests await runner.runTests(); } // Run tests if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { main().catch((error) => { console.error("Test runner failed:", error); process.exit(1); }); } export { TestRunner };