DEV Community

David Carr
David Carr

Posted on • Originally published at dcblog.dev on

Laravel how to test CSV download

When you have a CSV generated how do you test it runs. Take this extract:

public function export()
{
    $actions = $this->getData()->get();

    $columns = [
        'User',
        'Start Date',
        'End Date',
    ];

    $data = [];
    foreach ($actions as $action) {
        $data[] = [
            $action->user->name ?? '',
            $action->due_at,
            $action->completed_at,
        ];
    }

    $now = Carbon::now()->format('d-m-Y');
    $filename = "actions-{$now}";

    return csv_file($columns, $data, $filename);
}
Enter fullscreen mode Exit fullscreen mode

The above collects data and sends it to a helper function called csv_file which in turn will export a CSV file.

For completeness it contains:

if (! function_exists('csv_file')) {
    function csv_file($columns, $data, string $filename = 'export'): BinaryFileResponse
    {
        $file = fopen('php://memory', 'wb');
        $csvHeader = [...$columns];

        fputcsv($file, $csvHeader);

        foreach ($data as $line) {
            fputcsv($file, $line);
        }

        fseek($file, 0);

        $uid = unique_id();

        Storage::disk('local')->put("public/$uid", $file);

        return response()->download(public_path("storage/$uid"), "$filename.csv")->deleteFileAfterSend(true);
    }
}
Enter fullscreen mode Exit fullscreen mode

Now there are 2 tests I want to confirm first, I get 200 status response to ensure the endpoint does not throw an error and secondly, the response contains the generated file name for the CSV.

To cater for the 200 status code run the endpoint and assertOk() which is a shortcut for a 200 instead of assertStatus(200)

Next check the header of the response and read the content-disposition header this will contain an attachment followed by the filename. ** ** Doing an assert true and comparing the header with the expected response;

test('can export actions', function () {
    $this->authenticate();

    $response = $this
        ->get('admin/reports/actions/csv')
        ->assertOk();

    $this->assertTrue($response->headers->get('content-disposition') == 'attachment; filename=actions-'.date('d-m-Y').'.csv');
});
Enter fullscreen mode Exit fullscreen mode

Another way would be to use Pest's expect API:

$header = $response->headers->get('content-disposition');
$match = 'attachment; filename=actions-'.date('d-m-Y').'.csv';

expect($header)->toBe($match);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)