Skip to content

pushinbr/pam-http-testing

pushinbr/pam-http-testing invokes a pushinbr/pam-http application pipeline without opening a network port.

Install and verify the PAM runtime first, create an HTTP application, and add the test helpers as a development dependency through PAM Composer:

Terminal window
curl -fsSL https://github.com/push-in/pam/releases/latest/download/install.sh | sh
pam doctor
pam init my-api --template http
cd my-api
pam composer require --dev pushinbr/pam-http-testing
use Pam\App;
use Pam\Http\Testing\TestClient;
$app = new App();
$app->get('/users/{id}', static fn ($request, $response) =>
$response->json(['id' => $request->route('id')])
);
$client = new TestClient($app);
$client->get('/users/42')
->assertSuccessful()
->assertJsonPath('id', '42');

Use get(), postJson(), or the general request method:

$response = $client->request(
method: 'PATCH',
target: '/users/42?notify=1',
headers: [
'authorization' => 'Bearer test-token',
'x-request-id' => 'request-1',
],
body: '{"name":"Ada"}',
);

The target must contain an absolute path. Query parameters are parsed into the PAM request, header names are normalized, and the application receives a fresh response.

$client->postJson('/users', [
'name' => 'Ada',
])->assertStatus(201);

postJson() serializes with JSON_THROW_ON_ERROR, preserves Unicode, and sets content-type: application/json.

$response
->assertStatus(200)
->assertSuccessful()
->assertHeader('content-type')
->assertHeader('x-runtime', 'pam')
->assertJson(['id' => '42'])
->assertJsonPath('profile.name', 'Ada');

assertJson() performs an exact array comparison. assertJsonPath() traverses dot-separated array keys and uses strict comparison.

  • route matching and parameters;
  • middleware order;
  • application error boundaries;
  • PAM request and response composition;
  • status, headers, body, chunks, and JSON assertions; and
  • provider boot and configuration freeze.

In-memory tests do not open a socket and therefore do not prove:

  • HTTP parser behavior;
  • TLS, HTTP/2, or HTTP/3;
  • native request limits;
  • transport streaming and backpressure;
  • timeouts and slow clients;
  • client disconnection cancellation;
  • worker supervision; or
  • WebSocket framing.

Use PAM’s Rust integration suite for the runtime boundary.

Type Public surface
TestClient Constructor accepts ApplicationInterface; request(), get(), postJson() return TestResponse
TestResponse Readonly status, normalized headers, body, and streamed chunks; header(), json() and fluent assertions

request() accepts method, target, headers and string body. header() joins multiple values with , and can return a supplied default. json() uses JSON_THROW_ON_ERROR; invalid JSON raises JsonException. All assertions throw RuntimeException on failure and return the same response on success.