Completed
Pull Request — master (#19)
by Daniel
03:45
created

ProcessorTest::testSchemaOperations()   B

Complexity

Conditions 4
Paths 1

Size

Total Lines 128
Code Lines 86

Duplication

Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 3 Features 1
Metric Value
c 12
b 3
f 1
dl 0
loc 128
rs 8.1935
cc 4
eloc 86
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\ResolveStringResolverInterface;
14
use Youshido\GraphQL\Execution\ResolveInfo;
15
use Youshido\GraphQL\Field\Field;
16
use Youshido\GraphQL\Schema\Schema;
17
use Youshido\GraphQL\Type\ListType\ListType;
18
use Youshido\GraphQL\Type\NonNullType;
19
use Youshido\GraphQL\Type\Object\ObjectType;
20
use Youshido\GraphQL\Type\Scalar\BooleanType;
21
use Youshido\GraphQL\Type\Scalar\IntType;
22
use Youshido\GraphQL\Type\Scalar\StringType;
23
use Youshido\GraphQL\Type\Union\UnionType;
24
use Youshido\Tests\DataProvider\TestEmptySchema;
25
use Youshido\Tests\DataProvider\TestEnumType;
26
use Youshido\Tests\DataProvider\TestInterfaceType;
27
use Youshido\Tests\DataProvider\TestObjectType;
28
use Youshido\Tests\DataProvider\TestSchema;
29
30
class ProcessorTest extends \PHPUnit_Framework_TestCase
31
{
32
33
    private $_counter = 0;
34
35
    /**
36
     * @expectedException \Youshido\GraphQL\Validator\Exception\ConfigurationException
37
     * @expectedExceptionMessage Schema has to have fields
38
     */
39
    public function testInit()
40
    {
41
        new Processor(new TestEmptySchema());
42
    }
43
44
    public function testEmptyQueries()
45
    {
46
        $processor = new Processor(new TestSchema());
47
        $processor->processPayload('');
48
        $this->assertEquals(['errors' => [
49
            ['message' => 'Must provide an operation.']
50
        ]], $processor->getResponseData());
51
52
        $processor->processPayload('{ me { name } }');
53
        $this->assertEquals(['data' => [
54
            'me' => ['name' => 'John']
55
        ]], $processor->getResponseData());
56
57
    }
58
59
  public function testNestedVariables() {
60
    $processor = new Processor(new TestSchema());
61
    $noArgsQuery = '{ me { echo(value:"foo") } }';
62
    $expectedData = ['data' => ['me' => ['echo' => 'foo']]];
63
    $processor->processPayload($noArgsQuery, ['value' => 'foo']);
64
    $this->assertEquals($expectedData, $processor->getResponseData());
65
66
    $parameterizedFieldQuery =
67
        'query nestedFieldQuery($value:String!){
68
          me {
69
            echo(value:$value)
70
          }
71
        }';
72
    $processor->processPayload($parameterizedFieldQuery, ['value' => 'foo']);
73
    $this->assertEquals($expectedData, $processor->getResponseData());
74
75
    $parameterizedQueryQuery =
76
        'query nestedQueryQuery($value:Int){
77
          me {
78
            location(noop:$value) {
79
              address
80
            }
81
          }
82
        }';
83
    $processor->processPayload($parameterizedQueryQuery, ['value' => 1]);
84
    $this->assertArrayNotHasKey('errors', $processor->getResponseData());
85
  }
86
87 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...
88
    {
89
        $processor = new Processor(new Schema([
90
            'query' => new ObjectType([
91
                'name' => 'RootQuery',
92
                'fields' => [
93
                    'list' => [
94
                        'type' => new ListType(new StringType()),
95
                        'resolve' => function() {
96
                            return null;
97
                        }
98
                    ]
99
                ]
100
            ])
101
        ]));
102
        $data = $processor->processPayload(' { list }')->getResponseData();
103
        $this->assertEquals(['data' => ['list' => null]], $data);
104
    }
105
106
107 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...
108
    {
109
        $processor = new Processor(new Schema([
110
            'query' => new ObjectType([
111
                'name' => 'RootQuery',
112
                'fields' => [
113
                    'list' => [
114
                        'type' => new ListType(new StringType()),
115
                        'resolve' => function() {
116
                            return null;
117
                        }
118
                    ]
119
                ]
120
            ])
121
        ]));
122
        $data = $processor->processPayload(' { __schema { subscriptionType { name } } }')->getResponseData();
123
        $this->assertEquals(['data' => ['__schema' => ['subscriptionType' => null]]], $data);
124
    }
125
126
    public function testSchemaOperations()
127
    {
128
        $schema    = new Schema([
129
            'query' => new ObjectType([
130
                'name'   => 'RootQuery',
131
                'fields' => [
132
                    'me'                => [
133
                        'type'    => new ObjectType([
134
                            'name'   => 'User',
135
                            'fields' => [
136
                                'firstName' => [
137
                                    'type'    => new StringType(),
138
                                    'args'    => [
139
                                        'shorten' => new BooleanType()
140
                                    ],
141
                                    'resolve' => function ($value, $args) {
142
                                        return empty($args['shorten']) ? $value : $value;
143
                                    }
144
                                ],
145
                                'lastName'  => new StringType(),
146
                                'code'      => new StringType(),
147
                            ]
148
                        ]),
149
                        'resolve' => function ($value, $args) {
150
                            $data = ['firstName' => 'John', 'code' => '007'];
151
                            if (!empty($args['upper'])) {
152
                                foreach ($data as $key => $value) {
153
                                    $data[$key] = strtoupper($value);
154
                                }
155
                            }
156
157
                            return $data;
158
                        },
159
                        'args'    => [
160
                            'upper' => [
161
                                'type'    => new BooleanType(),
162
                                'default' => false
163
                            ]
164
                        ]
165
                    ],
166
                    'randomUser'        => [
167
                        'type'    => new TestObjectType(),
168
                        'resolve' => function () {
169
                            return ['invalidField' => 'John'];
170
                        }
171
                    ],
172
                    'invalidValueQuery' => [
173
                        'type'    => new TestObjectType(),
174
                        'resolve' => function () {
175
                            return 'stringValue';
176
                        }
177
                    ],
178
                ],
179
            ])
180
        ]);
181
        $processor = new Processor($schema);
182
183
        $processor->processPayload('{ me { firstName } }');
184
        $this->assertEquals(['data' => ['me' => ['firstName' => 'John']]], $processor->getResponseData());
185
186
        $processor->processPayload('{ me { firstName, lastName } }');
187
        $this->assertEquals(['data' => ['me' => ['firstName' => 'John', 'lastName' => null]]], $processor->getResponseData());
188
189
        $processor->processPayload('{ me { code } }');
190
        $this->assertEquals(['data' => ['me' => ['code' => 7]]], $processor->getResponseData());
191
192
        $processor->processPayload('{ me(upper:true) { firstName } }');
193
        $this->assertEquals(['data' => ['me' => ['firstName' => 'JOHN']]], $processor->getResponseData());
194
195
        $schema->getMutationType()
196
               ->addField(new Field([
197
                   'name'    => 'increaseCounter',
198
                   'type'    => new IntType(),
199
                   '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...
200
                       return $this->_counter += $args['amount'];
201
                   },
202
                   'args'    => [
203
                       'amount' => [
204
                           'type'    => new IntType(),
205
                           'default' => 1
206
                       ]
207
                   ]
208
               ]))->addField(new Field([
209
                'name'    => 'invalidResolveTypeMutation',
210
                'type'    => new NonNullType(new IntType()),
211
                'resolve' => function () {
212
                    return null;
213
                }
214
            ]))->addField(new Field([
215
                'name'    => 'interfacedMutation',
216
                'type'    => new TestInterfaceType(),
217
                'resolve' => function () {
218
                    return ['name' => 'John'];
219
                }
220
            ]));
221
        $processor->processPayload('mutation { increaseCounter }');
222
        $this->assertEquals(['data' => ['increaseCounter' => 1]], $processor->getResponseData());
223
224
        $processor->processPayload('mutation { invalidMutation }');
225
        $this->assertEquals(['errors' => [['message' => 'Field "invalidMutation" not found in type "RootSchemaMutation"']]], $processor->getResponseData());
226
227
        $processor->processPayload('mutation { increaseCounter(noArg: 2) }');
228
        $this->assertEquals(['errors' => [['message' => 'Unknown argument "noArg" on field "increaseCounter"']]], $processor->getResponseData());
229
230
        $processor->processPayload('mutation { increaseCounter(amount: 2) { invalidProp } }');
231
        $this->assertEquals(['errors' => [['message' => 'Field "invalidProp" not found in type "Int"']], 'data' => ['increaseCounter' => null]], $processor->getResponseData());
232
233
        $processor->processPayload('mutation { increaseCounter(amount: 2) }');
234
        $this->assertEquals(['data' => ['increaseCounter' => 5]], $processor->getResponseData());
235
236
        $processor->processPayload('{ invalidQuery }');
237
        $this->assertEquals(['errors' => [['message' => 'Field "invalidQuery" not found in type "RootQuery"']]], $processor->getResponseData());
238
239
        $processor->processPayload('{ invalidValueQuery { id } }');
240
        $this->assertEquals(['errors' => [['message' => 'Not valid value for OBJECT field invalidValueQuery']], 'data' => ['invalidValueQuery' => null]], $processor->getResponseData());
241
242
        $processor->processPayload('{ me { firstName(shorten: true), middle }}');
243
        $this->assertEquals(['errors' => [['message' => 'Field "middle" not found in type "User"']], 'data' => ['me' => null]], $processor->getResponseData());
244
245
        $processor->processPayload('{ randomUser { region }}');
246
        $this->assertEquals(['errors' => [['message' => 'Property "region" not found in resolve result']]], $processor->getResponseData());
247
248
        $processor->processPayload('mutation { invalidResolveTypeMutation }');
249
        $this->assertEquals(['errors' => [['message' => 'Cannot return null for non-nullable field invalidResolveTypeMutation']], 'data' => ['invalidResolveTypeMutation' => null]], $processor->getResponseData());
250
251
        $processor->processPayload('mutation { user:interfacedMutation { name }  }');
252
        $this->assertEquals(['data' => ['user' => ['name' => 'John']]], $processor->getResponseData());
253
    }
254
255
    public function testListEnumsSchemaOperations()
256
    {
257
        $processor = new Processor(new Schema([
258
            'query' => new ObjectType([
259
                'name'   => 'RootQuery',
260
                'fields' => [
261
                    'listQuery'                 => [
262
                        'type'    => new ListType(new TestEnumType()),
263
                        'resolve' => function () {
264
                            return 'invalid list';
265
                        }
266
                    ],
267
                    'listEnumQuery'             => [
268
                        'type'    => new ListType(new TestEnumType()),
269
                        'resolve' => function () {
270
                            return ['invalid enum'];
271
                        }
272
                    ],
273
                    'invalidEnumQuery'          => [
274
                        'type'    => new TestEnumType(),
275
                        'resolve' => function () {
276
                            return 'invalid enum';
277
                        }
278
                    ],
279
                    'enumQuery'                 => [
280
                        'type'    => new TestEnumType(),
281
                        'resolve' => function () {
282
                            return 1;
283
                        }
284
                    ],
285
                    'invalidNonNullQuery'       => [
286
                        'type'    => new NonNullType(new IntType()),
287
                        'resolve' => function () {
288
                            return null;
289
                        }
290
                    ],
291
                    'invalidNonNullInsideQuery' => [
292
                        'type'    => new NonNullType(new IntType()),
293
                        'resolve' => function () {
294
                            return 'hello';
295
                        }
296
                    ],
297
                    'objectQuery'               => [
298
                        'type'    => new TestObjectType(),
299
                        'resolve' => function () {
300
                            return ['name' => 'John'];
301
                        }
302
                    ],
303
                    'deepObjectQuery'           => [
304
                        'type'    => new ObjectType([
305
                            'name'   => 'deepObject',
306
                            'fields' => [
307
                                'object' => new TestObjectType(),
308
                                'enum'   => new TestEnumType(),
309
                            ],
310
                        ]),
311
                        'resolve' => function () {
312
                            return [
313
                                'object' => [
314
                                    'name' => 'John'
315
                                ],
316
                                'enum'   => 1
317
                            ];
318
                        },
319
                    ],
320
                ]
321
            ])
322
        ]));
323
324
        $processor->processPayload('{ listQuery }');
325
        $this->assertEquals(['errors' => [
326
            ['message' => 'Not valid value for LIST field listQuery']
327
        ], 'data'                     => ['listQuery' => null]], $processor->getResponseData());
328
329
        $processor->processPayload('{ listEnumQuery }');
330
        $this->assertEquals(['errors' => [
331
            ['message' => 'Not valid resolve value in listEnumQuery field']
332
        ], 'data'                     => ['listEnumQuery' => [null]]], $processor->getResponseData());
333
334
        $processor->processPayload('{ invalidEnumQuery }');
335
        $this->assertEquals(['errors' => [
336
            ['message' => 'Not valid value for ENUM field invalidEnumQuery']
337
        ], 'data'                     => ['invalidEnumQuery' => null]], $processor->getResponseData());
338
339
        $processor->processPayload('{ enumQuery }');
340
        $this->assertEquals(['data' => ['enumQuery' => 'FINISHED']], $processor->getResponseData());
341
342
        $processor->processPayload('{ invalidNonNullQuery }');
343
        $this->assertEquals(['errors' => [
344
            ['message' => 'Cannot return null for non-nullable field invalidNonNullQuery']
345
        ], 'data'                     => ['invalidNonNullQuery' => null]], $processor->getResponseData());
346
347
        $processor->processPayload('{ invalidNonNullInsideQuery }');
348
        $this->assertEquals(['errors' => [
349
            ['message' => 'Not valid value for SCALAR field invalidNonNullInsideQuery']
350
        ], 'data'                     => ['invalidNonNullInsideQuery' => null]], $processor->getResponseData());
351
352
        $processor->processPayload('{ test:deepObjectQuery { object { name } } }');
353
        $this->assertEquals(['data' => ['test' => ['object' => ['name' => 'John']]]], $processor->getResponseData());
354
    }
355
356
    public function testTypedFragment()
357
    {
358
359
        $object1 = new ObjectType([
360
            'name'   => 'Object1',
361
            'fields' => [
362
                'id' => ['type' => 'int']
363
            ]
364
        ]);
365
366
        $object2 = new ObjectType([
367
            'name'   => 'Object2',
368
            'fields' => [
369
                'name' => ['type' => 'string']
370
            ]
371
        ]);
372
373
        $object3 = new ObjectType([
374
            'name'   => 'Object3',
375
            'fields' => [
376
                'name' => ['type' => 'string']
377
            ]
378
        ]);
379
380
        $union        = new UnionType([
381
            'name'        => 'TestUnion',
382
            'types'       => [$object1, $object2],
383
            'resolveType' => function ($object) use ($object1, $object2) {
384
                if (isset($object['id'])) {
385
                    return $object1;
386
                }
387
388
                return $object2;
389
            }
390
        ]);
391
        $invalidUnion = new UnionType([
392
            'name'        => 'TestUnion',
393
            'types'       => [$object1, $object2],
394
            '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...
395
                return $object3;
396
            }
397
        ]);
398
        $processor    = new Processor(new Schema([
399
            'query' => new ObjectType([
400
                'name'   => 'RootQuery',
401
                'fields' => [
402
                    'union'        => [
403
                        'type'    => $union,
404
                        'args'    => [
405
                            'type' => ['type' => 'string']
406
                        ],
407
                        'resolve' => function ($value, $args) {
408
                            if ($args['type'] == 'object1') {
409
                                return [
410
                                    'id' => 43
411
                                ];
412
                            } else {
413
                                return [
414
                                    'name' => 'name resolved'
415
                                ];
416
                            }
417
                        }
418
                    ],
419
                    'invalidUnion' => [
420
                        'type'    => $invalidUnion,
421
                        'resolve' => function () {
422
                            return ['name' => 'name resolved'];
423
                        }
424
                    ],
425
                ]
426
            ])
427
        ]));
428
        $processor->processPayload('{ union(type: "object1") { ... on Object2 { id } } }');
429
        $this->assertEquals(['data' => ['union' => []]], $processor->getResponseData());
430
431
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { name } } }');
432
        $this->assertEquals([
433
            'data'   => [
434
                'union' => []
435
            ],
436
            'errors' => [
437
                ['message' => 'Field "name" not found in type "Object1"']
438
            ]
439
        ], $processor->getResponseData());
440
441
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { id } } }');
442
        $this->assertEquals(['data' => ['union' => ['id' => 43]]], $processor->getResponseData());
443
444
        $processor->processPayload('{ union(type: "asd") { ... on Object2 { name } } }');
445
        $this->assertEquals(['data' => ['union' => ['name' => 'name resolved']]], $processor->getResponseData());
446
447
        $processor->processPayload('{ invalidUnion { ... on Object2 { name } } }');
448
        $this->assertEquals(['errors' => [['message' => 'Type Object3 not exist in types of Object2']]], $processor->getResponseData());
449
450
    }
451
452
    public function testSchemaWithResolveString()
453
    {
454
        $resolveFactory = $this->prophesize(ResolveStringResolverInterface::class);
455
        $resolveFactory->resolve('service_name:get')
456
            ->shouldBeCalled()
457
            ->willReturn(function () {
458
                return 'hello';
459
            });
460
461
        $processor = new Processor(new Schema([
462
            'query' => new ObjectType([
463
                'name' => 'RootQuery',
464
                'fields' => [
465
                    'string' => [
466
                        'type' => new StringType(),
467
                        'resolveString' => 'service_name:get',
468
                    ]
469
                ]
470
            ])
471
        ]), $resolveFactory->reveal());
472
        $data = $processor->processPayload(' { string }')->getResponseData();
473
        $this->assertEquals(['data' => ['string' => 'hello']], $data);
474
    }
475
476
477
}
478