0

I've created an maatwebsite/excel import routine and i would like to test it.

The maatwebsite/excel testing page does not provide me with any other information than to fake it. But i need to upload my real excel-file, as i want to validate whether the data from the excel file was processed correctly.

Here's my upload input field and the corresponding button to hit the endpoint /import

<form action="/import" method="post" enctype="multipart/form-data">
   @csrf
   <div class="form-group">
       <input type="file" class="form-control-file file-path" name="fileToUpload">
   </div>
   <button type="submit" class="btn btn-primary">Import File</button>
</form>

on the controller side of view, the uploaded file will be processed and imported.

...

public function store(Request $request) {
        $request->validate([
            'fileToUpload' => 'required|file|max:4096|mimes:xls,xlsx',
        ]);

        // start the import
        Excel::import(new SheetNavigator, request()->file('fileToUpload'));
...

The file that needs to be imported is located within my testing environment under:

/tests
  /files
    /myexcel.xlsx
public function test_user_can_import_file() {

        Excel::fake();

        $datafile = new UploadedFile(
            base_path('tests/files/myfile.xlsx'),
            'myfile.xlsx',
            'xlsx',
            13071,
            true);

        $res = $this->post('/import', [
            'fileToUpload' => $datafile
        ]);

        // asserting, that everything works..

    }

I need a test to verify that the upload was successful and that the import-routine was triggered. I tried everything, from faking anything to using storages.

I appreciate any kind of help, thank you!

Chris

jo-chris
  • 362
  • 6
  • 13

1 Answers1

5

Generally speaking the ideal way to do this is by mocking the Excel class and then checking if import has been called with the given file. Despite the fact that this seems to be a static call it's actually a Facade call so you can swap it out with a mock. In fact it seems to offer this functionality on its own:

public function testThatItImportsTheUploadedFile() {
    $file = UploadedFile::fake()->create('myexcel.xlsx');

    Excel::fake();

    $this->post('/import', [
        'fileToUpload' => $file
    ]);

    Excel::assertImported('myexcel.xlsx');

}

Note: This verifies that the endpoint works as expected given that the file is uploaded and Excel::import will work as expected.

If you want to test with your real file you can possibly create a new UploadedFile instance (linking the symfony base class since that's where the constructor is).

$file = new UploadedFile(
    base_path('tests/files/myfile.xlsx'),
    'myfile.xlsx',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    null,
    true
);
apokryfos
  • 38,771
  • 9
  • 70
  • 114
  • Thank you! I tried to fake an excel sheet, and the import succeded. But i cant use my real file from my /files directory. – jo-chris May 12 '20 at 08:55
  • @jo-chris you can possibly create a new instance as per https://stackoverflow.com/a/36414073/487813 but I don't see any reason to do so. This is a unit test so you should only focus on the unit being tested, in this case the endpoint. I've updated my answer to show the "correct" way to instantiate this class – apokryfos May 12 '20 at 09:00