application/empty при отправке фэйкового файла в ларавел

Пишу http тест загрузки файла и получаю ошибку application/empty при запуске тестов
Мой тест:

public function testUploadContract() {

    $user = User::where('id', '=', $this->companyId)->first();
    $token = JWTAuth::fromUser($user);
    Storage::fake('files');
    $file = UploadedFile::fake()->create('file.pdf', 100, ['Content-Type' => 'application/pdf']);
    $response = $this->withHeaders(['Authorization' => "Bearer $token", 'Content-Type' => 'application/pdf'])->withoutExceptionHandling()->post('/api/v2/company/documents/upload', ['file' => $file]);
    $response->dump();
    $response->assertStatus(200);
}       

Мой контроллер:

public function upload(Request $request)
{
    // dd($request);
    if ($request->hasFile('file') == false) {
        // dump($request->file());
        return response()
            ->json([
                'title' => 'Ошибка',
                'message' => 'Не передан файл с реестром!'
            ], 400, [], JSON_UNESCAPED_UNICODE || JSON_UNESCAPED_SLASHES);
    }

    $validMimeTypes = [
        'application/pdf',
    ];
    $mimeType = mime_content_type($request->file->getPathname());
    if (in_array($mimeType, $validMimeTypes) == false) {
        return response()
            ->json([
                'title' => 'Ошибка',
                'message' => 'Плохой тип файла (' . $mimeType . ')'
            ], 400, [], JSON_UNESCAPED_UNICODE || JSON_UNESCAPED_SLASHES);
    }
    $path = Storage::disk('public')->putFile('temp', $request->file('file'));
    $url = Storage::disk('public')->url($path);

    Log::channel('debug')->debug("FILE IS $url");

    return response()
        ->json([
            'title' => 'Файл загружен',
            'message' => 'Файл успешно загружен',
            'path' => $path,
            'preview' => Storage::disk('public')->url($path)
        ], 200, [], JSON_UNESCAPED_UNICODE || JSON_UNESCAPED_SLASHES);
}       

Когда я загружаю файл с клиента как положено, то всё отлично, а в тестах такой вывод: введите сюда описание изображения
введите сюда описание изображения

И последнее что могу приложить сейчас это дамп файла от фэйкера: введите сюда описание изображения

Помогите пожалуйста чем можете, я уже правда не знаю, что с этим поделать(


Ответы (1 шт):

Автор решения: Total Pusher

В тестах используется такая конструкция:

UploadedFile::fake()->create('file.pdf', 100, ['Content-Type' => 'application/pdf']);

Посмотрим в сорцах, что делает create():

public function create($name, $kilobytes = 0, $mimeType = null)
{
    if (is_string($kilobytes)) {
        return $this->createWithContent($name, $kilobytes);
    }

    return tap(new File($name, tmpfile()), function ($file) use ($kilobytes, $mimeType) {
        $file->sizeToReport = $kilobytes * 1024;
        $file->mimeTypeToReport = $mimeType;
    });
}

Получается, mime-тип проставляется просто как свойство объекта UploadedFile, а содержимое файла - пустое.

Проверяем через тинкер: php artisan tinker:

$file = Illuminate\Http\UploadedFile::fake()->create('file.pdf', 100, ['Content-Type' => 'application/pdf']);

// "Content-Type" => "application/pdf" - передал клиент
$file->getMimeType();

// "" - пусто
$file->getContent();

// "application/x-empty"
mime_content_type($file->getRealPath());

В контроллере mime-тип определяется по содержимому (которое пустое):

mime_content_type($request->file->getPathname());

Поэтому application/x-empty.

Как исправить?

Нужно подготовить реальный pdf-файл, и использовать createWithContent(). При генерации фейковых изображений через image() именно так и делается.

Проверим снова через тинкер:

$file = Illuminate\Http\UploadedFile::fake()->createWithContent('file.pdf', file_get_contents(__DIR__ . '/file_1_k.pdf'));

// "application/pdf"
mime_content_type($file->getRealPath());

Также лучше исправить в контроллере определение типа на $request->file->getMimeType().

Тут также, как и в mime_content_type() происходит реальное определение типа файла по содержимому. Если посмотреть сорцы, используется finfo(), либо вызов оболочки file -b --mime - есть две реализации.

→ Ссылка