sanjeevkamat's avatar

Image file upload testing not working on update action.

I'm trying to test my update action method in a controller where a fake image needs to be created and uploaded to test if the update action method is working. So, I create fake image using UploadedFile::make()->image('imageName.jpeg') and it is validated before being saved as usual. But my test is failing throwing the validation errors for the image saying the "imageName" must be an image and of the specific mime type as set in the rules for validation. Can anyone tell me what I'm doing wrong. Any help much appreciated Below is the code:

The route:

Route::patch('/update/{icon}', [ProductIconController::class,'update'])->name('updateIcon')
            ->missing(function (Request $request){
                return Redirect::back()->with('failed', 'Icon not found!');
            });

The controller :

 public function update(UpdateIconRequest $request, ProductIcon $icon)
    {
       
        $attributes = $request->validated();
        if($request->hasFile('iconImage') || $request->hasFile('iconHoverImage')){

            if($request->hasFile('iconImage')){
                $inputType  = 'iconImage';
                $file       = $request->file('iconImage');

                if(Storage::exists('images/product_icons/'.$icon->image)){
                   
                    $deleted =  Storage::delete('images/product_icons/'.$icon->image);
 
                }

                $icon->image = $this->saveImage($file, $attributes, $inputType);
                
            }
            
            
            if($request->hasFile('iconHoverImage')){
                $inputType  = 'iconHoverImage';
                $file       = $request->file('iconHoverImage');
                

                if(Storage::exists('images/product_icons/'.$icon->image_hover)){

                   $deleted =  Storage::delete('images/product_icons/'.$icon->image_hover);

                }

                $icon->image_hover = $this->saveImage($file, $attributes, $inputType);
                
            }
        }
        

            $icon->name        = $attributes['name']; //make it unique
            $icon->ordering    = $attributes['order'];
            $icon->status      = $attributes['status'];
            $icon->modified    = now();
            $icon->trash       = null;
            
            $saveSuccess = $icon->save();


        if($saveSuccess){

            return redirect()->route('icons')->with('success', 'Icon has been Updated');

        }
        
        else{
            
            return redirect()->route('icons')->with('failed', 'Some error occured ! </br>Icon was not updated.');
        }

    }

Inside the UpdateIconRequest class:

public function rules()
    {
        
        return [
            'name' =>['required', 'string', 'min:3', 'max:80', 
                    Rule::unique('product_icons','name')->ignore($this->route('icon')->id)], //route('icon') is parameter of route update/{icon}
            'order' => ['required','numeric','min:1','max:120'],
            'status' => ['required', 'numeric'],
            'iconImage' => ['image','mimes:png,jpeg,svg','max:2048'],
            'iconHoverImage' => ['image','mimes:png,jpeg,svg','max:2048'],
        ];
    }

Inside the update.blade.php file :

<form action="{{route('updateIcon', ['icon'=> $icon->id])}}" method="post" enctype="multipart/form-data" id="iconUpdateForm">
            @csrf
            @method('PATCH')
				---other input fields --
            <div class="col-span-1">
                    
                    <input type="radio" name="status" id="no" value="no" {{$icon->status==0?'checked':''}} class="py-1">
                    <label for="no">Inactive</label>
                
                </div>
                
                @foreach ($errors->get('status') as $message)
                    <p class="text-red-600">{{$message}}</p>
                @endforeach
            </div>

           
            <div class="grid grid-cols-12 px-4 py-6 border-b text-xs">
                <div class="col-span-2 font-semibold leading-4 text-gray-700/90">
                    
                    <div>Image</div>

                </div>
                <div class="col-span-6 space-x-4 border-2 border-gray-700 p-4">
                    
                    <label for="thumbImg" class="button-15" role="button">Update Icon Image +</label>
                    
                    @if (empty($icon->image))
                        <p class="text-xs inline-block text-red-500">Please select Icon Image (Required)<span class="text-red-500"> *</span></p>
                    @endif
                    
                    <input type="file" id="thumbImg" name="iconImage" class="px-2 py-1 text-lg bg-blue-100 text-gray-500 hidden" accept=".jpg, .jpeg, .png .svg" required value="{{ old('iconImage') }}"/>
                    
                    <div class="fileImgContainer p-2 mt-2 border-2 border-gray-300 bg-gray-200 space-y-2 mb-3">
                        
                        <p class="head1 text-xs text-red-400">Please select images for Icon</p>
                      
                        <div class="preview flex flex-wrap gap-3">
                            @if (!empty($icon->image))
                                <div class="flex flex-col w-[200px] relative p-2 rounded-xl bg-gray-300">
                                    <div class="h-8 w-8 bg-gray-100/70 text-xl text-gray-600 rounded-full flex justify-center items-center align-middle hover:cursor-pointer"><i class="fa-solid fa-check"></i></div>
                                    <img src="{{asset('storage/images/product_icons/'.$icon->image)}}" alt="" class="object-contain h-[160px] w-[180px] mt-1">
                                </div>
                            @endif

                        </div>

                    </div>

                    @foreach ($errors->get('iconImage') as $message)
                        <p class="text-red-600">{{$message}}</p>
                    @endforeach

                </div>
                
            </div>

            <div class="grid grid-cols-12 px-4 py-6 border-b text-xs">
                <div class="col-span-2 font-semibold leading-4 text-gray-700/90">
                    
                    <div>Hover Image</div>

                </div>

                <div class="col-span-6 space-x-4 border-2 border-gray-700 p-4">
                    
                    <label for="thumbHoverImg" class="button-15" role="button">Update Icon Image +</label>
                    
                    @if (empty($icon->image_hover))
                        <p class="text-xs inline-block text-red-500">Please select Icon Image (Required)<span class="text-red-500"> *</span></p>
                    @endif
                    
                    <input type="file" id="thumbHoverImg" name="iconHoverImage" class="px-2 py-1 text-lg bg-blue-100 text-gray-500 hidden" accept=".jpg, .jpeg, .png .svg" required value="{{ old('iconHoverImage')}}"/>
                    
                    <div class="fileImgContainer p-2 mt-2 border-2 border-gray-300 bg-gray-200 space-y-2 mb-3">
                        
                        <p class="head1 text-xs text-red-400">Please select hover images for Icon</p>
                        <div class="preview flex flex-wrap gap-3">
                            @if (!empty($icon->image_hover))
                                <div class="flex flex-col w-[200px] relative p-2 rounded-xl bg-gray-300">
                                    <div class="h-8 w-8 bg-gray-100/70 text-xl text-gray-600 rounded-full flex justify-center items-center align-middle hover:cursor-pointer"><i class="fa-solid fa-check"></i></div>
                                    <img src="{{asset('storage/images/product_icons/'.$icon->image_hover)}}" alt="" class="object-contain h-[160px] w-[180px] mt-1">
                                </div>
                            @endif
                        </div>
                    
                    </div>
                </div>

                @foreach ($errors->get('iconHoverImage') as $message)
                    <p class="text-red-600">{{$message}}</p>
                @endforeach
                
            </div>

        </form>

And finally the test class code:

public function test_user_can_update_ProductIcon(){
        $updatedImage1 = UploadedFile::fake()->image('abcde.jpeg');
        $updatedHoverImage1 = UploadedFile::fake()->image('abcde1.jpeg');

        //test the route with the productIcon id
        $response = $this->patch(route('updateIcon', [
            'icon'=>2,  
            'name' =>'Updated Test Name',
            'status' => 'yes',
            'order' => 112,
            'iconImage' => $updatedImage1,
            'iconHoverImage' => $updatedHoverImage1
        ]));
        $response->assertStatus(302);
        $response->assertRedirectToRoute('icons');
        $response->assertSessionHas('success');
    }

The errors that is being thrown when the above test fails:

  FAIL  Tests\Feature\ProductIconTest
  ✓ user can access crud pages for  product icon
  ✓ user can create  product icon
  ⨯ user can update  product icon
  ! user can update  product icon image → This test did not perform any assertions  D:\Web Design\Website\watergaterestaurant\tests\Feature\ProductIconTest.php:101

  ---

  • Tests\Feature\ProductIconTest > user can update  product icon
  Failed asserting that two strings are equal.
  
  
  
  The following errors occurred during the last request:
  
  The icon image must be an image.
  
  The icon image must be a file of type: png, jpeg, svg.
  
  The icon hover image must be an image.
  
  The icon hover image must be a file of type: png, jpeg, svg.

  at D:\Web Design\Website\watergaterestaurant\tests\Feature\ProductIconTest.php:97
     93▕             'iconImage' => $updatedImage1,
     94▕             'iconHoverImage' => $updatedHoverImage1
     95▕         ]));
     96▕         $response->assertStatus(302);
  ➜  97▕         $response->assertRedirectToRoute('icons');
0 likes
1 reply
sanjeevkamat's avatar
sanjeevkamat
OP
Best Answer
Level 4

Well, I found out the issue. The parameter to the patch route is wrong. Instead of just passing the Icon id to the route method I had sent entire request data in the route method which was causing the issue. Here is the code:

public function test_user_can_update_ProductIcon(){
        $updatedImage1 = UploadedFile::fake()->image('abcde.jpeg');
        $updatedHoverImage1 = UploadedFile::fake()->image('abcde1.jpeg');

        //test the route with the productIcon id
        $response = $this->put(route('updateIcon',['icon'=>2]), [ //this is the corrected line
            'name'      =>'Updated Test Name',
            'status'    => 'yes',
            'order'     => 112,
            'iconImage' => $updatedImage1,
            'iconHoverImage' => $updatedHoverImage1
        ]);
        $response->assertStatus(302);
        $response->assertRedirectToRoute('icons');
        $response->assertSessionHas('success');
    }

Well, hope this helps someone.

Please or to participate in this conversation.