Files
michaelschiemer/tests/Framework/Http/Middlewares/RemovePoweredByMiddlewareTest.php
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

178 lines
5.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Http\Headers;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\HttpResponse;
use App\Framework\Http\Method;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\Middlewares\RemovePoweredByMiddleware;
use App\Framework\Http\Next;
use App\Framework\Http\RequestStateManager;
use App\Framework\Http\ResponseManipulator;
use App\Framework\Http\Status;
beforeEach(function () {
$this->responseManipulator = new ResponseManipulator();
$this->middleware = new RemovePoweredByMiddleware($this->responseManipulator);
// Create a test request
$this->request = new HttpRequest(
method: Method::GET,
path: '/test'
);
$this->stateManager = new RequestStateManager(new WeakMap(), $this->request);
$this->context = new MiddlewareContext($this->request);
});
it('removes X-Powered-By header from response', function () {
// Create response with X-Powered-By header
$headers = new Headers([
'Content-Type' => 'text/html',
'X-Powered-By' => 'PHP/8.2.0',
]);
$response = new HttpResponse(Status::OK, $headers, 'test content');
// Create next handler that returns context with response
$next = new class ($response) implements Next {
public function __construct(private HttpResponse $response)
{
}
public function __invoke(MiddlewareContext $context): MiddlewareContext
{
return $context->withResponse($this->response);
}
};
$result = $this->middleware->__invoke(
$this->context,
$next,
$this->stateManager
);
expect($result->hasResponse())->toBeTrue();
expect($result->response->headers->has('X-Powered-By'))->toBeFalse();
expect($result->response->headers->has('Content-Type'))->toBeTrue();
expect($result->response->headers->getFirst('Content-Type'))->toBe('text/html');
});
it('leaves response unchanged when no X-Powered-By header', function () {
// Create response without X-Powered-By header
$headers = new Headers([
'Content-Type' => 'application/json',
]);
$response = new HttpResponse(Status::OK, $headers, '{"test": true}');
$next = new class ($response) implements Next {
public function __construct(private HttpResponse $response)
{
}
public function __invoke(MiddlewareContext $context): MiddlewareContext
{
return $context->withResponse($this->response);
}
};
$result = $this->middleware->__invoke(
$this->context,
$next,
$this->stateManager
);
expect($result->hasResponse())->toBeTrue();
expect($result->response->headers->has('X-Powered-By'))->toBeFalse();
expect($result->response->headers->has('Content-Type'))->toBeTrue();
expect($result->response->headers->getFirst('Content-Type'))->toBe('application/json');
});
it('passes through context when no response present', function () {
// Next handler that doesn't set a response
$next = new class () implements Next {
public function __invoke(MiddlewareContext $context): MiddlewareContext
{
return $context;
}
};
$result = $this->middleware->__invoke(
$this->context,
$next,
$this->stateManager
);
expect($result->hasResponse())->toBeFalse();
});
it('removes multiple X-Powered-By headers', function () {
// Create response with multiple headers including X-Powered-By
$headers = new Headers([
'Content-Type' => 'text/html',
'X-Powered-By' => 'PHP/8.2.0',
'Cache-Control' => 'no-cache',
'Server' => 'nginx',
]);
$response = new HttpResponse(Status::OK, $headers, 'test content');
$next = new class ($response) implements Next {
public function __construct(private HttpResponse $response)
{
}
public function __invoke(MiddlewareContext $context): MiddlewareContext
{
return $context->withResponse($this->response);
}
};
$result = $this->middleware->__invoke(
$this->context,
$next,
$this->stateManager
);
expect($result->hasResponse())->toBeTrue();
expect($result->response->headers->has('X-Powered-By'))->toBeFalse();
expect($result->response->headers->has('Content-Type'))->toBeTrue();
expect($result->response->headers->has('Cache-Control'))->toBeTrue();
expect($result->response->headers->has('Server'))->toBeTrue();
});
it('preserves response body and status', function () {
$headers = new Headers([
'Content-Type' => 'application/json',
'X-Powered-By' => 'Custom-Server/1.0',
]);
$response = new HttpResponse(Status::CREATED, $headers, '{"created": true}');
$next = new class ($response) implements Next {
public function __construct(private HttpResponse $response)
{
}
public function __invoke(MiddlewareContext $context): MiddlewareContext
{
return $context->withResponse($this->response);
}
};
$result = $this->middleware->__invoke(
$this->context,
$next,
$this->stateManager
);
expect($result->hasResponse())->toBeTrue();
expect($result->response->status)->toBe(Status::CREATED);
expect($result->response->body)->toBe('{"created": true}');
expect($result->response->headers->has('X-Powered-By'))->toBeFalse();
expect($result->response->headers->getFirst('Content-Type'))->toBe('application/json');
});