Hoghoghi / frontend /dev /functional-test.html
Really-amin's picture
Upload 143 files
c636ebf verified
raw
history blame
38.3 kB
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Functional Testing - Legal Dashboard</title>
<style>
body {
font-family: 'Arial', sans-serif;
max-width: 1400px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
background: white;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.success { color: #10b981; }
.error { color: #ef4444; }
.info { color: #3b82f6; }
.warning { color: #f59e0b; }
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
font-size: 14px;
}
button:hover {
background: #0056b3;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.workflow-test {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
background: white;
}
.workflow-test.success {
border-color: #10b981;
background: #f0fdf4;
}
.workflow-test.error {
border-color: #ef4444;
background: #fef2f2;
}
.workflow-test.testing {
border-color: #3b82f6;
background: #eff6ff;
}
.test-results {
max-height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
background: #f8f9fa;
font-family: 'Courier New', monospace;
font-size: 12px;
}
.progress-bar {
width: 100%;
height: 6px;
background: #e5e7eb;
border-radius: 3px;
overflow: hidden;
margin: 10px 0;
}
.progress-fill {
height: 100%;
background: #3b82f6;
transition: width 0.3s ease;
}
.file-upload-area {
border: 2px dashed #ddd;
padding: 30px;
text-align: center;
border-radius: 8px;
margin: 20px 0;
background: #fafafa;
}
.file-upload-area.dragover {
border-color: #3b82f6;
background: #eff6ff;
}
.status-indicator {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
}
.status-indicator.success { background: #10b981; }
.status-indicator.error { background: #ef4444; }
.status-indicator.warning { background: #f59e0b; }
.status-indicator.info { background: #3b82f6; }
.status-indicator.testing {
background: #3b82f6;
animation: pulse 1s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.summary-stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: white;
padding: 15px;
border-radius: 8px;
text-align: center;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.stat-number {
font-size: 2rem;
font-weight: bold;
margin-bottom: 5px;
}
.stat-label {
color: #666;
font-size: 0.9rem;
}
</style>
</head>
<body>
<h1>🔧 Functional Testing - Legal Dashboard</h1>
<div class="test-section">
<h2>📊 Test Summary</h2>
<div class="summary-stats">
<div class="stat-card">
<div class="stat-number" id="totalWorkflows">0</div>
<div class="stat-label">Total Workflows</div>
</div>
<div class="stat-card">
<div class="stat-number" id="passedWorkflows">0</div>
<div class="stat-label">Passed</div>
</div>
<div class="stat-card">
<div class="stat-number" id="failedWorkflows">0</div>
<div class="stat-label">Failed</div>
</div>
<div class="stat-card">
<div class="stat-number" id="successRate">0%</div>
<div class="stat-label">Success Rate</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressBar" style="width: 0%"></div>
</div>
</div>
<div class="test-section">
<h2>🎛️ Test Controls</h2>
<button type="button" onclick="runAllWorkflows()" id="runAllBtn">Run All Workflows</button>
<button type="button" onclick="testDocumentWorkflow()">Document Workflow</button>
<button type="button" onclick="testUploadWorkflow()">Upload Workflow</button>
<button type="button" onclick="testScrapingWorkflow()">Scraping Workflow</button>
<button type="button" onclick="testAnalyticsWorkflow()">Analytics Workflow</button>
<button type="button" onclick="clearResults()">Clear Results</button>
<button type="button" onclick="exportResults()">Export Results</button>
</div>
<div class="test-section">
<h2>📁 File Upload Test</h2>
<div class="file-upload-area" id="uploadZone">
<p><strong>Drag and drop a file here or click to select</strong></p>
<p>Supported formats: PDF, JPG, JPEG, PNG, TIFF</p>
<input type="file" id="testFileInput" accept=".pdf,.jpg,.jpeg,.png,.tiff" style="display: none;">
<button type="button" onclick="document.getElementById('testFileInput').click()">Select File</button>
</div>
<div id="uploadResults"></div>
</div>
<div class="test-section">
<h2>🔄 Workflow Tests</h2>
<div id="workflowTests">
<!-- Workflow tests will be generated here -->
</div>
</div>
<div class="test-section">
<h2>📋 Test Results</h2>
<div class="test-results" id="testResults">
<!-- Test results will be displayed here -->
</div>
</div>
<script src="../js/api-client.js"></script>
<script>
class FunctionalTester {
constructor() {
this.baseURL = window.location.origin;
this.results = [];
this.testStats = {
total: 0,
passed: 0,
failed: 0,
successRate: 0
};
this.isRunning = false;
this.workflows = [
{
name: 'Document Management Workflow',
description: 'Test complete document CRUD operations',
steps: [
{ name: 'Get Documents List', action: 'getDocuments' },
{ name: 'Create Test Document', action: 'createDocument' },
{ name: 'Update Document', action: 'updateDocument' },
{ name: 'Search Documents', action: 'searchDocuments' },
{ name: 'Delete Test Document', action: 'deleteDocument' }
]
},
{
name: 'File Upload & OCR Workflow',
description: 'Test file upload and OCR processing',
steps: [
{ name: 'Upload Test File', action: 'uploadFile' },
{ name: 'Process OCR', action: 'processOCR' },
{ name: 'Get OCR Status', action: 'getOCRStatus' },
{ name: 'Extract Text', action: 'extractText' }
]
},
{
name: 'Dashboard Analytics Workflow',
description: 'Test dashboard and analytics functionality',
steps: [
{ name: 'Get Dashboard Summary', action: 'getDashboardSummary' },
{ name: 'Get Charts Data', action: 'getChartsData' },
{ name: 'Get AI Suggestions', action: 'getAISuggestions' },
{ name: 'Get Performance Metrics', action: 'getPerformanceMetrics' }
]
},
{
name: 'Scraping & Rating Workflow',
description: 'Test web scraping and content rating',
steps: [
{ name: 'Get Scraping Status', action: 'getScrapingStatus' },
{ name: 'Get Scraping Statistics', action: 'getScrapingStatistics' },
{ name: 'Get Rating Summary', action: 'getRatingSummary' },
{ name: 'Check Scraping Health', action: 'getScrapingHealth' }
]
},
{
name: 'Analytics & Reporting Workflow',
description: 'Test advanced analytics and reporting',
steps: [
{ name: 'Get Analytics Overview', action: 'getAnalyticsOverview' },
{ name: 'Get Performance Analytics', action: 'getPerformanceAnalytics' },
{ name: 'Get Entity Analysis', action: 'getEntityAnalysis' },
{ name: 'Get Quality Analysis', action: 'getQualityAnalysis' }
]
}
];
this.initialize();
}
initialize() {
this.createWorkflowTests();
this.setupFileUpload();
this.updateStats();
}
createWorkflowTests() {
const container = document.getElementById('workflowTests');
container.innerHTML = '';
this.workflows.forEach((workflow, index) => {
const testDiv = document.createElement('div');
testDiv.className = 'workflow-test';
testDiv.id = `workflow-${index}`;
testDiv.innerHTML = `
<div class="status-indicator"></div>
<h3>${workflow.name}</h3>
<p>${workflow.description}</p>
<div class="steps" id="steps-${index}">
${workflow.steps.map((step, stepIndex) => `
<div class="step" id="step-${index}-${stepIndex}">
<span class="status-indicator"></span>
${step.name}
</div>
`).join('')}
</div>
<button type="button" onclick="tester.runWorkflow(${index})" class="run-workflow-btn">
Run Workflow
</button>
`;
container.appendChild(testDiv);
});
}
setupFileUpload() {
const uploadZone = document.getElementById('uploadZone');
const fileInput = document.getElementById('testFileInput');
uploadZone.addEventListener('dragover', (e) => {
e.preventDefault();
uploadZone.classList.add('dragover');
});
uploadZone.addEventListener('dragleave', () => {
uploadZone.classList.remove('dragover');
});
uploadZone.addEventListener('drop', (e) => {
e.preventDefault();
uploadZone.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length > 0) {
this.testFileUpload(files[0]);
}
});
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
this.testFileUpload(e.target.files[0]);
}
});
}
async runWorkflow(workflowIndex) {
const workflow = this.workflows[workflowIndex];
const testDiv = document.getElementById(`workflow-${workflowIndex}`);
// Set testing state
testDiv.className = 'workflow-test testing';
testDiv.querySelector('.status-indicator').className = 'status-indicator testing';
testDiv.querySelector('.run-workflow-btn').disabled = true;
this.logResult({
workflow: workflow.name,
status: 'started',
message: `Starting ${workflow.name}`
});
let allStepsPassed = true;
for (let stepIndex = 0; stepIndex < workflow.steps.length; stepIndex++) {
const step = workflow.steps[stepIndex];
const stepDiv = document.getElementById(`step-${workflowIndex}-${stepIndex}`);
// Set step testing state
stepDiv.querySelector('.status-indicator').className = 'status-indicator testing';
try {
const result = await this.executeStep(step.action);
if (result.success) {
stepDiv.querySelector('.status-indicator').className = 'status-indicator success';
this.logResult({
workflow: workflow.name,
step: step.name,
status: 'success',
message: `${step.name} completed successfully`
});
} else {
stepDiv.querySelector('.status-indicator').className = 'status-indicator error';
allStepsPassed = false;
this.logResult({
workflow: workflow.name,
step: step.name,
status: 'error',
message: `${step.name} failed: ${result.error}`
});
}
} catch (error) {
stepDiv.querySelector('.status-indicator').className = 'status-indicator error';
allStepsPassed = false;
this.logResult({
workflow: workflow.name,
step: step.name,
status: 'error',
message: `${step.name} failed: ${error.message}`
});
}
await this.delay(200); // Small delay between steps
}
// Update workflow status
testDiv.className = `workflow-test ${allStepsPassed ? 'success' : 'error'}`;
testDiv.querySelector('.status-indicator').className = `status-indicator ${allStepsPassed ? 'success' : 'error'}`;
testDiv.querySelector('.run-workflow-btn').disabled = false;
this.logResult({
workflow: workflow.name,
status: allStepsPassed ? 'completed' : 'failed',
message: `${workflow.name} ${allStepsPassed ? 'completed successfully' : 'failed'}`
});
this.updateStats();
}
async executeStep(action) {
switch (action) {
case 'getDocuments':
return await this.testGetDocuments();
case 'createDocument':
return await this.testCreateDocument();
case 'updateDocument':
return await this.testUpdateDocument();
case 'searchDocuments':
return await this.testSearchDocuments();
case 'deleteDocument':
return await this.testDeleteDocument();
case 'uploadFile':
return await this.testUploadFile();
case 'processOCR':
return await this.testProcessOCR();
case 'getOCRStatus':
return await this.testGetOCRStatus();
case 'extractText':
return await this.testExtractText();
case 'getDashboardSummary':
return await this.testGetDashboardSummary();
case 'getChartsData':
return await this.testGetChartsData();
case 'getAISuggestions':
return await this.testGetAISuggestions();
case 'getPerformanceMetrics':
return await this.testGetPerformanceMetrics();
case 'getScrapingStatus':
return await this.testGetScrapingStatus();
case 'getScrapingStatistics':
return await this.testGetScrapingStatistics();
case 'getRatingSummary':
return await this.testGetRatingSummary();
case 'getScrapingHealth':
return await this.testGetScrapingHealth();
case 'getAnalyticsOverview':
return await this.testGetAnalyticsOverview();
case 'getPerformanceAnalytics':
return await this.testGetPerformanceAnalytics();
case 'getEntityAnalysis':
return await this.testGetEntityAnalysis();
case 'getQualityAnalysis':
return await this.testGetQualityAnalysis();
default:
return { success: false, error: 'Unknown action' };
}
}
// Individual step implementations
async testGetDocuments() {
try {
const response = await fetch(`${this.baseURL}/api/documents`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testCreateDocument() {
try {
const testDoc = {
title: `Test Document ${Date.now()}`,
content: 'This is a test document for functional testing',
category: 'test',
source: 'functional_test'
};
const response = await fetch(`${this.baseURL}/api/documents`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(testDoc)
});
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testUpdateDocument() {
try {
const response = await fetch(`${this.baseURL}/api/documents/1`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Updated Test Document' })
});
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testSearchDocuments() {
try {
const response = await fetch(`${this.baseURL}/api/documents/search?q=test`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testDeleteDocument() {
try {
const response = await fetch(`${this.baseURL}/api/documents/1`, {
method: 'DELETE'
});
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testUploadFile() {
try {
// Create a test file
const testContent = 'This is a test file for functional testing';
const blob = new Blob([testContent], { type: 'text/plain' });
const file = new File([blob], 'test.txt', { type: 'text/plain' });
const formData = new FormData();
formData.append('file', file);
const response = await fetch(`${this.baseURL}/api/ocr/upload`, {
method: 'POST',
body: formData
});
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testProcessOCR() {
try {
const response = await fetch(`${this.baseURL}/api/ocr/process`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_id: 'test_file' })
});
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetOCRStatus() {
try {
const response = await fetch(`${this.baseURL}/api/ocr/status`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testExtractText() {
try {
const response = await fetch(`${this.baseURL}/api/ocr/extract`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_id: 'test_file' })
});
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetDashboardSummary() {
try {
const response = await fetch(`${this.baseURL}/api/dashboard/summary`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetChartsData() {
try {
const response = await fetch(`${this.baseURL}/api/dashboard/charts-data`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetAISuggestions() {
try {
const response = await fetch(`${this.baseURL}/api/dashboard/ai-suggestions`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetPerformanceMetrics() {
try {
const response = await fetch(`${this.baseURL}/api/dashboard/performance-metrics`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetScrapingStatus() {
try {
const response = await fetch(`${this.baseURL}/api/scraping/scrape/status`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetScrapingStatistics() {
try {
const response = await fetch(`${this.baseURL}/api/scraping/scrape/statistics`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetRatingSummary() {
try {
const response = await fetch(`${this.baseURL}/api/scraping/rating/summary`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetScrapingHealth() {
try {
const response = await fetch(`${this.baseURL}/api/scraping/health`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetAnalyticsOverview() {
try {
const response = await fetch(`${this.baseURL}/api/analytics/overview`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetPerformanceAnalytics() {
try {
const response = await fetch(`${this.baseURL}/api/analytics/performance`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetEntityAnalysis() {
try {
const response = await fetch(`${this.baseURL}/api/analytics/entities`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testGetQualityAnalysis() {
try {
const response = await fetch(`${this.baseURL}/api/analytics/quality-analysis`);
return { success: response.ok, error: response.ok ? null : `HTTP ${response.status}` };
} catch (error) {
return { success: false, error: error.message };
}
}
async testFileUpload(file) {
const resultsDiv = document.getElementById('uploadResults');
resultsDiv.innerHTML = `<p>Testing file upload: ${file.name} (${file.size} bytes)</p>`;
try {
const formData = new FormData();
formData.append('file', file);
const startTime = Date.now();
const response = await fetch(`${this.baseURL}/api/ocr/upload`, {
method: 'POST',
body: formData
});
const responseTime = Date.now() - startTime;
const responseData = await response.json();
const success = response.ok;
resultsDiv.innerHTML = `
<div class="${success ? 'success' : 'error'}">
<h4>File Upload Test Results</h4>
<p><strong>File:</strong> ${file.name}</p>
<p><strong>Size:</strong> ${file.size} bytes</p>
<p><strong>Status:</strong> ${response.status} ${response.statusText}</p>
<p><strong>Response Time:</strong> ${responseTime}ms</p>
<div class="response-data">
${JSON.stringify(responseData, null, 2)}
</div>
</div>
`;
this.logResult({
workflow: 'File Upload',
status: success ? 'success' : 'error',
message: `File upload ${success ? 'succeeded' : 'failed'}: ${file.name}`
});
} catch (error) {
resultsDiv.innerHTML = `
<div class="error">
<h4>File Upload Test Failed</h4>
<p>Error: ${error.message}</p>
</div>
`;
this.logResult({
workflow: 'File Upload',
status: 'error',
message: `File upload failed: ${error.message}`
});
}
this.updateStats();
}
async runAllWorkflows() {
if (this.isRunning) return;
this.isRunning = true;
document.getElementById('runAllBtn').disabled = true;
document.getElementById('runAllBtn').textContent = 'Running...';
this.clearResults();
for (let i = 0; i < this.workflows.length; i++) {
await this.runWorkflow(i);
await this.delay(500); // Delay between workflows
}
this.isRunning = false;
document.getElementById('runAllBtn').disabled = false;
document.getElementById('runAllBtn').textContent = 'Run All Workflows';
}
logResult(result) {
this.results.push({
...result,
timestamp: new Date().toISOString()
});
const resultsDiv = document.getElementById('testResults');
const resultEntry = document.createElement('div');
resultEntry.className = `test-result ${result.status === 'success' || result.status === 'completed' ? 'success' : 'error'}`;
resultEntry.innerHTML = `
<strong>${result.workflow}</strong>${result.step ? ` - ${result.step}` : ''} -
${result.status.toUpperCase()} -
${result.message}
<br><small>${new Date().toLocaleTimeString()}</small>
`;
resultsDiv.appendChild(resultEntry);
resultsDiv.scrollTop = resultsDiv.scrollHeight;
}
updateStats() {
const total = this.results.length;
const passed = this.results.filter(r =>
r.status === 'success' || r.status === 'completed'
).length;
const failed = total - passed;
const successRate = total > 0 ? Math.round((passed / total) * 100) : 0;
this.testStats = { total, passed, failed, successRate };
document.getElementById('totalWorkflows').textContent = total;
document.getElementById('passedWorkflows').textContent = passed;
document.getElementById('failedWorkflows').textContent = failed;
document.getElementById('successRate').textContent = successRate + '%';
const progressBar = document.getElementById('progressBar');
progressBar.style.width = successRate + '%';
progressBar.style.background = successRate >= 80 ? '#10b981' : successRate >= 60 ? '#f59e0b' : '#ef4444';
}
clearResults() {
this.results = [];
document.getElementById('testResults').innerHTML = '';
this.updateStats();
// Reset all workflow tests
this.workflows.forEach((workflow, index) => {
const testDiv = document.getElementById(`workflow-${index}`);
testDiv.className = 'workflow-test';
testDiv.querySelector('.status-indicator').className = 'status-indicator';
testDiv.querySelector('.run-workflow-btn').disabled = false;
workflow.steps.forEach((step, stepIndex) => {
const stepDiv = document.getElementById(`step-${index}-${stepIndex}`);
stepDiv.querySelector('.status-indicator').className = 'status-indicator';
});
});
}
exportResults() {
const data = {
timestamp: new Date().toISOString(),
stats: this.testStats,
results: this.results
};
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `functional-test-results-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`;
a.click();
URL.revokeObjectURL(url);
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Global tester instance
const tester = new FunctionalTester();
// Global functions for button clicks
function runAllWorkflows() {
tester.runAllWorkflows();
}
function testDocumentWorkflow() {
tester.runWorkflow(0);
}
function testUploadWorkflow() {
tester.runWorkflow(1);
}
function testScrapingWorkflow() {
tester.runWorkflow(3);
}
function testAnalyticsWorkflow() {
tester.runWorkflow(4);
}
function clearResults() {
tester.clearResults();
}
function exportResults() {
tester.exportResults();
}
console.log('🔧 Functional Tester initialized');
</script>
</body>
</html>