Files
michaelschiemer/tests/Unit/Framework/LiveComponents/Middleware/ComponentMiddlewarePipelineTest.php
2025-11-24 21:28:25 +01:00

173 lines
6.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\LiveComponents\Middleware;
use App\Framework\DI\Container;
use App\Framework\DI\DefaultContainer;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\Middleware\ComponentMiddlewarePipeline;
use App\Framework\LiveComponents\Middleware\MiddlewareRegistration;
use App\Framework\LiveComponents\ValueObjects\ActionParameters;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentState;
use App\Framework\LiveComponents\ValueObjects\ComponentUpdate;
use App\Framework\LiveComponents\ValueObjects\LiveComponentState;
use Tests\Unit\Framework\LiveComponents\Middleware\TestMiddleware1;
use Tests\Unit\Framework\LiveComponents\Middleware\TestMiddleware2;
use Tests\Unit\Framework\LiveComponents\Middleware\TestPassThroughMiddleware;
use Tests\Unit\Framework\LiveComponents\Middleware\TestCaptureMiddleware;
// Ensure test middleware classes are loaded
require_once __DIR__ . '/TestMiddleware.php';
describe('ComponentMiddlewarePipeline', function () {
beforeEach(function () {
$this->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);
});
});