Added comprehensive plugin system for independent JavaScript UI development: **Plugin Infrastructure:** - Extended existing MarkiTect plugin system with RenderingEnginePlugin base class - Added RENDERING plugin type to PluginType enum - Created RenderingConfig for asset management and deployment - Implemented RenderingEngineManager for plugin discovery and lifecycle **TestDrive JSUI Plugin:** - Extracted JavaScript UI components to independent testdrive-jsui plugin - Created standalone development environment (no Python required) - Implemented compass-positioned control panels (NW, NE, E, SE) - Added clean JSON configuration interface for Python↔JavaScript data transfer **Asset Management:** - Development mode: serve assets directly from plugin source directory - Production mode: deploy to _markitect/plugins/[plugin-name]/ structure - Configurable asset URLs and deployment strategies - Support for external dependencies (CDN resources) **Standalone Development:** - testdrive-jsui/test.html for browser-based development - Package.json with npm scripts for development server - Complete separation of JavaScript development from Python environment - Hot reload and standard web development workflow **Integration Demo:** - demo_plugin_integration.py showcasing all plugin capabilities - Standalone, plugin discovery, production deployment examples - Asset URL generation for different deployment modes This enables JavaScript-first development while maintaining clean integration with the MarkiTect Python ecosystem. Developers can now work on UI components independently using standard web development tools and workflows. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
196 lines
7.0 KiB
JavaScript
196 lines
7.0 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* TDD Test for SectionManager Component Extraction
|
|
*
|
|
* Tests the extraction of SectionManager from the monolithic editor.js
|
|
* Ensures all functionality is preserved during refactoring.
|
|
*/
|
|
|
|
const RefactorTestRunner = require('./refactor-test-runner.js');
|
|
|
|
const runner = new RefactorTestRunner();
|
|
|
|
// First, let's define what the SectionManager API should look like
|
|
const EXPECTED_SECTION_MANAGER_API = [
|
|
'constructor',
|
|
'createSectionsFromMarkdown',
|
|
'startEditing',
|
|
'stopEditing',
|
|
'getAllSections',
|
|
'sections', // Map property, not method
|
|
'getDocumentStatus',
|
|
'getDocumentMarkdown',
|
|
'on', // event system
|
|
'emit', // event system
|
|
'handleSectionSplit',
|
|
'updateContent',
|
|
'acceptChanges',
|
|
'cancelChanges',
|
|
'resetSection'
|
|
];
|
|
|
|
runner.describe('SectionManager Component Extraction', () => {
|
|
|
|
runner.it('should define expected API methods', () => {
|
|
// This test defines what we expect from the extracted SectionManager
|
|
const expectedMethods = EXPECTED_SECTION_MANAGER_API;
|
|
runner.expect(expectedMethods.length).toBe(15);
|
|
runner.expect(expectedMethods).toContain('createSectionsFromMarkdown');
|
|
runner.expect(expectedMethods).toContain('startEditing');
|
|
runner.expect(expectedMethods).toContain('stopEditing');
|
|
});
|
|
|
|
runner.it('should extract from monolithic editor.js', () => {
|
|
// Load the monolithic editor.js to extract SectionManager
|
|
delete require.cache[require.resolve('/home/worsch/markitect_project/markitect/static/editor.js')];
|
|
|
|
try {
|
|
const editorModule = require('/home/worsch/markitect_project/markitect/static/editor.js');
|
|
runner.expect(editorModule.SectionManager).toBeTruthy();
|
|
// Set global for other tests
|
|
global.SectionManager = editorModule.SectionManager;
|
|
global.Section = editorModule.Section;
|
|
global.EditState = editorModule.EditState;
|
|
} catch (error) {
|
|
throw new Error(`Failed to load monolithic editor.js: ${error.message}`);
|
|
}
|
|
});
|
|
|
|
runner.it('should preserve SectionManager constructor functionality', () => {
|
|
const SectionManager = global.SectionManager;
|
|
|
|
const manager = new SectionManager();
|
|
runner.expect(manager).toBeInstanceOf(SectionManager);
|
|
runner.expect(manager.sections).toBeInstanceOf(Map);
|
|
});
|
|
|
|
runner.it('should preserve createSectionsFromMarkdown functionality', () => {
|
|
const SectionManager = global.SectionManager;
|
|
const manager = new SectionManager();
|
|
|
|
const testMarkdown = `# Heading 1\nContent 1\n\n## Heading 2\nContent 2`;
|
|
const sections = manager.createSectionsFromMarkdown(testMarkdown);
|
|
|
|
runner.expect(Array.isArray(sections)).toBeTruthy();
|
|
runner.expect(sections.length).toBe(2);
|
|
runner.expect(sections[0].currentMarkdown).toContain('Heading 1');
|
|
runner.expect(sections[1].currentMarkdown).toContain('Heading 2');
|
|
});
|
|
|
|
runner.it('should preserve section editing state management', () => {
|
|
const SectionManager = global.SectionManager;
|
|
const manager = new SectionManager();
|
|
|
|
const sections = manager.createSectionsFromMarkdown('# Test\nContent');
|
|
const sectionId = sections[0].id;
|
|
|
|
// Test start editing
|
|
runner.expect(manager.startEditing(sectionId)).toBeTruthy();
|
|
const section = manager.sections.get(sectionId);
|
|
runner.expect(section.isEditing()).toBeTruthy();
|
|
|
|
// Test stop editing
|
|
section.stopEditing();
|
|
runner.expect(section.isEditing()).toBeFalsy();
|
|
});
|
|
|
|
runner.it('should preserve event system functionality', () => {
|
|
const SectionManager = global.SectionManager;
|
|
const manager = new SectionManager();
|
|
|
|
let eventFired = false;
|
|
let eventData = null;
|
|
|
|
manager.on('test-event', (data) => {
|
|
eventFired = true;
|
|
eventData = data;
|
|
});
|
|
|
|
manager.emit('test-event', { test: 'data' });
|
|
|
|
runner.expect(eventFired).toBeTruthy();
|
|
runner.expect(eventData).toEqual({ test: 'data' });
|
|
});
|
|
|
|
runner.it('should preserve document status functionality', () => {
|
|
const SectionManager = global.SectionManager;
|
|
const manager = new SectionManager();
|
|
|
|
manager.createSectionsFromMarkdown('# Test\nContent');
|
|
const status = manager.getDocumentStatus();
|
|
|
|
runner.expect(status).toHaveProperty('totalSections');
|
|
runner.expect(status).toHaveProperty('editingSections');
|
|
runner.expect(status.totalSections).toBe(1);
|
|
});
|
|
|
|
runner.it('should preserve getAllSections functionality', () => {
|
|
const SectionManager = global.SectionManager;
|
|
const manager = new SectionManager();
|
|
|
|
const testMarkdown = '# One\nContent\n\n# Two\nMore content';
|
|
manager.createSectionsFromMarkdown(testMarkdown);
|
|
|
|
const allSections = manager.getAllSections();
|
|
runner.expect(Array.isArray(allSections)).toBeTruthy();
|
|
runner.expect(allSections.length).toBe(2);
|
|
});
|
|
|
|
runner.it('should preserve section splitting functionality', () => {
|
|
const SectionManager = global.SectionManager;
|
|
const manager = new SectionManager();
|
|
|
|
const sections = manager.createSectionsFromMarkdown('# Original\nContent');
|
|
const sectionId = sections[0].id;
|
|
|
|
const newContent = '# Split 1\nContent 1\n\n# Split 2\nContent 2';
|
|
const newSections = manager.handleSectionSplit(sectionId, newContent);
|
|
|
|
runner.expect(Array.isArray(newSections)).toBeTruthy();
|
|
runner.expect(newSections.length).toBe(2);
|
|
runner.expect(manager.sections.has(sectionId)).toBeFalsy(); // Original removed
|
|
});
|
|
});
|
|
|
|
// Export API tests for use during extraction
|
|
const SECTION_MANAGER_API_TESTS = [
|
|
(SectionManager) => {
|
|
const manager = new SectionManager();
|
|
if (!manager.sections || !(manager.sections instanceof Map)) {
|
|
throw new Error('sections property missing or not a Map');
|
|
}
|
|
},
|
|
(SectionManager) => {
|
|
const manager = new SectionManager();
|
|
if (typeof manager.createSectionsFromMarkdown !== 'function') {
|
|
throw new Error('createSectionsFromMarkdown method missing');
|
|
}
|
|
},
|
|
(SectionManager) => {
|
|
const manager = new SectionManager();
|
|
if (typeof manager.startEditing !== 'function') {
|
|
throw new Error('startEditing method missing');
|
|
}
|
|
},
|
|
(SectionManager) => {
|
|
const manager = new SectionManager();
|
|
if (typeof manager.stopEditing !== 'function') {
|
|
throw new Error('stopEditing method missing');
|
|
}
|
|
}
|
|
];
|
|
|
|
module.exports = {
|
|
runner,
|
|
EXPECTED_SECTION_MANAGER_API,
|
|
SECTION_MANAGER_API_TESTS
|
|
};
|
|
|
|
// Run tests if called directly
|
|
if (require.main === module) {
|
|
console.log('🧪 Testing SectionManager Component Extraction');
|
|
runner.run().then(() => {
|
|
console.log('✅ SectionManager extraction tests completed');
|
|
});
|
|
} |