harness = new LiveComponentTestHarness(); }); it('renders Island component via endpoint', function () { $componentId = ComponentId::create('island-test', 'demo'); $response = $this->harness->get("/live-component/{$componentId->toString()}/island"); expect($response->status())->toBe(200); $data = $response->json(); expect($data['success'])->toBeTrue(); expect($data)->toHaveKey('html'); expect($data)->toHaveKey('state'); expect($data)->toHaveKey('csrf_token'); expect($data['component_id'])->toBe($componentId->toString()); }); it('renders Island component without template wrapper', function () { $componentId = ComponentId::create('island-test', 'demo'); $response = $this->harness->get("/live-component/{$componentId->toString()}/island"); $data = $response->json(); $html = $data['html']; // Island HTML should not contain layout/meta wrappers // It should only contain the component HTML itself expect($html)->not->toContain(''); expect($html)->not->toContain(''); expect($html)->not->toContain(''); // Should contain component-specific HTML expect($html)->toContain('data-component-id'); }); it('generates lazy Island placeholder in XComponentProcessor', function () { // This test would require template rendering, which is complex // For now, we verify the endpoint works correctly $componentId = ComponentId::create('lazy-island-test', 'demo'); $response = $this->harness->get("/live-component/{$componentId->toString()}/island"); expect($response->status())->toBe(200); expect($response->json()['success'])->toBeTrue(); }); it('handles non-existent Island component gracefully', function () { $response = $this->harness->get('/live-component/nonexistent:test/island'); expect($response->status())->toBe(500); $data = $response->json(); expect($data['success'])->toBeFalse(); expect($data)->toHaveKey('error'); }); it('returns CSRF token for Island component', function () { $componentId = ComponentId::create('island-test', 'demo'); $response = $this->harness->get("/live-component/{$componentId->toString()}/island"); $data = $response->json(); expect($data['csrf_token'])->not->toBeEmpty(); expect($data['csrf_token'])->toBeString(); }); it('returns component state for Island component', function () { $componentId = ComponentId::create('island-test', 'demo'); $response = $this->harness->get("/live-component/{$componentId->toString()}/island"); $data = $response->json(); expect($data['state'])->toBeArray(); expect($data['state'])->not->toBeEmpty(); }); }); // Test Island component #[LiveComponent('island-test')] #[Island] final readonly class IslandTestComponent implements LiveComponentContract { public function __construct( public ComponentId $id, public ComponentState $state ) { } public function getRenderData(): ComponentRenderData { return new ComponentRenderData( templatePath: 'livecomponent-counter', // Reuse counter template for testing data: [ 'componentId' => $this->id->toString(), 'stateJson' => json_encode($this->state->toArray()), ] ); } } #[LiveComponent('lazy-island-test')] #[Island(isolated: true, lazy: true, placeholder: 'Loading component...')] final readonly class LazyIslandTestComponent implements LiveComponentContract { public function __construct( public ComponentId $id, public ComponentState $state ) { } public function getRenderData(): ComponentRenderData { return new ComponentRenderData( templatePath: 'livecomponent-counter', data: [ 'componentId' => $this->id->toString(), 'stateJson' => json_encode($this->state->toArray()), ] ); } }