Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

DanielSetreus's avatar

Laravel HTTP fake ConnectException

I'm trying wi write a test for a scenario where in a pool of requests, one specific URL fails with a ConnectException (meaning that there was no response at all, in fact, the request could not be made).

In the code we deal with this like so:

$responses = Http::pool(function (Pool $pool) use ($user) {
    $pool->as('first')->timeout(5)
        ->get('http://non-existing-third-party.com/endpoint', [
            'foo' => 'bar',
        ]);

    $pool->as('second')->timeout(5)
        ->get('http://third-party.com/second-endpoint', [
            'foo' => 'bar2OrWhatever',
        ]);
});

foreach ($responses as $response) {
	if ($response instanceof TransferException) {
		// Throw another exception that we can expect in tests.
	}
	if ($response->failed()) {
		// Response code => 400
	}
	// handle success of that request
}

What I'm searching for is how to test the ConnectException/TransferException scenario here?

Tryied so far with

Http::fake([
            'http://non-existing-third-party.com/endpoint'=> fn () => new ConnectException('Connection error', $request),
            'http://third-party.com/second-endpoint'=> Http::response(...),
        ]);

But that just gives me an error

"Call to undefined method GuzzleHttp\Exception\ConnectException::then()" at /home/vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:916

Is there a way to fake a request exception in the HTTP facade?

0 likes
6 replies
splatEric's avatar
Level 2

I think the reason this is happening is because you actually need to be returning a rejecting promise rather than simply throwing the exception. This is a bit of speculation from digging into the Http code, but you could try something like:

use GuzzleHttp\Promise\RejectedPromise;

Http::fake([
            'http://third-party.com/endpoint'=> fn ($request) => new RejectedPromise(new ConnectException('Connection error', $request)),
            'http://third-party.com/second-endpoint'=> Http::response(...),
        ]);

ref: https://github.com/guzzle/promises#rejectedpromise

5 likes
DanielSetreus's avatar

@splatEric Thank you!

It help me alot in figuring this out. Following works:

$url = 'http://non-existing-third-party.com/endpoint';
$guzzleRequest = new Psr7Request('get', $url);
Http::fake([
    $url => fn (Request $request) => new RejectedPromise(new ConnectException('Connection error', $guzzleRequest)),
    'http://third-party.com/second-endpoint' => Http::response(...),
        ]);

The callback gets a Illuminate\Http\Client\Request - but the ConnectException expects a Psr\Http\Message\RequestInterface. So a separate request instance must be created to populate the exception itself.

Also, note that the RejectedPromise is of type GuzzleHttp\Promise\RejectedPromise.

5 likes
mangrovestudios's avatar

@DanielSetreus Thanks for posting this incredibly helpful question and answer.

I found an other way to construct the ConnectException, overcoming the request instance having to be created with a new Psr7Request :

Http::fake([
    '*' => fn($request) => new RejectedPromise(
        new ConnectException('Foo', $request->toPsrRequest())
    )
]);

The toPsrRequest() function exposed the underlying Guzzle request, which in my case was needed as I had custom headers attached.

3 likes
da_Mask's avatar

I'll probably get roasted for commenting on an old post, esp. as I'm not answering the OP's exact question, but I came here from a search, and this might help other googlers.

Recently added to Laravel is the failedConnection() function, so you can :

Http::fake([ '*' => Http::failedConnection()]);

It might be what you need.

1 like
bkuhl's avatar

I must be missing something, because failedConnection doesn't exist in my project at all, I'm on v11 of laravel.

Please or to participate in this conversation.