How to check if the file is downloaded during Laravel Dusk test

Published on Jun 21, 2022

There is no official solution, but we can resolve it with a trick.

First, we must think about what's happening when downloading a new file. The file is added to a folder, so we need to count that folder's files before and after the download. If both counters are the same, then the download process didn't start or if the second counter is bigger than the file is downloaded.

Let's make a new assertion rules (I created a trait for this):

<?php

namespace Tests\Components;

use PHPUnit\Framework\Assert as PHPUnit;

trait Assertions
{
    /**
     * Assert file is downloaded
     */
    public function assertFileDownloaded($before, $after)
    {
        PHPUnit::assertGreaterThan(
            $before, $after,
            "Assert file folder has new file"
        );
    }
}

Now we need one function, which counts our files in the download folder.

namespace Tests\Components;

use Illuminate\Support\Str;

trait Helpers
{
    /**
     * Count download folder files
     *
     * @return int
     */
    public function countFolderFiles(): int
    {
        return count(scandir(base_path('tmp')));
    }
}

After that, we make a tmp folder for our route base directory and add it to the .gitignore file.

At the end we need to add the Google Chrome default download directory to the driver function.

protected function driver()
{
    $options = (new ChromeOptions)->addArguments(collect([
        '--window-size=1920,1080',
    ])->unless($this->hasHeadlessDisabled(), function ($items) {
        return $items->merge([
            '--disable-gpu',
            '--headless',
        ]);
    })->all())->setExperimentalOption('prefs', [
        // Set Chrome file download folder
        'download.default_directory' => base_path('tmp'),
    ]);

    return RemoteWebDriver::create(
        $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515',
        DesiredCapabilities::chrome()->setCapability(
            ChromeOptions::CAPABILITY, $options
        )
    );
}

Example usage:

    public function testEventFileIsDownloaded()
    {

        $countDirBefore = $this->countDownloadFiles();

        $this->browse(function (Browser $browser) {
            $browser->visit('home')
                ->waitFor('@button-event')
                ->click('@button-event');
        });

        $countDirAfter = $this->countDownloadFiles();

        $this->assertFileIsDownloaded($countDirBefore, $countDirAfter);
    }