How to use a local MinIO S3 server with Laravel, and automatically configure it for your Laravel Dusk test suite

If you're writing tests for your Laravel application and you need to interact with its storage system, you might have come across the Storage::fake() method. This method brilliantly fakes an entire filesystem disk, whether a local disk or an external disk like an S3 service. As a result, you don't have to rewrite a single thing in your code. For end-to-end tests with Laravel Dusk, there are helper methods as well. For example, an attach method easily attaches a file to an input element.

While this covers most of the testing tools you'll ever need, I've found myself in need of interacting and testing with a real, live S3 service. In my case, I implemented S3's multipart upload feature and wanted a complete end-to-end test. I want to ensure that everything, from attaching a file to the input element to handling the multipart upload, is guaranteed to work.

I've stumbled upon MinIO, an open-source storage suite that runs on all major platforms. It's super lightweight and still fully S3-compatible. There's hardly a thing you have to configure to make it sing with Laravel. You need to point the endpoint and url configuration key to the MinIO server and set the use_path_style_endpoint configuration key to true.

AWS_ACCESS_KEY_ID=user
AWS_SECRET_ACCESS_KEY=password
AWS_DEFAULT_REGION=eu-west-1
AWS_BUCKET=bucket-name
AWS_URL=https://127.0.0.1:9000
AWS_ENDPOINT=https://127.0.0.1:9000
AWS_USE_PATH_STYLE_ENDPOINT=true

To make the testing part even more effortless, I've created a little package that automatically starts and configures a MinIO server for each test. It works fantastic on GitHub Actions as well. You can choose to start a new server for each test or use the same server for the entire test suite. You only have to add a trait to your test, and add the bootUsesMinIOServer method:

<?php
 
namespace Tests\Browser;
 
use Illuminate\Foundation\Testing\DatabaseMigrations;
use ProtoneMedia\LaravelMinioTestingTools\UsesMinioServer;
use Tests\DuskTestCase;
 
class UploadVideoTest extends DuskTestCase
{
use DatabaseMigrations;
use UsesMinioServer;
 
protected function setUp(): void
{
parent::setUp();
 
$this->bootUsesMinIOServer();
}
 
/** @test */
public function it_can_upload_a_video_using_multipart_upload()
{
}
}

In the README.md of the repository, you'll find how to configure GitHub Actions to use MinIO for your test suite.