Description
Add support for file uploads for test client. Current client does not seem to support this.
Please see the relevant docs section here: https://symfony.com/doc/current/components/http_client.html#uploading-data
To submit a form with file uploads, it is your responsibility to encode the body according to the multipart/form-data content-type. The Symfony Mime component makes it a few lines of code:
use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\Multipart\FormDataPart; $formFields = [ 'regular_field' => 'some value', 'file_field' => DataPart::fromPath('/path/to/uploaded/file'), ]; $formData = new FormDataPart($formFields); $client->request('POST', 'https://...', [ 'headers' => $formData->getPreparedHeaders()->toArray(), 'body' => $formData->bodyToIterable(), ]);
That being said, it could be nice to add a link to this Symfony docs entry in our own docs.
Sorry, I was mistaken on this one. Our test Client indeed does not support file uploads.
/cc @morganetouati thanks for re-discovering this problem.
See
We're passing an empty array for the $files argument (4th argument).
Hello, is there any option to test file upload with Api-Platform? I'm using Vich and Flysystem with your guide. Thanks
I have managed to make it work using the following code:
<?php
namespace App\Tests\Controller\Api;
use App\Entity\Media;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use App\Repository\UserRepository;
/**
* @group functional
* @group api
*/
class MediaApiTest extends WebTestCase
{
/**
* Create a client with a default Authorization header.
*
* @param string $username
* @param string $password
*
* @return \Symfony\Bundle\FrameworkBundle\Client
*/
protected function createAuthenticatedApiClient($username = 'test')
{
$client = static::createClient();
/** @var JWTTokenManagerInterface $tokenManager */
$tokenManager = static::$kernel->getContainer()->get('lexik_jwt_authentication.jwt_manager');
/** @var UserRepository $userRepository */
$userRepository = static::$kernel->getContainer()->get(UserRepository::class);
$token = $tokenManager->create($userRepository->findOneBy(['username' => $username]));
$client->setServerParameter('HTTP_Authorization', sprintf('Bearer %s', $token));
$client->setServerParameter('HTTP_ACCEPT', 'application/ld+json');
$client->setServerParameter('CONTENT_TYPE', 'application/ld+json');
return $client;
}
public function testUserIsAbleToCreateNewMediaForAvatar()
{
$username = 'test';
$client = $this->createAuthenticatedApiClient($username);
$avatar = new UploadedFile(
__DIR__ . '/../../../src/DataFixtures/media/test.jpg',
'test.jpg',
'image/jpeg',
null,
true
);
$crawler = $client->request(
'POST', // $method
'/api/auth/v1/media', // $url
array( // $parameters
'mediaType' => Media::MEDIA_TYPE_AVATAR
),
array('mediaFile' => ['file' => $avatar]), // $files
array( // $server
'CONTENT_TYPE' => 'multipart/form-data',
)
);
$this->assertSame(Response::HTTP_CREATED, $client->getResponse()->getStatusCode());
}
}
The important parts are:
$client->setServerParameter('HTTP_ACCEPT', 'application/ld+json');
$client->setServerParameter('CONTENT_TYPE', 'application/ld+json');
And the last parameter for the request() method:
array( // $server
'CONTENT_TYPE' => 'multipart/form-data',
)
@MrNicodemuz I hope you can simplify it, when my MR is in a tagged release.
$crawler = $client->request( 'POST', // $method '/api/auth/v1/media', // $url array( // $parameters 'mediaType' => Media::MEDIA_TYPE_AVATAR ), array('mediaFile' => ['file' => $avatar]), // $files array( // $server 'CONTENT_TYPE' => 'multipart/form-data', ) ); $this->assertSame(Response::HTTP_CREATED, $client->getResponse()->getStatusCode());
Hello, thanks for your help, I am trying to implement your solution but I don't understand what is the constant MEDIA_TYPE_AVATAR should contains.
Thanks in advance for your reply :)
mediaType is just a entity field (database field) in my Media table indicating what type of media upload it is (e.g. for an user avatar)... you can omit it as it's not relevant towards file uploads...
mediaTypeis just a entity field (database field) in my Media table indicating what type of media upload it is (e.g. for an user avatar)... you can omit it as it's not relevant towards file uploads...
Thanks for your answer it works for me !
Most helpful comment
See
https://github.com/api-platform/core/blob/215709aafd73a5daa491c977b76f152a3aa2aaed/src/Bridge/Symfony/Bundle/Test/Client.php#L124
We're passing an empty array for the
$filesargument (4th argument).