$value) { $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); $_SERVER[$key] = $value; } Router::$params = new Neuron(); HttpStubs::reset(); http_response_code(200); ob_start(); try { Router::apply(parse_url($path, PHP_URL_PATH) ?: $path); } finally { $body = (string) ob_get_clean(); } return new Response( http_response_code(), $body, HttpStubs::$headers, HttpStubs::$cookies ); } protected function get(string $path, array $headers = []): Response { return $this->dispatch('GET', $path, [], $headers); } protected function post(string $path, array $data = [], array $headers = []): Response { return $this->dispatch('POST', $path, $data, $headers); } protected function patch(string $path, array $data = [], array $headers = []): Response { return $this->dispatch('PATCH', $path, $data, $headers); } protected function delete(string $path, array $data = [], array $headers = []): Response { return $this->dispatch('DELETE', $path, $data, $headers); } protected function assertStatus(int $expected, Response $response): void { $this->assertSame( $expected, $response->status, "Expected status {$expected}, got {$response->status}. Body: {$response->body}" ); } protected function assertRedirect(string $expectedPath, Response $response): void { $target = $response->redirectTarget(); $this->assertNotNull($target, 'Expected a redirect header (HX-Redirect or Location).'); $this->assertStringEndsWith($expectedPath, $target); } protected function assertHtmxTrigger(string $event, Response $response): void { $this->assertSame($event, $response->trigger()); } }