""" Test suite for the new clean architecture implementation Tests the JSON configuration interface and separation of concerns """ import pytest import tempfile import json from pathlib import Path from markitect.clean_document_manager import CleanDocumentManager class TestCleanArchitecture: """Test suite for clean JavaScript-Python separation""" def setup_method(self): """Setup for each test""" self.manager = CleanDocumentManager() def test_clean_edit_mode_json_configuration(self): """Test that edit mode uses clean JSON configuration interface""" test_markdown = '''# Test Document ## Section with Problematic Content ```python script = f""" function test() { console.log("Hello {name}"); } """ ``` This content has quotes that previously broke JavaScript generation. ''' with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as md_file: md_file.write(test_markdown) md_file.flush() with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as html_file: result = self.manager.render_file( input_file=md_file.name, output_file=html_file.name, edit_mode=True ) assert result['success'] is True # Read generated HTML html_content = Path(html_file.name).read_text() # Test 1: Check for clean template usage assert 'markitect-config' in html_content assert 'type="application/json"' in html_content # Test 2: Extract and validate JSON configuration config_json = self.extract_config_json(html_content) assert config_json is not None, "Configuration JSON not found" config = json.loads(config_json) # Test 3: Validate configuration structure required_fields = ['markdownContent', 'mode', 'theme', 'originalFilename'] for field in required_fields: assert field in config, f"Required field '{field}' missing from configuration" # Test 4: Check that problematic content is properly escaped assert 'script = f"""' in config['markdownContent'] # Should be in JSON assert '"""' not in html_content.split('markitect-config')[1].split('')[0], "Unescaped quotes in HTML" def test_clean_architecture_no_python_js_mixing(self): """Test that no Python code generates JavaScript strings""" test_markdown = "# Simple Test\n\nBasic content." with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as md_file: md_file.write(test_markdown) md_file.flush() with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as html_file: result = self.manager.render_file( input_file=md_file.name, output_file=html_file.name, edit_mode=True ) assert result['success'] is True html_content = Path(html_file.name).read_text() # Test 1: No direct JavaScript variable assignments from Python problematic_patterns = [ 'const markdownContent = "', # Old way 'const markdownContentWithDogtag = "', # Old way 'var markdownContent = "', 'let markdownContent = "' ] for pattern in problematic_patterns: assert pattern not in html_content, f"Found problematic pattern: {pattern}" # Test 2: Configuration should be in JSON script tag only config_sections = html_content.count('markitect-config') assert config_sections >= 2, f"Expected at least 2 config references (opening and closing), found {config_sections}" # Test 3: JavaScript files should be embedded inline (no external src attributes) js_components = [ 'config-loader', 'section-manager', 'dom-renderer' ] for component in js_components: # Check that the component JavaScript is embedded, not referenced externally assert f'src="js/' not in html_content, "Found external JavaScript references - should be embedded" # Check that components are embedded inline assert '{js_config_loader}' not in html_content, "Template placeholder not replaced" assert 'class MarkitectConfig' in html_content, "Config loader not embedded" assert 'class SectionManager' in html_content, "Section manager not embedded" def test_configuration_interface_completeness(self): """Test that all required data is passed through the configuration interface""" test_markdown = "# Config Test\n\nTesting configuration completeness." with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as md_file: md_file.write(test_markdown) md_file.flush() with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as html_file: result = self.manager.render_file( input_file=md_file.name, output_file=html_file.name, edit_mode=True, editor_theme='dark', keyboard_shortcuts=False ) assert result['success'] is True html_content = Path(html_file.name).read_text() config_json = self.extract_config_json(html_content) config = json.loads(config_json) # Test configuration completeness expected_config = { 'markdownContent': test_markdown, 'mode': 'edit', 'theme': 'dark', 'keyboardShortcuts': False, 'autosave': False, 'sections': True, 'base64References': {} } for key, expected_value in expected_config.items(): assert key in config, f"Configuration missing key: {key}" if key == 'markdownContent': assert config[key] == expected_value, f"Configuration {key} value mismatch" def test_insert_mode_configuration(self): """Test insert mode specific configuration""" test_markdown = "# Insert Mode Test" with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as md_file: md_file.write(test_markdown) md_file.flush() with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as html_file: result = self.manager.render_file( input_file=md_file.name, output_file=html_file.name, insert_mode=True ) assert result['success'] is True html_content = Path(html_file.name).read_text() # Check body class assert 'class="markitect-insert-mode"' in html_content # Check configuration config_json = self.extract_config_json(html_content) config = json.loads(config_json) assert config['mode'] == 'insert' assert 'restrictedHeadingLevels' in config assert config['restrictedHeadingLevels'] == [1, 2, 3] def test_static_vs_edit_mode_separation(self): """Test that static mode and edit mode use different templates""" test_markdown = "# Mode Test\n\nTesting template separation." # Test static mode with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as md_file: md_file.write(test_markdown) md_file.flush() with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as static_file: static_result = self.manager.render_file( input_file=md_file.name, output_file=static_file.name, edit_mode=False ) static_content = Path(static_file.name).read_text() # Static mode should NOT have configuration interface assert 'markitect-config' not in static_content assert 'application/json' not in static_content # Test edit mode with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as edit_file: edit_result = self.manager.render_file( input_file=md_file.name, output_file=edit_file.name, edit_mode=True ) edit_content = Path(edit_file.name).read_text() # Edit mode should HAVE configuration interface assert 'markitect-config' in edit_content assert 'application/json' in edit_content # Helper methods def extract_config_json(self, html_content): """Extract JSON configuration from HTML""" try: # Find the config script tag start_marker = 'id="markitect-config" type="application/json">' end_marker = '' start_pos = html_content.find(start_marker) if start_pos == -1: return None start_pos += len(start_marker) end_pos = html_content.find(end_marker, start_pos) if end_pos == -1: return None config_json = html_content[start_pos:end_pos].strip() return config_json except Exception as e: print(f"Failed to extract config JSON: {e}") return None