Laravel, Docker, and Storage::fake()
Understanding and Solving Permission Problem
Introduction
When running tests in Laravel, Storage::fake()
is a powerful tool that allows developers to simulate the file system without affecting real files. However, when using Docker for development, subtle permission conflicts can arise—particularly if you’re using Laravel Sail alongside PhpStorm's Docker-based CLI interpreter.
In this article, we’ll explore why this happens, how it affects your tests, and how to resolve it.
The Issue: Permission Conflicts Between Docker and Laravel Sail
When using Storage::fake()
in Laravel, a temporary disk is created under the path storage/framework/testing/disks/local
. This disk is cleared when Storage::fake()
is called, ensuring an isolated environment. However, the problem arises when Docker services create directories as the root
user.
If you’re running Laravel Sail, which uses the sail
user, you’ll encounter permission issues when Sail tries to clean up directories created by the root
user. This conflict often results in errors like:
ErrorException: Unable to delete directory: Permission denied
The root cause? Docker containers typically run processes as root
in PHPStorm and its not configurable.
Steps to Reproduce the Problem
- Set Up PhpStorm with a Docker-Based CLI Interpreter
Configure the interpreter to use thelaravel.test
service from yourdocker-compose.yml
. - Write a Simple Test
UseStorage::fake()
in a Laravel test:
public function test_fake_storage()
{
Storage::fake();
Storage::put('test.txt', 'Sample content');
Storage::assertExists('test.txt');
}
3. Run the Test in PhpStorm
Observe that the storage/framework/testing/disks/local
folder is created with root
ownership.
4. Run the Test in Sail
Attempt to run sail phpunit
in the terminal. Permission errors occur because the sail
user cannot delete files created by root
.
Why Storage::fake()
Doesn’t Fully Solve the Problem
Storage::fake()
does clean up the fake storage at the start of the test. However, if there are lingering directories from previous tests , the cleanup process won’t address permissions on these directories. This leaves root
-owned folders that conflict with Sail's sail
user.
Workaround to Fix the Problem
Manually Clean Up Directories in tearDown()
Add the following code to your test class to ensure all fake storage directories are cleared after each test:
protected function tearDown(): void
{
Storage::fake();
parent::tearDown();
}
This ensures no lingering files or directories remain, regardless of ownership.
Special Workaround for FPDF
When working with Storage::fake()
one needs to make sure to store files always via Storage
facade. For example, when using FPDF
library you may have stored your genereated PDF like this:
$pdf->Output('F', storage_path('app/reports/report.pdf'));
This can be avoided, as the output function offers to return the document as a string instead of saving it, so we can manually safe it via Storage
facade like this:
Storage::put('reports/report.pdf', $pdf->output('S'));
Final Thoughts
Unfortunately, it is currently not possible to change the user for the Docker-Based CLI Interpreter in PhpStorm. This limitation has been a longstanding issue, with requests for this feature dating back at least seven years. Many developers have reported similar challenges, as highlighted in the following issue: Add option to choose the user with which to run in a Docker-Compose environment.
Until JetBrains addresses this limitation, developers must rely on workarounds like adjusting permissions, cleaning up directories manually, or modifying Docker configurations to avoid conflicts. While these solutions help mitigate the issue, a built-in option to select the user in Docker-based environments would greatly simplify workflows for Laravel developers and others facing similar challenges.
If this issue affects your workflow, consider upvoting and commenting on the linked JetBrains issue to help prioritize its resolution.