guzzlehttp/test-server
Guzzle Test Server is a dev-only testing helper that starts a local Node.js HTTP server, letting PHP tests queue responses and inspect received requests for handler and integration tests.
guzzlehttp/test-server package is a specialized tool for HTTP client integration testing, making it a strong fit for Laravel applications where HTTP interactions (API clients, webhooks, or third-party service calls) require deterministic testing. It complements Laravel’s built-in testing tools (e.g., Http::fake()) by offering advanced mocking capabilities for complex scenarios like authentication, dynamic responses, streaming payloads, or multi-step workflows.Http::fake(), which is optimized for Laravel’s HTTP layer, this package provides real HTTP server behavior, including:
1.1.0 via Server::enqueueRawByteParts()), allowing tests to exercise chunked transfer encoding, Server-Sent Events (SSE), large file downloads, progressive delivery, and binary/raw bodies written in delayed parts — none of which are reliably reproducible through Http::fake() or static fixture responses.Symfony\Component\HttpFoundation\Response can be converted using GuzzleHttp\Psr7\Utils.enqueueRawByteParts() helper lets teams assert correct handling of chunked and partial responses against real HTTP semantics, which is difficult to replicate with Http::fake() since it returns a fully materialized response.Http::fake(): Simpler but limited to Laravel’s HTTP layer, and returns fully materialized bodies — unsuitable for streaming tests.| Risk | Severity | Mitigation Strategy |
|---|---|---|
| Node.js Dependency | High | Use Docker (e.g., node:22) or enforce Node.js version in CI/CD (.nvmrc). |
| Port Conflicts | Medium | Explicitly configure ports or use dynamic allocation (e.g., Server::start(['port' => 0])). |
| Cross-Platform Issues | Medium | Test on CI matrices (Linux/Windows/macOS); leverage Windows-specific fixes (e.g., 0.3.1). |
| Node.js Process Overhead | Low | Reuse server instances across tests (e.g., static singleton). |
| PSR-7 Response Complexity | Medium | Validate responses with assertEquals and use GuzzleHttp\Psr7\Utils for conversions. |
| Streaming/Byte-Part Semantics | Medium | enqueueRawByteParts() is newly introduced in 1.1.0; pin the version, add regression tests for chunk ordering, and verify client-side buffering/timeout behavior in CI rather than production-only. |
| Limited Adoption (0 Dependents) | Low | Fallback to Guzzle’s original test server or Laravel’s tools if issues arise. |
Http::fake() or Mockery are insufficient?enqueueRawByteParts() is a strong reason to adopt; if not, it is a low-impact addition.Server::enqueueRawByteParts().Http::fake() for complex scenarios while keeping simple cases in Laravel’s ecosystem.Http::fake(): When testing non-Laravel HTTP clients (e.g., Guzzle, custom PSR-7 clients), or when response streaming/latency semantics matter.// tests/Feature/PaymentServiceTest.php
use GuzzleHttp\Server\Server;
use GuzzleHttp\Psr7\Response;
beforeEach(function () {
Server::start();
register_shutdown_function([Server::class, 'stop']);
});
it('processes a payment successfully', function () {
Server::enqueue(new Response(200, [], json_encode(['id' => 'test_123'])));
$client = new GuzzleClient();
$response = $client->request('POST', Server::$url . '/payments', [
'json' => ['amount' => 100],
]);
expect($response->getStatusCode())->toBe(200);
});
Http::fake() for simple Laravel HTTP tests and the test server for external API interactions.enqueueRawByteParts() for one high-value consumer (e.g., SSE-based notifications) to validate client-side chunk handling:
Server::enqueueRawByteParts([
"data: {\"event\":\"start\"}\n\n",
"data: {\"event\":\"update\"}\n\n",
"data: {\"event\":\"done\"}\n\n",
]);
// For Laravel routes:
$this->get('/api/user')->assertOk();
// For external API calls (e.g., Stripe):
Server::enqueue(new Response(200, [], '{"status": "success"}'));
$stripeClient->createCharge(100);
| Component | Compatibility | Notes |
|---|---|---|
| PHP Version | Laravel’s supported PHP (8.1+) | No issues expected. |
| Node.js | `^20.19 | |
| PSR-7 Responses | Yes (Guzzle, Symfony, or Laravel responses via adapter) | Use GuzzleHttp\Psr7\Utils::response() for Laravel responses. |
| Guzzle/Symfony HTTP Client | Native support | Works out-of-the-box. |
| Laravel Testing Tools | Complementary (not replacement for all cases) | Use Http::fake() for Laravel routes; test server for external APIs and streaming. |
| Cross-Platform | Windows/Linux/macOS (with fixes for Windows) | Test on CI matrices to catch edge cases. |
| Streaming Helpers | Server::enqueueRawByteParts() (added in 1.1.0) |
Pin ^1.1 in composer.json; verify consumer clients correctly handle delayed chunks. |
20.19+ or 22.13+) and the PHP package (^1.1 to ensure enqueueRawByteParts() is available):
# Option 1: Local Node.js
npm install -g node@22
composer require guzzlehttp/test-server:^1.1
# Option 2: Docker (recommended for CI/CD)
FROM node:22
RUN composer require guzzlehttp/test-server:^1.1
TestCase or PestTestCase:
// tests/TestCase.php
use GuzzleHttp\Server\Server;
protected function setUp(): void {
Server::start(['port' => 0]);
register_shutdown_function([Server::class, 'stop']);
}
enqueueRawByteParts() to verify the target client processes delayed chunks correctly before broadening adoption.1.1.0, but the added streaming API reinforces the case for pinning Node and package versions in CI so that delayed-part semantics behave consistently.enqueueRawByteParts() is brand-new in 1.1.0, pin to ^1.1 in composer.json and add a smoke test to catch regressions if the internal streaming behavior changes in later releases.Http::fake() for non-streaming cases; the streaming feature is additive and does not force adoption.'port' => 0) to prevent conflicts under increased concurrency; enqueueRawByteParts() tests especially need isolation to avoid queue cross-talk.register_shutdown_function cleanup, and CI-level port health checks.enqueueRawByteParts() for teams unfamiliar with chunked transfer semantics.Http::fake().1.1.0 (or later) primarily for teams that need realistic streaming tests; for others, it is a low-risk incremental improvement that can ride along in the next test-infrastructure maintenance window.How can I help you explore Laravel packages today?