I use Spatie Laravel Data and maatwebsite Laravel Excel.
My test need use specific xlsx file stored inside my tests folder. I've seen a lot of test used fake files but I can't use one because it's special template.
I try to create test to upload file with Laravel Excel. But I always this error :
FAIL Tests\Feature\Pages\Settings\Preparation\CreateTest
⨯ it can import an preparation list 0.57s
✓ it can not possible to upload a file with a wrong format 0.38s
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
FAILED Tests\Feature\Pages\Settings\Preparation\CreateTest > it can import an preparation list ValidationException
The file field must be a file.
at vendor/laravel/framework/src/Illuminate/Support/helpers.php:328
324▕ function throw_if($condition, $exception = 'RuntimeException', ...$parameters)
325▕ {
326▕ if ($condition) {
327▕ if (is_string($exception) && class_exists($exception)) {
➜ 328▕ $exception = new $exception(...$parameters);
329▕ }
330▕
331▕ throw is_string($exception) ? new RuntimeException($exception) : $exception;
332▕ }
+3 vendor frames
4 app/Http/Controllers/PreparationController.php:28
+52 vendor frames
57 tests/Feature/Pages/Settings/Preparation/CreateTest.php:24
Tests: 1 failed, 1 passed (2 assertions)
Duration: 1.06s
My test :
it('can import an preparation list', function () {
Excel::fake();
$preparation = new UploadedFile(
preparationListPath(),
'preparation.xlsx',
'application/vnd.ms-excel.sheet.macroenabled.12',
null,
true
);
$this->withoutExceptionHandling();
asAdmin()->post(action([PreparationController::class, 'store']), [
'file' => $preparation,
])->assertRedirect(action([PreparationController::class, 'edit'], ['preparation' => 1]));
assertDatabaseCount('preparations', 1);
})->only();
Tests Helpers :
function preparationListPath(): string
{
return base_path('tests/Files/preparation.xlsx');
}
Controller store function :
public function store(CreatePreparationFormRequestData $request): RedirectResponse
{
$request->validate([
'file' => 'mimes:xlsx,xls,csv,xlsm',
]);
Excel::import(new FirstSheetImport, $request->file);
toast('Fichier importé', 'Le fichier a bien été importé.');
return Redirect::action([PreparationController::class, 'edit'], ['preparation' => 1]);
}
DTO :
<?php
namespace App\Data;
use Illuminate\Http\UploadedFile;
use Spatie\LaravelData\Attributes\Validation\File;
use Spatie\LaravelData\Data;
use Spatie\TypeScriptTransformer\Attributes\TypeScript;
#[TypeScript]
class CreatePreparationFormRequestData extends Data
{
public function __construct(
#[File]
public UploadedFile $file,
) {
}
}
Thank you in advance for your help
What I tried :
We've fixed it and split it in to two tests:
First to check if file are imported :
it('can import an preparation list', function () {
Excel::fake();
Storage::fake();
$file = UploadedFile::fake()->create(
base_path('tests/Files/preparation.xlsm'),
'preparation.xlsm'
);
asAdmin()
->post(action([PreparationController::class, 'store']), [
'file' => $file,
], [])
->assertRedirect(action([PreparationController::class, 'edit'], ['preparation' => 1]));
Excel::assertImported('preparation.xlsm');
});
Second to check if all data are correctly imported :
test('a preparation is correctly imported', function () {
Excel::import(new PreparationImport,
base_path('tests/Files/preparation.xlsm'));
assertDatabaseCount('preparations', 1);
assertDatabaseHas('preparations', [
'order_number' => '22202959',
'plan' => '22302959-DWG-070',
'project' => '',
]);
});
Like that both works.
Make attention to one thing when you use Laravel Excel, I had an error when file passed in to my logical and it returned SQL error. This one was fixed with coalesce.
My code before :
public function model(array $row): Preparation
{
return new Preparation([
'order_number' => $row['order_number'],
'plan' => $row['plan'],
'project' => $row['project'],
]);
}
My code now:
public function model(array $row): Preparation
{
return new Preparation([
'order_number' => $row['order_number'] ?? '',
'plan' => $row['plan'] ?? '',
'project' => $row['project'] ?? '',
]);
}
Just need return empty string in case $row are null.