container = new DefaultContainer(); }); it('executes middleware in priority order', function () { $executionOrder = []; // Register middleware in container $this->container->instance(TestMiddleware1::class, new TestMiddleware1($executionOrder)); $this->container->instance(TestMiddleware2::class, new TestMiddleware2($executionOrder)); // Create pipeline with middleware (higher priority first) $middlewares = [ new MiddlewareRegistration(TestMiddleware1::class, priority: 200), new MiddlewareRegistration(TestMiddleware2::class, priority: 100), ]; $pipeline = new ComponentMiddlewarePipeline($middlewares, $this->container); // Create test component $component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract { public function __construct(public ComponentId $id, public ComponentState $state) {} public function getRenderData() { return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []); } }; // Execute pipeline $result = $pipeline->process( $component, 'testAction', ActionParameters::fromArray([]), fn($c, $a, $p) => new ComponentUpdate( component: $c, state: LiveComponentState::fromArray([]), events: [] ) ); // Middleware should execute in priority order (higher first) expect($executionOrder)->toBe(['middleware1', 'middleware2']); }); it('passes component, action, and params through middleware chain', function () { $receivedComponent = null; $receivedAction = null; $receivedParams = null; $middleware = new TestCaptureMiddleware($receivedComponent, $receivedAction, $receivedParams); $this->container->instance(TestCaptureMiddleware::class, $middleware); $middlewares = [ new MiddlewareRegistration(TestCaptureMiddleware::class, priority: 100), ]; $pipeline = new ComponentMiddlewarePipeline($middlewares, $this->container); $component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract { public function __construct(public ComponentId $id, public ComponentState $state) {} public function getRenderData() { return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []); } }; $params = ActionParameters::fromArray(['test' => 'value']); $pipeline->process( $component, 'testAction', $params, fn($c, $a, $p) => new ComponentUpdate( component: $c, state: LiveComponentState::fromArray([]), events: [] ) ); expect($receivedComponent)->toBe($component); expect($receivedAction)->toBe('testAction'); expect($receivedParams)->toBe($params); }); it('returns action handler result', function () { $expectedResult = new ComponentUpdate( component: new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract { public function __construct(public ComponentId $id, public ComponentState $state) {} public function getRenderData() { return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []); } }, state: LiveComponentState::fromArray(['result' => 'success']), events: [] ); $middleware = new TestPassThroughMiddleware(); $this->container->instance(TestPassThroughMiddleware::class, $middleware); $middlewares = [ new MiddlewareRegistration(TestPassThroughMiddleware::class, priority: 100), ]; $pipeline = new ComponentMiddlewarePipeline($middlewares, $this->container); $component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract { public function __construct(public ComponentId $id, public ComponentState $state) {} public function getRenderData() { return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []); } }; $result = $pipeline->process( $component, 'testAction', ActionParameters::fromArray([]), fn($c, $a, $p) => $expectedResult ); expect($result)->toBe($expectedResult); }); it('handles empty middleware array', function () { $pipeline = new ComponentMiddlewarePipeline([], $this->container); $component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract { public function __construct(public ComponentId $id, public ComponentState $state) {} public function getRenderData() { return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []); } }; $expectedResult = new ComponentUpdate( component: $component, state: LiveComponentState::fromArray([]), events: [] ); $result = $pipeline->process( $component, 'testAction', ActionParameters::fromArray([]), fn($c, $a, $p) => $expectedResult ); expect($result)->toBe($expectedResult); }); });