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

RomainB's avatar
Level 13

withoutExceptionHandling stil throw exception with Http facade

Hi!

I already used withoutExceptionHandling for a dozen of tests before but never combined with the Http::stubUrl feature and I'm struggling into this:

I want to test that if a user upload some images to our server and the API we are using is not available, the directory where the uploaded files are stored is removed from our server:

$fakedStorage = Storage::fake('s3');

Http::stubUrl(
    'https://external-api.com/endpoint',
    Http::response('An error occurred', 500)
);

$image1 = UploadedFile::fake()->image('image1.jpg');
$image2 = UploadedFile::fake()->image('image2.jpg');

$initialDirectoriesCount = $fakedStorage->directories('prompts');
$this
    ->withoutExceptionHandling()
    ->actingAs(User::factory()->create())
    ->postJson(
        route('prompt.store-prompt'),
        ['images' => [$image1, $image2]]
    );

expect($fakedStorage->directories('prompts'))->toBe($initialDirectoriesCount);

But this tests continues to fail on the Error 500 Exception:

Illuminate\Http\Client\RequestException: HTTP request returned status code 500:
An error occurred

What am I missing?

0 likes
2 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

The issue you're encountering is due to the fact that the withoutExceptionHandling method in Laravel is designed to disable exception handling for HTTP requests made to your application, not for HTTP client requests made using the Http facade. When you stub an HTTP request using Http::stubUrl, it simulates an external request, and exceptions thrown by these requests are not affected by withoutExceptionHandling.

To handle this situation, you can catch the exception thrown by the HTTP client request and handle it within your test. Here's how you can modify your test to achieve this:

use Illuminate\Http\Client\RequestException;

$fakedStorage = Storage::fake(config()->string('chat3d.storage.disk'));

Http::stubUrl(
    'https://external-api.com/endpoint',
    Http::response('An error occurred', 500)
);

$image1 = UploadedFile::fake()->image('image1.jpg');
$image2 = UploadedFile::fake()->image('image2.jpg');

$initialDirectoriesCount = $fakedStorage->directories('prompts');

try {
    $this
        ->withoutExceptionHandling()
        ->actingAs(User::factory()->create())
        ->postJson(
            route('prompt.store-prompt'),
            ['images' => [$image1, $image2]]
        );
} catch (RequestException $e) {
    // Handle the exception if needed, or just let it pass
    // This is where you can assert that the exception is what you expect
}

expect($fakedStorage->directories('prompts'))->toBe($initialDirectoriesCount);

In this modified test, we wrap the postJson call in a try-catch block to catch the RequestException that is thrown when the HTTP client request fails. This allows the test to continue executing and reach the assertion that checks the directory count. You can also add assertions within the catch block to verify that the exception is what you expect, if necessary.

Tray2's avatar

->withoutExceptionHandling() doesn't prevent them from being thrown, it prevents the Laravel exception handling from "hiding" the actual error. It should only be used to debug your tests and the code inplemented. Once the test passes, it should be removed.

Please or to participate in this conversation.