Spaces:
Paused
Paused
/** | |
* API Connection Test Script | |
* ========================= | |
* | |
* Automated test script to validate all backend API endpoints | |
* and provide detailed reporting on frontend-backend integration. | |
*/ | |
class APIConnectionTester { | |
constructor() { | |
this.baseURL = window.location.origin; | |
this.results = []; | |
this.startTime = null; | |
this.endTime = null; | |
} | |
/** | |
* Run comprehensive API tests | |
*/ | |
async runAllTests() { | |
console.log('π Starting API Connection Tests...'); | |
this.startTime = Date.now(); | |
const tests = [ | |
// System Health Tests | |
{ name: 'Health Check', url: '/api/health', method: 'GET', category: 'System' }, | |
// Dashboard Tests | |
{ name: 'Dashboard Summary', url: '/api/dashboard/summary', method: 'GET', category: 'Dashboard' }, | |
{ name: 'Charts Data', url: '/api/dashboard/charts-data', method: 'GET', category: 'Dashboard' }, | |
{ name: 'AI Suggestions', url: '/api/dashboard/ai-suggestions', method: 'GET', category: 'Dashboard' }, | |
{ name: 'Performance Metrics', url: '/api/dashboard/performance-metrics', method: 'GET', category: 'Dashboard' }, | |
{ name: 'Trends', url: '/api/dashboard/trends', method: 'GET', category: 'Dashboard' }, | |
// Documents Tests | |
{ name: 'Documents List', url: '/api/documents?limit=5', method: 'GET', category: 'Documents' }, | |
{ name: 'Document Categories', url: '/api/documents/categories/', method: 'GET', category: 'Documents' }, | |
{ name: 'Document Sources', url: '/api/documents/sources/', method: 'GET', category: 'Documents' }, | |
{ name: 'Document Search', url: '/api/documents/search/?q=test', method: 'GET', category: 'Documents' }, | |
// OCR Tests | |
{ name: 'OCR Status', url: '/api/ocr/status', method: 'GET', category: 'OCR' }, | |
{ name: 'OCR Models', url: '/api/ocr/models', method: 'GET', category: 'OCR' }, | |
// Analytics Tests | |
{ name: 'Analytics Overview', url: '/api/analytics/overview', method: 'GET', category: 'Analytics' }, | |
{ name: 'Analytics Performance', url: '/api/analytics/performance', method: 'GET', category: 'Analytics' }, | |
{ name: 'Analytics Entities', url: '/api/analytics/entities?limit=10', method: 'GET', category: 'Analytics' }, | |
{ name: 'Analytics Quality', url: '/api/analytics/quality-analysis', method: 'GET', category: 'Analytics' }, | |
// Scraping Tests | |
{ name: 'Scraping Statistics', url: '/api/scraping/statistics', method: 'GET', category: 'Scraping' }, | |
{ name: 'Scraping Status', url: '/api/scraping/status', method: 'GET', category: 'Scraping' }, | |
{ name: 'Rating Summary', url: '/api/scraping/rating/summary', method: 'GET', category: 'Scraping' }, | |
{ name: 'Scraping Health', url: '/api/scraping/health', method: 'GET', category: 'Scraping' }, | |
// Phase 2 - File Upload Tests | |
{ name: 'OCR Upload', url: '/api/ocr/upload', method: 'POST', category: 'File Upload' }, | |
{ name: 'OCR Process', url: '/api/ocr/process', method: 'POST', category: 'File Upload' }, | |
{ name: 'OCR Quality Metrics', url: '/api/ocr/quality-metrics', method: 'GET', category: 'File Upload' }, | |
// Phase 2 - Document Management Tests | |
{ name: 'Create Document', url: '/api/documents', method: 'POST', category: 'Document Management' }, | |
{ name: 'Update Document', url: '/api/documents/1', method: 'PUT', category: 'Document Management' }, | |
{ name: 'Delete Document', url: '/api/documents/1', method: 'DELETE', category: 'Document Management' }, | |
// Phase 2 - Advanced Scraping Tests | |
{ name: 'Scraping Start', url: '/api/scraping/start', method: 'POST', category: 'Advanced Scraping' }, | |
{ name: 'Scraping Stop', url: '/api/scraping/stop', method: 'POST', category: 'Advanced Scraping' }, | |
{ name: 'Scraping Results', url: '/api/scraping/results', method: 'GET', category: 'Advanced Scraping' } | |
]; | |
console.log(`π Running ${tests.length} API tests...`); | |
for (const test of tests) { | |
await this.runSingleTest(test); | |
// Small delay to avoid overwhelming the server | |
await this.delay(100); | |
} | |
this.endTime = Date.now(); | |
this.generateReport(); | |
} | |
/** | |
* Run a single API test | |
*/ | |
async runSingleTest(test) { | |
const startTime = Date.now(); | |
let result = { | |
name: test.name, | |
category: test.category, | |
url: test.url, | |
method: test.method, | |
success: false, | |
status: null, | |
responseTime: 0, | |
data: null, | |
error: null, | |
timestamp: new Date().toISOString() | |
}; | |
try { | |
const response = await fetch(test.url, { | |
method: test.method, | |
headers: { | |
'Content-Type': 'application/json' | |
} | |
}); | |
result.status = response.status; | |
result.responseTime = Date.now() - startTime; | |
if (response.ok) { | |
result.success = true; | |
try { | |
result.data = await response.json(); | |
} catch (e) { | |
result.data = 'Non-JSON response'; | |
} | |
} else { | |
result.error = `${response.status}: ${response.statusText}`; | |
} | |
} catch (error) { | |
result.error = error.message; | |
result.responseTime = Date.now() - startTime; | |
} | |
this.results.push(result); | |
// Log result | |
const status = result.success ? 'β ' : 'β'; | |
console.log(`${status} ${test.name}: ${result.success ? 'PASS' : 'FAIL'} (${result.responseTime}ms)`); | |
return result; | |
} | |
/** | |
* Generate comprehensive test report | |
*/ | |
generateReport() { | |
const totalTests = this.results.length; | |
const passedTests = this.results.filter(r => r.success).length; | |
const failedTests = totalTests - passedTests; | |
const totalTime = this.endTime - this.startTime; | |
const avgResponseTime = this.results.reduce((sum, r) => sum + r.responseTime, 0) / totalTests; | |
console.log('\nπ API Connection Test Report'); | |
console.log('='.repeat(50)); | |
console.log(`Total Tests: ${totalTests}`); | |
console.log(`Passed: ${passedTests} β `); | |
console.log(`Failed: ${failedTests} β`); | |
console.log(`Success Rate: ${((passedTests / totalTests) * 100).toFixed(1)}%`); | |
console.log(`Total Time: ${totalTime}ms`); | |
console.log(`Average Response Time: ${avgResponseTime.toFixed(0)}ms`); | |
// Group results by category | |
const categories = {}; | |
this.results.forEach(result => { | |
if (!categories[result.category]) { | |
categories[result.category] = []; | |
} | |
categories[result.category].push(result); | |
}); | |
console.log('\nπ Results by Category:'); | |
Object.entries(categories).forEach(([category, results]) => { | |
const passed = results.filter(r => r.success).length; | |
const total = results.length; | |
const rate = ((passed / total) * 100).toFixed(1); | |
console.log(`${category}: ${passed}/${total} (${rate}%)`); | |
}); | |
// Show failed tests | |
const failedTests = this.results.filter(r => !r.success); | |
if (failedTests.length > 0) { | |
console.log('\nβ Failed Tests:'); | |
failedTests.forEach(test => { | |
console.log(` - ${test.name}: ${test.error}`); | |
}); | |
} | |
// Show slow tests | |
const slowTests = this.results.filter(r => r.responseTime > 1000); | |
if (slowTests.length > 0) { | |
console.log('\nπ Slow Tests (>1s):'); | |
slowTests.forEach(test => { | |
console.log(` - ${test.name}: ${test.responseTime}ms`); | |
}); | |
} | |
this.displayResultsInUI(); | |
} | |
/** | |
* Display results in the UI | |
*/ | |
displayResultsInUI() { | |
const container = document.getElementById('apiTestResults'); | |
if (!container) { | |
console.warn('No #apiTestResults container found'); | |
return; | |
} | |
const totalTests = this.results.length; | |
const passedTests = this.results.filter(r => r.success).length; | |
const failedTests = totalTests - passedTests; | |
const successRate = ((passedTests / totalTests) * 100).toFixed(1); | |
container.innerHTML = ` | |
<div class="test-report"> | |
<h3>API Connection Test Results</h3> | |
<div class="test-summary"> | |
<div class="test-stat"> | |
<span class="stat-label">Total Tests:</span> | |
<span class="stat-value">${totalTests}</span> | |
</div> | |
<div class="test-stat"> | |
<span class="stat-label">Passed:</span> | |
<span class="stat-value success">${passedTests} β </span> | |
</div> | |
<div class="test-stat"> | |
<span class="stat-label">Failed:</span> | |
<span class="stat-value error">${failedTests} β</span> | |
</div> | |
<div class="test-stat"> | |
<span class="stat-label">Success Rate:</span> | |
<span class="stat-value">${successRate}%</span> | |
</div> | |
</div> | |
<div class="test-details"> | |
<h4>Test Details:</h4> | |
<div class="test-list"> | |
${this.results.map(result => ` | |
<div class="test-item ${result.success ? 'success' : 'error'}"> | |
<span class="test-name">${result.name}</span> | |
<span class="test-status">${result.success ? 'PASS' : 'FAIL'}</span> | |
<span class="test-time">${result.responseTime}ms</span> | |
${result.error ? `<span class="test-error">${result.error}</span>` : ''} | |
</div> | |
`).join('')} | |
</div> | |
</div> | |
</div> | |
`; | |
} | |
/** | |
* Test specific endpoint patterns | |
*/ | |
async testEndpointPatterns() { | |
console.log('\nπ Testing Endpoint Patterns...'); | |
const patterns = [ | |
// Test the broken endpoints that frontend is trying to call | |
{ name: 'Frontend Dashboard Summary (BROKEN)', url: '/api/dashboard-summary', expected: false }, | |
{ name: 'Frontend Charts Data (BROKEN)', url: '/api/charts-data', expected: false }, | |
{ name: 'Frontend AI Suggestions (BROKEN)', url: '/api/ai-suggestions', expected: false }, | |
{ name: 'Frontend Train AI (BROKEN)', url: '/api/train-ai', expected: false }, | |
{ name: 'Frontend Scrape Trigger (BROKEN)', url: '/api/scrape-trigger', expected: false }, | |
// Test the correct endpoints | |
{ name: 'Backend Dashboard Summary (CORRECT)', url: '/api/dashboard/summary', expected: true }, | |
{ name: 'Backend Charts Data (CORRECT)', url: '/api/dashboard/charts-data', expected: true }, | |
{ name: 'Backend AI Suggestions (CORRECT)', url: '/api/dashboard/ai-suggestions', expected: true }, | |
{ name: 'Backend AI Feedback (CORRECT)', url: '/api/dashboard/ai-feedback', expected: true }, | |
{ name: 'Backend Scrape (CORRECT)', url: '/api/scraping/scrape', expected: true } | |
]; | |
for (const pattern of patterns) { | |
try { | |
const response = await fetch(pattern.url); | |
const actual = response.ok; | |
const status = actual === pattern.expected ? 'β ' : 'β'; | |
console.log(`${status} ${pattern.name}: ${actual ? 'EXISTS' : 'MISSING'} (Expected: ${pattern.expected ? 'EXISTS' : 'MISSING'})`); | |
} catch (error) { | |
const status = pattern.expected ? 'β' : 'β '; | |
console.log(`${status} ${pattern.name}: MISSING (Expected: ${pattern.expected ? 'EXISTS' : 'MISSING'})`); | |
} | |
} | |
} | |
/** | |
* Test file upload functionality | |
*/ | |
async testFileUpload() { | |
console.log('\nπ Testing File Upload...'); | |
// Create a test file | |
const testFile = new File(['Test PDF content'], 'test.pdf', { type: 'application/pdf' }); | |
const formData = new FormData(); | |
formData.append('file', testFile); | |
formData.append('title', 'Test Document'); | |
formData.append('source', 'Test'); | |
formData.append('category', 'Test'); | |
try { | |
const response = await fetch('/api/ocr/process-and-save', { | |
method: 'POST', | |
body: formData | |
}); | |
if (response.ok) { | |
console.log('β File upload endpoint is accessible'); | |
const result = await response.json(); | |
console.log('π Upload response:', result); | |
} else { | |
console.log('β File upload failed:', response.status, response.statusText); | |
} | |
} catch (error) { | |
console.log('β File upload error:', error.message); | |
} | |
} | |
/** | |
* Utility function for delays | |
*/ | |
delay(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
} | |
// Global instance | |
window.apiTester = new APIConnectionTester(); | |
// Auto-run tests when page loads | |
document.addEventListener('DOMContentLoaded', () => { | |
console.log('π§ API Connection Tester loaded'); | |
// Add test button if not exists | |
if (!document.getElementById('runAPITests')) { | |
const testButton = document.createElement('button'); | |
testButton.id = 'runAPITests'; | |
testButton.textContent = 'Run API Tests'; | |
testButton.style.cssText = ` | |
position: fixed; | |
top: 10px; | |
right: 10px; | |
z-index: 10000; | |
padding: 10px 20px; | |
background: #007bff; | |
color: white; | |
border: none; | |
border-radius: 5px; | |
cursor: pointer; | |
`; | |
testButton.onclick = () => { | |
window.apiTester.runAllTests(); | |
}; | |
document.body.appendChild(testButton); | |
} | |
// Add results container if not exists | |
if (!document.getElementById('apiTestResults')) { | |
const resultsContainer = document.createElement('div'); | |
resultsContainer.id = 'apiTestResults'; | |
resultsContainer.style.cssText = ` | |
position: fixed; | |
top: 60px; | |
right: 10px; | |
width: 400px; | |
max-height: 500px; | |
overflow-y: auto; | |
background: white; | |
border: 1px solid #ccc; | |
border-radius: 5px; | |
padding: 15px; | |
z-index: 10000; | |
display: none; | |
`; | |
document.body.appendChild(resultsContainer); | |
} | |
}); | |
// Export for use in other scripts | |
if (typeof module !== 'undefined' && module.exports) { | |
module.exports = APIConnectionTester; | |
} |