Let's talk about testing the file uploads and checking various things:
Like a few other "external" things in Laravel, file uploads need to be faked for testing.
So, you don't work with the actual file uploads to the real storage. You fake the Storage driver, then Laravel, with its testing mechanism, puts those files elsewhere in a separate temporary folder, and then you assert whether that Storage temporary fake disk contains the file.
For example, you have a Controller to store a product, and one of the fields is photo
. You store the photo in the products
folder and save the filename as a string to the photo
database field.
use App\Models\Product;use Illuminate\Http\Request;use Illuminate\Http\RedirectResponse; class ProductController extends Controller{ // ... public function store(Request $request): RedirectResponse { $product = Product::create($request->all()); if ($request->hasFile('photo')) { $filename = $request->file('photo')->getClientOriginalName(); $request->file('photo')->storeAs('products', $filename); $product->update(['photo' => $filename]); } return redirect()->route('products.index'); } // ...}
The start of the test is the same as many tests, acting as some user posting to the route.
use function Pest\Laravel\actingAs; beforeEach(function () { $this->user = User::factory()->create();}); test('product create photo upload successful', function () { actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, 'photo' => '', ]); // asserts});
Now, how do you pass the photo, and what do you assert? First, we must use the Storage
facade, and we will call the fake()
method from it. If you have created a specific disk, it can be passed through the fake()
method.
For the photo, you must call the fake()
method from the UploadedFile
facade. You can call the image()
method from there and pass in parameters such as the filename.
use Illuminate\Http\UploadedFile;use function Pest\Laravel\actingAs;use Illuminate\Support\Facades\Storage; beforeEach(function () { $this->user = User::factory()->create();}); test('product create photo upload successful', function () { Storage::fake(); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, 'photo' => UploadedFile::fake()->image('photo1.jpg'), ]); // asserts});
Now, how do we assert? We need to make two assertions: first, the file exists in the storage, and second, the correct filename is saved to the database.
We can use assertExists()
from the same Storage
facade for the storage assertion.
use App\Models\User;use App\Models\Product;use Illuminate\Http\UploadedFile;use function Pest\Laravel\actingAs;use Illuminate\Support\Facades\Storage; beforeEach(function () { $this->user = User::factory()->create();}); test('product create photo upload successful', function () { Storage::fake(); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, 'photo' => UploadedFile::fake()->image('photo1.jpg'), ]); expect(Product::latest()->first()->photo) ->toBe('photo1.jpg'); Storage::assertExists('products/photo1.jpg');});