Completed
Branch master (f63bf1)
by Adrien
01:47
created

php$0 ➔ testInvalidRequestShouldThrows()   A

Complexity

Conditions 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQLTests\Upload;
6
7
use GraphQL\Error\InvariantViolation;
8
use GraphQL\Executor\ExecutionResult;
9
use GraphQL\Server\RequestError;
10
use GraphQL\Server\StandardServer;
11
use GraphQL\Type\Definition\ObjectType;
12
use GraphQL\Type\Definition\Type;
13
use GraphQL\Type\Schema;
14
use GraphQL\Upload\UploadMiddleware;
15
use GraphQL\Upload\UploadType;
16
use GraphQLTests\Upload\Psr7\PsrUploadedFileStub;
17
use PHPUnit\Framework\TestCase;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
use Psr\Http\Message\UploadedFileInterface;
21
use Psr\Http\Server\RequestHandlerInterface;
22
use Zend\Diactoros\Response;
23
use Zend\Diactoros\ServerRequest;
24
25
class UploadMiddlewareTest extends TestCase
26
{
27
    /**
28
     * @var UploadMiddleware
29
     */
30
    private $middleware;
31
32
    public function setUp(): void
33
    {
34
        $this->middleware = new UploadMiddleware();
35
    }
36
37
    public function testProcess(): void
38
    {
39
        $response = new Response();
40
        $handler = new class($response) implements RequestHandlerInterface {
41
            private $response;
42
43
            public function __construct(ResponseInterface $response)
44
            {
45
                $this->response = $response;
46
            }
47
48
            public function handle(ServerRequestInterface $request): ResponseInterface
49
            {
50
                return $this->response;
51
            }
52
        };
53
54
        $middleware = $this->getMockBuilder(UploadMiddleware::class)
55
            ->setMethods(['processRequest'])
56
            ->getMock();
57
58
        // The request should be forward to processRequest()
59
        $request = new ServerRequest();
60
        $middleware->expects($this->once())->method('processRequest')->with($request);
61
62
        $actualResponse = $middleware->process($request, $handler);
0 ignored issues
show
Bug introduced by
The method process() does not exist on PHPUnit\Framework\MockObject\MockObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

62
        /** @scrutinizer ignore-call */ 
63
        $actualResponse = $middleware->process($request, $handler);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
63
        self::assertSame($response, $actualResponse, 'should return the mocked response');
64
    }
65
66
    public function testParsesMultipartRequest(): void
67
    {
68
        $query = '{my query}';
69
        $variables = [
70
            'test' => 1,
71
            'test2' => 2,
72
            'uploads' => [
73
                0 => null,
74
                1 => null,
75
            ],
76
        ];
77
        $map = [
78
            1 => ['variables.uploads.0'],
79
            2 => ['variables.uploads.1'],
80
        ];
81
82
        $file1 = new PsrUploadedFileStub('image.jpg', 'image/jpeg');
83
        $file2 = new PsrUploadedFileStub('foo.txt', 'text/plain');
84
        $files = [
85
            1 => $file1,
86
            2 => $file2,
87
        ];
88
89
        $request = $this->createRequest($query, $variables, $map, $files, 'op');
90
        $processedRequest = $this->middleware->processRequest($request);
91
92
        $variables['uploads'] = [
93
            0 => $file1,
94
            1 => $file2,
95
        ];
96
97
        self::assertSame('application/json', $processedRequest->getHeader('content-type')[0], 'request should have been transformed as application/json');
98
        self::assertSame($variables, $processedRequest->getParsedBody()['variables'], 'uploaded files should have been injected into variables');
99
    }
100
101
    public function testEmptyRequestIsValid(): void
102
    {
103
        $request = $this->createRequest('{my query}', [], [], [], 'op');
104
        $processedRequest = $this->middleware->processRequest($request);
105
106
        self::assertSame('application/json', $processedRequest->getHeader('content-type')[0], 'request should have been transformed as application/json');
107
        self::assertSame([], $processedRequest->getParsedBody()['variables'], 'variables should still be empty');
108
    }
109
110
    public function testNonMultipartRequestAreNotTouched(): void
111
    {
112
        $request = new ServerRequest();
113
        $processedRequest = $this->middleware->processRequest($request);
114
115
        self::assertSame($request, $processedRequest, 'request should have been transformed as application/json');
116
    }
117
118
    public function testEmptyRequestShouldThrows(): void
119
    {
120
        $request = new ServerRequest();
121
        $request = $request
122
            ->withHeader('content-type', ['multipart/form-data'])
123
            ->withParsedBody([]);
124
125
        $this->expectException(InvariantViolation::class);
126
        $this->expectExceptionMessage('PSR-7 request is expected to provide parsed body for "multipart/form-data" requests but got empty array');
127
        $this->middleware->processRequest($request);
128
    }
129
130
    public function testNullRequestShouldThrows(): void
131
    {
132
        $request = new ServerRequest();
133
        $request = $request
134
            ->withHeader('content-type', ['multipart/form-data'])
135
            ->withParsedBody(null);
136
137
        $this->expectException(InvariantViolation::class);
138
        $this->expectExceptionMessage('PSR-7 request is expected to provide parsed body for "multipart/form-data" requests but got null');
139
        $this->middleware->processRequest($request);
140
    }
141
142
    public function testInvalidRequestShouldThrows(): void
143
    {
144
        $request = new ServerRequest();
145
        $request = $request
146
            ->withHeader('content-type', ['multipart/form-data'])
147
            ->withParsedBody(new \stdClass());
148
149
        $this->expectException(RequestError::class);
150
        $this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got []');
151
        $this->middleware->processRequest($request);
152
    }
153
154
    public function testOtherContentTypeShouldNotBeTouched(): void
155
    {
156
        $request = new ServerRequest();
157
        $request = $request
158
            ->withHeader('content-type', ['application/json'])
159
            ->withParsedBody(new \stdClass());
160
161
        $processedRequest = $this->middleware->processRequest($request);
162
        self::assertSame($request, $processedRequest);
163
    }
164
165
    public function testRequestWithoutMapShouldThrows(): void
166
    {
167
        $request = $this->createRequest('{my query}', [], [], [], 'op');
168
169
        // Remove the map
170
        $body = $request->getParsedBody();
171
        unset($body['map']);
172
        $request = $request->withParsedBody($body);
173
174
        $this->expectException(RequestError::class);
175
        $this->expectExceptionMessage('The request must define a `map`');
176
        $this->middleware->processRequest($request);
177
    }
178
179
    public function testCanUploadFileWithStandardServer(): void
180
    {
181
        $query = 'mutation TestUpload($text: String, $file: Upload) {
182
    testUpload(text: $text, file: $file)
183
}';
184
        $variables = [
185
            'text' => 'foo bar',
186
            'file' => null,
187
        ];
188
        $map = [
189
            1 => ['variables.file'],
190
        ];
191
        $files = [
192
            1 => new PsrUploadedFileStub('image.jpg', 'image/jpeg'),
193
        ];
194
195
        $request = $this->createRequest($query, $variables, $map, $files, 'TestUpload');
196
197
        $processedRequest = $this->middleware->processRequest($request);
198
199
        $server = $this->createServer();
200
201
        /** @var ExecutionResult $response */
202
        $response = $server->executePsrRequest($processedRequest);
203
204
        $expected = ['testUpload' => 'Uploaded file was image.jpg (image/jpeg) with description: foo bar'];
205
        $this->assertSame($expected, $response->data);
206
    }
207
208
    private function createRequest(string $query, array $variables, array $map, array $files, string $operation): ServerRequestInterface
209
    {
210
        $request = new ServerRequest();
211
        $request = $request
212
            ->withMethod('POST')
213
            ->withHeader('content-type', ['multipart/form-data; boundary=----WebKitFormBoundarySl4GaqVa1r8GtAbn'])
214
            ->withParsedBody([
215
                'operations' => json_encode([
216
                    'query' => $query,
217
                    'variables' => $variables,
218
                    'operationName' => $operation,
219
                ]),
220
                'map' => json_encode($map),
221
            ])
222
            ->withUploadedFiles($files);
223
224
        return $request;
225
    }
226
227
    private function createServer(): StandardServer
228
    {
229
        return new StandardServer([
230
            'debug' => true,
231
            'schema' => new Schema([
232
                'query' => new ObjectType([
233
                    'name' => 'Query',
234
                ]),
235
                'mutation' => new ObjectType([
236
                    'name' => 'Mutation',
237
                    'fields' => [
238
                        'testUpload' => [
239
                            'type' => Type::string(),
240
                            'args' => [
241
                                'text' => Type::string(),
242
                                'file' => new UploadType(),
243
                            ],
244
                            'resolve' => function ($root, array $args): string {
245
                                /** @var UploadedFileInterface $file */
246
                                $file = $args['file'];
247
                                $this->assertInstanceOf(UploadedFileInterface::class, $file);
248
249
                                // Do something more interesting with the file
250
                                // $file->moveTo('some/folder/in/my/project');
251
252
                                return 'Uploaded file was ' . $file->getClientFilename() . ' (' . $file->getClientMediaType() . ') with description: ' . $args['text'];
253
                            },
254
                        ],
255
                    ],
256
                ]),
257
            ]),
258
        ]);
259
    }
260
}
261