Completed
Push — master ( 9e787e...177394 )
by Vladimir
25s queued 13s
created

VariablesTest::testUsingStdClassVariables()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 15
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Tests\Executor;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Executor\Executor;
9
use GraphQL\Language\Parser;
10
use GraphQL\Tests\Executor\TestClasses\ComplexScalar;
11
use GraphQL\Type\Definition\InputObjectType;
12
use GraphQL\Type\Definition\ObjectType;
13
use GraphQL\Type\Definition\Type;
14
use GraphQL\Type\Schema;
15
use PHPUnit\Framework\TestCase;
16
use function json_encode;
17
18
/**
19
 * Execute: Handles inputs
20
 * Handles objects and nullability
21
 */
22
class VariablesTest extends TestCase
23
{
24
    public function testUsingInlineStructs() : void
25
    {
26
        // executes with complex input:
27
        $result = $this->executeQuery('
28
        {
29
          fieldWithObjectInput(input: {a: "foo", b: ["bar"], c: "baz"})
30
        }
31
        ');
32
33
        $expected = [
34
            'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'],
35
        ];
36
        self::assertEquals($expected, $result->toArray());
0 ignored issues
show
Bug introduced by
The method toArray() does not exist on GraphQL\Executor\Promise\Promise. ( Ignorable by Annotation )

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

36
        self::assertEquals($expected, $result->/** @scrutinizer ignore-call */ toArray());

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...
37
38
        // properly parses single value to list:
39
        $result   = $this->executeQuery('
40
        {
41
          fieldWithObjectInput(input: {a: "foo", b: "bar", c: "baz"})
42
        }
43
        ');
44
        $expected = ['data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}']];
45
46
        self::assertEquals($expected, $result->toArray());
47
48
        // properly parses null value to null
49
        $result   = $this->executeQuery('
50
        {
51
          fieldWithObjectInput(input: {a: null, b: null, c: "C", d: null})
52
        }
53
        ');
54
        $expected = ['data' => ['fieldWithObjectInput' => '{"a":null,"b":null,"c":"C","d":null}']];
55
56
        self::assertEquals($expected, $result->toArray());
57
58
        // properly parses null value in list
59
        $result   = $this->executeQuery('
60
        {
61
          fieldWithObjectInput(input: {b: ["A",null,"C"], c: "C"})
62
        }
63
        ');
64
        $expected = ['data' => ['fieldWithObjectInput' => '{"b":["A",null,"C"],"c":"C"}']];
65
66
        self::assertEquals($expected, $result->toArray());
67
68
        // does not use incorrect value
69
        $result = $this->executeQuery('
70
        {
71
          fieldWithObjectInput(input: ["foo", "bar", "baz"])
72
        }
73
        ');
74
75
        $expected = [
76
            'data'   => ['fieldWithObjectInput' => null],
77
            'errors' => [[
78
                'message'   => 'Argument "input" has invalid value ["foo", "bar", "baz"].',
79
                'path'      => ['fieldWithObjectInput'],
80
                'locations' => [['line' => 3, 'column' => 39]],
81
            ],
82
            ],
83
        ];
84
        self::assertArraySubset($expected, $result->toArray());
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertArraySubset() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3494 ( Ignorable by Annotation )

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

84
        /** @scrutinizer ignore-deprecated */ self::assertArraySubset($expected, $result->toArray());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
85
86
        // properly runs parseLiteral on complex scalar types
87
        $result = $this->executeQuery('
88
        {
89
          fieldWithObjectInput(input: {c: "foo", d: "SerializedValue"})
90
        }
91
        ');
92
        self::assertEquals(
93
            ['data' => ['fieldWithObjectInput' => '{"c":"foo","d":"DeserializedValue"}']],
94
            $result->toArray()
95
        );
96
    }
97
98
    private function executeQuery($query, $variableValues = null)
99
    {
100
        $document = Parser::parse($query);
101
102
        return Executor::execute($this->schema(), $document, null, null, $variableValues);
103
    }
104
105
    /**
106
     * Describe: Handles nullable scalars
107
     */
108
    public function schema() : Schema
109
    {
110
        $ComplexScalarType = ComplexScalar::create();
111
112
        $TestInputObject = new InputObjectType([
113
            'name'   => 'TestInputObject',
114
            'fields' => [
115
                'a' => ['type' => Type::string()],
116
                'b' => ['type' => Type::listOf(Type::string())],
117
                'c' => ['type' => Type::nonNull(Type::string())],
118
                'd' => ['type' => $ComplexScalarType],
119
            ],
120
        ]);
121
122
        $TestNestedInputObject = new InputObjectType([
123
            'name'   => 'TestNestedInputObject',
124
            'fields' => [
125
                'na' => ['type' => Type::nonNull($TestInputObject)],
126
                'nb' => ['type' => Type::nonNull(Type::string())],
127
            ],
128
        ]);
129
130
        $TestType = new ObjectType([
131
            'name'   => 'TestType',
132
            'fields' => [
133
                'fieldWithObjectInput'            => $this->fieldWithInputArg(['type' => $TestInputObject]),
134
                'fieldWithNullableStringInput'    => $this->fieldWithInputArg(['type' => Type::string()]),
135
                'fieldWithNonNullableStringInput' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::string())]),
136
                'fieldWithDefaultArgumentValue'   => $this->fieldWithInputArg([
137
                    'type'         => Type::string(),
138
                    'defaultValue' => 'Hello World',
139
                ]),
140
                'fieldWithNestedInputObject'      => $this->fieldWithInputArg([
141
                    'type'         => $TestNestedInputObject,
142
                    'defaultValue' => 'Hello World',
143
                ]),
144
                'list'                            => $this->fieldWithInputArg(['type' => Type::listOf(Type::string())]),
145
                'nnList'                          => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::string()))]),
146
                'listNN'                          => $this->fieldWithInputArg(['type' => Type::listOf(Type::nonNull(Type::string()))]),
147
                'nnListNN'                        => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))]),
148
            ],
149
        ]);
150
151
        return new Schema(['query' => $TestType]);
152
    }
153
154
    private function fieldWithInputArg($inputArg)
155
    {
156
        return [
157
            'type'    => Type::string(),
158
            'args'    => ['input' => $inputArg],
159
            'resolve' => static function ($_, $args) {
160
                if (isset($args['input'])) {
161
                    return json_encode($args['input']);
162
                }
163
164
                return null;
165
            },
166
        ];
167
    }
168
169
    public function testUsingVariables() : void
170
    {
171
        $doc = '
172
            query q($input:TestInputObject) {
173
              fieldWithObjectInput(input: $input)
174
            }
175
        ';
176
177
        // executes with complex input:
178
        $params = ['input' => ['a' => 'foo', 'b' => ['bar'], 'c' => 'baz']];
179
        $result = $this->executeQuery($doc, $params);
180
181
        self::assertEquals(
182
            ['data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}']],
183
            $result->toArray()
184
        );
185
186
        // uses default value when not provided:
187
        $result = $this->executeQuery('
188
          query ($input: TestInputObject = {a: "foo", b: ["bar"], c: "baz"}) {
189
            fieldWithObjectInput(input: $input)
190
          }
191
        ');
192
193
        $expected = [
194
            'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'],
195
        ];
196
        self::assertEquals($expected, $result->toArray());
197
198
        // properly parses single value to list:
199
        $params = ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz']];
200
        $result = $this->executeQuery($doc, $params);
201
        self::assertEquals(
202
            ['data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}']],
203
            $result->toArray()
204
        );
205
206
        // executes with complex scalar input:
207
        $params   = ['input' => ['c' => 'foo', 'd' => 'SerializedValue']];
208
        $result   = $this->executeQuery($doc, $params);
209
        $expected = [
210
            'data' => ['fieldWithObjectInput' => '{"c":"foo","d":"DeserializedValue"}'],
211
        ];
212
        self::assertEquals($expected, $result->toArray());
213
214
        // errors on null for nested non-null:
215
        $params   = ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => null]];
216
        $result   = $this->executeQuery($doc, $params);
217
        $expected = [
218
            'errors' => [
219
                [
220
                    'message'   =>
221
                        'Variable "$input" got invalid value ' .
222
                        '{"a":"foo","b":"bar","c":null}; ' .
223
                        'Expected non-nullable type String! not to be null at value.c.',
224
                    'locations' => [['line' => 2, 'column' => 21]],
225
                    'extensions' => ['category' => 'graphql'],
226
                ],
227
            ],
228
        ];
229
230
        self::assertEquals($expected, $result->toArray());
231
232
        // errors on incorrect type:
233
        $params   = ['input' => 'foo bar'];
234
        $result   = $this->executeQuery($doc, $params);
235
        $expected = [
236
            'errors' => [
237
                [
238
                    'message'   =>
239
                        'Variable "$input" got invalid value "foo bar"; ' .
240
                        'Expected type TestInputObject to be an object.',
241
                    'locations' => [['line' => 2, 'column' => 21]],
242
                    'extensions' => ['category' => 'graphql'],
243
                ],
244
            ],
245
        ];
246
        self::assertEquals($expected, $result->toArray());
247
248
        // errors on omission of nested non-null:
249
        $params = ['input' => ['a' => 'foo', 'b' => 'bar']];
250
251
        $result   = $this->executeQuery($doc, $params);
252
        $expected = [
253
            'errors' => [
254
                [
255
                    'message'   =>
256
                        'Variable "$input" got invalid value {"a":"foo","b":"bar"}; ' .
257
                        'Field value.c of required type String! was not provided.',
258
                    'locations' => [['line' => 2, 'column' => 21]],
259
                    'extensions' => ['category' => 'graphql'],
260
                ],
261
            ],
262
        ];
263
        self::assertEquals($expected, $result->toArray());
264
265
        // errors on deep nested errors and with many errors
266
        $nestedDoc = '
267
          query q($input: TestNestedInputObject) {
268
            fieldWithNestedObjectInput(input: $input)
269
          }
270
        ';
271
        $params    = ['input' => ['na' => ['a' => 'foo']]];
272
273
        $result   = $this->executeQuery($nestedDoc, $params);
274
        $expected = [
275
            'errors' => [
276
                [
277
                    'message'   =>
278
                        'Variable "$input" got invalid value {"na":{"a":"foo"}}; ' .
279
                        'Field value.na.c of required type String! was not provided.',
280
                    'locations' => [['line' => 2, 'column' => 19]],
281
                    'extensions' => ['category' => 'graphql'],
282
                ],
283
                [
284
                    'message'   =>
285
                        'Variable "$input" got invalid value {"na":{"a":"foo"}}; ' .
286
                        'Field value.nb of required type String! was not provided.',
287
                    'locations' => [['line' => 2, 'column' => 19]],
288
                    'extensions' => ['category' => 'graphql'],
289
                ],
290
            ],
291
        ];
292
        self::assertEquals($expected, $result->toArray());
293
294
        // errors on addition of unknown input field
295
        $params   = ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'extra' => 'dog']];
296
        $result   = $this->executeQuery($doc, $params);
297
        $expected = [
298
            'errors' => [
299
                [
300
                    'message'   =>
301
                        'Variable "$input" got invalid value ' .
302
                        '{"a":"foo","b":"bar","c":"baz","extra":"dog"}; ' .
303
                        'Field "extra" is not defined by type TestInputObject.',
304
                    'locations' => [['line' => 2, 'column' => 21]],
305
                    'extensions' => ['category' => 'graphql'],
306
                ],
307
            ],
308
        ];
309
        self::assertEquals($expected, $result->toArray());
310
    }
311
312
    public function testUsingStdClassVariables() : void
313
    {
314
        $doc = '
315
            query q($input:TestNestedInputObject) {
316
                fieldWithNestedInputObject(input: $input)
317
            }
318
        ';
319
320
        // executes with complex input:
321
        $params = ['input' => (object) ['na' => (object) ['a' => 'foo', 'b' => ['bar'], 'c' => 'baz'], 'nb' => 'test']];
322
        $result = $this->executeQuery($doc, $params);
323
324
        self::assertEquals(
325
            ['data' => ['fieldWithNestedInputObject' => '{"na":{"a":"foo","b":["bar"],"c":"baz"},"nb":"test"}']],
326
            $result->toArray()
327
        );
328
    }
329
330
    /**
331
     * @see it('allows nullable inputs to be omitted')
332
     */
333
    public function testAllowsNullableInputsToBeOmitted() : void
334
    {
335
        $result   = $this->executeQuery('
336
      {
337
        fieldWithNullableStringInput
338
      }
339
        ');
340
        $expected = [
341
            'data' => ['fieldWithNullableStringInput' => null],
342
        ];
343
344
        self::assertEquals($expected, $result->toArray());
345
    }
346
347
    /**
348
     * @see it('allows nullable inputs to be omitted in a variable')
349
     */
350
    public function testAllowsNullableInputsToBeOmittedInAVariable() : void
351
    {
352
        $result   = $this->executeQuery('
353
      query SetsNullable($value: String) {
354
        fieldWithNullableStringInput(input: $value)
355
      }
356
        ');
357
        $expected = ['data' => ['fieldWithNullableStringInput' => null]];
358
359
        self::assertEquals($expected, $result->toArray());
360
    }
361
362
    /**
363
     * @see it('allows nullable inputs to be omitted in an unlisted variable')
364
     */
365
    public function testAllowsNullableInputsToBeOmittedInAnUnlistedVariable() : void
366
    {
367
        $result   = $this->executeQuery('
368
      query SetsNullable {
369
        fieldWithNullableStringInput(input: $value)
370
      }
371
      ');
372
        $expected = ['data' => ['fieldWithNullableStringInput' => null]];
373
        self::assertEquals($expected, $result->toArray());
374
    }
375
376
    // Describe: Handles non-nullable scalars
377
378
    /**
379
     * @see it('allows nullable inputs to be set to null in a variable')
380
     */
381
    public function testAllowsNullableInputsToBeSetToNullInAVariable() : void
382
    {
383
        $result   = $this->executeQuery('
384
      query SetsNullable($value: String) {
385
        fieldWithNullableStringInput(input: $value)
386
      }
387
        ');
388
        $expected = ['data' => ['fieldWithNullableStringInput' => null]];
389
390
        self::assertEquals($expected, $result->toArray());
391
    }
392
393
    /**
394
     * @see it('allows nullable inputs to be set to a value in a variable')
395
     */
396
    public function testAllowsNullableInputsToBeSetToAValueInAVariable() : void
397
    {
398
        $doc      = '
399
      query SetsNullable($value: String) {
400
        fieldWithNullableStringInput(input: $value)
401
      }
402
        ';
403
        $result   = $this->executeQuery($doc, ['value' => 'a']);
404
        $expected = ['data' => ['fieldWithNullableStringInput' => '"a"']];
405
        self::assertEquals($expected, $result->toArray());
406
    }
407
408
    /**
409
     * @see it('allows nullable inputs to be set to a value directly')
410
     */
411
    public function testAllowsNullableInputsToBeSetToAValueDirectly() : void
412
    {
413
        $result   = $this->executeQuery('
414
      {
415
        fieldWithNullableStringInput(input: "a")
416
      }
417
        ');
418
        $expected = ['data' => ['fieldWithNullableStringInput' => '"a"']];
419
        self::assertEquals($expected, $result->toArray());
420
    }
421
422
    /**
423
     * @see it('allows non-nullable inputs to be omitted given a default')
424
     */
425
    public function testAllowsNonNullableInputsToBeOmittedGivenADefault() : void
426
    {
427
        $result   = $this->executeQuery('
428
        query SetsNonNullable($value: String = "default") {
429
          fieldWithNonNullableStringInput(input: $value)
430
        }
431
        ');
432
        $expected = [
433
            'data' => ['fieldWithNonNullableStringInput' => '"default"'],
434
        ];
435
        self::assertEquals($expected, $result->toArray());
436
    }
437
438
    /**
439
     * @see it('does not allow non-nullable inputs to be omitted in a variable')
440
     */
441
    public function testDoesntAllowNonNullableInputsToBeOmittedInAVariable() : void
442
    {
443
        $result = $this->executeQuery('
444
        query SetsNonNullable($value: String!) {
445
          fieldWithNonNullableStringInput(input: $value)
446
        }
447
        ');
448
449
        $expected = [
450
            'errors' => [
451
                [
452
                    'message'   => 'Variable "$value" of required type "String!" was not provided.',
453
                    'locations' => [['line' => 2, 'column' => 31]],
454
                    'extensions' => ['category' => 'graphql'],
455
                ],
456
            ],
457
        ];
458
        self::assertEquals($expected, $result->toArray());
459
    }
460
461
    /**
462
     * @see it('does not allow non-nullable inputs to be set to null in a variable')
463
     */
464
    public function testDoesNotAllowNonNullableInputsToBeSetToNullInAVariable() : void
465
    {
466
        $doc      = '
467
        query SetsNonNullable($value: String!) {
468
          fieldWithNonNullableStringInput(input: $value)
469
        }
470
        ';
471
        $result   = $this->executeQuery($doc, ['value' => null]);
472
        $expected = [
473
            'errors' => [
474
                [
475
                    'message'   =>
476
                        'Variable "$value" got invalid value null; ' .
477
                        'Expected non-nullable type String! not to be null.',
478
                    'locations' => [['line' => 2, 'column' => 31]],
479
                    'extensions' => ['category' => 'graphql'],
480
                ],
481
            ],
482
        ];
483
        self::assertEquals($expected, $result->toArray());
484
    }
485
486
    /**
487
     * @see it('allows non-nullable inputs to be set to a value in a variable')
488
     */
489
    public function testAllowsNonNullableInputsToBeSetToAValueInAVariable() : void
490
    {
491
        $doc      = '
492
        query SetsNonNullable($value: String!) {
493
          fieldWithNonNullableStringInput(input: $value)
494
        }
495
        ';
496
        $result   = $this->executeQuery($doc, ['value' => 'a']);
497
        $expected = ['data' => ['fieldWithNonNullableStringInput' => '"a"']];
498
        self::assertEquals($expected, $result->toArray());
499
    }
500
501
    /**
502
     * @see it('allows non-nullable inputs to be set to a value directly')
503
     */
504
    public function testAllowsNonNullableInputsToBeSetToAValueDirectly() : void
505
    {
506
        $result   = $this->executeQuery('
507
      {
508
        fieldWithNonNullableStringInput(input: "a")
509
      }
510
        ');
511
        $expected = ['data' => ['fieldWithNonNullableStringInput' => '"a"']];
512
        self::assertEquals($expected, $result->toArray());
513
    }
514
515
    /**
516
     * @see it('reports error for missing non-nullable inputs')
517
     */
518
    public function testReportsErrorForMissingNonNullableInputs() : void
519
    {
520
        $result   = $this->executeQuery('
521
      {
522
        fieldWithNonNullableStringInput
523
      }
524
        ');
525
        $expected = [
526
            'data'   => ['fieldWithNonNullableStringInput' => null],
527
            'errors' => [[
528
                'message'   => 'Argument "input" of required type "String!" was not provided.',
529
                'locations' => [['line' => 3, 'column' => 9]],
530
                'path'      => ['fieldWithNonNullableStringInput'],
531
                'extensions' => ['category' => 'graphql'],
532
            ],
533
            ],
534
        ];
535
        self::assertEquals($expected, $result->toArray());
536
    }
537
538
    // Describe: Handles lists and nullability
539
540
    /**
541
     * @see it('reports error for array passed into string input')
542
     */
543
    public function testReportsErrorForArrayPassedIntoStringInput() : void
544
    {
545
        $doc       = '
546
        query SetsNonNullable($value: String!) {
547
          fieldWithNonNullableStringInput(input: $value)
548
        }
549
        ';
550
        $variables = ['value' => [1, 2, 3]];
551
        $result    = $this->executeQuery($doc, $variables);
552
553
        $expected = [
554
            'errors' => [[
555
                'message'   =>
556
                    'Variable "$value" got invalid value [1,2,3]; Expected type ' .
557
                    'String; String cannot represent an array value: [1,2,3]',
558
                'locations' => [
559
                    ['line' => 2, 'column' => 31],
560
                ],
561
                'extensions' => ['category' => 'graphql'],
562
            ],
563
            ],
564
        ];
565
        self::assertEquals($expected, $result->toArray());
566
    }
567
568
    /**
569
     * @see it('serializing an array via GraphQLString throws TypeError')
570
     */
571
    public function testSerializingAnArrayViaGraphQLStringThrowsTypeError() : void
572
    {
573
        $this->expectException(Error::class);
574
        $this->expectExceptionMessage('String cannot represent non scalar value: [1,2,3]');
575
        Type::string()->serialize([1, 2, 3]);
576
    }
577
578
    /**
579
     * @see it('reports error for non-provided variables for non-nullable inputs')
580
     */
581
    public function testReportsErrorForNonProvidedVariablesForNonNullableInputs() : void
582
    {
583
        // Note: this test would typically fail validation before encountering
584
        // this execution error, however for queries which previously validated
585
        // and are being run against a new schema which have introduced a breaking
586
        // change to make a formerly non-required argument required, this asserts
587
        // failure before allowing the underlying code to receive a non-null value.
588
        $result   = $this->executeQuery('
589
      {
590
        fieldWithNonNullableStringInput(input: $foo)
591
      }
592
        ');
593
        $expected = [
594
            'data'   => ['fieldWithNonNullableStringInput' => null],
595
            'errors' => [[
596
                'message'   =>
597
                    'Argument "input" of required type "String!" was provided the ' .
598
                    'variable "$foo" which was not provided a runtime value.',
599
                'locations' => [['line' => 3, 'column' => 48]],
600
                'path'      => ['fieldWithNonNullableStringInput'],
601
                'extensions' => ['category' => 'graphql'],
602
            ],
603
            ],
604
        ];
605
        self::assertEquals($expected, $result->toArray());
606
    }
607
608
    /**
609
     * @see it('allows lists to be null')
610
     */
611
    public function testAllowsListsToBeNull() : void
612
    {
613
        $doc      = '
614
        query q($input:[String]) {
615
          list(input: $input)
616
        }
617
        ';
618
        $result   = $this->executeQuery($doc, ['input' => null]);
619
        $expected = ['data' => ['list' => null]];
620
621
        self::assertEquals($expected, $result->toArray());
622
    }
623
624
    /**
625
     * @see it('allows lists to contain values')
626
     */
627
    public function testAllowsListsToContainValues() : void
628
    {
629
        $doc      = '
630
        query q($input:[String]) {
631
          list(input: $input)
632
        }
633
        ';
634
        $result   = $this->executeQuery($doc, ['input' => ['A']]);
635
        $expected = ['data' => ['list' => '["A"]']];
636
        self::assertEquals($expected, $result->toArray());
637
    }
638
639
    /**
640
     * @see it('allows lists to contain null')
641
     */
642
    public function testAllowsListsToContainNull() : void
643
    {
644
        $doc      = '
645
        query q($input:[String]) {
646
          list(input: $input)
647
        }
648
        ';
649
        $result   = $this->executeQuery($doc, ['input' => ['A', null, 'B']]);
650
        $expected = ['data' => ['list' => '["A",null,"B"]']];
651
        self::assertEquals($expected, $result->toArray());
652
    }
653
654
    /**
655
     * @see it('does not allow non-null lists to be null')
656
     */
657
    public function testDoesNotAllowNonNullListsToBeNull() : void
658
    {
659
        $doc      = '
660
        query q($input:[String]!) {
661
          nnList(input: $input)
662
        }
663
        ';
664
        $result   = $this->executeQuery($doc, ['input' => null]);
665
        $expected = [
666
            'errors' => [
667
                [
668
                    'message'   =>
669
                        'Variable "$input" got invalid value null; ' .
670
                        'Expected non-nullable type [String]! not to be null.',
671
                    'locations' => [['line' => 2, 'column' => 17]],
672
                    'extensions' => ['category' => 'graphql'],
673
                ],
674
            ],
675
        ];
676
        self::assertEquals($expected, $result->toArray());
677
    }
678
679
    /**
680
     * @see it('allows non-null lists to contain values')
681
     */
682
    public function testAllowsNonNullListsToContainValues() : void
683
    {
684
        $doc      = '
685
        query q($input:[String]!) {
686
          nnList(input: $input)
687
        }
688
        ';
689
        $result   = $this->executeQuery($doc, ['input' => ['A']]);
690
        $expected = ['data' => ['nnList' => '["A"]']];
691
        self::assertEquals($expected, $result->toArray());
692
    }
693
694
    /**
695
     * @see it('allows non-null lists to contain null')
696
     */
697
    public function testAllowsNonNullListsToContainNull() : void
698
    {
699
        $doc      = '
700
        query q($input:[String]!) {
701
          nnList(input: $input)
702
        }
703
        ';
704
        $result   = $this->executeQuery($doc, ['input' => ['A', null, 'B']]);
705
        $expected = ['data' => ['nnList' => '["A",null,"B"]']];
706
        self::assertEquals($expected, $result->toArray());
707
    }
708
709
    /**
710
     * @see it('allows lists of non-nulls to be null')
711
     */
712
    public function testAllowsListsOfNonNullsToBeNull() : void
713
    {
714
        $doc      = '
715
        query q($input:[String!]) {
716
          listNN(input: $input)
717
        }
718
        ';
719
        $result   = $this->executeQuery($doc, ['input' => null]);
720
        $expected = ['data' => ['listNN' => null]];
721
        self::assertEquals($expected, $result->toArray());
722
    }
723
724
    /**
725
     * @see it('allows lists of non-nulls to contain values')
726
     */
727
    public function testAllowsListsOfNonNullsToContainValues() : void
728
    {
729
        $doc      = '
730
        query q($input:[String!]) {
731
          listNN(input: $input)
732
        }
733
        ';
734
        $result   = $this->executeQuery($doc, ['input' => ['A']]);
735
        $expected = ['data' => ['listNN' => '["A"]']];
736
        self::assertEquals($expected, $result->toArray());
737
    }
738
739
    /**
740
     * @see it('does not allow lists of non-nulls to contain null')
741
     */
742
    public function testDoesNotAllowListsOfNonNullsToContainNull() : void
743
    {
744
        $doc      = '
745
        query q($input:[String!]) {
746
          listNN(input: $input)
747
        }
748
        ';
749
        $result   = $this->executeQuery($doc, ['input' => ['A', null, 'B']]);
750
        $expected = [
751
            'errors' => [
752
                [
753
                    'message'   =>
754
                        'Variable "$input" got invalid value ["A",null,"B"]; ' .
755
                        'Expected non-nullable type String! not to be null at value[1].',
756
                    'locations' => [['line' => 2, 'column' => 17]],
757
                    'extensions' => ['category' => 'graphql'],
758
                ],
759
            ],
760
        ];
761
        self::assertEquals($expected, $result->toArray());
762
    }
763
764
    /**
765
     * @see it('does not allow non-null lists of non-nulls to be null')
766
     */
767
    public function testDoesNotAllowNonNullListsOfNonNullsToBeNull() : void
768
    {
769
        $doc      = '
770
        query q($input:[String!]!) {
771
          nnListNN(input: $input)
772
        }
773
        ';
774
        $result   = $this->executeQuery($doc, ['input' => null]);
775
        $expected = [
776
            'errors' => [
777
                [
778
                    'message'   =>
779
                        'Variable "$input" got invalid value null; ' .
780
                        'Expected non-nullable type [String!]! not to be null.',
781
                    'locations' => [['line' => 2, 'column' => 17]],
782
                    'extensions' => ['category' => 'graphql'],
783
                ],
784
            ],
785
        ];
786
        self::assertEquals($expected, $result->toArray());
787
    }
788
789
    /**
790
     * @see it('allows non-null lists of non-nulls to contain values')
791
     */
792
    public function testAllowsNonNullListsOfNonNullsToContainValues() : void
793
    {
794
        $doc      = '
795
        query q($input:[String!]!) {
796
          nnListNN(input: $input)
797
        }
798
        ';
799
        $result   = $this->executeQuery($doc, ['input' => ['A']]);
800
        $expected = ['data' => ['nnListNN' => '["A"]']];
801
        self::assertEquals($expected, $result->toArray());
802
    }
803
804
    // Describe: Execute: Uses argument default values
805
806
    /**
807
     * @see it('does not allow non-null lists of non-nulls to contain null')
808
     */
809
    public function testDoesNotAllowNonNullListsOfNonNullsToContainNull() : void
810
    {
811
        $doc      = '
812
        query q($input:[String!]!) {
813
          nnListNN(input: $input)
814
        }
815
        ';
816
        $result   = $this->executeQuery($doc, ['input' => ['A', null, 'B']]);
817
        $expected = [
818
            'errors' => [
819
                [
820
                    'message'   =>
821
                        'Variable "$input" got invalid value ["A",null,"B"]; ' .
822
                        'Expected non-nullable type String! not to be null at value[1].',
823
                    'locations' => [['line' => 2, 'column' => 17]],
824
                    'extensions' => ['category' => 'graphql'],
825
                ],
826
            ],
827
        ];
828
        self::assertEquals($expected, $result->toArray());
829
    }
830
831
    /**
832
     * @see it('does not allow invalid types to be used as values')
833
     */
834
    public function testDoesNotAllowInvalidTypesToBeUsedAsValues() : void
835
    {
836
        $doc      = '
837
        query q($input: TestType!) {
838
          fieldWithObjectInput(input: $input)
839
        }
840
        ';
841
        $vars     = ['input' => ['list' => ['A', 'B']]];
842
        $result   = $this->executeQuery($doc, $vars);
843
        $expected = [
844
            'errors' => [
845
                [
846
                    'message'   =>
847
                        'Variable "$input" expected value of type "TestType!" which cannot ' .
848
                        'be used as an input type.',
849
                    'locations' => [['line' => 2, 'column' => 25]],
850
                    'extensions' => ['category' => 'graphql'],
851
                ],
852
            ],
853
        ];
854
        self::assertEquals($expected, $result->toArray());
855
    }
856
857
    /**
858
     * @see it('does not allow unknown types to be used as values')
859
     */
860
    public function testDoesNotAllowUnknownTypesToBeUsedAsValues() : void
861
    {
862
        $doc  = '
863
        query q($input: UnknownType!) {
864
          fieldWithObjectInput(input: $input)
865
        }
866
        ';
867
        $vars = ['input' => 'whoknows'];
868
869
        $result   = $this->executeQuery($doc, $vars);
870
        $expected = [
871
            'errors' => [
872
                [
873
                    'message'   =>
874
                        'Variable "$input" expected value of type "UnknownType!" which ' .
875
                        'cannot be used as an input type.',
876
                    'locations' => [['line' => 2, 'column' => 25]],
877
                    'extensions' => ['category' => 'graphql'],
878
                ],
879
            ],
880
        ];
881
        self::assertEquals($expected, $result->toArray());
882
    }
883
884
    /**
885
     * @see it('when no argument provided')
886
     */
887
    public function testWhenNoArgumentProvided() : void
888
    {
889
        $result = $this->executeQuery('{
890
        fieldWithDefaultArgumentValue
891
        }');
892
893
        self::assertEquals(
894
            ['data' => ['fieldWithDefaultArgumentValue' => '"Hello World"']],
895
            $result->toArray()
896
        );
897
    }
898
899
    /**
900
     * @see it('when omitted variable provided')
901
     */
902
    public function testWhenOmittedVariableProvided() : void
903
    {
904
        $result = $this->executeQuery('query optionalVariable($optional: String) {
905
            fieldWithDefaultArgumentValue(input: $optional)
906
        }');
907
908
        self::assertEquals(
909
            ['data' => ['fieldWithDefaultArgumentValue' => '"Hello World"']],
910
            $result->toArray()
911
        );
912
    }
913
914
    /**
915
     * @see it('not when argument cannot be coerced')
916
     */
917
    public function testNotWhenArgumentCannotBeCoerced() : void
918
    {
919
        $result = $this->executeQuery('{
920
            fieldWithDefaultArgumentValue(input: WRONG_TYPE)
921
        }');
922
923
        $expected = [
924
            'data'   => ['fieldWithDefaultArgumentValue' => null],
925
            'errors' => [[
926
                'message'   =>
927
                    'Argument "input" has invalid value WRONG_TYPE.',
928
                'locations' => [['line' => 2, 'column' => 50]],
929
                'path'      => ['fieldWithDefaultArgumentValue'],
930
                'extensions' => ['category' => 'graphql'],
931
            ],
932
            ],
933
        ];
934
935
        self::assertEquals($expected, $result->toArray());
936
    }
937
}
938