- Add .gitignore to exclude node_modules, dist, logs, and system files - Add comprehensive project documentation including README, deployment guide, and development setup - Add .kiro project specifications for amazon-product-bar-extension, appwrite-cloud-storage, appwrite-userid-repair, blacklist-feature, and enhanced-item-management - Add .kiro steering documents for product, structure, styling, and tech guidelines - Add VSCode settings configuration for consistent development environment - Add manifest.json and babel/vite configuration for extension build setup - Add complete source code implementation including AppWrite integration, storage managers, UI components, and services - Add comprehensive test suite with Jest configuration and 30+ test files covering all major modules - Add test HTML files for integration testing and validation - Add coverage reports and build validation scripts - Add AppWrite setup and repair documentation for database schema management - Add migration guides and responsive accessibility implementation documentation - Establish foundation for Amazon product bar extension with full feature set including blacklist management, enhanced item workflows, and real-time synchronization
394 lines
16 KiB
HTML
394 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>ErrorHandler Integration Test</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
.test-section {
|
|
background: white;
|
|
padding: 20px;
|
|
margin: 20px 0;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.test-result {
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 4px;
|
|
}
|
|
.success {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
border: 1px solid #c3e6cb;
|
|
}
|
|
.error {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
border: 1px solid #f5c6cb;
|
|
}
|
|
.info {
|
|
background-color: #d1ecf1;
|
|
color: #0c5460;
|
|
border: 1px solid #bee5eb;
|
|
}
|
|
button {
|
|
background-color: #007acc;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
button:hover {
|
|
background-color: #005a9e;
|
|
}
|
|
.log-entry {
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
background: #f8f9fa;
|
|
padding: 5px;
|
|
margin: 2px 0;
|
|
border-left: 3px solid #007acc;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>ErrorHandler Integration Test</h1>
|
|
<p>Diese Seite testet die umfassende Fehlerbehandlung für Enhanced Item Management.</p>
|
|
|
|
<div class="test-section">
|
|
<h2>Error Classification Tests</h2>
|
|
<button onclick="testErrorClassification()">Test Error Classification</button>
|
|
<div id="classification-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Retry Logic Tests</h2>
|
|
<button onclick="testRetryLogic()">Test Retry Logic</button>
|
|
<div id="retry-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>AI Service Fallback Tests</h2>
|
|
<button onclick="testAIFallback()">Test AI Fallback</button>
|
|
<div id="ai-fallback-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Extraction Fallback Tests</h2>
|
|
<button onclick="testExtractionFallback()">Test Extraction Fallback</button>
|
|
<div id="extraction-fallback-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Storage Error Handling Tests</h2>
|
|
<button onclick="testStorageErrorHandling()">Test Storage Error Handling</button>
|
|
<div id="storage-error-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>User-Friendly Messages Tests</h2>
|
|
<button onclick="testUserFriendlyMessages()">Test User-Friendly Messages</button>
|
|
<div id="user-friendly-results"></div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>Error Log</h2>
|
|
<button onclick="showErrorLog()">Show Recent Errors</button>
|
|
<button onclick="clearErrorLog()">Clear Error Log</button>
|
|
<div id="error-log"></div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import { ErrorHandler, errorHandler } from './src/ErrorHandler.js';
|
|
|
|
// Make available globally for testing
|
|
window.errorHandler = errorHandler;
|
|
window.ErrorHandler = ErrorHandler;
|
|
|
|
// Mock event bus for testing
|
|
window.amazonExtEventBus = {
|
|
emit: (event, data) => {
|
|
console.log('Event emitted:', event, data);
|
|
}
|
|
};
|
|
|
|
window.testErrorClassification = function() {
|
|
const results = document.getElementById('classification-results');
|
|
results.innerHTML = '';
|
|
|
|
const testCases = [
|
|
{ error: new Error('Network request failed'), expectedType: 'network' },
|
|
{ error: new Error('Invalid API key'), expectedType: 'api_key' },
|
|
{ error: new Error('Request timeout'), expectedType: 'timeout' },
|
|
{ error: new Error('Storage failed'), expectedType: 'storage' },
|
|
{ error: new Error('quota exceeded'), expectedType: 'quota' },
|
|
{ error: new Error('Validation failed'), expectedType: 'validation' },
|
|
{ error: new Error('Failed to extract title'), expectedType: 'extraction' },
|
|
{ error: new Error('Mistral AI unavailable'), expectedType: 'ai_service' },
|
|
{ error: new Error('Random unknown error'), expectedType: 'unknown' }
|
|
];
|
|
|
|
testCases.forEach((testCase, index) => {
|
|
try {
|
|
const processed = errorHandler.handleError(testCase.error, {
|
|
component: 'test',
|
|
operation: `classification_test_${index}`
|
|
});
|
|
|
|
const isCorrect = processed.type === testCase.expectedType;
|
|
const resultDiv = document.createElement('div');
|
|
resultDiv.className = `test-result ${isCorrect ? 'success' : 'error'}`;
|
|
resultDiv.innerHTML = `
|
|
<strong>Test ${index + 1}:</strong> "${testCase.error.message}"<br>
|
|
Expected: ${testCase.expectedType}, Got: ${processed.type}
|
|
${isCorrect ? '✓' : '✗'}
|
|
`;
|
|
results.appendChild(resultDiv);
|
|
} catch (error) {
|
|
const resultDiv = document.createElement('div');
|
|
resultDiv.className = 'test-result error';
|
|
resultDiv.innerHTML = `<strong>Test ${index + 1} Failed:</strong> ${error.message}`;
|
|
results.appendChild(resultDiv);
|
|
}
|
|
});
|
|
};
|
|
|
|
window.testRetryLogic = async function() {
|
|
const results = document.getElementById('retry-results');
|
|
results.innerHTML = '<div class="test-result info">Testing retry logic...</div>';
|
|
|
|
try {
|
|
// Test successful operation
|
|
let attemptCount = 0;
|
|
const successOperation = async () => {
|
|
attemptCount++;
|
|
return 'success';
|
|
};
|
|
|
|
const successResult = await errorHandler.executeWithRetry(successOperation, {
|
|
component: 'test',
|
|
operationName: 'success_test'
|
|
});
|
|
|
|
// Test retryable error
|
|
let retryAttemptCount = 0;
|
|
const retryableOperation = async () => {
|
|
retryAttemptCount++;
|
|
if (retryAttemptCount < 3) {
|
|
throw new Error('Network error');
|
|
}
|
|
return 'success after retries';
|
|
};
|
|
|
|
const retryResult = await errorHandler.executeWithRetry(retryableOperation, {
|
|
maxRetries: 3,
|
|
component: 'test',
|
|
operationName: 'retry_test'
|
|
});
|
|
|
|
// Test non-retryable error
|
|
const nonRetryableOperation = async () => {
|
|
throw new Error('Invalid API key');
|
|
};
|
|
|
|
const nonRetryResult = await errorHandler.executeWithRetry(nonRetryableOperation, {
|
|
maxRetries: 3,
|
|
component: 'test',
|
|
operationName: 'non_retry_test'
|
|
});
|
|
|
|
results.innerHTML = `
|
|
<div class="test-result success">
|
|
<strong>Success Test:</strong> ${successResult.success ? '✓' : '✗'}
|
|
(${successResult.attempts} attempt)
|
|
</div>
|
|
<div class="test-result success">
|
|
<strong>Retry Test:</strong> ${retryResult.success ? '✓' : '✗'}
|
|
(${retryResult.attempts} attempts)
|
|
</div>
|
|
<div class="test-result success">
|
|
<strong>Non-Retry Test:</strong> ${!nonRetryResult.success && nonRetryResult.attempts === 1 ? '✓' : '✗'}
|
|
(${nonRetryResult.attempts} attempt, correctly not retried)
|
|
</div>
|
|
`;
|
|
} catch (error) {
|
|
results.innerHTML = `<div class="test-result error">Retry test failed: ${error.message}</div>`;
|
|
}
|
|
};
|
|
|
|
window.testAIFallback = function() {
|
|
const results = document.getElementById('ai-fallback-results');
|
|
results.innerHTML = '';
|
|
|
|
const testCases = [
|
|
{ title: 'Samsung Galaxy S21 Ultra 5G Smartphone 128GB', description: 'Normal title' },
|
|
{ title: 'Very Long Product Title That Exceeds Fifty Characters And Should Be Shortened', description: 'Long title' },
|
|
{ title: '', description: 'Empty title' },
|
|
{ title: null, description: 'Null title' }
|
|
];
|
|
|
|
testCases.forEach((testCase, index) => {
|
|
try {
|
|
const fallback = errorHandler.handleAIServiceFallback(
|
|
testCase.title,
|
|
new Error('AI service unavailable')
|
|
);
|
|
|
|
const isValid = fallback.titleSuggestions && fallback.titleSuggestions.length === 3;
|
|
const resultDiv = document.createElement('div');
|
|
resultDiv.className = `test-result ${isValid ? 'success' : 'error'}`;
|
|
resultDiv.innerHTML = `
|
|
<strong>${testCase.description}:</strong> ${isValid ? '✓' : '✗'}<br>
|
|
Suggestions: ${fallback.titleSuggestions ? fallback.titleSuggestions.join(', ') : 'None'}
|
|
`;
|
|
results.appendChild(resultDiv);
|
|
} catch (error) {
|
|
const resultDiv = document.createElement('div');
|
|
resultDiv.className = 'test-result error';
|
|
resultDiv.innerHTML = `<strong>${testCase.description} Failed:</strong> ${error.message}`;
|
|
results.appendChild(resultDiv);
|
|
}
|
|
});
|
|
};
|
|
|
|
window.testExtractionFallback = function() {
|
|
const results = document.getElementById('extraction-fallback-results');
|
|
results.innerHTML = '';
|
|
|
|
const testUrl = 'https://amazon.de/dp/B08N5WRWNW';
|
|
const extractionError = new Error('Could not extract product data');
|
|
|
|
try {
|
|
const fallback = errorHandler.handleExtractionFallback(testUrl, extractionError);
|
|
|
|
const isValid = fallback.requiresManualInput &&
|
|
fallback.url === testUrl &&
|
|
fallback.fallbackData &&
|
|
fallback.fallbackData.currency === 'EUR';
|
|
|
|
results.innerHTML = `
|
|
<div class="test-result ${isValid ? 'success' : 'error'}">
|
|
<strong>Extraction Fallback:</strong> ${isValid ? '✓' : '✗'}<br>
|
|
Manual Input Required: ${fallback.requiresManualInput}<br>
|
|
URL Preserved: ${fallback.url === testUrl}<br>
|
|
Fallback Data: ${JSON.stringify(fallback.fallbackData)}
|
|
</div>
|
|
`;
|
|
} catch (error) {
|
|
results.innerHTML = `<div class="test-result error">Extraction fallback test failed: ${error.message}</div>`;
|
|
}
|
|
};
|
|
|
|
window.testStorageErrorHandling = function() {
|
|
const results = document.getElementById('storage-error-results');
|
|
results.innerHTML = '';
|
|
|
|
const testData = { id: 'test', title: 'Test Item', price: '29.99' };
|
|
const storageError = new Error('Storage quota exceeded');
|
|
|
|
try {
|
|
const result = errorHandler.handleStorageError(testData, storageError);
|
|
|
|
const isValid = !result.success &&
|
|
result.dataPreserved &&
|
|
result.preservedData &&
|
|
result.preservedData.id === testData.id;
|
|
|
|
results.innerHTML = `
|
|
<div class="test-result ${isValid ? 'success' : 'error'}">
|
|
<strong>Storage Error Handling:</strong> ${isValid ? '✓' : '✗'}<br>
|
|
Data Preserved: ${result.dataPreserved}<br>
|
|
Message: ${result.message}<br>
|
|
Preserved Data ID: ${result.preservedData ? result.preservedData.id : 'None'}
|
|
</div>
|
|
`;
|
|
} catch (error) {
|
|
results.innerHTML = `<div class="test-result error">Storage error test failed: ${error.message}</div>`;
|
|
}
|
|
};
|
|
|
|
window.testUserFriendlyMessages = function() {
|
|
const results = document.getElementById('user-friendly-results');
|
|
results.innerHTML = '';
|
|
|
|
const errorTypes = [
|
|
'network', 'api_key', 'timeout', 'storage', 'quota',
|
|
'validation', 'extraction', 'ai_service', 'unknown'
|
|
];
|
|
|
|
errorTypes.forEach(errorType => {
|
|
try {
|
|
const error = new Error(`Test ${errorType} error`);
|
|
const processed = errorHandler.handleError(error, { component: 'test' });
|
|
processed.type = errorType; // Force type for testing
|
|
|
|
const friendlyError = errorHandler.getUserFriendlyError(processed);
|
|
|
|
const isValid = friendlyError.title &&
|
|
friendlyError.message &&
|
|
friendlyError.action &&
|
|
typeof friendlyError.canRetry === 'boolean';
|
|
|
|
const resultDiv = document.createElement('div');
|
|
resultDiv.className = `test-result ${isValid ? 'success' : 'error'}`;
|
|
resultDiv.innerHTML = `
|
|
<strong>${errorType}:</strong> ${isValid ? '✓' : '✗'}<br>
|
|
Title: ${friendlyError.title}<br>
|
|
Message: ${friendlyError.message}<br>
|
|
Action: ${friendlyError.action}<br>
|
|
Can Retry: ${friendlyError.canRetry}
|
|
`;
|
|
results.appendChild(resultDiv);
|
|
} catch (error) {
|
|
const resultDiv = document.createElement('div');
|
|
resultDiv.className = 'test-result error';
|
|
resultDiv.innerHTML = `<strong>${errorType} Failed:</strong> ${error.message}`;
|
|
results.appendChild(resultDiv);
|
|
}
|
|
});
|
|
};
|
|
|
|
window.showErrorLog = function() {
|
|
const logDiv = document.getElementById('error-log');
|
|
const recentErrors = errorHandler.getRecentErrors(10);
|
|
|
|
if (recentErrors.length === 0) {
|
|
logDiv.innerHTML = '<div class="test-result info">No errors in log</div>';
|
|
return;
|
|
}
|
|
|
|
logDiv.innerHTML = '<h3>Recent Errors:</h3>';
|
|
recentErrors.forEach((error, index) => {
|
|
const logEntry = document.createElement('div');
|
|
logEntry.className = 'log-entry';
|
|
logEntry.innerHTML = `
|
|
<strong>${index + 1}.</strong> [${error.component}] ${error.operation}: ${error.originalMessage}<br>
|
|
<small>Type: ${error.type} | Time: ${new Date(error.timestamp).toLocaleString()}</small>
|
|
`;
|
|
logDiv.appendChild(logEntry);
|
|
});
|
|
};
|
|
|
|
window.clearErrorLog = function() {
|
|
errorHandler.clearErrorLog();
|
|
document.getElementById('error-log').innerHTML = '<div class="test-result success">Error log cleared</div>';
|
|
};
|
|
|
|
// Auto-run basic test on load
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
console.log('ErrorHandler Integration Test loaded');
|
|
console.log('ErrorHandler instance:', errorHandler);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |