Files
markitect-main/history/javascript-dev-tests/test_enhanced_dom_events.js
tegwick c4877543d5 refactor: clean up JavaScript development files and enhance automated testing
Complete cleanup and modernization of JavaScript testing infrastructure with
comprehensive automated test coverage and improved output formatting.

JavaScript Development Files Cleanup:
- Moved 53 manual development/debugging test files to history/javascript-dev-tests/
- Added comprehensive README documenting archived files and their purposes
- Cleaned main project directory of development artifacts

New Automated Test Suite (68 tests):
- keyboard-shortcuts.test.js: Tests Ctrl+Enter, Escape, accessibility features (8 tests)
- section-splitting.test.js: Tests heading detection, content parsing, ID generation (14 tests)
- image-editing.test.js: Tests dialog positioning, alt text, reset functionality (19 tests)
- button-events.test.js: Tests click handling, state management, event delegation (21 tests)

Integration Test Fixes:
- Fixed 13 failing integration tests by properly mocking component dependencies
- Updated tests to match actual component APIs instead of assumed interfaces
- Improved error handling and test reliability

Enhanced Test Output Formatting:
- Updated testdrive-jsui-test-all target to show clear test count summaries
- Separated JavaScript (68 tests) and Python (11 tests) results distinctly
- Added combined summary showing total coverage (79 tests)
- Improved error handling and visual formatting

Main Makefile Improvements:
- Fixed default target issue by adding .DEFAULT_GOAL := help
- Restored proper make help behavior when called without arguments

Key Achievements:
- Replaced 53 manual test files with 68 automated tests
- Achieved 100% test pass rate (79/79 tests passing)
- Enhanced CI/CD integration with clear test reporting
- Preserved all critical UI functionality in automated test coverage
- Improved developer experience with clearer test output

Testing Status:
-  68 JavaScript tests (Jest) - Core UI functionality
-  11 Python tests (pytest) - Integration bridge testing
-  100% automated test coverage for critical functionality
-  Clean, maintainable test codebase

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 23:16:47 +01:00

305 lines
13 KiB
JavaScript

#!/usr/bin/env node
/**
* TDD Tests for Enhanced DOM Event System Features
*/
const { TestRunner } = require('./test_runner.js');
const runner = new TestRunner();
// Test enhanced DOM event system advanced features
runner.describe('Enhanced DOM Event System Advanced Features', () => {
runner.it('should track event statistics and history', async () => {
// Load editor
delete require.cache[require.resolve('/home/worsch/markitect_project/markitect/static/editor.js')];
require('/home/worsch/markitect_project/markitect/static/editor.js');
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
// Verify event tracking capabilities
runner.expect(typeof renderer.getEventStats).toBe('function');
runner.expect(Array.isArray(renderer.eventHistory)).toBeTruthy();
runner.expect(typeof renderer.eventStats).toBe('object');
// Initial state should be empty
const initialStats = renderer.getEventStats();
runner.expect(initialStats.totalEvents).toBe(0);
runner.expect(initialStats.recentEvents.length).toBe(0);
}
});
runner.it('should track section-click events with detailed data', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
// Simulate click and verify tracking
const sectionElement = container.querySelector('[data-section-id]');
if (sectionElement) {
const clickEvent = new Event('click', { bubbles: true });
sectionElement.dispatchEvent(clickEvent);
const stats = renderer.getEventStats();
runner.expect(stats.stats['section-click']).toBe(1);
runner.expect(stats.recentEvents.length).toBe(1);
runner.expect(stats.recentEvents[0].type).toBe('section-click');
runner.expect(stats.recentEvents[0].data.sectionId).toBeTruthy();
}
}
});
runner.it('should track hover events separately for enter/leave', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
const sectionElement = container.querySelector('[data-section-id]');
if (sectionElement) {
// Simulate hover enter and leave
const mouseEnterEvent = new Event('mouseenter');
const mouseLeaveEvent = new Event('mouseleave');
sectionElement.dispatchEvent(mouseEnterEvent);
sectionElement.dispatchEvent(mouseLeaveEvent);
const stats = renderer.getEventStats();
runner.expect(stats.stats['section-hover-enter']).toBe(1);
runner.expect(stats.stats['section-hover-leave']).toBe(1);
}
}
});
runner.it('should track keyboard shortcuts with action data', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
manager.startEditing(sections[0].id);
const textarea = container.querySelector('textarea');
if (textarea) {
// Simulate Ctrl+Enter
const keyEvent = new KeyboardEvent('keydown', {
key: 'Enter',
ctrlKey: true,
bubbles: true
});
textarea.dispatchEvent(keyEvent);
const stats = renderer.getEventStats();
runner.expect(stats.stats['keyboard-shortcut']).toBe(1);
const shortcutEvent = stats.recentEvents.find(e => e.type === 'keyboard-shortcut');
if (shortcutEvent) {
runner.expect(shortcutEvent.data.shortcut).toBe('ctrl+enter');
runner.expect(shortcutEvent.data.action).toBe('accept');
}
}
}
});
runner.it('should make sections draggable with proper attributes', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
const sectionElements = container.querySelectorAll('[data-section-id]');
runner.expect(sectionElements.length).toBeGreaterThan(0);
if (sectionElements.length > 0) {
const sectionElement = sectionElements[0];
// Check draggable attribute
runner.expect(sectionElement.draggable).toBeTruthy();
// Check accessibility attributes
runner.expect(sectionElement.tabIndex).toBe(0);
runner.expect(sectionElement.getAttribute('role')).toBe('article');
runner.expect(sectionElement.getAttribute('aria-label')).toBeTruthy();
// Check for drag handle
const dragHandle = sectionElement.querySelector('.ui-edit-drag-handle');
runner.expect(dragHandle).toBeTruthy();
}
}
});
runner.it('should support context menu with proper menu items', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
const sectionElement = container.querySelector('[data-section-id]');
if (sectionElement) {
// Simulate right-click
const contextMenuEvent = new Event('contextmenu', { bubbles: true });
Object.defineProperty(contextMenuEvent, 'clientX', { value: 100 });
Object.defineProperty(contextMenuEvent, 'clientY', { value: 200 });
sectionElement.dispatchEvent(contextMenuEvent);
// Check if context menu was created
const contextMenu = document.querySelector('.ui-edit-context-menu');
runner.expect(contextMenu).toBeTruthy();
if (contextMenu) {
// Should have menu items
const menuItems = contextMenu.querySelectorAll('div');
runner.expect(menuItems.length).toBeGreaterThan(3); // At least 4 items
// Clean up
contextMenu.remove();
}
// Should track the event
const stats = renderer.getEventStats();
runner.expect(stats.stats['section-context-menu']).toBe(1);
}
}
});
runner.it('should support drag and drop event tracking', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Section 1\n\nContent 1\n\n# Section 2\n\nContent 2');
const sectionElements = container.querySelectorAll('[data-section-id]');
if (sectionElements.length >= 2) {
const source = sectionElements[0];
const target = sectionElements[1];
// Simulate drag start
const dragStartEvent = new Event('dragstart');
Object.defineProperty(dragStartEvent, 'dataTransfer', {
value: {
setData: () => {},
effectAllowed: null
}
});
source.dispatchEvent(dragStartEvent);
// Simulate drag over
const dragOverEvent = new Event('dragover');
Object.defineProperty(dragOverEvent, 'dataTransfer', {
value: { dropEffect: null }
});
Object.defineProperty(dragOverEvent, 'preventDefault', {
value: () => {}
});
target.dispatchEvent(dragOverEvent);
const stats = renderer.getEventStats();
runner.expect(stats.stats['section-drag-start']).toBe(1);
runner.expect(stats.stats['section-drag-over']).toBe(1);
}
}
});
runner.it('should handle multiple keyboard shortcuts correctly', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
manager.startEditing(sections[0].id);
const textarea = container.querySelector('textarea');
if (textarea) {
// Test different shortcuts
const shortcuts = [
{ key: 'Enter', ctrlKey: true, expected: 'ctrl+enter' },
{ key: 's', ctrlKey: true, expected: 'ctrl+s' },
{ key: 'Escape', ctrlKey: false, expected: 'escape' }
];
for (const shortcut of shortcuts) {
// Need to restart editing for each test
if (!sections[0].isEditing()) {
manager.startEditing(sections[0].id);
}
const keyEvent = new KeyboardEvent('keydown', {
key: shortcut.key,
ctrlKey: shortcut.ctrlKey,
bubbles: true
});
textarea.dispatchEvent(keyEvent);
}
const stats = renderer.getEventStats();
runner.expect(stats.stats['keyboard-shortcut']).toBeGreaterThanOrEqual(3);
}
}
});
runner.it('should support event history with timestamps', async () => {
if (global.DOMRenderer && global.SectionManager) {
const container = document.createElement('div');
const manager = new global.SectionManager();
const renderer = new global.DOMRenderer(manager, container);
const sections = manager.createSectionsFromMarkdown('# Test Section\n\nTest content');
// Generate multiple events
const sectionElement = container.querySelector('[data-section-id]');
if (sectionElement) {
// Click event
const clickEvent = new Event('click', { bubbles: true });
sectionElement.dispatchEvent(clickEvent);
// Hover events
const mouseEnterEvent = new Event('mouseenter');
const mouseLeaveEvent = new Event('mouseleave');
sectionElement.dispatchEvent(mouseEnterEvent);
sectionElement.dispatchEvent(mouseLeaveEvent);
const stats = renderer.getEventStats();
runner.expect(stats.totalEvents).toBe(3);
runner.expect(stats.recentEvents.length).toBe(3);
// Check that events have timestamps
const hasTimestamps = stats.recentEvents.every(event =>
event.timestamp && typeof event.timestamp === 'string'
);
runner.expect(hasTimestamps).toBeTruthy();
// Check that events are properly typed
const eventTypes = stats.recentEvents.map(e => e.type);
runner.expect(eventTypes.includes('section-click')).toBeTruthy();
runner.expect(eventTypes.includes('section-hover-enter')).toBeTruthy();
runner.expect(eventTypes.includes('section-hover-leave')).toBeTruthy();
}
}
});
});
// Run the tests
if (require.main === module) {
console.log('⚡ Running Enhanced DOM Event System Advanced Feature Tests');
runner.run().then(() => {
console.log('✅ Enhanced DOM event system tests complete!');
});
}
module.exports = runner;