#!/usr/bin/env node /** * Comprehensive API Endpoint Test Suite * Tests all endpoints in unified-server.js */ const axios = require('axios'); const BASE_URL = 'http://localhost:4031'; const AUTH = { username: 'toemrer', password: 'REDACTED_AUTH' }; // Test results tracking const results = { total: 0, passed: 0, failed: 0, skipped: 0, errors: [] }; // Color output const colors = { green: '\x1b[32m', red: '\x1b[31m', yellow: '\x1b[33m', blue: '\x1b[34m', reset: '\x1b[0m' }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } async function testEndpoint(method, path, options = {}) { results.total++; const testName = `${method.toUpperCase()} ${path}`; try { const config = { method, url: `${BASE_URL}${path}`, auth: AUTH, timeout: 5000, validateStatus: () => true, // Don't throw on any status ...options }; const response = await axios(config); if (response.status >= 200 && response.status < 300) { results.passed++; log(`✅ ${testName} - ${response.status}`, 'green'); return { success: true, status: response.status, data: response.data }; } else if (response.status === 404) { results.failed++; log(`❌ ${testName} - 404 NOT FOUND (REMOVE THIS ENDPOINT)`, 'red'); results.errors.push({ endpoint: testName, error: '404 - Endpoint should be removed' }); return { success: false, status: 404 }; } else if (response.status === 400 || response.status === 422) { results.passed++; log(`⚠️ ${testName} - ${response.status} (Expected validation error)`, 'yellow'); return { success: true, status: response.status }; } else { results.failed++; log(`❌ ${testName} - ${response.status}`, 'red'); results.errors.push({ endpoint: testName, status: response.status, error: response.data }); return { success: false, status: response.status }; } } catch (error) { results.failed++; log(`❌ ${testName} - ${error.message}`, 'red'); results.errors.push({ endpoint: testName, error: error.message }); return { success: false, error: error.message }; } } async function runTests() { log('\n🔍 COMPREHENSIVE API ENDPOINT TEST\n', 'blue'); log('Testing all 180+ endpoints in unified-server.js\n', 'blue'); // ============================================ // HEALTH & ANALYTICS // ============================================ log('\n📊 HEALTH & ANALYTICS ENDPOINTS', 'blue'); await testEndpoint('get', '/health'); await testEndpoint('get', '/api/health'); await testEndpoint('get', '/api/analytics/kpis'); await testEndpoint('get', '/api/analytics/employees'); await testEndpoint('get', '/api/analytics/customers'); await testEndpoint('get', '/api/analytics/materials'); await testEndpoint('get', '/api/analytics/projects'); await testEndpoint('get', '/api/analytics/search?q=test'); // ============================================ // AUTHENTICATION // ============================================ log('\n🔐 AUTHENTICATION ENDPOINTS', 'blue'); await testEndpoint('post', '/api/auth/login', { data: { username: 'toemrer', password: 'REDACTED_AUTH' } }); await testEndpoint('post', '/api/auth', { data: { username: 'toemrer', password: 'REDACTED_AUTH' } }); // ============================================ // QUOTES // ============================================ log('\n📄 QUOTES ENDPOINTS', 'blue'); await testEndpoint('get', '/api/quotes/completed'); await testEndpoint('get', '/api/quotes/openai/stats'); await testEndpoint('post', '/api/quotes/openai/stats/update', { data: { prompt_tokens: 100, completion_tokens: 50, cost: 0.01 } }); await testEndpoint('post', '/api/quotes/generate', { data: { projectId: 1, customerName: 'Test Customer', projectType: 'Tagkonstruktion' } }); await testEndpoint('post', '/api/quotes/carpenter-hours', { data: { projectType: 'Tagkonstruktion', area: 100 } }); // ============================================ // PRICING & MATERIALS // ============================================ log('\n💰 PRICING & MATERIALS ENDPOINTS', 'blue'); await testEndpoint('get', '/api/pricing/health'); await testEndpoint('get', '/api/pricing/materials'); await testEndpoint('get', '/api/pricing/categories'); await testEndpoint('get', '/api/pricing/materials/stats'); await testEndpoint('get', '/api/pricing/search?query=spær'); await testEndpoint('get', '/api/prices/suggestions'); await testEndpoint('get', '/api/prices/template'); await testEndpoint('get', '/api/materials/dynamic'); // ============================================ // BYGMA INTEGRATION // ============================================ log('\n🏗️ BYGMA INTEGRATION ENDPOINTS', 'blue'); await testEndpoint('get', '/api/pricing/bygma-imports'); await testEndpoint('get', '/api/pricing/bygma-prices?search=spær'); await testEndpoint('get', '/api/pricing/bygma-stats'); await testEndpoint('get', '/api/material-categories/bygma'); // ============================================ // WEB PRICES // ============================================ log('\n🌐 WEB PRICES ENDPOINTS', 'blue'); await testEndpoint('post', '/api/web-prices/search', { data: { query: 'spær', limit: 10 } }); await testEndpoint('post', '/api/web-prices/carpenter-rates', { data: { projectType: 'Tagkonstruktion' } }); await testEndpoint('get', '/api/web-prices/suggestions/roof'); // ============================================ // CATEGORIES // ============================================ log('\n📁 CATEGORIES ENDPOINTS', 'blue'); await testEndpoint('get', '/api/categories'); await testEndpoint('get', '/api/categories/list'); // ============================================ // MATERIAL PACKAGES // ============================================ log('\n📦 MATERIAL PACKAGES ENDPOINTS', 'blue'); await testEndpoint('get', '/api/material-packages'); await testEndpoint('post', '/api/material-packages', { data: { name: 'Test Package', description: 'Test', materials: [] } }); // ============================================ // CUSTOMER PROJECTS // ============================================ log('\n🏠 CUSTOMER PROJECTS ENDPOINTS', 'blue'); await testEndpoint('get', '/api/customer-projects/projects'); await testEndpoint('get', '/api/customer-projects/similar?projectType=Tagkonstruktion'); await testEndpoint('get', '/api/customer-projects/material-categories'); await testEndpoint('get', '/api/customer-projects/tag-experience-suggestions'); await testEndpoint('get', '/api/tag-geometry-estimates'); await testEndpoint('get', '/api/real-project-types'); await testEndpoint('post', '/api/real-project-suggestions', { data: { projectType: 'Tagkonstruktion', area: 100 } }); // Test creating a project const createResult = await testEndpoint('post', '/api/customer-projects/projects', { data: { customer_name: 'API Test Customer', project_type: 'Tagkonstruktion', project_description: 'Test project for API validation' } }); if (createResult.success && createResult.data && createResult.data.projectId) { const projectId = createResult.data.projectId; log(`\n🔍 Testing project-specific endpoints for project ${projectId}`, 'blue'); await testEndpoint('get', `/api/customer-projects/${projectId}`); await testEndpoint('get', `/api/customer-projects/${projectId}/breakdown`); await testEndpoint('get', `/api/customer-projects/${projectId}/quotes`); await testEndpoint('get', `/api/customer-projects/${projectId}/geometry`); await testEndpoint('get', `/api/customer-projects/${projectId}/labor`); await testEndpoint('get', `/api/customer-projects/${projectId}/materials`); await testEndpoint('get', `/api/customer-projects/${projectId}/packages`); await testEndpoint('get', `/api/customer-projects/${projectId}/calculation`); await testEndpoint('get', `/api/customer-projects/${projectId}/tasks`); // Update geometry await testEndpoint('post', `/api/customer-projects/${projectId}/geometry`, { data: { area_m2: 100, vindskede_lbm: 50 } }); // Update project await testEndpoint('put', `/api/customer-projects/${projectId}`, { data: { project_description: 'Updated description' } }); // Clean up: delete test project await testEndpoint('delete', `/api/customer-projects/${projectId}`); } // ============================================ // INSTALLATION MANUALS // ============================================ log('\n📖 INSTALLATION MANUALS ENDPOINTS', 'blue'); await testEndpoint('get', '/api/customer/installation-manual/search?product_name=280'); // ============================================ // ORDERS (if implemented) // ============================================ log('\n📋 ORDERS ENDPOINTS', 'blue'); await testEndpoint('get', '/api/orders'); await testEndpoint('get', '/api/orders/status-summary'); // ============================================ // UPLOADS // ============================================ log('\n📤 UPLOADS ENDPOINTS', 'blue'); await testEndpoint('get', '/api/uploads/recent'); // ============================================ // SUMMARY // ============================================ log('\n' + '='.repeat(60), 'blue'); log('📊 TEST SUMMARY', 'blue'); log('='.repeat(60), 'blue'); log(`Total Tests: ${results.total}`); log(`✅ Passed: ${results.passed}`, 'green'); log(`❌ Failed: ${results.failed}`, results.failed > 0 ? 'red' : 'green'); log(`⏭️ Skipped: ${results.skipped}`, 'yellow'); const successRate = ((results.passed / results.total) * 100).toFixed(1); log(`\n📈 Success Rate: ${successRate}%`, successRate > 90 ? 'green' : 'yellow'); if (results.errors.length > 0) { log('\n❌ ERRORS FOUND:', 'red'); results.errors.forEach((error, index) => { log(`${index + 1}. ${error.endpoint}`, 'red'); log(` ${JSON.stringify(error.error || error.status)}`, 'red'); }); } log('\n✨ Test completed!\n', 'blue'); // Exit with error code if tests failed process.exit(results.failed > 0 ? 1 : 0); } // Run tests runTests().catch(error => { log(`\n💥 Fatal error: ${error.message}`, 'red'); console.error(error); process.exit(1); });