templateRenderer = Mockery::mock(TemplateRenderer::class); $this->fragmentRenderer = new FragmentRenderer($this->templateRenderer); }); afterEach(function () { Mockery::close(); }); it('renders single fragment from template', function () { $component = Mockery::mock(LiveComponent::class); $component->shouldReceive('getId')->andReturn(ComponentId::fromString('counter:demo')); $component->shouldReceive('getData')->andReturn(ComponentData::fromArray(['count' => 5])); $component->shouldReceive('getTemplateName')->andReturn('livecomponent-counter'); $fullHtml = <<
Count: 5
HTML; $this->templateRenderer ->shouldReceive('render') ->once() ->with('livecomponent-counter', ['count' => 5]) ->andReturn($fullHtml); $fragments = $this->fragmentRenderer->renderFragments( $component, ['counter-display'] ); expect($fragments->isEmpty())->toBeFalse(); expect($fragments->has('counter-display'))->toBeTrue(); $displayFragment = $fragments->get('counter-display'); expect($displayFragment)->toContain('Count: 5'); expect($displayFragment)->toContain('span'); }); it('renders multiple fragments from template', function () { $component = Mockery::mock(LiveComponent::class); $component->shouldReceive('getId')->andReturn(ComponentId::fromString('counter:demo')); $component->shouldReceive('getData')->andReturn(ComponentData::fromArray(['count' => 10])); $component->shouldReceive('getTemplateName')->andReturn('livecomponent-counter'); $fullHtml = <<
Count: 10
HTML; $this->templateRenderer ->shouldReceive('render') ->once() ->andReturn($fullHtml); $fragments = $this->fragmentRenderer->renderFragments( $component, ['counter-display', 'counter-controls'] ); expect($fragments->count())->toBe(2); expect($fragments->has('counter-display'))->toBeTrue(); expect($fragments->has('counter-controls'))->toBeTrue(); expect($fragments->get('counter-display'))->toContain('Count: 10'); expect($fragments->get('counter-controls'))->toContain('Increment'); expect($fragments->get('counter-controls'))->toContain('Decrement'); }); it('returns empty collection when fragments not found', function () { $component = Mockery::mock(LiveComponent::class); $component->shouldReceive('getId')->andReturn(ComponentId::fromString('counter:demo')); $component->shouldReceive('getData')->andReturn(ComponentData::fromArray([])); $component->shouldReceive('getTemplateName')->andReturn('livecomponent-counter'); $fullHtml = '
No fragments
'; $this->templateRenderer ->shouldReceive('render') ->once() ->andReturn($fullHtml); $fragments = $this->fragmentRenderer->renderFragments( $component, ['non-existent-fragment'] ); expect($fragments->isEmpty())->toBeTrue(); }); it('handles nested fragments correctly', function () { $component = Mockery::mock(LiveComponent::class); $component->shouldReceive('getId')->andReturn(ComponentId::fromString('form:demo')); $component->shouldReceive('getData')->andReturn(ComponentData::fromArray([])); $component->shouldReceive('getTemplateName')->andReturn('livecomponent-form'); $fullHtml = <<
Invalid email
HTML; $this->templateRenderer ->shouldReceive('render') ->once() ->andReturn($fullHtml); $fragments = $this->fragmentRenderer->renderFragments( $component, ['form-fields', 'form-errors'] ); expect($fragments->count())->toBe(2); expect($fragments->has('form-fields'))->toBeTrue(); expect($fragments->has('form-errors'))->toBeTrue(); // Nested fragment should still be extractable expect($fragments->get('form-errors'))->toContain('Invalid email'); }); it('preserves HTML structure in fragments', function () { $component = Mockery::mock(LiveComponent::class); $component->shouldReceive('getId')->andReturn(ComponentId::fromString('card:demo')); $component->shouldReceive('getData')->andReturn(ComponentData::fromArray(['title' => 'Test Card'])); $component->shouldReceive('getTemplateName')->andReturn('livecomponent-card'); $fullHtml = <<

Test Card

New

Card content

HTML; $this->templateRenderer ->shouldReceive('render') ->once() ->andReturn($fullHtml); $fragments = $this->fragmentRenderer->renderFragments( $component, ['card-header'] ); $header = $fragments->get('card-header'); // Should preserve attributes and nested structure expect($header)->toContain('class="card-header"'); expect($header)->toContain('

Test Card

'); expect($header)->toContain('class="badge"'); }); it('handles empty fragment list', function () { $component = Mockery::mock(LiveComponent::class); $component->shouldReceive('getId')->andReturn(ComponentId::fromString('test:demo')); $component->shouldReceive('getData')->andReturn(ComponentData::fromArray([])); $component->shouldReceive('getTemplateName')->andReturn('livecomponent-test'); // Should not call renderer if no fragments requested $this->templateRenderer->shouldNotReceive('render'); $fragments = $this->fragmentRenderer->renderFragments($component, []); expect($fragments->isEmpty())->toBeTrue(); }); });