#!/usr/bin/env node /** * End-to-End Tests for HTML Editor * * Comprehensive test suite for section editing and image manipulation */ const fs = require('fs'); const { TestRunner, HTMLFileTester } = require('./test_runner.js'); const runner = new TestRunner(); async function runE2ETests(htmlFile) { console.log('šŸŽ­ Running End-to-End Tests for HTML Editor'); let tester; runner.describe('Section Detection and Creation', () => { runner.it('should load and parse HTML successfully', async () => { tester = new HTMLFileTester(htmlFile); const loaded = await tester.load(); runner.expect(loaded || tester.html).toBeTruthy(); }); runner.it('should detect image sections correctly', async () => { // Check if image sections are being created const hasImageSection = tester.html.includes('section.isImage()'); runner.expect(hasImageSection).toBeTruthy(); }); runner.it('should have proper section IDs', async () => { // Check for data-section-id attributes runner.expect(tester.html.includes('data-section-id')).toBeTruthy(); }); }); runner.describe('JavaScript Functions Availability', () => { runner.it('should have image editor dialog function', async () => { runner.expect(tester.hasJavaScript('showImageEditor')).toBeTruthy(); }); runner.it('should have all image manipulation functions', async () => { const imageFunctions = [ 'replaceImage', 'resizeImage', 'addImageCaption', 'removeImage' ]; for (const func of imageFunctions) { runner.expect(tester.hasJavaScript(func)).toBeTruthy(); } }); runner.it('should have button creation function', async () => { runner.expect(tester.hasJavaScript('createButton')).toBeTruthy(); }); runner.it('should have auto-resize functionality', async () => { runner.expect(tester.hasJavaScript('setupAutoResize')).toBeTruthy(); }); }); runner.describe('DOM Structure Validation', () => { runner.it('should have container element', async () => { if (tester.document) { const container = tester.getElement('#markdown-content'); runner.expect(container).toBeTruthy(); } else { runner.expect(tester.hasElement('#markdown-content')).toBeTruthy(); } }); runner.it('should create sections with proper classes', async () => { // Check if setupSectionElement is being called runner.expect(tester.hasJavaScript('setupSectionElement')).toBeTruthy(); runner.expect(tester.hasJavaScript('ui-edit-section')).toBeTruthy(); }); }); if (tester.document && tester.window) { runner.describe('Interactive Testing (DOM Available)', () => { runner.it('should have MarkitectEditor available globally', async () => { const hasGlobalEditor = tester.window.MarkitectEditor !== undefined; runner.expect(hasGlobalEditor).toBeTruthy(); }); runner.it('should have sections rendered in DOM', async () => { if (tester.document) { const sections = tester.document.querySelectorAll('[data-section-id]'); runner.expect(sections.length > 0).toBeTruthy(); } }); runner.it('should have clickable sections', async () => { const sections = tester.document.querySelectorAll('.ui-edit-section'); runner.expect(sections.length > 0).toBeTruthy(); }); runner.it('should detect image sections properly', async () => { // Look for sections that contain image markdown const allSections = tester.document.querySelectorAll('[data-section-id]'); let imageCount = 0; for (const section of allSections) { if (section.innerHTML.includes(' 0).toBeTruthy(); }); runner.it('should have global editor controls', async () => { // Wait a bit for elements to be created await new Promise(resolve => setTimeout(resolve, 100)); const saveBtn = tester.document.getElementById('save-document'); const resetBtn = tester.document.getElementById('reset-all'); const statusBtn = tester.document.getElementById('show-status'); // At least one should exist (they're created dynamically) const hasControls = saveBtn || resetBtn || statusBtn || tester.document.querySelector('[id*="save"]') || tester.document.querySelector('[id*="reset"]') || tester.document.querySelector('[id*="status"]'); runner.expect(hasControls).toBeTruthy(); }); }); runner.describe('Button Functionality Validation', () => { runner.it('should create buttons with proper event handlers', async () => { // Check if createButton function includes addEventListener const createButtonCode = tester.html.match(/createButton\([\s\S]*?\{[\s\S]*?\}/); if (createButtonCode) { const hasEventListener = createButtonCode[0].includes('addEventListener'); runner.expect(hasEventListener).toBeTruthy(); } }); runner.it('should bind image manipulation handlers correctly', async () => { // Check if the image buttons are created with proper actions const hasImageButtonSetup = tester.html.includes('replaceImage(sectionId)') || tester.html.includes('this.replaceImage') || tester.html.includes('() => this.replaceImage'); runner.expect(hasImageButtonSetup).toBeTruthy(); }); runner.it('should have proper button styling', async () => { // Check if buttons have CSS styling const hasButtonStyling = tester.html.includes('btn.style.cssText') || tester.html.includes('style.background') || tester.html.includes('ui-edit-image-btn'); runner.expect(hasButtonStyling).toBeTruthy(); }); }); } await runner.run(); return runner.results; } // Debug information extractor function extractDebugInfo(htmlFile) { const html = fs.readFileSync(htmlFile, 'utf8'); console.log('\nšŸ” Debug Information Analysis:'); console.log('━'.repeat(50)); // Count different types of functions const functions = { 'Image Functions': ['replaceImage', 'resizeImage', 'addImageCaption', 'removeImage'], 'Editor Functions': ['showEditor', 'showImageEditor', 'hideEditor'], 'UI Functions': ['createButton', 'setupAutoResize', 'setupSectionElement'], 'Manager Functions': ['handleSectionClick', 'handleAccept', 'handleCancel'] }; for (const [category, funcList] of Object.entries(functions)) { console.log(`\nšŸ“‹ ${category}:`); for (const func of funcList) { const exists = html.includes(func); console.log(` ${exists ? 'āœ…' : 'āŒ'} ${func}`); } } // Check for common issues console.log('\nšŸ”§ Common Issues Check:'); const issues = [ { name: 'Button Event Binding', check: html.includes('addEventListener(\'click\'') }, { name: 'Arrow Function Binding', check: html.includes('() => this.') }, { name: 'Method Context Binding', check: html.includes('.bind(this)') }, { name: 'Image Editor Creation', check: html.includes('ui-edit-image-editor-container') } ]; for (const issue of issues) { console.log(` ${issue.check ? 'āœ…' : 'āŒ'} ${issue.name}`); } } // Main execution if (require.main === module) { const htmlFile = process.argv[2] || '/tmp/test_complete_functionality.html'; if (!fs.existsSync(htmlFile)) { console.error(`āŒ File not found: ${htmlFile}`); process.exit(1); } // Extract debug information first extractDebugInfo(htmlFile); // Run e2e tests runE2ETests(htmlFile).then(results => { const passed = results.filter(r => r.status === 'PASS').length; const failed = results.filter(r => r.status === 'FAIL').length; console.log(`\nšŸŽÆ E2E Test Summary: ${passed} passed, ${failed} failed`); if (failed > 0) { console.log('\n🚨 Issues found - investigate button functionality'); } else { console.log('\n✨ All tests passed - functionality should work correctly'); } }).catch(error => { console.error('āŒ E2E test runner failed:', error); process.exit(1); }); }