# TestDrive-JSUI Standalone Reusability Plan **Date**: 2025-12-16 **Goal**: Make testdrive-jsui truly reusable independently from MarkiTect **Current Maturity**: 60% → **Target**: 95% --- ## Executive Summary TestDrive-JSUI has excellent JavaScript architecture and testing infrastructure, but its Python rendering engine lives in the MarkiTect codebase, preventing true standalone reuse. This plan outlines how to make it a fully independent, pip-installable package that works in any Python project. **Key Problem**: Cannot `pip install testdrive-jsui` and use it in non-MarkiTect projects. **Solution**: Move rendering engine and dependencies into the capability package. --- ## Current State Analysis ### What Works ✅ - JavaScript components are self-contained - Testing infrastructure is independent - Asset structure is clean - Documentation is comprehensive ### What Doesn't ❌ - Rendering engine in `/markitect/plugins/testdrive_jsui.py` - Depends on `markitect.plugins.rendering.RenderingConfig` - Python package (`src/testdrive_jsui/`) is empty shells - Not pip-installable for standalone use --- ## Phase 1: Move Core Rendering Engine ### Objective Move the rendering engine from MarkiTect plugins into the capability package. ### Current Location ``` /markitect/plugins/testdrive_jsui.py (242 lines) /markitect/plugins/rendering.py (316 lines - base classes) /markitect/plugins/base.py (Plugin metadata) ``` ### Target Location ``` src/testdrive_jsui/ ├── __init__.py # Export main classes ├── engine.py # TestDriveJSUIEngine (moved) ├── rendering.py # RenderingEnginePlugin, RenderingConfig (extracted) ├── models.py # PluginMetadata, etc. └── testing/ # ✅ Already independent ``` ### Implementation Steps #### Step 1.1: Extract Base Classes **Create**: `src/testdrive_jsui/models.py` ```python """ Data models and metadata for TestDrive-JSUI. """ from dataclasses import dataclass from enum import Enum from typing import Optional class PluginType(Enum): """Plugin type enumeration.""" RENDERING = "rendering" TESTING = "testing" @dataclass class PluginMetadata: """Plugin metadata information.""" name: str version: str description: str author: str plugin_type: PluginType ``` **Why**: Remove dependency on MarkiTect's plugin system. --- #### Step 1.2: Create Standalone Rendering Base **Create**: `src/testdrive_jsui/rendering.py` Extract and adapt from `/markitect/plugins/rendering.py`: - `RenderingEnginePlugin` (abstract base) - `RenderingConfig` (configuration) - Remove MarkiTect-specific integrations - Make it generic for any Python project ```python """ Rendering engine plugin architecture for TestDrive-JSUI. This module provides a standalone rendering system that can be used independently of MarkiTect or integrated into any Python project. """ from abc import ABC, abstractmethod from typing import Dict, List, Optional, Any from pathlib import Path import json class RenderingEnginePlugin(ABC): """Base class for rendering engine plugins.""" @abstractmethod def get_supported_modes(self) -> List[str]: """Return supported rendering modes (e.g., ['edit', 'view']).""" pass @abstractmethod def get_required_assets(self) -> Dict[str, List[str]]: """Return required assets by type (js, css, images).""" pass @abstractmethod def render_document(self, content: str, mode: str, config: 'RenderingConfig') -> str: """Render markdown content to HTML.""" pass # ... rest of interface class RenderingConfig: """Configuration for rendering engine.""" def __init__(self, asset_base_url: str = "_static", development_mode: bool = False, plugin_source_dirs: Optional[Dict[str, Path]] = None, output_directory: Optional[Path] = None): """Initialize configuration for standalone use.""" self.asset_base_url = asset_base_url self.development_mode = development_mode self.plugin_source_dirs = plugin_source_dirs or {} self.output_directory = output_directory # ... rest of implementation ``` **Why**: Standalone projects shouldn't import `markitect.plugins.rendering`. --- #### Step 1.3: Move Engine Implementation **Create**: `src/testdrive_jsui/engine.py` Move from `/markitect/plugins/testdrive_jsui.py`: ```python """ TestDrive-JSUI Rendering Engine. Standalone JavaScript UI rendering engine for markdown content. Can be used independently or integrated into any Python application. """ from pathlib import Path from typing import Dict, List, Optional import json from .models import PluginMetadata, PluginType from .rendering import RenderingEnginePlugin, RenderingConfig class TestDriveJSUIEngine(RenderingEnginePlugin): """ TestDrive JavaScript UI rendering engine. Usage: >>> from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig >>> engine = TestDriveJSUIEngine() >>> config = RenderingConfig(development_mode=True) >>> html = engine.render_document("# Hello", "edit", config) """ def __init__(self): super().__init__() self._metadata = PluginMetadata( name="testdrive-jsui", version="1.0.0", description="Independent JavaScript UI engine for markdown", author="MarkiTect Team", plugin_type=PluginType.RENDERING ) # ... full implementation from markitect/plugins/testdrive_jsui.py ``` **Why**: Makes the engine part of the testdrive-jsui package, not MarkiTect. --- #### Step 1.4: Update Package __init__.py **Update**: `src/testdrive_jsui/__init__.py` ```python """ TestDrive-JSUI: Standalone JavaScript UI Rendering Engine and Testing Framework A self-contained capability providing: - Interactive JavaScript UI for markdown editing and viewing - Python-JavaScript test integration bridge - Standalone rendering engine for any Python project """ __version__ = "1.0.0" __author__ = "MarkiTect Team" # Core rendering engine from .engine import TestDriveJSUIEngine from .rendering import RenderingEnginePlugin, RenderingConfig from .models import PluginMetadata, PluginType # Testing infrastructure from .testing.js_test_runner import JavaScriptTestRunner, JSTestResult from .testing.integration import PythonJSBridge __all__ = [ # Engine "TestDriveJSUIEngine", "RenderingEnginePlugin", "RenderingConfig", # Models "PluginMetadata", "PluginType", # Testing "JavaScriptTestRunner", "JSTestResult", "PythonJSBridge", ] ``` **Why**: Clean, documented public API for standalone use. --- ### Step 1.5: Maintain MarkiTect Compatibility **Update**: `/markitect/plugins/testdrive_jsui.py` ```python """ TestDrive-JSUI Plugin Integration for MarkiTect. This is a thin compatibility wrapper that imports the standalone TestDrive-JSUI engine and integrates it with MarkiTect's plugin system. """ from pathlib import Path # Import from standalone package from testdrive_jsui import TestDriveJSUIEngine as StandaloneEngine from testdrive_jsui import RenderingConfig as StandaloneConfig # Re-export for MarkiTect compatibility TestDriveJSUIEngine = StandaloneEngine RenderingConfig = StandaloneConfig # MarkiTect-specific plugin system integration from .base import PluginMetadata, PluginType from .rendering import RenderingEnginePlugin as MarkitectRenderingPlugin # Adapter if needed for MarkiTect's plugin system class MarkitectTestDriveJSUIAdapter(MarkitectRenderingPlugin): """Adapter to integrate standalone engine with MarkiTect plugin system.""" def __init__(self): self._engine = StandaloneEngine() def __getattr__(self, name): # Delegate all calls to standalone engine return getattr(self._engine, name) ``` **Why**: Existing MarkiTect code continues to work without changes. --- ### Step 1.6: Update Dependencies **Update**: `pyproject.toml` ```toml [project] name = "testdrive-jsui" version = "1.0.0" description = "Standalone JavaScript UI rendering engine and testing framework" dependencies = [ # Minimal dependencies for standalone use "pathlib2>=2.3.0;python_version<'3.4'", ] [project.optional-dependencies] # Testing remains same testing = [ "pytest>=7.0.0", "pytest-xvfb>=3.0.0", "selenium>=4.0.0", ] # Development tools dev = [ "pytest-cov>=4.0.0", "black>=23.0.0", "flake8>=6.0.0", "mypy>=1.0.0", ] # MarkiTect integration (optional) markitect = [ # Only needed if using with MarkiTect plugin system ] ``` **Why**: Minimal dependencies for standalone use. --- ## Phase 2: Create Standalone Examples ### Objective Provide working examples showing standalone usage without MarkiTect. ### Implementation #### Create: `examples/standalone_basic.py` ```python """ Basic standalone usage of TestDrive-JSUI. This example shows how to use TestDrive-JSUI in any Python project without MarkiTect. """ from pathlib import Path from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig # Create engine instance engine = TestDriveJSUIEngine() # Configure for standalone use config = RenderingConfig( asset_base_url=".", # Serve from current directory development_mode=True, plugin_source_dirs={ 'testdrive-jsui': engine.get_plugin_source_dir() } ) # Markdown content to render markdown_content = """ # TestDrive-JSUI Standalone Demo This document demonstrates **TestDrive-JSUI** running standalone, without any MarkiTect dependencies. ## Features - Interactive markdown editing - Section management - Debug controls - Keyboard shortcuts Try editing this content in the browser! """ # Render to HTML html = engine.render_document( content=markdown_content, mode='edit', # or 'view' for read-only config=config ) # Save to file output_path = Path('output.html') output_path.write_text(html, encoding='utf-8') print(f"✅ Rendered to: {output_path.absolute()}") print(f"📂 Open in browser: file://{output_path.absolute()}") ``` --- #### Create: `examples/flask_integration.py` ```python """ Flask integration example. Shows how to integrate TestDrive-JSUI into a Flask web application. """ from flask import Flask, render_template_string from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig from pathlib import Path app = Flask(__name__) # Initialize engine once engine = TestDriveJSUIEngine() config = RenderingConfig( asset_base_url="/static", development_mode=False ) @app.route('/') def index(): """Render markdown with TestDrive-JSUI.""" markdown = """ # Flask + TestDrive-JSUI Edit this markdown content in your browser! """ html = engine.render_document(markdown, 'edit', config) return html @app.route('/view/') def view_document(document_id): """View a document in read-only mode.""" # Load markdown from database/file markdown = load_document(document_id) html = engine.render_document(markdown, 'view', config) return html if __name__ == '__main__': app.run(debug=True) ``` --- #### Create: `examples/django_integration.py` ```python """ Django integration example. Shows how to use TestDrive-JSUI in Django views. """ from django.http import HttpResponse from django.views import View from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig class MarkdownEditorView(View): """View for editing markdown with TestDrive-JSUI.""" def __init__(self): self.engine = TestDriveJSUIEngine() self.config = RenderingConfig( asset_base_url="/static", development_mode=False ) def get(self, request, document_id=None): """Render markdown editor.""" # Load markdown content markdown = self.load_markdown(document_id) # Render with TestDrive-JSUI html = self.engine.render_document( markdown, 'edit', self.config ) return HttpResponse(html) def post(self, request, document_id): """Save markdown content.""" markdown = request.POST.get('content') self.save_markdown(document_id, markdown) return HttpResponse(status=200) ``` --- #### Create: `examples/README.md` ```markdown # TestDrive-JSUI Examples ## Standalone Usage ### Basic Example ```bash python examples/standalone_basic.py ``` Opens `output.html` with an interactive markdown editor. ### Flask Integration ```bash pip install flask python examples/flask_integration.py ``` Visit http://localhost:5000 to see TestDrive-JSUI in Flask. ### Django Integration See `django_integration.py` for integration with Django views. ## Requirements All examples work with just: ```bash pip install testdrive-jsui ``` No MarkiTect required! ``` --- ## Phase 3: Update Documentation ### Update README.md **Section to Add**: "Standalone Installation" ```markdown ## Standalone Installation TestDrive-JSUI can be used completely independently: ```bash # Install from PyPI pip install testdrive-jsui # Or install from source pip install -e ./capabilities/testdrive-jsui ``` ## Quick Start (Standalone) ```python from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig engine = TestDriveJSUIEngine() config = RenderingConfig(development_mode=True) html = engine.render_document("# Hello World", "edit", config) ``` See `examples/` directory for Flask, Django, and other integrations. ``` --- ### Create: `docs/STANDALONE_GUIDE.md` Comprehensive guide covering: - Installation in non-MarkiTect projects - Configuration options - Asset deployment strategies - Framework integrations (Flask, Django, FastAPI) - Production deployment - Customization options --- ## Phase 4: Testing and Validation ### Create Standalone Tests **Create**: `tests/test_standalone.py` ```python """ Test standalone usage without MarkiTect dependencies. These tests verify the package works independently. """ import pytest from pathlib import Path def test_import_without_markitect(): """Verify imports work without MarkiTect.""" # Should not raise ImportError from testdrive_jsui import TestDriveJSUIEngine from testdrive_jsui import RenderingConfig from testdrive_jsui import JavaScriptTestRunner assert TestDriveJSUIEngine is not None assert RenderingConfig is not None assert JavaScriptTestRunner is not None def test_engine_initialization(): """Test engine can be initialized standalone.""" from testdrive_jsui import TestDriveJSUIEngine engine = TestDriveJSUIEngine() assert engine is not None assert engine.metadata.name == "testdrive-jsui" def test_render_document_standalone(): """Test document rendering works standalone.""" from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig engine = TestDriveJSUIEngine() config = RenderingConfig(development_mode=True) html = engine.render_document("# Test", "edit", config) assert html is not None assert "Test" in html assert "