Completed
Push — master ( d52ee7...e7842c )
by Alexandr
03:54
created

ProcessorTest::testEmptyQueries()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 14
rs 9.4285
cc 1
eloc 10
nc 1
nop 0
1
<?php
2
/*
3
 * This file is a part of GraphQL project.
4
 *
5
 * @author Alexandr Viniychuk <[email protected]>
6
 * created: 11:02 PM 5/13/16
7
 */
8
9
namespace Youshido\Tests\Schema;
10
11
12
use Youshido\GraphQL\Execution\Processor;
13
use Youshido\GraphQL\Execution\ResolveInfo;
14
use Youshido\GraphQL\Field\Field;
15
use Youshido\GraphQL\Schema\Schema;
16
use Youshido\GraphQL\Type\ListType\ListType;
17
use Youshido\GraphQL\Type\NonNullType;
18
use Youshido\GraphQL\Type\Object\ObjectType;
19
use Youshido\GraphQL\Type\Scalar\BooleanType;
20
use Youshido\GraphQL\Type\Scalar\IntType;
21
use Youshido\GraphQL\Type\Scalar\StringType;
22
use Youshido\GraphQL\Type\Union\UnionType;
23
use Youshido\Tests\DataProvider\TestEmptySchema;
24
use Youshido\Tests\DataProvider\TestEnumType;
25
use Youshido\Tests\DataProvider\TestInterfaceType;
26
use Youshido\Tests\DataProvider\TestObjectType;
27
use Youshido\Tests\DataProvider\TestSchema;
28
29
class ProcessorTest extends \PHPUnit_Framework_TestCase
30
{
31
32
    private $_counter = 0;
33
34
    /**
35
     * @expectedException \Youshido\GraphQL\Validator\Exception\ConfigurationException
36
     * @expectedExceptionMessage Schema has to have fields
37
     */
38
    public function testInit()
39
    {
40
        new Processor(new TestEmptySchema());
41
    }
42
43
    public function testEmptyQueries()
44
    {
45
        $processor = new Processor(new TestSchema());
46
        $processor->processPayload('');
47
        $this->assertEquals(['errors' => [
48
            ['message' => 'Must provide an operation.']
49
        ]], $processor->getResponseData());
50
51
        $processor->processPayload('{ me { name } }');
52
        $this->assertEquals(['data' => [
53
            'me' => ['name' => 'John']
54
        ]], $processor->getResponseData());
55
56
    }
57
58 View Code Duplication
    public function testListNullResponse()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
59
    {
60
        $processor = new Processor(new Schema([
61
            'query' => new ObjectType([
62
                'name' => 'RootQuery',
63
                'fields' => [
64
                    'list' => [
65
                        'type' => new ListType(new StringType()),
66
                        'resolve' => function() {
67
                            return null;
68
                        }
69
                    ]
70
                ]
71
            ])
72
        ]));
73
        $data = $processor->processPayload(' { list }')->getResponseData();
74
        $this->assertEquals(['data' => ['list' => null]], $data);
75
    }
76
77
78 View Code Duplication
    public function testSubscriptionNullResponse()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
79
    {
80
        $processor = new Processor(new Schema([
81
            'query' => new ObjectType([
82
                'name' => 'RootQuery',
83
                'fields' => [
84
                    'list' => [
85
                        'type' => new ListType(new StringType()),
86
                        'resolve' => function() {
87
                            return null;
88
                        }
89
                    ]
90
                ]
91
            ])
92
        ]));
93
        $data = $processor->processPayload(' { __schema { subscriptionType { name } } }')->getResponseData();
94
        $this->assertEquals(['data' => ['__schema' => ['subscriptionType' => null]]], $data);
95
    }
96
97
    public function testSchemaOperations()
98
    {
99
        $schema    = new Schema([
100
            'query' => new ObjectType([
101
                'name'   => 'RootQuery',
102
                'fields' => [
103
                    'me'                => [
104
                        'type'    => new ObjectType([
105
                            'name'   => 'User',
106
                            'fields' => [
107
                                'firstName' => [
108
                                    'type'    => new StringType(),
109
                                    'args'    => [
110
                                        'shorten' => new BooleanType()
111
                                    ],
112
                                    'resolve' => function ($value, $args) {
113
                                        return empty($args['shorten']) ? $value : $value;
114
                                    }
115
                                ],
116
                                'lastName'  => new StringType(),
117
                                'code'      => new StringType(),
118
                            ]
119
                        ]),
120
                        'resolve' => function ($value, $args) {
121
                            $data = ['firstName' => 'John', 'code' => '007'];
122
                            if (!empty($args['upper'])) {
123
                                foreach ($data as $key => $value) {
124
                                    $data[$key] = strtoupper($value);
125
                                }
126
                            }
127
128
                            return $data;
129
                        },
130
                        'args'    => [
131
                            'upper' => [
132
                                'type'    => new BooleanType(),
133
                                'default' => false
134
                            ]
135
                        ]
136
                    ],
137
                    'randomUser'        => [
138
                        'type'    => new TestObjectType(),
139
                        'resolve' => function () {
140
                            return ['invalidField' => 'John'];
141
                        }
142
                    ],
143
                    'invalidValueQuery' => [
144
                        'type'    => new TestObjectType(),
145
                        'resolve' => function () {
146
                            return 'stringValue';
147
                        }
148
                    ],
149
                ],
150
            ])
151
        ]);
152
        $processor = new Processor($schema);
153
154
        $processor->processPayload('{ me { firstName } }');
155
        $this->assertEquals(['data' => ['me' => ['firstName' => 'John']]], $processor->getResponseData());
156
157
        $processor->processPayload('{ me { firstName, lastName } }');
158
        $this->assertEquals(['data' => ['me' => ['firstName' => 'John', 'lastName' => null]]], $processor->getResponseData());
159
160
        $processor->processPayload('{ me { code } }');
161
        $this->assertEquals(['data' => ['me' => ['code' => 7]]], $processor->getResponseData());
162
163
        $processor->processPayload('{ me(upper:true) { firstName } }');
164
        $this->assertEquals(['data' => ['me' => ['firstName' => 'JOHN']]], $processor->getResponseData());
165
166
        $schema->getMutationType()
167
               ->addField(new Field([
168
                   'name'    => 'increaseCounter',
169
                   'type'    => new IntType(),
170
                   'resolve' => function ($value, $args, ResolveInfo $info) {
0 ignored issues
show
Unused Code introduced by
The parameter $info is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
171
                       return $this->_counter += $args['amount'];
172
                   },
173
                   'args'    => [
174
                       'amount' => [
175
                           'type'    => new IntType(),
176
                           'default' => 1
177
                       ]
178
                   ]
179
               ]))->addField(new Field([
180
                'name'    => 'invalidResolveTypeMutation',
181
                'type'    => new NonNullType(new IntType()),
182
                'resolve' => function () {
183
                    return null;
184
                }
185
            ]))->addField(new Field([
186
                'name'    => 'interfacedMutation',
187
                'type'    => new TestInterfaceType(),
188
                'resolve' => function () {
189
                    return ['name' => 'John'];
190
                }
191
            ]));
192
        $processor->processPayload('mutation { increaseCounter }');
193
        $this->assertEquals(['data' => ['increaseCounter' => 1]], $processor->getResponseData());
194
195
        $processor->processPayload('mutation { invalidMutation }');
196
        $this->assertEquals(['errors' => [['message' => 'Field "invalidMutation" not found in type "RootSchemaMutation"']]], $processor->getResponseData());
197
198
        $processor->processPayload('mutation { increaseCounter(noArg: 2) }');
199
        $this->assertEquals(['errors' => [['message' => 'Unknown argument "noArg" on field "increaseCounter"']]], $processor->getResponseData());
200
201
        $processor->processPayload('mutation { increaseCounter(amount: 2) { invalidProp } }');
202
        $this->assertEquals(['errors' => [['message' => 'Field "invalidProp" not found in type "Int"']], 'data' => ['increaseCounter' => null]], $processor->getResponseData());
203
204
        $processor->processPayload('mutation { increaseCounter(amount: 2) }');
205
        $this->assertEquals(['data' => ['increaseCounter' => 5]], $processor->getResponseData());
206
207
        $processor->processPayload('{ invalidQuery }');
208
        $this->assertEquals(['errors' => [['message' => 'Field "invalidQuery" not found in type "RootQuery"']]], $processor->getResponseData());
209
210
        $processor->processPayload('{ invalidValueQuery { id } }');
211
        $this->assertEquals(['errors' => [['message' => 'Not valid value for OBJECT field invalidValueQuery']], 'data' => ['invalidValueQuery' => null]], $processor->getResponseData());
212
213
        $processor->processPayload('{ me { firstName(shorten: true), middle }}');
214
        $this->assertEquals(['errors' => [['message' => 'Field "middle" not found in type "User"']], 'data' => ['me' => null]], $processor->getResponseData());
215
216
        $processor->processPayload('{ randomUser { region }}');
217
        $this->assertEquals(['errors' => [['message' => 'Property "region" not found in resolve result']]], $processor->getResponseData());
218
219
        $processor->processPayload('mutation { invalidResolveTypeMutation }');
220
        $this->assertEquals(['errors' => [['message' => 'Cannot return null for non-nullable field invalidResolveTypeMutation']], 'data' => ['invalidResolveTypeMutation' => null]], $processor->getResponseData());
221
222
        $processor->processPayload('mutation { user:interfacedMutation { name }  }');
223
        $this->assertEquals(['data' => ['user' => ['name' => 'John']]], $processor->getResponseData());
224
    }
225
226
    public function testListEnumsSchemaOperations()
227
    {
228
        $processor = new Processor(new Schema([
229
            'query' => new ObjectType([
230
                'name'   => 'RootQuery',
231
                'fields' => [
232
                    'listQuery'                 => [
233
                        'type'    => new ListType(new TestEnumType()),
234
                        'resolve' => function () {
235
                            return 'invalid list';
236
                        }
237
                    ],
238
                    'listEnumQuery'             => [
239
                        'type'    => new ListType(new TestEnumType()),
240
                        'resolve' => function () {
241
                            return ['invalid enum'];
242
                        }
243
                    ],
244
                    'invalidEnumQuery'          => [
245
                        'type'    => new TestEnumType(),
246
                        'resolve' => function () {
247
                            return 'invalid enum';
248
                        }
249
                    ],
250
                    'enumQuery'                 => [
251
                        'type'    => new TestEnumType(),
252
                        'resolve' => function () {
253
                            return 1;
254
                        }
255
                    ],
256
                    'invalidNonNullQuery'       => [
257
                        'type'    => new NonNullType(new IntType()),
258
                        'resolve' => function () {
259
                            return null;
260
                        }
261
                    ],
262
                    'invalidNonNullInsideQuery' => [
263
                        'type'    => new NonNullType(new IntType()),
264
                        'resolve' => function () {
265
                            return 'hello';
266
                        }
267
                    ],
268
                    'objectQuery'               => [
269
                        'type'    => new TestObjectType(),
270
                        'resolve' => function () {
271
                            return ['name' => 'John'];
272
                        }
273
                    ],
274
                    'deepObjectQuery'           => [
275
                        'type'    => new ObjectType([
276
                            'name'   => 'deepObject',
277
                            'fields' => [
278
                                'object' => new TestObjectType(),
279
                                'enum'   => new TestEnumType(),
280
                            ],
281
                        ]),
282
                        'resolve' => function () {
283
                            return [
284
                                'object' => [
285
                                    'name' => 'John'
286
                                ],
287
                                'enum'   => 1
288
                            ];
289
                        },
290
                    ],
291
                ]
292
            ])
293
        ]));
294
295
        $processor->processPayload('{ listQuery }');
296
        $this->assertEquals(['errors' => [
297
            ['message' => 'Not valid value for LIST field listQuery']
298
        ], 'data'                     => ['listQuery' => null]], $processor->getResponseData());
299
300
        $processor->processPayload('{ listEnumQuery }');
301
        $this->assertEquals(['errors' => [
302
            ['message' => 'Not valid resolve value in listEnumQuery field']
303
        ], 'data'                     => ['listEnumQuery' => [null]]], $processor->getResponseData());
304
305
        $processor->processPayload('{ invalidEnumQuery }');
306
        $this->assertEquals(['errors' => [
307
            ['message' => 'Not valid value for ENUM field invalidEnumQuery']
308
        ], 'data'                     => ['invalidEnumQuery' => null]], $processor->getResponseData());
309
310
        $processor->processPayload('{ enumQuery }');
311
        $this->assertEquals(['data' => ['enumQuery' => 'FINISHED']], $processor->getResponseData());
312
313
        $processor->processPayload('{ invalidNonNullQuery }');
314
        $this->assertEquals(['errors' => [
315
            ['message' => 'Cannot return null for non-nullable field invalidNonNullQuery']
316
        ], 'data'                     => ['invalidNonNullQuery' => null]], $processor->getResponseData());
317
318
        $processor->processPayload('{ invalidNonNullInsideQuery }');
319
        $this->assertEquals(['errors' => [
320
            ['message' => 'Not valid value for SCALAR field invalidNonNullInsideQuery']
321
        ], 'data'                     => ['invalidNonNullInsideQuery' => null]], $processor->getResponseData());
322
323
        $processor->processPayload('{ test:deepObjectQuery { object { name } } }');
324
        $this->assertEquals(['data' => ['test' => ['object' => ['name' => 'John']]]], $processor->getResponseData());
325
    }
326
327
    public function testTypedFragment()
328
    {
329
330
        $object1 = new ObjectType([
331
            'name'   => 'Object1',
332
            'fields' => [
333
                'id' => ['type' => 'int']
334
            ]
335
        ]);
336
337
        $object2 = new ObjectType([
338
            'name'   => 'Object2',
339
            'fields' => [
340
                'name' => ['type' => 'string']
341
            ]
342
        ]);
343
344
        $object3 = new ObjectType([
345
            'name'   => 'Object3',
346
            'fields' => [
347
                'name' => ['type' => 'string']
348
            ]
349
        ]);
350
351
        $union        = new UnionType([
352
            'name'        => 'TestUnion',
353
            'types'       => [$object1, $object2],
354
            'resolveType' => function ($object) use ($object1, $object2) {
355
                if (isset($object['id'])) {
356
                    return $object1;
357
                }
358
359
                return $object2;
360
            }
361
        ]);
362
        $invalidUnion = new UnionType([
363
            'name'        => 'TestUnion',
364
            'types'       => [$object1, $object2],
365
            'resolveType' => function ($object) use ($object3) {
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
366
                return $object3;
367
            }
368
        ]);
369
        $processor    = new Processor(new Schema([
370
            'query' => new ObjectType([
371
                'name'   => 'RootQuery',
372
                'fields' => [
373
                    'union'        => [
374
                        'type'    => $union,
375
                        'args'    => [
376
                            'type' => ['type' => 'string']
377
                        ],
378
                        'resolve' => function ($value, $args) {
379
                            if ($args['type'] == 'object1') {
380
                                return [
381
                                    'id' => 43
382
                                ];
383
                            } else {
384
                                return [
385
                                    'name' => 'name resolved'
386
                                ];
387
                            }
388
                        }
389
                    ],
390
                    'invalidUnion' => [
391
                        'type'    => $invalidUnion,
392
                        'resolve' => function () {
393
                            return ['name' => 'name resolved'];
394
                        }
395
                    ],
396
                ]
397
            ])
398
        ]));
399
        $processor->processPayload('{ union(type: "object1") { ... on Object2 { id } } }');
400
        $this->assertEquals(['data' => ['union' => []]], $processor->getResponseData());
401
402
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { name } } }');
403
        $this->assertEquals([
404
            'data'   => [
405
                'union' => []
406
            ],
407
            'errors' => [
408
                ['message' => 'Field "name" not found in type "Object1"']
409
            ]
410
        ], $processor->getResponseData());
411
412
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { id } } }');
413
        $this->assertEquals(['data' => ['union' => ['id' => 43]]], $processor->getResponseData());
414
415
        $processor->processPayload('{ union(type: "asd") { ... on Object2 { name } } }');
416
        $this->assertEquals(['data' => ['union' => ['name' => 'name resolved']]], $processor->getResponseData());
417
418
        $processor->processPayload('{ invalidUnion { ... on Object2 { name } } }');
419
        $this->assertEquals(['errors' => [['message' => 'Type Object3 not exist in types of Object2']]], $processor->getResponseData());
420
421
    }
422
423
424
}
425