shouldReceive('getId') ->andReturn(ComponentId::create('counter', 'test')); $mockComponent->shouldReceive('getData') ->andReturn(ComponentData::fromArray(['value' => 10])); $mockComponent->shouldReceive('getRenderData') ->andReturn(new ComponentRenderData('counter-template', ['value' => 10])); // Mock LiveComponent Registry $liveComponentRegistry = Mockery::mock(ComponentRegistryInterface::class); $liveComponentRegistry->shouldReceive('isRegistered') ->with('counter') ->andReturn(true); $liveComponentRegistry->shouldReceive('getClassName') ->with('counter') ->andReturn('TestCounterComponent'); $liveComponentRegistry->shouldReceive('resolve') ->andReturn($mockComponent); $liveComponentRegistry->shouldReceive('renderWithWrapper') ->with($mockComponent) ->andReturn('
Counter: 10
'); $liveComponentRegistry->shouldReceive('getAllComponentNames') ->andReturn(['counter']); // Mock HTML Component Registry $htmlComponentRegistry = Mockery::mock(HtmlComponentRegistryInterface::class); $htmlComponentRegistry->shouldReceive('has') ->andReturn(false); $htmlComponentRegistry->shouldReceive('getAllComponentNames') ->andReturn([]); // Mock Metadata Cache $mockMetadata = new CompiledComponentMetadata( className: 'TestCounterComponent', componentName: 'counter', properties: [ 'value' => new ComponentPropertyMetadata( name: 'value', type: 'int', isPublic: true, isReadonly: false ) ], actions: [], constructorParams: [] ); $metadataCache = Mockery::mock(ComponentMetadataCacheInterface::class); $metadataCache->shouldReceive('get') ->with('TestCounterComponent') ->andReturn($mockMetadata); // Create Container and register dependencies $container = new DefaultContainer(); $container->singleton(ComponentRegistryInterface::class, $liveComponentRegistry); $container->singleton(HtmlComponentRegistryInterface::class, $htmlComponentRegistry); $container->singleton(ComponentMetadataCacheInterface::class, $metadataCache); // Register processors (with dependencies) $componentRegistry = Mockery::mock(\App\Framework\LiveComponents\ComponentRegistry::class); $placeholderReplacer = new PlaceholderReplacer($container, $componentRegistry); $forStringProcessor = new ForStringProcessor(); $container->singleton(PlaceholderReplacer::class, $placeholderReplacer); $container->singleton(ForStringProcessor::class, $forStringProcessor); // XComponentTransformer wird automatisch vom Container resolved // (benötigt HtmlParser, der wird automatisch erstellt) // Create TemplateProcessor with AST transformers $templateProcessor = new TemplateProcessor( astTransformers: [XComponentTransformer::class], stringProcessors: [ ForStringProcessor::class, PlaceholderReplacer::class, ], container: $container ); // Test HTML with placeholders and x-component $html = << {title}

{greeting}

Welcome {username}!

HTML; echo "Input HTML:\n$html\n\n"; // Create RenderContext with data $context = new RenderContext( template: 'test-page', metaData: new MetaData('Test Page'), data: [ 'title' => 'Test Page Title', 'greeting' => 'Hello World', 'username' => 'John Doe' ], processingMode: ProcessingMode::FULL ); // Render through TemplateProcessor try { $output = $templateProcessor->render($context, $html); echo "Output HTML:\n$output\n\n"; // Verify results $checks = [ 'title replacement' => str_contains($output, 'Test Page Title'), 'greeting replacement' => str_contains($output, '

Hello World

'), 'username replacement' => str_contains($output, 'Welcome John Doe!'), 'component rendering' => str_contains($output, 'data-component-id="counter:test"'), 'component content' => str_contains($output, 'Counter: 10'), 'footer preserved' => str_contains($output, '© 2024') ]; echo "Verification:\n"; foreach ($checks as $check => $passed) { echo ($passed ? '✓' : '✗') . " $check\n"; } $allPassed = array_reduce($checks, fn($carry, $item) => $carry && $item, true); echo "\n" . ($allPassed ? '✅ ALL TESTS PASSED!' : '❌ SOME TESTS FAILED') . "\n"; } catch (\Throwable $e) { echo "❌ ERROR: {$e->getMessage()}\n"; echo "Stack trace:\n{$e->getTraceAsString()}\n"; exit(1); }