helin16's avatar

Help needed for Testing with vfsStream for fileupload to Restful API

Anyone did TDD testing with file upload before, i am having trouble to get this code working.

on the test side

public function createAssetSuccessfully()
    {
        //removing from database;
        $this->fake_asset_object->delete();
        $this->assertCount(0, Asset::all());

        $expected_file_name = 'test_some_test_file.txt';
        $expected_type_id = self::FAKE_ASSET_TYPE_ID;
        $file = vfsStream::newFile($expected_file_name)->at($this->fake_file_root)->setContent(self::FAKE_FILE_CONTENT); // vfsStream is from "mikey179/vfsStream"
        $upload_file = new UploadedFile($file->url(), $expected_file_name);

        // Trigger the upload
        $headers = $this->getAuthHeader();
        $server = $this->transformHeadersToServerVars($headers);
        $response = $this->call('POST', '/api/asset/', ['type_id' => $expected_type_id], [], ['files' => [$upload_file]], $server);

        $this->assertResponseStatus(200);
        // Check in Database
        $assets = Asset::all();
        $this->assertCount(1, $assets);
    }

on The API side

 /**
     * Creating an asset , route to match /api/asset with POST
     */
    public function create()
    {
        $errors = array();
        $isValidated = $this->_validate([
            'type_id' => 'required|exists:assetTypes,id',
            'files' => 'required|array|min:1'
        ], $errors);
        if ($isValidated !== true) {
            return $this->getErrorResp(400, '', $errors);
        }

        try {
            DB::beginTransaction();
            $assets = [];
            foreach(Input::file('files') as $file) {
                $file_path = '/tmp/' . $file->getClientOriginalName();
                $file->move($file_path);
                $data = [
                    'filename' => $file->getClientOriginalName(),
                    'type_id' => Input::get('type_id'),
                    'mimeType' => $file->getMimeType(),
                    'absolute_file_path' => $file_path,
                ];
                // TODO: need to use Storage from laravel in the future!!!
                $assets[] = Asset::create($data);
            }

            DB::commit();

            return $assets;
        } catch (\Exception $e) {
            DB::rollback();
            throw $e;
        }
    }

it alway give me this:

"The file "test_some_test_file.txt" was not uploaded due to an unknown error."

from

AssetController.php: Symfony\Component\HttpFoundation\File\UploadedFile->move('/tmp/test_some_...')
0 likes
3 replies
ifpingram's avatar

This is because the POST call is uploading a vfsStream object, which Input::file() does not know how to read. If you dd the contents of Input::file:

try {
            dd(Input::file('files'));
            foreach(Input::file('files') as $file) {

You will see that it gives you something like:

array:1 [
  0 => Symfony\Component\HttpFoundation\File\UploadedFile {#153
    -test: false
    -originalName: "test_some_test_file.txt"
    -mimeType: "application/octet-stream"
    -size: null
    -error: 0
    path: "vfs://exampleDir"
    filename: "test_some_test_file.txt"
    basename: "test_some_test_file.txt"
    pathname: "vfs://exampleDir/test_some_test_file.txt"
    extension: "txt"
    realPath: false

There isn't as far as I can think a way around this with vfsStream. All I can suggest is that you use vfsStream for more lower level unit testing, that is not reliant upon the Request-Response cycle. Ergo, for this integration level testing, you will need to use a real file.

Good luck!

1 like
helin16's avatar

Cheers, man! I had to use a temp file now. but I am not sure whether it's the right way.

Please or to participate in this conversation.