I have an endpoint, that allows file upload, everything works fine.
Next thing is to cover the endpoint with proper functional test.
And here's the problem - I can't pass the file to the client making the request.
My test class extends \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase.
static::createClient() method creates an instance of ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client and these Client does not support file uploads.
Beacuse of implementing the Symfony\Contracts\HttpClient\HttpClientInterface which defines public function request(string $method, string $url, array $options = []): ResponseInterface; there's no place for passing files argument.
The allowed options in Client does not support files array.
Internaly it looks like this:
ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client::request passes to the internal kernelBrowser an empty array in place of files params (2nd array): $this->kernelBrowser->request($method, $resolvedUrl, [], [], $server, $options['body'] ?? null)
How do you test endpoints with file upload by extending Base class for functional API tests which is ApiTestCase?
Here's some code, to help you visualize the problem:
ApiResource definition in entity:
/**
* @ApiResource(
* collectionOperations={
* "file_upload"={
* "method"="post",
* "controller"=FileUpload::class,
* "path"="/api/file-upload-endpoint",
* "deserialize"=false,
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* },
* },
* )
*/
Test class (don't mind the instance of UploadedFile, it's just there, to show you, that it cannot be passed anywhere):
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
And here is what i'm looking for:
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
[
'file'=>$file
]
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
When modyfing the vendor itself and passing the files to the Client::request and then to the kernelBrowser in place of 2nd empty array, everything works fine (I'm aware of breaking the contract, that's not the issue here ;)).
I'm thinking if there's missing feature of uploading files in ApiTestCase or I just can't find the solution.
Pls halp!
Api Platform version: 2.5.6
PS: I know i can use different client - test.client
$client = static::$kernel->getContainer()->get('test.client');
which is an instance of Symfony\Bundle\FrameworkBundle\KernelBrowser, the same that is used internally by the Api Platform's Client and that supports files array, but that's not the point of my question. I'd like to know how to do file upload with ApiTestCase.