- 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
419 lines
17 KiB
HTML
419 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>CORS Fallback Test - Amazon Extension</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 20px;
|
|
background: #f5f5f5;
|
|
}
|
|
.test-container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}
|
|
.status {
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
|
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
|
.warning { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7; }
|
|
.info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
|
|
|
|
.test-section {
|
|
margin: 20px 0;
|
|
padding: 15px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
button {
|
|
background: #007bff;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
|
|
button:hover {
|
|
background: #0056b3;
|
|
}
|
|
|
|
.log {
|
|
background: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 4px;
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.mock-product {
|
|
border: 1px solid #ddd;
|
|
padding: 15px;
|
|
margin: 10px 0;
|
|
border-radius: 4px;
|
|
background: #fafafa;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="test-container">
|
|
<h1>🔧 CORS Fallback Test - Amazon Extension</h1>
|
|
|
|
<div class="status info">
|
|
<strong>Test Purpose:</strong> Verify that the extension automatically falls back to localStorage when AppWrite CORS errors occur.
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>1. Extension Status</h2>
|
|
<div id="extension-status" class="status warning">Checking extension...</div>
|
|
<button onclick="checkExtensionStatus()">Check Extension Status</button>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>2. AppWrite Connection Test</h2>
|
|
<div id="appwrite-status" class="status warning">Testing AppWrite connection...</div>
|
|
<button onclick="testAppWriteConnection()">Test AppWrite Connection</button>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>3. CORS Fallback Test</h2>
|
|
<div id="cors-fallback-status" class="status warning">Ready to test CORS fallback...</div>
|
|
<button onclick="testCORSFallback()">Test CORS Fallback</button>
|
|
<button onclick="simulateLogin()">Simulate Login (Trigger CORS)</button>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>4. localStorage Fallback Operations</h2>
|
|
<div id="fallback-operations-status" class="status warning">Ready to test fallback operations...</div>
|
|
<button onclick="testFallbackSave()">Test Fallback Save</button>
|
|
<button onclick="testFallbackLoad()">Test Fallback Load</button>
|
|
<button onclick="clearFallbackData()">Clear Fallback Data</button>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>5. Mock Amazon Product (for testing)</h2>
|
|
<div class="mock-product">
|
|
<h3>Test Product: Smartphone XYZ</h3>
|
|
<p><strong>URL:</strong> https://www.amazon.de/dp/B08N5WRWNW</p>
|
|
<p><strong>Price:</strong> €299.99</p>
|
|
<button onclick="addMockProduct()">Add to Enhanced Items (Test Fallback)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="test-section">
|
|
<h2>6. Event Log</h2>
|
|
<button onclick="clearLog()">Clear Log</button>
|
|
<div id="event-log" class="log">Waiting for events...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Load the extension content script -->
|
|
<script src="dist/content.js"></script>
|
|
|
|
<script>
|
|
let logContainer = document.getElementById('event-log');
|
|
|
|
function log(message, type = 'info') {
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
const logEntry = document.createElement('div');
|
|
logEntry.innerHTML = `<span style="color: #666;">[${timestamp}]</span> <span style="color: ${type === 'error' ? 'red' : type === 'success' ? 'green' : type === 'warning' ? 'orange' : 'blue'};">${message}</span>`;
|
|
logContainer.appendChild(logEntry);
|
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|
}
|
|
|
|
function clearLog() {
|
|
logContainer.innerHTML = 'Log cleared...';
|
|
}
|
|
|
|
function updateStatus(elementId, message, type) {
|
|
const element = document.getElementById(elementId);
|
|
element.textContent = message;
|
|
element.className = `status ${type}`;
|
|
}
|
|
|
|
// Listen for extension events
|
|
if (typeof window !== 'undefined' && window.amazonExtEventBus) {
|
|
// AppWrite events
|
|
window.amazonExtEventBus.on('appwrite:unavailable', (data) => {
|
|
log('🚨 AppWrite unavailable - fallback activated', 'warning');
|
|
updateStatus('appwrite-status', 'AppWrite unavailable - using localStorage fallback', 'warning');
|
|
});
|
|
|
|
window.amazonExtEventBus.on('appwrite:restored', (data) => {
|
|
log('✅ AppWrite service restored', 'success');
|
|
updateStatus('appwrite-status', 'AppWrite service restored', 'success');
|
|
});
|
|
|
|
// Authentication events
|
|
window.amazonExtEventBus.on('authentication:expired', (data) => {
|
|
log('🔐 Authentication expired', 'warning');
|
|
});
|
|
|
|
// Error events
|
|
window.amazonExtEventBus.on('error:occurred', (error) => {
|
|
log(`❌ Error: ${error.userMessage || error.originalMessage}`, 'error');
|
|
});
|
|
|
|
// Enhanced item events
|
|
window.amazonExtEventBus.on('enhanced:item:saved', (data) => {
|
|
log(`💾 Enhanced item saved: ${data.usedFallback ? 'localStorage fallback' : 'AppWrite'}`, 'success');
|
|
});
|
|
}
|
|
|
|
function checkExtensionStatus() {
|
|
log('Checking extension status...', 'info');
|
|
|
|
if (typeof window.amazonExtEventBus !== 'undefined') {
|
|
updateStatus('extension-status', 'Extension loaded successfully', 'success');
|
|
log('✅ Extension event bus available', 'success');
|
|
} else {
|
|
updateStatus('extension-status', 'Extension not loaded', 'error');
|
|
log('❌ Extension event bus not available', 'error');
|
|
return;
|
|
}
|
|
|
|
if (typeof window.errorHandler !== 'undefined') {
|
|
log('✅ ErrorHandler available', 'success');
|
|
|
|
const appWriteStatus = window.errorHandler.getAppWriteStatus();
|
|
log(`AppWrite Status: Available=${appWriteStatus.available}, Fallback=${appWriteStatus.fallbackActive}`, 'info');
|
|
} else {
|
|
log('❌ ErrorHandler not available', 'error');
|
|
}
|
|
|
|
if (typeof window.appWriteManager !== 'undefined') {
|
|
log('✅ AppWriteManager available', 'success');
|
|
} else {
|
|
log('❌ AppWriteManager not available', 'error');
|
|
}
|
|
}
|
|
|
|
async function testAppWriteConnection() {
|
|
log('Testing AppWrite connection...', 'info');
|
|
|
|
if (!window.appWriteManager) {
|
|
updateStatus('appwrite-status', 'AppWriteManager not available', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const healthCheck = await window.appWriteManager.healthCheck();
|
|
if (healthCheck.success) {
|
|
updateStatus('appwrite-status', 'AppWrite connection successful', 'success');
|
|
log('✅ AppWrite health check passed', 'success');
|
|
} else {
|
|
updateStatus('appwrite-status', 'AppWrite connection failed', 'error');
|
|
log('❌ AppWrite health check failed', 'error');
|
|
}
|
|
} catch (error) {
|
|
updateStatus('appwrite-status', `AppWrite connection error: ${error.message}`, 'error');
|
|
log(`❌ AppWrite connection error: ${error.message}`, 'error');
|
|
|
|
// Check if this triggers CORS fallback
|
|
if (error.message.toLowerCase().includes('cors') ||
|
|
error.message.toLowerCase().includes('access-control-allow-origin')) {
|
|
log('🔄 CORS error detected - should trigger fallback', 'warning');
|
|
}
|
|
}
|
|
}
|
|
|
|
async function testCORSFallback() {
|
|
log('Testing CORS fallback mechanism...', 'info');
|
|
|
|
if (!window.errorHandler) {
|
|
updateStatus('cors-fallback-status', 'ErrorHandler not available', 'error');
|
|
return;
|
|
}
|
|
|
|
// Simulate a CORS error
|
|
const corsError = new Error('Access to fetch at \'https://appwrite.webklar.com/v1/account/sessions/email\' from origin \'https://www.amazon.de\' has been blocked by CORS policy');
|
|
|
|
const result = await window.errorHandler.handleAppWriteUnavailabilityFallback({
|
|
type: 'saveEnhancedItem',
|
|
data: {
|
|
itemId: 'test_cors_' + Date.now(),
|
|
amazonUrl: 'https://www.amazon.de/dp/TEST123',
|
|
originalTitle: 'CORS Test Product',
|
|
customTitle: 'CORS Test Product',
|
|
price: '99.99',
|
|
currency: 'EUR'
|
|
}
|
|
}, corsError);
|
|
|
|
if (result.success && result.usedFallback) {
|
|
updateStatus('cors-fallback-status', 'CORS fallback working correctly', 'success');
|
|
log('✅ CORS fallback test successful - data saved to localStorage', 'success');
|
|
} else {
|
|
updateStatus('cors-fallback-status', 'CORS fallback failed', 'error');
|
|
log('❌ CORS fallback test failed', 'error');
|
|
}
|
|
}
|
|
|
|
async function simulateLogin() {
|
|
log('Simulating login to trigger CORS error...', 'info');
|
|
|
|
if (!window.authService) {
|
|
log('❌ AuthService not available', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// This should trigger the CORS error we're seeing
|
|
await window.authService.login('test@example.com', 'testpassword');
|
|
} catch (error) {
|
|
log(`Expected CORS error occurred: ${error.message}`, 'warning');
|
|
|
|
// Check if fallback was activated
|
|
if (window.errorHandler && window.errorHandler.isUsingLocalStorageFallback()) {
|
|
log('✅ localStorage fallback automatically activated', 'success');
|
|
updateStatus('cors-fallback-status', 'CORS detected - localStorage fallback active', 'warning');
|
|
} else {
|
|
log('❌ Fallback not activated', 'error');
|
|
}
|
|
}
|
|
}
|
|
|
|
async function testFallbackSave() {
|
|
log('Testing localStorage fallback save...', 'info');
|
|
|
|
const testData = {
|
|
itemId: 'fallback_test_' + Date.now(),
|
|
amazonUrl: 'https://www.amazon.de/dp/FALLBACK123',
|
|
originalTitle: 'Fallback Test Product',
|
|
customTitle: 'Fallback Test Product',
|
|
price: '149.99',
|
|
currency: 'EUR',
|
|
createdAt: new Date().toISOString()
|
|
};
|
|
|
|
try {
|
|
// Save directly to localStorage fallback
|
|
const fallbackKey = 'amazon-ext-fallback-enhanced-items';
|
|
const existingData = JSON.parse(localStorage.getItem(fallbackKey) || '[]');
|
|
existingData.push({
|
|
...testData,
|
|
fallbackSavedAt: new Date().toISOString(),
|
|
needsSync: true
|
|
});
|
|
localStorage.setItem(fallbackKey, JSON.stringify(existingData));
|
|
|
|
updateStatus('fallback-operations-status', 'Fallback save successful', 'success');
|
|
log('✅ Test data saved to localStorage fallback', 'success');
|
|
} catch (error) {
|
|
updateStatus('fallback-operations-status', 'Fallback save failed', 'error');
|
|
log(`❌ Fallback save error: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
function testFallbackLoad() {
|
|
log('Testing localStorage fallback load...', 'info');
|
|
|
|
try {
|
|
const fallbackKey = 'amazon-ext-fallback-enhanced-items';
|
|
const fallbackData = JSON.parse(localStorage.getItem(fallbackKey) || '[]');
|
|
|
|
if (fallbackData.length > 0) {
|
|
updateStatus('fallback-operations-status', `Loaded ${fallbackData.length} items from fallback`, 'success');
|
|
log(`✅ Loaded ${fallbackData.length} items from localStorage fallback`, 'success');
|
|
|
|
fallbackData.forEach((item, index) => {
|
|
log(` Item ${index + 1}: ${item.originalTitle} (${item.fallbackSavedAt})`, 'info');
|
|
});
|
|
} else {
|
|
updateStatus('fallback-operations-status', 'No fallback data found', 'warning');
|
|
log('⚠️ No data found in localStorage fallback', 'warning');
|
|
}
|
|
} catch (error) {
|
|
updateStatus('fallback-operations-status', 'Fallback load failed', 'error');
|
|
log(`❌ Fallback load error: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
function clearFallbackData() {
|
|
log('Clearing localStorage fallback data...', 'info');
|
|
|
|
try {
|
|
const fallbackKeys = [
|
|
'amazon-ext-fallback-enhanced-items',
|
|
'amazon-ext-fallback-blacklist',
|
|
'amazon-ext-fallback-settings'
|
|
];
|
|
|
|
let clearedCount = 0;
|
|
fallbackKeys.forEach(key => {
|
|
if (localStorage.getItem(key)) {
|
|
localStorage.removeItem(key);
|
|
clearedCount++;
|
|
}
|
|
});
|
|
|
|
updateStatus('fallback-operations-status', `Cleared ${clearedCount} fallback stores`, 'success');
|
|
log(`✅ Cleared ${clearedCount} localStorage fallback stores`, 'success');
|
|
} catch (error) {
|
|
log(`❌ Error clearing fallback data: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
async function addMockProduct() {
|
|
log('Adding mock product to test fallback...', 'info');
|
|
|
|
if (!window.enhancedStorageManager) {
|
|
log('❌ EnhancedStorageManager not available', 'error');
|
|
return;
|
|
}
|
|
|
|
const mockProduct = {
|
|
itemId: 'mock_' + Date.now(),
|
|
amazonUrl: 'https://www.amazon.de/dp/B08N5WRWNW',
|
|
originalTitle: 'Smartphone XYZ - 128GB, Schwarz',
|
|
customTitle: 'Smartphone XYZ - 128GB, Schwarz',
|
|
price: '299.99',
|
|
currency: 'EUR',
|
|
titleSuggestions: [
|
|
'Smartphone XYZ - 128GB, Schwarz',
|
|
'Premium Smartphone XYZ 128GB',
|
|
'XYZ Smartphone 128GB Schwarz'
|
|
]
|
|
};
|
|
|
|
try {
|
|
const result = await window.enhancedStorageManager.saveEnhancedItem(mockProduct);
|
|
|
|
if (result.success) {
|
|
log(`✅ Mock product saved successfully (fallback: ${result.usedFallback})`, 'success');
|
|
} else {
|
|
log(`❌ Failed to save mock product: ${result.error?.userMessage}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
log(`❌ Error saving mock product: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
// Initialize on page load
|
|
window.addEventListener('load', () => {
|
|
log('🚀 CORS Fallback Test page loaded', 'info');
|
|
|
|
// Wait a bit for extension to initialize
|
|
setTimeout(() => {
|
|
checkExtensionStatus();
|
|
}, 1000);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |