Laravel Response::download() test
Asked Answered
M

4

15

I have the following code in one of my routes:

return Response::download('cv.pdf');

Any idea how to test this? I've tried to use shouldReceive() but that doesn't seem to work ('shouldReceive() undefined function....').

Millepore answered 13/1, 2014 at 12:19 Comment(2)
The Illuminate\Support\Facades\Response class doesn't actually extend Illuminate\Support\Facades\Facade so doesnt have the shouldRecieve() method. You need to test the response of this route after calling it in a test.Shellback
@DavidBarker I tested with laravel 8 and Response facade has shouldRecieve() nowWallacewallach
Z
3

EDIT: As pointed by @DavidBarker in his comment to the OP question

The Illuminate\Support\Facades\Response class doesn't actually extend Illuminate\Support\Facades\Facade so doesnt have the shouldRecieve() method. You need to test the response of this route after calling it in a test.


So if you want to test your download functionality, you can try checking the response for errors with:

$this->assertTrue(preg_match('/(error|notice)/i', $response) === false);
Zaragoza answered 13/1, 2014 at 13:3 Comment(0)
F
14

$response->assertDownload() was added in Laravel 8.45.0:

Assert that the response is a "download". Typically, this means the invoked route that returned the response returned a Response::download response, BinaryFileResponse, or Storage::download response:

$response->assertDownload();

Learn More:

https://laravel.com/docs/8.x/http-tests#assert-download

It does not currently (2023) allow one to test the contents of the file, but you can use test mocks for that:

    public function test_successful_download(): void
    {
        $this->authenticateAsAdmin();

        $this->instance(
            ResponseFactory::class,
            Mockery::mock(ResponseFactory::class, static function(MockInterface $mock) {
                $mock
                    ->shouldReceive('download')
                    ->with('[[ FILE CONTENTS ]]', '[[ FILE NAME]]')
                    ->once()
                ;
            }),
        );

        $this->call('POST', route('my-download-csv'));
    }
# mycontroller.php
// ...
    public function downloadCsv(Request $request)
    {
        return response()->download('[[ FILE CONTENTS ]]', '[[ FILE NAME]]');
    }
// ...
OK (1 test, 1 assertion)
Fortuneteller answered 6/6, 2021 at 14:52 Comment(4)
Thank you for this information, but is there a way to test the "contents" of the file and not just the response headers?Hakan
(in my case, the endpoint for the download is a dynamically generated and signed file based on input parameters)Hakan
If the "content" has a mime type of text/plain, there might be a way to test the content. But if the content has something like application/octet-stream then I don't think you can test that.Fortuneteller
Thanks. I realised what is actually happening (testing against the response object, not the output itself) and realised that what I was doing is stupid. If the content is dynamic it wouldn't be pulled from a static test file I was using, but it would be output in the content. So asserting against the content of the response I should be able to evaluate that the content is correct. Silly me, thank you.Hakan
Z
3

EDIT: As pointed by @DavidBarker in his comment to the OP question

The Illuminate\Support\Facades\Response class doesn't actually extend Illuminate\Support\Facades\Facade so doesnt have the shouldRecieve() method. You need to test the response of this route after calling it in a test.


So if you want to test your download functionality, you can try checking the response for errors with:

$this->assertTrue(preg_match('/(error|notice)/i', $response) === false);
Zaragoza answered 13/1, 2014 at 13:3 Comment(0)
P
2

You can assert that the status code is 200

$this->assertEquals($response->getStatusCode(), 200);

because sometimes you might have some data returned that match "error" or "notice" and that would be misleading.

I additionally assert that there's an attachment in the response headers:

$this->assertContains('attachment', (string)$response);
Preparation answered 15/2, 2016 at 11:17 Comment(2)
For those from 2020: $this->assertEquals('attachment; filename=cv.pdf', $response->headers->get('content-disposition'));Inflationary
For those from 2023: $response->assertHeader('content-disposition', 'attachment; filename=cv.pdf');Jefferey
L
1

You can use Mockery to mock the download method, for this you will need to mock ResponseFactory.

public function testDownloadCsv()
{
    $this->instance(
        ResponseFactory::class, Mockery::mock(ResponseFactory::class, function ($mock) {
        $mock->shouldReceive('download')
            ->once()
            ->andReturn(['header' => 'data']);
    }));

    $response = $this->get('/dowload-csv');

    $response->assertStatus(Response::HTTP_OK);
    $response->assertJson(['header' => 'data']); // Response
}
Leonoraleonore answered 4/9, 2019 at 18:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.