Loading...

Laravel how to test CSV download

David Carr

2 min read - 11th Jul, 2022

Laravel Testing

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);
}

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(storage_path('app/public/'.$uid), "$filename.csv")->deleteFileAfterSend(true);

    }
}

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');
});

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);
0 comments
Add a comment