test-localStorage-injection.js•7.1 kB
/**
* @document Browser Automation Test for localStorage Injection
* @version 1.0.0
* @status active
* @author Claude Code
* @created 2025-06-30
* @description Automated test to validate localStorage injection in Composer
*/
import { chromium } from 'playwright';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Load the injection script as a string for browser evaluation
async function loadInjectionScript() {
const scriptPath = path.join(__dirname, '../../tools/injection/localStorage-injection-v1.0.0.js');
const compositionPath = path.join(__dirname, '../../compositions/fotossintese-composer-json-v1.1.0.js');
// Read both files
const injectionScript = await fs.readFile(scriptPath, 'utf-8');
const compositionScript = await fs.readFile(compositionPath, 'utf-8');
// Combine and adapt for browser context
return `
// Define fotossintesesComposerJSON in browser context
${compositionScript.replace('export const', 'const')}
// Injection functions
${injectionScript
.replace(/import.*?;/g, '') // Remove imports
.replace('export default', '')
.replace(/export /g, '')}
// Execute injection
injectFotossinteseComposition();
`;
}
async function testLocalStorageInjection() {
console.log('🎭 Starting localStorage injection test...\n');
const browser = await chromium.launch({
headless: false, // Show browser for debugging
slowMo: 500 // Slow down for visibility
});
try {
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 }
});
const page = await context.newPage();
// Step 1: Navigate to Composer
console.log('📍 Step 1: Navigating to Composer...');
const composerUrl = 'https://composer.euconquisto.com/composer';
await page.goto(composerUrl, { waitUntil: 'networkidle' });
// Take screenshot of initial state
await page.screenshot({
path: 'logs/screenshots/injection/01-initial-composer.png',
fullPage: true
});
// Step 2: Execute injection script
console.log('💉 Step 2: Injecting fotossíntese composition...');
const injectionScript = await loadInjectionScript();
const injectionResult = await page.evaluate(injectionScript);
// Step 3: Verify localStorage content
console.log('🔍 Step 3: Verifying localStorage content...');
const storageData = await page.evaluate(() => {
const data = localStorage.getItem('rdp-composer-data');
if (!data) return null;
try {
const parsed = JSON.parse(data);
return {
hasData: true,
compositionId: parsed.composition?.id,
title: parsed.composition?.title,
elementCount: parsed.composition?.elements?.length || 0,
firstElement: parsed.composition?.elements?.[0]?.type
};
} catch (e) {
return { hasData: false, error: e.message };
}
});
console.log('📦 localStorage verification:', storageData);
// Take screenshot after injection
await page.screenshot({
path: 'logs/screenshots/injection/02-after-injection.png',
fullPage: true
});
// Step 4: Navigate to editor to trigger composition load
console.log('🎨 Step 4: Navigating to editor mode...');
// Try to find and click edit/new composition button
// This may need adjustment based on actual Composer UI
await page.waitForTimeout(2000);
// Look for common editor triggers
const editorTriggers = [
'button:has-text("Nova Composição")',
'button:has-text("New Composition")',
'a[href*="/editor"]',
'button[class*="create"]',
'button[class*="new"]'
];
let foundTrigger = false;
for (const selector of editorTriggers) {
try {
await page.click(selector, { timeout: 5000 });
foundTrigger = true;
console.log(`✅ Clicked editor trigger: ${selector}`);
break;
} catch (e) {
// Continue trying other selectors
}
}
if (!foundTrigger) {
console.log('⚠️ Could not find editor trigger, attempting direct navigation...');
// Try direct navigation to editor
await page.goto(`${composerUrl}/editor`, { waitUntil: 'networkidle' });
}
// Wait for potential composition load
await page.waitForTimeout(3000);
// Take screenshot of editor state
await page.screenshot({
path: 'logs/screenshots/injection/03-editor-state.png',
fullPage: true
});
// Step 5: Validate composition rendering
console.log('✨ Step 5: Validating composition rendering...');
// Check for composition elements
const validationResult = await page.evaluate(() => {
// Look for common Composer element indicators
const indicators = {
hasTitle: !!document.querySelector('*[class*="title"]:has-text("Fotossíntese")'),
hasHeader: !!document.querySelector('*[class*="head-1"], *[class*="header"]'),
hasContent: !!document.querySelector('*[class*="text-1"], *[class*="content"]'),
hasWidgets: document.querySelectorAll('*[class*="widget"], *[class*="element"]').length,
visibleText: document.body.innerText.includes('Fotossíntese') ||
document.body.innerText.includes('fotossíntese')
};
return indicators;
});
console.log('🎯 Validation results:', validationResult);
// Take final screenshot
await page.screenshot({
path: 'logs/screenshots/injection/04-final-validation.png',
fullPage: true
});
// Generate test report
const testReport = {
timestamp: new Date().toISOString(),
success: !!storageData?.hasData && validationResult.visibleText,
localStorage: storageData,
rendering: validationResult,
screenshots: [
'01-initial-composer.png',
'02-after-injection.png',
'03-editor-state.png',
'04-final-validation.png'
]
};
console.log('\n📊 Test Summary:');
console.log('================');
console.log(`✅ localStorage injection: ${storageData?.hasData ? 'SUCCESS' : 'FAILED'}`);
console.log(`✅ Composition detected: ${validationResult.visibleText ? 'YES' : 'NO'}`);
console.log(`📍 Composition ID: ${storageData?.compositionId || 'N/A'}`);
console.log(`📝 Title: ${storageData?.title || 'N/A'}`);
console.log(`🧩 Elements: ${storageData?.elementCount || 0}`);
return testReport;
} catch (error) {
console.error('❌ Test failed:', error);
throw error;
} finally {
await browser.close();
}
}
// Run the test
testLocalStorageInjection()
.then(report => {
console.log('\n✅ Test completed successfully!');
process.exit(0);
})
.catch(error => {
console.error('\n❌ Test failed:', error);
process.exit(1);
});