I have a route in Laravel 7 that saves a file to a S3 disk and returns a temporary URL to it. Simplified the code looks like this:
Storage::disk('s3')->put('image.jpg', $file);
return Storage::disk('s3')->temporaryUrl('image.jpg');
I want to write a test for that route. This is normally straightforward with Laravel. I mock the storage with Storage::fake('s3')
and assert the file creation with Storage::disk('s3')->assertExists('image.jpg')
.
The fake storage does not support Storage::temporaryUrl()
. If trying to use that method it throws the following error:
This driver does not support creating temporary URLs.
A common work-a-round is to use Laravel's low level mocking API like this:
Storage::shouldReceive('temporaryUrl')
->once()
->andReturn('http://examples.com/a-temporary-url');
This solution is recommended in a LaraCasts thread and a GitHub issue about that limitation of Storage::fake()
.
Is there any way I can combine that two approaches to test a route that does both?
I would like to avoid reimplementing Storage::fake()
. Also, I would like to avoid adding a check into the production code to not call Storage::temporaryUrl()
if the environment is testing. The latter one is another work-a-round proposed in the LaraCasts thread already mentioned above.
Storage::fake()
andStorage::shouldReceive('temporaryUrl')
together in the same test. But it isn't working for me. In my tests it's not cumulative. Mocking seems to override theStorage::fake()
. I'm facing errors likeReceived Mockery_0_Illuminate_Filesystem_FilesystemManager::disk(), but no expectations were specified
. I'm using Laravel v7.25.0. – Leffert