#!/usr/bin/env node /** * HTML Editor Test Runner * * This script provides a test environment for our HTML editor functionality * using puppeteer for headless browser testing. */ const fs = require('fs'); const path = require('path'); // Simple test framework class TestRunner { constructor() { this.tests = []; this.results = []; this.currentTest = null; } describe(description, testFn) { console.log(`\n๐Ÿ“‹ Test Suite: ${description}`); console.log('โ”'.repeat(50)); testFn(); } it(description, testFn) { this.tests.push({ description, testFn }); } async run() { console.log(`\n๐Ÿš€ Running ${this.tests.length} tests...\n`); for (const test of this.tests) { this.currentTest = test; try { console.log(` ๐Ÿงช ${test.description}`); await test.testFn(); this.results.push({ ...test, status: 'PASS' }); console.log(` โœ… PASS`); } catch (error) { this.results.push({ ...test, status: 'FAIL', error }); console.log(` โŒ FAIL: ${error.message}`); } } this.printSummary(); } printSummary() { const passed = this.results.filter(r => r.status === 'PASS').length; const failed = this.results.filter(r => r.status === 'FAIL').length; console.log('\n' + 'โ•'.repeat(50)); console.log(`๐Ÿ“Š Test Results: ${passed} passed, ${failed} failed`); if (failed > 0) { console.log('\nโŒ Failed Tests:'); this.results.filter(r => r.status === 'FAIL').forEach(test => { console.log(` โ€ข ${test.description}: ${test.error.message}`); }); } console.log('โ•'.repeat(50)); } expect(actual) { const expectObj = { toBe: (expected) => { if (actual !== expected) { throw new Error(`Expected ${expected}, got ${actual}`); } }, toContain: (expected) => { if (!actual.includes(expected)) { throw new Error(`Expected "${actual}" to contain "${expected}"`); } }, toBeTruthy: () => { if (!actual) { throw new Error(`Expected truthy value, got ${actual}`); } }, toBeFalsy: () => { if (actual) { throw new Error(`Expected falsy value, got ${actual}`); } }, toBeGreaterThan: (expected) => { if (actual <= expected) { throw new Error(`Expected ${actual} to be greater than ${expected}`); } }, toBeGreaterThanOrEqual: (expected) => { if (actual < expected) { throw new Error(`Expected ${actual} to be greater than or equal to ${expected}`); } }, toBeLessThan: (expected) => { if (actual >= expected) { throw new Error(`Expected ${actual} to be less than ${expected}`); } } }; // Add 'not' property for negation expectObj.not = { toBe: (expected) => { if (actual === expected) { throw new Error(`Expected ${actual} not to be ${expected}`); } }, toContain: (expected) => { if (actual.includes(expected)) { throw new Error(`Expected "${actual}" not to contain "${expected}"`); } }, toBeTruthy: () => { if (actual) { throw new Error(`Expected falsy value, got ${actual}`); } }, toBeFalsy: () => { if (!actual) { throw new Error(`Expected truthy value, got ${actual}`); } } }; return expectObj; } } // HTML File Tester class HTMLFileTester { constructor(htmlFilePath) { this.htmlFilePath = htmlFilePath; this.html = null; this.jsdom = null; this.window = null; this.document = null; } async load() { try { // Try to use jsdom if available const { JSDOM } = require('jsdom'); this.html = fs.readFileSync(this.htmlFilePath, 'utf8'); // Create a DOM environment this.jsdom = new JSDOM(this.html, { runScripts: "dangerously", resources: "usable", pretendToBeVisual: true }); this.window = this.jsdom.window; this.document = this.window.document; // Wait for content to load await new Promise(resolve => { if (this.document.readyState === 'complete') { resolve(); } else { this.window.addEventListener('load', resolve); } }); return true; } catch (error) { // Fallback to simple HTML parsing this.html = fs.readFileSync(this.htmlFilePath, 'utf8'); console.log('โš ๏ธ Using fallback HTML parsing (install jsdom for full testing)'); return false; } } hasElement(selector) { if (this.document) { return !!this.document.querySelector(selector); } // Fallback: simple text search return this.html.includes(selector); } getElement(selector) { if (this.document) { return this.document.querySelector(selector); } return null; } hasJavaScript(functionName) { return this.html.includes(functionName); } hasDebugMode() { return this.html.includes('DEBUG_MODE'); } getDebugMode() { const match = this.html.match(/const DEBUG_MODE = ['"`](\w+)['"`];/); return match ? match[1] : null; } simulate(action, selector) { if (!this.document) { throw new Error('Cannot simulate actions without DOM environment'); } const element = this.document.querySelector(selector); if (!element) { throw new Error(`Element not found: ${selector}`); } switch (action) { case 'click': element.click(); break; case 'focus': element.focus(); break; default: throw new Error(`Unknown action: ${action}`); } } } // Main test runner instance const runner = new TestRunner(); // Export for use module.exports = { TestRunner, HTMLFileTester, runner }; // If run directly, run basic tests if (require.main === module) { console.log('๐Ÿงช HTML Editor Test Runner'); console.log('Usage: node test_runner.js [html-file-path]'); const htmlFile = process.argv[2] || '/tmp/test_complete_functionality.html'; if (!fs.existsSync(htmlFile)) { console.error(`โŒ File not found: ${htmlFile}`); process.exit(1); } // Basic structural tests runner.describe('HTML Structure Tests', () => { let tester; runner.it('should load HTML file successfully', async () => { tester = new HTMLFileTester(htmlFile); const loaded = await tester.load(); runner.expect(loaded || tester.html).toBeTruthy(); }); runner.it('should have markdown content container', async () => { runner.expect(tester.hasElement('#markdown-content')).toBeTruthy(); }); runner.it('should have debug system', async () => { runner.expect(tester.hasDebugMode()).toBeTruthy(); }); runner.it('should use console debug mode', async () => { runner.expect(tester.getDebugMode()).toBe('console'); }); runner.it('should have section editor functions', async () => { runner.expect(tester.hasJavaScript('MarkitectCleanEditor')).toBeTruthy(); runner.expect(tester.hasJavaScript('showImageEditor')).toBeTruthy(); runner.expect(tester.hasJavaScript('setupAutoResize')).toBeTruthy(); }); runner.it('should have image manipulation functions', async () => { runner.expect(tester.hasJavaScript('replaceImage')).toBeTruthy(); runner.expect(tester.hasJavaScript('resizeImage')).toBeTruthy(); runner.expect(tester.hasJavaScript('addImageCaption')).toBeTruthy(); runner.expect(tester.hasJavaScript('removeImage')).toBeTruthy(); }); }); // Run the tests runner.run().then(() => { console.log('\n๐Ÿ Testing complete!'); }).catch(error => { console.error('โŒ Test runner failed:', error); process.exit(1); }); }