Build Laravel 8 + Livewire File Upload Feature with TDD Part: 1

Arif Khan
6 min readMay 3, 2021

In this article we will discuss how we can build a file upload functionality in Laravel 8 using Livewire with TDD (Test Driven Development).

Prerequisite: Basic knowledge of Laravel, Livewire and TDD

Let’s Get Started

Step 1: Create a laravel project

laravel new fileupload

Step 2: Install Jetstream

Install package:

composer require laravel/jetstream

Run installation command.

php artisan jetstream:install livewire

Finalise the setup:

npm install
npm run dev
php artisan migrate

Note: Don’t forget to configure database in your project’s .env file.

Step 3: Setup phpunit.xml

Uncomment following two lines in your project’s phpunit.xml file exists in the root directory.

<server name="DB_CONNECTION" value="sqlite"/><server name="DB_DATABASE" value=":memory:"/>

Note: You must have installed sqlite database and required PHP driver(s).

Step 4: Create a test

php artisan make:test FileUploadTest

Let’s write down the objective:

/** @test */public function page_contains_a_file_upload_component(){   // 1. Sign In a user   // 2. Goto Upload file url   // 3. Assert the url has the file-upload livewire component.}

Convert the objectives in the code:

FileUploadTest.php

Now let’s run this test:

php artisan test --fitler page_contains_a_file_upload_component

Following is the output of the above command.

It says we don’t have route named upload_file let’s create one. Inside web.php file create the following route

web.php

Now let’s run the test again.

Now the error has changed it says upload.blade.php does not exists so let’s create it in : resources/views/upload.blade.php

Let’s run the test one more time:

Last thing to pass this test is create the file-upload component. Run the following command in the root of the project:

php artisan make:livewire FileUpload

and update upload.blade.php it should looks like:

<div>     @livewire('file-upload')</div>

Finally the test should return green.

I hope you get the idea how TDD works. As you can see the failed test keep telling us what we should do next isn’t it cool. I feel, this approach helps me to focus more on the main objective of the task.

Step 5: File Upload test

Now let’s right a test for Livewire component i.e. FileUpload.

Before writing the test first set the objectives:

1. It requires a file.
2. File should be a type of pdf
3. Assert the file has been uploaded successfully.

Add the following test to the FileUploadTest.php

FileUploadTest.php

In this test we are using Livewire\Livewire class to test the component, this helper is provided by its official package. And using it we are mounting FileUpload component and calling method upload which does not exists yet so for obvious reasons test going to be failed.

But still we will run it so that output can lead us. Let’s run it:

php artisan test --fitler it_requires_a_file

Let’s create the method upload in FileUpload.php component.

FileUpload.php

Let’s run the test again:

Error has changed now we need to add code for the validation:

FileUpload.php

Run the test again:

Now it says no property found for validation let’s add the file property.

FileUpload.php

Let’s run it again

And here we go it returns green. Happy Faces :).

Now add following test to ensure the file should be type pdf.

FileUploadTest.php

In this test we using Illuminate\Http\UploadedFile to create fake file and we are asserting two scenario one for invalid file i.e. non pdf other for valid pdf. Notice I have used assertHasNoErrors in the second scenario.

Let’s run the test:

php artisan test --fitler file_should_of_type_pdf

The error is related to Livewire file upload implementation i.e. Livewire provides a trait Livewire\WithFileUploads which we have to use in FileUpload.php class. Let’s do it.

FileUpload.php

Now let’s run the test again.

Now add the validation for mime type pdf.

FileUpload.php

Now run the test one last time:

It returns green. Yay!

Now the last piece of the puzzle i.e ensure the file should be uploaded to the disk. To do that add following test:

FileUploadTest.php

In this test we are using Illuminate\Support\Facades\Storage; to create a fake directory for testing.

let’s run it:

Now add following code to save the file to the disk.

FileUpload.php

Run it again:

What it still failing but Why? Reason being the file hash that we are asserting is different than the actual hash with which the file is stored. So the work around here is we can use one more property to store the hash generated after storing the file and then assert it.

FileUpload.php

In this file I have created a property $path and set the $disk.

FileUploadTest.php

In this method I am getting the property $path then asserting it.

Now run the test.

File must be saved to the disk test

Make sure all tests returning green:

php artisan test --fitler FileUploadTest
All Tests returning Green

So far we have developed a file upload functionality without a browser isn’t it cool! Now in the Part II we will implement the UI please appreciate my work so that it can motivate me to write more content to help the community

I hope you enjoyed the article and learned something new today.

Thank you!

--

--

Arif Khan

My specialties include quickly learning new skills and programming languages, problem-solving. Besides, I love circuit training 🤸 and weight lifting 🏋️