Search code examples
phplaravelintegration-testing

Integration Testing File Uploads


I am currently developing an MVC website with some form functionality. As part of the form, users can choose to upload a file. The I've written the code for this and it is working perfectly but my issue comes from trying to write automated tests to ensure I don't break anything with future refactors.

I have read through the laravel documentation for file uploads and attempted to replicate this but get an failure when asserting that the file exists. The form is optional but there is some data that is required to be sent with it.

TestFile

 public function testDirect_FormPassesWithFile() 
    {
        Storage::fake('local');
        $file = UploadedFile::fake()->create('document.pdf');
        $response = $this->post('/direct', $this->data());
        $response->assertSessionHasNoErrors();
        Storage::disk('local')->assertExists($file->hashName());
        $response->assertStatus(302);
        $this->assertCount(1, QuickQuote::all()); 
    }

 private function data() 
    { 
        return [
            'name' => $this->faker->name,
            'email' => $this->faker->email,
            'phone' =>'07718285557',
            'risk' => $this->faker->address,
            'rebuild' => $this->faker->numberBetween($min = 500000, $max = 1000000),
            'startdate' => '2019-09-01',
            'currentpremium' => $this->faker->numberBetween($min = 100, $max = 1000),
            'file' => 'document.pdf',
            '_token' => csrf_token()
        ];
    }

Controller


 public function store(StoreQuickQuote $request)
    {
        $validated = $request->validated();

        //Code entered if there are any files uploaded
        if ($request->file('file')) {
            //loop through each file and store, saving path to an array
            $files = array();
            foreach($request->file('file') as $file) {
                $path = $file->store('uploads'); 
                array_push($files, $path);
            }
            //Turn the array into json and then insert into the validated data
            $filenames = json_encode($files);
            $merged = array_merge($validated, ['file' => $filenames]);

            $quick_quote = QuickQuote::create($merged);
        }

        //No files so just store
        $quick_quote = QuickQuote::create($validated);

        return redirect('/direct')->with('success', 'Thanks! We\'ll Be In Touch.');
    }

Validation Request

 public function rules()
    {
        return [
            'name' => 'required',
            'email' => 'required|email',
            'phone' => 'required',
            'risk' => 'required',
            'rebuild' => 'required',
            'startdate' => 'required',
            'currentpremium' => 'present',
            'file' => 'nullable'
        ];
    }

Form Input

<input type="file" id="file" name="file[]" multiple> 

My output is always

There was 1 failure:

1) Tests\Feature\DirectTest::testDirect_FormPassesWithFile
Unable to find a file at path [mJ4jQ2hmxW6uMMPEneUVS6O4bZziuuTT5kq2NFVS.pdf].
Failed asserting that false is true.

I'm not too sure where I am going so any tips would be great.

Thanks


Solution

  • You are passing the name of the file in as a string in the POST data, but this is incorrect. You need to post the file itself to the test framework. You can do this with the call method. The 5th parameter is for posted files.

    $this->call('POST', route('route.to.test'), $params, [], compact('file'))