attributeRegistry = new AttributeRegistry(); $this->discoveryRegistry = new DiscoveryRegistry( attributes: $this->attributeRegistry, interfaces: new InterfaceRegistry([]), templates: new TemplateRegistry([]) ); $this->collector = new MiddlewareCollector($this->discoveryRegistry); }); it('collects component-level middleware', function () { $componentClass = ClassName::create('Test\\Component'); // Add component-level middleware attribute $discovered = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_CLASS, arguments: [LoggingMiddleware::class, 100] ); $this->attributeRegistry->add(MiddlewareAttribute::class, $discovered); $middlewares = $this->collector->collectForAction( $componentClass, MethodName::create('testAction') ); expect($middlewares)->toHaveCount(1); expect($middlewares[0]->middlewareClass)->toBe(LoggingMiddleware::class); expect($middlewares[0]->priority)->toBe(100); }); it('collects action-level middleware', function () { $componentClass = ClassName::create('Test\\Component'); $actionMethod = MethodName::create('testAction'); // Add action-level middleware attribute $discovered = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_METHOD, methodName: $actionMethod, arguments: [LoggingMiddleware::class, 200] ); $this->attributeRegistry->add(MiddlewareAttribute::class, $discovered); $middlewares = $this->collector->collectForAction( $componentClass, $actionMethod ); expect($middlewares)->toHaveCount(1); expect($middlewares[0]->middlewareClass)->toBe(LoggingMiddleware::class); expect($middlewares[0]->priority)->toBe(200); }); it('combines component and action-level middleware', function () { $componentClass = ClassName::create('Test\\Component'); $actionMethod = MethodName::create('testAction'); // Add component-level middleware $componentMiddleware = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_CLASS, arguments: [LoggingMiddleware::class, 100] ); // Add action-level middleware $actionMiddleware = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_METHOD, methodName: $actionMethod, arguments: [\App\Framework\LiveComponents\Middleware\CachingMiddleware::class, 200] ); $this->attributeRegistry->add(MiddlewareAttribute::class, $componentMiddleware); $this->attributeRegistry->add(MiddlewareAttribute::class, $actionMiddleware); $middlewares = $this->collector->collectForAction( $componentClass, $actionMethod ); expect($middlewares)->toHaveCount(2); // Should be sorted by priority (higher first) expect($middlewares[0]->priority)->toBe(200); expect($middlewares[1]->priority)->toBe(100); }); it('sorts middleware by priority descending', function () { $componentClass = ClassName::create('Test\\Component'); // Add multiple middleware with different priorities $middleware1 = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_CLASS, arguments: [LoggingMiddleware::class, 50] ); $middleware2 = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_CLASS, arguments: [\App\Framework\LiveComponents\Middleware\CachingMiddleware::class, 150] ); $middleware3 = new DiscoveredAttribute( className: $componentClass, attributeClass: MiddlewareAttribute::class, target: AttributeTarget::TARGET_CLASS, arguments: [\App\Framework\LiveComponents\Middleware\RateLimitMiddleware::class, 100] ); $this->attributeRegistry->add(MiddlewareAttribute::class, $middleware1); $this->attributeRegistry->add(MiddlewareAttribute::class, $middleware2); $this->attributeRegistry->add(MiddlewareAttribute::class, $middleware3); $middlewares = $this->collector->collectForAction( $componentClass, MethodName::create('testAction') ); expect($middlewares)->toHaveCount(3); // Should be sorted by priority descending expect($middlewares[0]->priority)->toBe(150); expect($middlewares[1]->priority)->toBe(100); expect($middlewares[2]->priority)->toBe(50); }); it('returns empty array when no middleware found', function () { $componentClass = ClassName::create('Test\\Component'); $middlewares = $this->collector->collectForAction( $componentClass, MethodName::create('testAction') ); expect($middlewares)->toBeEmpty(); }); });