Total Complexity | 87 |
Total Lines | 1904 |
Duplicated Lines | 0 % |
Changes | 8 | ||
Bugs | 0 | Features | 0 |
Complex classes like SchemaExtenderTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SchemaExtenderTest, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
43 | class SchemaExtenderTest extends TestCase |
||
44 | { |
||
45 | /** @var Schema */ |
||
46 | protected $testSchema; |
||
47 | |||
48 | /** @var string[] */ |
||
49 | protected $testSchemaDefinitions; |
||
50 | |||
51 | /** @var ObjectType */ |
||
52 | protected $FooType; |
||
53 | |||
54 | /** @var Directive */ |
||
55 | protected $FooDirective; |
||
56 | |||
57 | public function setUp() |
||
58 | { |
||
59 | parent::setUp(); |
||
60 | |||
61 | $SomeScalarType = new CustomScalarType([ |
||
62 | 'name' => 'SomeScalar', |
||
63 | 'serialize' => static function ($x) { |
||
64 | return $x; |
||
65 | }, |
||
66 | ]); |
||
67 | |||
68 | $SomeInterfaceType = new InterfaceType([ |
||
69 | 'name' => 'SomeInterface', |
||
70 | 'fields' => static function () use (&$SomeInterfaceType) { |
||
71 | return [ |
||
72 | 'name' => [ 'type' => Type::string()], |
||
73 | 'some' => [ 'type' => $SomeInterfaceType], |
||
74 | ]; |
||
75 | }, |
||
76 | ]); |
||
77 | |||
78 | $FooType = new ObjectType([ |
||
79 | 'name' => 'Foo', |
||
80 | 'interfaces' => [$SomeInterfaceType], |
||
81 | 'fields' => static function () use ($SomeInterfaceType, &$FooType) { |
||
82 | return [ |
||
83 | 'name' => [ 'type' => Type::string() ], |
||
84 | 'some' => [ 'type' => $SomeInterfaceType ], |
||
85 | 'tree' => [ 'type' => Type::nonNull(Type::listOf($FooType))], |
||
86 | ]; |
||
87 | }, |
||
88 | ]); |
||
89 | |||
90 | $BarType = new ObjectType([ |
||
91 | 'name' => 'Bar', |
||
92 | 'interfaces' => [$SomeInterfaceType], |
||
93 | 'fields' => static function () use ($SomeInterfaceType, $FooType) : array { |
||
94 | return [ |
||
95 | 'name' => [ 'type' => Type::string() ], |
||
96 | 'some' => [ 'type' => $SomeInterfaceType ], |
||
97 | 'foo' => [ 'type' => $FooType ], |
||
98 | ]; |
||
99 | }, |
||
100 | ]); |
||
101 | |||
102 | $BizType = new ObjectType([ |
||
103 | 'name' => 'Biz', |
||
104 | 'fields' => static function () : array { |
||
105 | return [ |
||
106 | 'fizz' => [ 'type' => Type::string() ], |
||
107 | ]; |
||
108 | }, |
||
109 | ]); |
||
110 | |||
111 | $SomeUnionType = new UnionType([ |
||
112 | 'name' => 'SomeUnion', |
||
113 | 'types' => [$FooType, $BizType], |
||
114 | ]); |
||
115 | |||
116 | $SomeEnumType = new EnumType([ |
||
117 | 'name' => 'SomeEnum', |
||
118 | 'values' => [ |
||
119 | 'ONE' => [ 'value' => 1 ], |
||
120 | 'TWO' => [ 'value' => 2 ], |
||
121 | ], |
||
122 | ]); |
||
123 | |||
124 | $SomeInputType = new InputObjectType([ |
||
125 | 'name' => 'SomeInput', |
||
126 | 'fields' => static function () : array { |
||
127 | return [ |
||
128 | 'fooArg' => [ 'type' => Type::string() ], |
||
129 | ]; |
||
130 | }, |
||
131 | ]); |
||
132 | |||
133 | $FooDirective = new Directive([ |
||
134 | 'name' => 'foo', |
||
135 | 'args' => [ |
||
136 | new FieldArgument([ |
||
137 | 'name' => 'input', |
||
138 | 'type' => $SomeInputType, |
||
139 | ]), |
||
140 | ], |
||
141 | 'locations' => [ |
||
142 | DirectiveLocation::SCHEMA, |
||
143 | DirectiveLocation::SCALAR, |
||
144 | DirectiveLocation::OBJECT, |
||
145 | DirectiveLocation::FIELD_DEFINITION, |
||
146 | DirectiveLocation::ARGUMENT_DEFINITION, |
||
147 | DirectiveLocation::IFACE, |
||
148 | DirectiveLocation::UNION, |
||
149 | DirectiveLocation::ENUM, |
||
150 | DirectiveLocation::ENUM_VALUE, |
||
151 | DirectiveLocation::INPUT_OBJECT, |
||
152 | DirectiveLocation::INPUT_FIELD_DEFINITION, |
||
153 | ], |
||
154 | ]); |
||
155 | |||
156 | $this->testSchema = new Schema([ |
||
157 | 'query' => new ObjectType([ |
||
158 | 'name' => 'Query', |
||
159 | 'fields' => static function () use ($FooType, $SomeScalarType, $SomeUnionType, $SomeEnumType, $SomeInterfaceType, $SomeInputType) : array { |
||
160 | return [ |
||
161 | 'foo' => [ 'type' => $FooType ], |
||
162 | 'someScalar' => [ 'type' => $SomeScalarType ], |
||
163 | 'someUnion' => [ 'type' => $SomeUnionType ], |
||
164 | 'someEnum' => [ 'type' => $SomeEnumType ], |
||
165 | 'someInterface' => [ |
||
166 | 'args' => [ |
||
167 | 'id' => [ |
||
168 | 'type' => Type::nonNull(Type::id()), |
||
169 | ], |
||
170 | ], |
||
171 | 'type' => $SomeInterfaceType, |
||
172 | ], |
||
173 | 'someInput' => [ |
||
174 | 'args' => [ 'input' => [ 'type' => $SomeInputType ] ], |
||
175 | 'type' => Type::string(), |
||
176 | ], |
||
177 | ]; |
||
178 | }, |
||
179 | ]), |
||
180 | 'types' => [$FooType, $BarType], |
||
181 | 'directives' => array_merge(GraphQL::getStandardDirectives(), [$FooDirective]), |
||
182 | ]); |
||
183 | |||
184 | $testSchemaAst = Parser::parse(SchemaPrinter::doPrint($this->testSchema)); |
||
185 | |||
186 | $this->testSchemaDefinitions = array_map(static function ($node) { |
||
187 | return Printer::doPrint($node); |
||
188 | }, iterator_to_array($testSchemaAst->definitions->getIterator())); |
||
189 | |||
190 | $this->FooDirective = $FooDirective; |
||
191 | $this->FooType = $FooType; |
||
192 | } |
||
193 | |||
194 | protected function dedent(string $str) : string |
||
195 | { |
||
196 | $trimmedStr = trim($str, "\n"); |
||
197 | $trimmedStr = preg_replace('/[ \t]*$/', '', $trimmedStr); |
||
198 | |||
199 | preg_match('/^[ \t]*/', $trimmedStr, $indentMatch); |
||
200 | $indent = $indentMatch[0]; |
||
201 | |||
202 | return preg_replace('/^' . $indent . '/m', '', $trimmedStr); |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * @param mixed[]|null $options |
||
207 | */ |
||
208 | protected function extendTestSchema(string $sdl, ?array $options = null) : Schema |
||
216 | } |
||
217 | |||
218 | protected function printTestSchemaChanges(Schema $extendedSchema) : string |
||
219 | { |
||
220 | $ast = Parser::parse(SchemaPrinter::doPrint($extendedSchema)); |
||
221 | $ast->definitions = array_values(array_filter( |
||
222 | $ast->definitions instanceof NodeList |
||
223 | ? iterator_to_array($ast->definitions->getIterator()) |
||
224 | : $ast->definitions, |
||
225 | function (Node $node) : bool { |
||
226 | return ! in_array(Printer::doPrint($node), $this->testSchemaDefinitions, true); |
||
227 | } |
||
228 | )); |
||
229 | |||
230 | return Printer::doPrint($ast); |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * @see it('returns the original schema when there are no type definitions') |
||
235 | */ |
||
236 | public function testReturnsTheOriginalSchemaWhenThereAreNoTypeDefinitions() |
||
237 | { |
||
238 | $extendedSchema = $this->extendTestSchema('{ field }'); |
||
239 | self::assertEquals($extendedSchema, $this->testSchema); |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * @see it('extends without altering original schema') |
||
244 | */ |
||
245 | public function testExtendsWithoutAlteringOriginalSchema() |
||
246 | { |
||
247 | $extendedSchema = $this->extendTestSchema(' |
||
248 | extend type Query { |
||
249 | newField: String |
||
250 | }'); |
||
251 | self::assertNotEquals($extendedSchema, $this->testSchema); |
||
252 | self::assertContains('newField', SchemaPrinter::doPrint($extendedSchema)); |
||
253 | self::assertNotContains('newField', SchemaPrinter::doPrint($this->testSchema)); |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * @see it('can be used for limited execution') |
||
258 | */ |
||
259 | public function testCanBeUsedForLimitedExecution() |
||
260 | { |
||
261 | $extendedSchema = $this->extendTestSchema(' |
||
262 | extend type Query { |
||
263 | newField: String |
||
264 | } |
||
265 | '); |
||
266 | |||
267 | $result = GraphQL::executeQuery($extendedSchema, '{ newField }', ['newField' => 123]); |
||
268 | |||
269 | self::assertEquals($result->toArray(), [ |
||
270 | 'data' => ['newField' => '123'], |
||
271 | ]); |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * @see it('can describe the extended fields') |
||
276 | */ |
||
277 | public function testCanDescribeTheExtendedFields() |
||
278 | { |
||
279 | $extendedSchema = $this->extendTestSchema(' |
||
280 | extend type Query { |
||
281 | "New field description." |
||
282 | newField: String |
||
283 | } |
||
284 | '); |
||
285 | |||
286 | self::assertEquals( |
||
287 | $extendedSchema->getQueryType()->getField('newField')->description, |
||
288 | 'New field description.' |
||
289 | ); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * @see it('can describe the extended fields with legacy comments') |
||
294 | */ |
||
295 | public function testCanDescribeTheExtendedFieldsWithLegacyComments() |
||
296 | { |
||
297 | $extendedSchema = $this->extendTestSchema(' |
||
298 | extend type Query { |
||
299 | # New field description. |
||
300 | newField: String |
||
301 | } |
||
302 | ', ['commentDescriptions' => true]); |
||
303 | |||
304 | self::assertEquals( |
||
305 | $extendedSchema->getQueryType()->getField('newField')->description, |
||
306 | 'New field description.' |
||
307 | ); |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * @see it('describes extended fields with strings when present') |
||
312 | */ |
||
313 | public function testDescribesExtendedFieldsWithStringsWhenPresent() |
||
314 | { |
||
315 | $extendedSchema = $this->extendTestSchema(' |
||
316 | extend type Query { |
||
317 | # New field description. |
||
318 | "Actually use this description." |
||
319 | newField: String |
||
320 | } |
||
321 | ', ['commentDescriptions' => true ]); |
||
322 | |||
323 | self::assertEquals( |
||
324 | $extendedSchema->getQueryType()->getField('newField')->description, |
||
325 | 'Actually use this description.' |
||
326 | ); |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * @see it('extends objects by adding new fields') |
||
331 | */ |
||
332 | public function testExtendsObjectsByAddingNewFields() |
||
333 | { |
||
334 | $extendedSchema = $this->extendTestSchema( |
||
335 | ' |
||
336 | extend type Foo { |
||
337 | newField: String |
||
338 | } |
||
339 | ' |
||
340 | ); |
||
341 | |||
342 | self::assertEquals( |
||
343 | $this->printTestSchemaChanges($extendedSchema), |
||
344 | $this->dedent(' |
||
345 | type Foo implements SomeInterface { |
||
346 | name: String |
||
347 | some: SomeInterface |
||
348 | tree: [Foo]! |
||
349 | newField: String |
||
350 | } |
||
351 | ') |
||
352 | ); |
||
353 | |||
354 | $fooType = $extendedSchema->getType('Foo'); |
||
355 | $fooField = $extendedSchema->getQueryType()->getField('foo'); |
||
356 | self::assertEquals($fooField->getType(), $fooType); |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * @see it('extends enums by adding new values') |
||
361 | */ |
||
362 | public function testExtendsEnumsByAddingNewValues() |
||
363 | { |
||
364 | $extendedSchema = $this->extendTestSchema(' |
||
365 | extend enum SomeEnum { |
||
366 | NEW_ENUM |
||
367 | } |
||
368 | '); |
||
369 | |||
370 | self::assertEquals( |
||
371 | $this->printTestSchemaChanges($extendedSchema), |
||
372 | $this->dedent(' |
||
373 | enum SomeEnum { |
||
374 | ONE |
||
375 | TWO |
||
376 | NEW_ENUM |
||
377 | } |
||
378 | ') |
||
379 | ); |
||
380 | |||
381 | $someEnumType = $extendedSchema->getType('SomeEnum'); |
||
382 | $enumField = $extendedSchema->getQueryType()->getField('someEnum'); |
||
383 | self::assertEquals($enumField->getType(), $someEnumType); |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * @see it('extends unions by adding new types') |
||
388 | */ |
||
389 | public function testExtendsUnionsByAddingNewTypes() |
||
390 | { |
||
391 | $extendedSchema = $this->extendTestSchema(' |
||
392 | extend union SomeUnion = Bar |
||
393 | '); |
||
394 | self::assertEquals( |
||
395 | $this->printTestSchemaChanges($extendedSchema), |
||
396 | $this->dedent(' |
||
397 | union SomeUnion = Foo | Biz | Bar |
||
398 | ') |
||
399 | ); |
||
400 | |||
401 | $someUnionType = $extendedSchema->getType('SomeUnion'); |
||
402 | $unionField = $extendedSchema->getQueryType()->getField('someUnion'); |
||
403 | self::assertEquals($unionField->getType(), $someUnionType); |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * @see it('allows extension of union by adding itself') |
||
408 | */ |
||
409 | public function testAllowsExtensionOfUnionByAddingItself() |
||
410 | { |
||
411 | $extendedSchema = $this->extendTestSchema(' |
||
412 | extend union SomeUnion = SomeUnion |
||
413 | '); |
||
414 | |||
415 | $errors = $extendedSchema->validate(); |
||
416 | self::assertGreaterThan(0, count($errors)); |
||
417 | |||
418 | self::assertEquals( |
||
419 | $this->printTestSchemaChanges($extendedSchema), |
||
420 | $this->dedent(' |
||
421 | union SomeUnion = Foo | Biz | SomeUnion |
||
422 | ') |
||
423 | ); |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * @see it('extends inputs by adding new fields') |
||
428 | */ |
||
429 | public function testExtendsInputsByAddingNewFields() |
||
430 | { |
||
431 | $extendedSchema = $this->extendTestSchema(' |
||
432 | extend input SomeInput { |
||
433 | newField: String |
||
434 | } |
||
435 | '); |
||
436 | |||
437 | self::assertEquals( |
||
438 | $this->printTestSchemaChanges($extendedSchema), |
||
439 | $this->dedent(' |
||
440 | input SomeInput { |
||
441 | fooArg: String |
||
442 | newField: String |
||
443 | } |
||
444 | ') |
||
445 | ); |
||
446 | |||
447 | $someInputType = $extendedSchema->getType('SomeInput'); |
||
448 | $inputField = $extendedSchema->getQueryType()->getField('someInput'); |
||
449 | self::assertEquals($inputField->args[0]->getType(), $someInputType); |
||
450 | |||
451 | $fooDirective = $extendedSchema->getDirective('foo'); |
||
452 | self::assertEquals($fooDirective->args[0]->getType(), $someInputType); |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * @see it('extends scalars by adding new directives') |
||
457 | */ |
||
458 | public function testExtendsScalarsByAddingNewDirectives() |
||
459 | { |
||
460 | $extendedSchema = $this->extendTestSchema(' |
||
461 | extend scalar SomeScalar @foo |
||
462 | '); |
||
463 | |||
464 | $someScalar = $extendedSchema->getType('SomeScalar'); |
||
465 | self::assertCount(1, $someScalar->extensionASTNodes); |
||
466 | self::assertEquals( |
||
467 | Printer::doPrint($someScalar->extensionASTNodes[0]), |
||
468 | 'extend scalar SomeScalar @foo' |
||
469 | ); |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * @see it('correctly assign AST nodes to new and extended types') |
||
474 | */ |
||
475 | public function testCorrectlyAssignASTNodesToNewAndExtendedTypes() |
||
476 | { |
||
477 | $extendedSchema = $this->extendTestSchema(' |
||
478 | extend type Query { |
||
479 | newField(testArg: TestInput): TestEnum |
||
480 | } |
||
481 | extend scalar SomeScalar @foo |
||
482 | extend enum SomeEnum { |
||
483 | NEW_VALUE |
||
484 | } |
||
485 | extend union SomeUnion = Bar |
||
486 | extend input SomeInput { |
||
487 | newField: String |
||
488 | } |
||
489 | extend interface SomeInterface { |
||
490 | newField: String |
||
491 | } |
||
492 | enum TestEnum { |
||
493 | TEST_VALUE |
||
494 | } |
||
495 | input TestInput { |
||
496 | testInputField: TestEnum |
||
497 | } |
||
498 | '); |
||
499 | |||
500 | $ast = Parser::parse(' |
||
501 | extend type Query { |
||
502 | oneMoreNewField: TestUnion |
||
503 | } |
||
504 | extend scalar SomeScalar @test |
||
505 | extend enum SomeEnum { |
||
506 | ONE_MORE_NEW_VALUE |
||
507 | } |
||
508 | extend union SomeUnion = TestType |
||
509 | extend input SomeInput { |
||
510 | oneMoreNewField: String |
||
511 | } |
||
512 | extend interface SomeInterface { |
||
513 | oneMoreNewField: String |
||
514 | } |
||
515 | union TestUnion = TestType |
||
516 | interface TestInterface { |
||
517 | interfaceField: String |
||
518 | } |
||
519 | type TestType implements TestInterface { |
||
520 | interfaceField: String |
||
521 | } |
||
522 | directive @test(arg: Int) on FIELD | SCALAR |
||
523 | '); |
||
524 | |||
525 | $extendedTwiceSchema = SchemaExtender::extend($extendedSchema, $ast); |
||
526 | $query = $extendedTwiceSchema->getQueryType(); |
||
527 | /** @var ScalarType $someScalar */ |
||
528 | $someScalar = $extendedTwiceSchema->getType('SomeScalar'); |
||
529 | /** @var EnumType $someEnum */ |
||
530 | $someEnum = $extendedTwiceSchema->getType('SomeEnum'); |
||
531 | /** @var UnionType $someUnion */ |
||
532 | $someUnion = $extendedTwiceSchema->getType('SomeUnion'); |
||
533 | /** @var InputObjectType $someInput */ |
||
534 | $someInput = $extendedTwiceSchema->getType('SomeInput'); |
||
535 | /** @var InterfaceType $someInterface */ |
||
536 | $someInterface = $extendedTwiceSchema->getType('SomeInterface'); |
||
537 | |||
538 | /** @var InputObjectType $testInput */ |
||
539 | $testInput = $extendedTwiceSchema->getType('TestInput'); |
||
540 | /** @var EnumType $testEnum */ |
||
541 | $testEnum = $extendedTwiceSchema->getType('TestEnum'); |
||
542 | /** @var UnionType $testUnion */ |
||
543 | $testUnion = $extendedTwiceSchema->getType('TestUnion'); |
||
544 | /** @var InterfaceType $testInterface */ |
||
545 | $testInterface = $extendedTwiceSchema->getType('TestInterface'); |
||
546 | /** @var ObjectType $testType */ |
||
547 | $testType = $extendedTwiceSchema->getType('TestType'); |
||
548 | /** @var Directive $testDirective */ |
||
549 | $testDirective = $extendedTwiceSchema->getDirective('test'); |
||
550 | |||
551 | self::assertCount(2, $query->extensionASTNodes); |
||
552 | self::assertCount(2, $someScalar->extensionASTNodes); |
||
553 | self::assertCount(2, $someEnum->extensionASTNodes); |
||
554 | self::assertCount(2, $someUnion->extensionASTNodes); |
||
555 | self::assertCount(2, $someInput->extensionASTNodes); |
||
556 | self::assertCount(2, $someInterface->extensionASTNodes); |
||
557 | |||
558 | self::assertCount(0, $testType->extensionASTNodes ?? []); |
||
559 | self::assertCount(0, $testEnum->extensionASTNodes ?? []); |
||
560 | self::assertCount(0, $testUnion->extensionASTNodes ?? []); |
||
561 | self::assertCount(0, $testInput->extensionASTNodes ?? []); |
||
562 | self::assertCount(0, $testInterface->extensionASTNodes ?? []); |
||
563 | |||
564 | $restoredExtensionAST = new DocumentNode([ |
||
565 | 'definitions' => array_merge( |
||
566 | $query->extensionASTNodes, |
||
567 | $someScalar->extensionASTNodes, |
||
568 | $someEnum->extensionASTNodes, |
||
569 | $someUnion->extensionASTNodes, |
||
570 | $someInput->extensionASTNodes, |
||
571 | $someInterface->extensionASTNodes, |
||
572 | [ |
||
573 | $testInput->astNode, |
||
574 | $testEnum->astNode, |
||
575 | $testUnion->astNode, |
||
576 | $testInterface->astNode, |
||
577 | $testType->astNode, |
||
578 | $testDirective->astNode, |
||
579 | ] |
||
580 | ), |
||
581 | ]); |
||
582 | |||
583 | self::assertEquals( |
||
584 | SchemaPrinter::doPrint(SchemaExtender::extend($this->testSchema, $restoredExtensionAST)), |
||
585 | SchemaPrinter::doPrint($extendedTwiceSchema) |
||
586 | ); |
||
587 | |||
588 | $newField = $query->getField('newField'); |
||
589 | |||
590 | self::assertEquals(Printer::doPrint($newField->astNode), 'newField(testArg: TestInput): TestEnum'); |
||
591 | self::assertEquals(Printer::doPrint($newField->args[0]->astNode), 'testArg: TestInput'); |
||
592 | self::assertEquals(Printer::doPrint($query->getField('oneMoreNewField')->astNode), 'oneMoreNewField: TestUnion'); |
||
593 | self::assertEquals(Printer::doPrint($someEnum->getValue('NEW_VALUE')->astNode), 'NEW_VALUE'); |
||
594 | self::assertEquals(Printer::doPrint($someEnum->getValue('ONE_MORE_NEW_VALUE')->astNode), 'ONE_MORE_NEW_VALUE'); |
||
595 | self::assertEquals(Printer::doPrint($someInput->getField('newField')->astNode), 'newField: String'); |
||
596 | self::assertEquals(Printer::doPrint($someInput->getField('oneMoreNewField')->astNode), 'oneMoreNewField: String'); |
||
597 | self::assertEquals(Printer::doPrint($someInterface->getField('newField')->astNode), 'newField: String'); |
||
598 | self::assertEquals(Printer::doPrint($someInterface->getField('oneMoreNewField')->astNode), 'oneMoreNewField: String'); |
||
599 | self::assertEquals(Printer::doPrint($testInput->getField('testInputField')->astNode), 'testInputField: TestEnum'); |
||
600 | self::assertEquals(Printer::doPrint($testEnum->getValue('TEST_VALUE')->astNode), 'TEST_VALUE'); |
||
601 | self::assertEquals(Printer::doPrint($testInterface->getField('interfaceField')->astNode), 'interfaceField: String'); |
||
602 | self::assertEquals(Printer::doPrint($testType->getField('interfaceField')->astNode), 'interfaceField: String'); |
||
603 | self::assertEquals(Printer::doPrint($testDirective->args[0]->astNode), 'arg: Int'); |
||
604 | } |
||
605 | |||
606 | /** |
||
607 | * @see it('builds types with deprecated fields/values') |
||
608 | */ |
||
609 | public function testBuildsTypesWithDeprecatedFieldsOrValues() |
||
610 | { |
||
611 | $extendedSchema = $this->extendTestSchema(' |
||
612 | type TypeWithDeprecatedField { |
||
613 | newDeprecatedField: String @deprecated(reason: "not used anymore") |
||
614 | } |
||
615 | enum EnumWithDeprecatedValue { |
||
616 | DEPRECATED @deprecated(reason: "do not use") |
||
617 | } |
||
618 | '); |
||
619 | |||
620 | /** @var ObjectType $typeWithDeprecatedField */ |
||
621 | $typeWithDeprecatedField = $extendedSchema->getType('TypeWithDeprecatedField'); |
||
622 | $deprecatedFieldDef = $typeWithDeprecatedField->getField('newDeprecatedField'); |
||
623 | |||
624 | self::assertEquals(true, $deprecatedFieldDef->isDeprecated()); |
||
625 | self::assertEquals('not used anymore', $deprecatedFieldDef->deprecationReason); |
||
626 | |||
627 | /** @var EnumType $enumWithDeprecatedValue */ |
||
628 | $enumWithDeprecatedValue = $extendedSchema->getType('EnumWithDeprecatedValue'); |
||
629 | $deprecatedEnumDef = $enumWithDeprecatedValue->getValue('DEPRECATED'); |
||
630 | |||
631 | self::assertEquals(true, $deprecatedEnumDef->isDeprecated()); |
||
632 | self::assertEquals('do not use', $deprecatedEnumDef->deprecationReason); |
||
633 | } |
||
634 | |||
635 | /** |
||
636 | * @see it('extends objects with deprecated fields') |
||
637 | */ |
||
638 | public function testExtendsObjectsWithDeprecatedFields() |
||
639 | { |
||
640 | $extendedSchema = $this->extendTestSchema(' |
||
641 | extend type Foo { |
||
642 | deprecatedField: String @deprecated(reason: "not used anymore") |
||
643 | } |
||
644 | '); |
||
645 | /** @var ObjectType $fooType */ |
||
646 | $fooType = $extendedSchema->getType('Foo'); |
||
647 | $deprecatedFieldDef = $fooType->getField('deprecatedField'); |
||
648 | |||
649 | self::assertTrue($deprecatedFieldDef->isDeprecated()); |
||
650 | self::assertEquals('not used anymore', $deprecatedFieldDef->deprecationReason); |
||
651 | } |
||
652 | |||
653 | /** |
||
654 | * @see it('extends enums with deprecated values') |
||
655 | */ |
||
656 | public function testExtendsEnumsWithDeprecatedValues() |
||
657 | { |
||
658 | $extendedSchema = $this->extendTestSchema(' |
||
659 | extend enum SomeEnum { |
||
660 | DEPRECATED @deprecated(reason: "do not use") |
||
661 | } |
||
662 | '); |
||
663 | |||
664 | /** @var EnumType $someEnumType */ |
||
665 | $someEnumType = $extendedSchema->getType('SomeEnum'); |
||
666 | $deprecatedEnumDef = $someEnumType->getValue('DEPRECATED'); |
||
667 | |||
668 | self::assertTrue($deprecatedEnumDef->isDeprecated()); |
||
669 | self::assertEquals('do not use', $deprecatedEnumDef->deprecationReason); |
||
670 | } |
||
671 | |||
672 | /** |
||
673 | * @see it('adds new unused object type') |
||
674 | */ |
||
675 | public function testAddsNewUnusedObjectType() |
||
676 | { |
||
677 | $extendedSchema = $this->extendTestSchema(' |
||
678 | type Unused { |
||
679 | someField: String |
||
680 | } |
||
681 | '); |
||
682 | self::assertNotEquals($this->testSchema, $extendedSchema); |
||
683 | self::assertEquals( |
||
684 | $this->dedent(' |
||
685 | type Unused { |
||
686 | someField: String |
||
687 | } |
||
688 | '), |
||
689 | $this->printTestSchemaChanges($extendedSchema) |
||
690 | ); |
||
691 | } |
||
692 | |||
693 | /** |
||
694 | * @see it('adds new unused enum type') |
||
695 | */ |
||
696 | public function testAddsNewUnusedEnumType() |
||
697 | { |
||
698 | $extendedSchema = $this->extendTestSchema(' |
||
699 | enum UnusedEnum { |
||
700 | SOME |
||
701 | } |
||
702 | '); |
||
703 | self::assertNotEquals($extendedSchema, $this->testSchema); |
||
704 | self::assertEquals( |
||
705 | $this->dedent(' |
||
706 | enum UnusedEnum { |
||
707 | SOME |
||
708 | } |
||
709 | '), |
||
710 | $this->printTestSchemaChanges($extendedSchema) |
||
711 | ); |
||
712 | } |
||
713 | |||
714 | /** |
||
715 | * @see it('adds new unused input object type') |
||
716 | */ |
||
717 | public function testAddsNewUnusedInputObjectType() |
||
718 | { |
||
719 | $extendedSchema = $this->extendTestSchema(' |
||
720 | input UnusedInput { |
||
721 | someInput: String |
||
722 | } |
||
723 | '); |
||
724 | |||
725 | self::assertNotEquals($extendedSchema, $this->testSchema); |
||
726 | self::assertEquals( |
||
727 | $this->dedent(' |
||
728 | input UnusedInput { |
||
729 | someInput: String |
||
730 | } |
||
731 | '), |
||
732 | $this->printTestSchemaChanges($extendedSchema) |
||
733 | ); |
||
734 | } |
||
735 | |||
736 | /** |
||
737 | * @see it('adds new union using new object type') |
||
738 | */ |
||
739 | public function testAddsNewUnionUsingNewObjectType() |
||
740 | { |
||
741 | $extendedSchema = $this->extendTestSchema(' |
||
742 | type DummyUnionMember { |
||
743 | someField: String |
||
744 | } |
||
745 | |||
746 | union UnusedUnion = DummyUnionMember |
||
747 | '); |
||
748 | |||
749 | self::assertNotEquals($extendedSchema, $this->testSchema); |
||
750 | self::assertEquals( |
||
751 | $this->dedent(' |
||
752 | type DummyUnionMember { |
||
753 | someField: String |
||
754 | } |
||
755 | |||
756 | union UnusedUnion = DummyUnionMember |
||
757 | '), |
||
758 | $this->printTestSchemaChanges($extendedSchema) |
||
759 | ); |
||
760 | } |
||
761 | |||
762 | /** |
||
763 | * @see it('extends objects by adding new fields with arguments') |
||
764 | */ |
||
765 | public function testExtendsObjectsByAddingNewFieldsWithArguments() |
||
766 | { |
||
767 | $extendedSchema = $this->extendTestSchema(' |
||
768 | extend type Foo { |
||
769 | newField(arg1: String, arg2: NewInputObj!): String |
||
770 | } |
||
771 | |||
772 | input NewInputObj { |
||
773 | field1: Int |
||
774 | field2: [Float] |
||
775 | field3: String! |
||
776 | } |
||
777 | '); |
||
778 | |||
779 | self::assertEquals( |
||
780 | $this->dedent(' |
||
781 | type Foo implements SomeInterface { |
||
782 | name: String |
||
783 | some: SomeInterface |
||
784 | tree: [Foo]! |
||
785 | newField(arg1: String, arg2: NewInputObj!): String |
||
786 | } |
||
787 | |||
788 | input NewInputObj { |
||
789 | field1: Int |
||
790 | field2: [Float] |
||
791 | field3: String! |
||
792 | } |
||
793 | '), |
||
794 | $this->printTestSchemaChanges($extendedSchema) |
||
795 | ); |
||
796 | } |
||
797 | |||
798 | /** |
||
799 | * @see it('extends objects by adding new fields with existing types') |
||
800 | */ |
||
801 | public function testExtendsObjectsByAddingNewFieldsWithExistingTypes() |
||
802 | { |
||
803 | $extendedSchema = $this->extendTestSchema(' |
||
804 | extend type Foo { |
||
805 | newField(arg1: SomeEnum!): SomeEnum |
||
806 | } |
||
807 | '); |
||
808 | |||
809 | self::assertEquals( |
||
810 | $this->dedent(' |
||
811 | type Foo implements SomeInterface { |
||
812 | name: String |
||
813 | some: SomeInterface |
||
814 | tree: [Foo]! |
||
815 | newField(arg1: SomeEnum!): SomeEnum |
||
816 | } |
||
817 | '), |
||
818 | $this->printTestSchemaChanges($extendedSchema) |
||
819 | ); |
||
820 | } |
||
821 | |||
822 | /** |
||
823 | * @see it('extends objects by adding implemented interfaces') |
||
824 | */ |
||
825 | public function testExtendsObjectsByAddingImplementedInterfaces() |
||
826 | { |
||
827 | $extendedSchema = $this->extendTestSchema(' |
||
828 | extend type Biz implements SomeInterface { |
||
829 | name: String |
||
830 | some: SomeInterface |
||
831 | } |
||
832 | '); |
||
833 | |||
834 | self::assertEquals( |
||
835 | $this->dedent(' |
||
836 | type Biz implements SomeInterface { |
||
837 | fizz: String |
||
838 | name: String |
||
839 | some: SomeInterface |
||
840 | } |
||
841 | '), |
||
842 | $this->printTestSchemaChanges($extendedSchema) |
||
843 | ); |
||
844 | } |
||
845 | |||
846 | /** |
||
847 | * @see it('extends objects by including new types') |
||
848 | */ |
||
849 | public function testExtendsObjectsByIncludingNewTypes() |
||
850 | { |
||
851 | $extendedSchema = $this->extendTestSchema(' |
||
852 | extend type Foo { |
||
853 | newObject: NewObject |
||
854 | newInterface: NewInterface |
||
855 | newUnion: NewUnion |
||
856 | newScalar: NewScalar |
||
857 | newEnum: NewEnum |
||
858 | newTree: [Foo]! |
||
859 | } |
||
860 | |||
861 | type NewObject implements NewInterface { |
||
862 | baz: String |
||
863 | } |
||
864 | |||
865 | type NewOtherObject { |
||
866 | fizz: Int |
||
867 | } |
||
868 | |||
869 | interface NewInterface { |
||
870 | baz: String |
||
871 | } |
||
872 | |||
873 | union NewUnion = NewObject | NewOtherObject |
||
874 | |||
875 | scalar NewScalar |
||
876 | |||
877 | enum NewEnum { |
||
878 | OPTION_A |
||
879 | OPTION_B |
||
880 | } |
||
881 | '); |
||
882 | |||
883 | self::assertEquals( |
||
884 | $this->dedent(' |
||
885 | type Foo implements SomeInterface { |
||
886 | name: String |
||
887 | some: SomeInterface |
||
888 | tree: [Foo]! |
||
889 | newObject: NewObject |
||
890 | newInterface: NewInterface |
||
891 | newUnion: NewUnion |
||
892 | newScalar: NewScalar |
||
893 | newEnum: NewEnum |
||
894 | newTree: [Foo]! |
||
895 | } |
||
896 | |||
897 | enum NewEnum { |
||
898 | OPTION_A |
||
899 | OPTION_B |
||
900 | } |
||
901 | |||
902 | interface NewInterface { |
||
903 | baz: String |
||
904 | } |
||
905 | |||
906 | type NewObject implements NewInterface { |
||
907 | baz: String |
||
908 | } |
||
909 | |||
910 | type NewOtherObject { |
||
911 | fizz: Int |
||
912 | } |
||
913 | |||
914 | scalar NewScalar |
||
915 | |||
916 | union NewUnion = NewObject | NewOtherObject |
||
917 | '), |
||
918 | $this->printTestSchemaChanges($extendedSchema) |
||
919 | ); |
||
920 | } |
||
921 | |||
922 | /** |
||
923 | * @see it('extends objects by adding implemented new interfaces') |
||
924 | */ |
||
925 | public function testExtendsObjectsByAddingImplementedNewInterfaces() |
||
926 | { |
||
927 | $extendedSchema = $this->extendTestSchema(' |
||
928 | extend type Foo implements NewInterface { |
||
929 | baz: String |
||
930 | } |
||
931 | |||
932 | interface NewInterface { |
||
933 | baz: String |
||
934 | } |
||
935 | '); |
||
936 | |||
937 | self::assertEquals( |
||
938 | $this->dedent(' |
||
939 | type Foo implements SomeInterface & NewInterface { |
||
940 | name: String |
||
941 | some: SomeInterface |
||
942 | tree: [Foo]! |
||
943 | baz: String |
||
944 | } |
||
945 | |||
946 | interface NewInterface { |
||
947 | baz: String |
||
948 | } |
||
949 | '), |
||
950 | $this->printTestSchemaChanges($extendedSchema) |
||
951 | ); |
||
952 | } |
||
953 | |||
954 | /** |
||
955 | * @see it('extends different types multiple times') |
||
956 | */ |
||
957 | public function testExtendsDifferentTypesMultipleTimes() |
||
958 | { |
||
959 | $extendedSchema = $this->extendTestSchema(' |
||
960 | extend type Biz implements NewInterface { |
||
961 | buzz: String |
||
962 | } |
||
963 | |||
964 | extend type Biz implements SomeInterface { |
||
965 | name: String |
||
966 | some: SomeInterface |
||
967 | newFieldA: Int |
||
968 | } |
||
969 | |||
970 | extend type Biz { |
||
971 | newFieldA: Int |
||
972 | newFieldB: Float |
||
973 | } |
||
974 | |||
975 | interface NewInterface { |
||
976 | buzz: String |
||
977 | } |
||
978 | |||
979 | extend enum SomeEnum { |
||
980 | THREE |
||
981 | } |
||
982 | |||
983 | extend enum SomeEnum { |
||
984 | FOUR |
||
985 | } |
||
986 | |||
987 | extend union SomeUnion = Boo |
||
988 | |||
989 | extend union SomeUnion = Joo |
||
990 | |||
991 | type Boo { |
||
992 | fieldA: String |
||
993 | } |
||
994 | |||
995 | type Joo { |
||
996 | fieldB: String |
||
997 | } |
||
998 | |||
999 | extend input SomeInput { |
||
1000 | fieldA: String |
||
1001 | } |
||
1002 | |||
1003 | extend input SomeInput { |
||
1004 | fieldB: String |
||
1005 | } |
||
1006 | '); |
||
1007 | |||
1008 | self::assertEquals( |
||
1009 | $this->dedent(' |
||
1010 | type Biz implements NewInterface & SomeInterface { |
||
1011 | fizz: String |
||
1012 | buzz: String |
||
1013 | name: String |
||
1014 | some: SomeInterface |
||
1015 | newFieldA: Int |
||
1016 | newFieldB: Float |
||
1017 | } |
||
1018 | |||
1019 | type Boo { |
||
1020 | fieldA: String |
||
1021 | } |
||
1022 | |||
1023 | type Joo { |
||
1024 | fieldB: String |
||
1025 | } |
||
1026 | |||
1027 | interface NewInterface { |
||
1028 | buzz: String |
||
1029 | } |
||
1030 | |||
1031 | enum SomeEnum { |
||
1032 | ONE |
||
1033 | TWO |
||
1034 | THREE |
||
1035 | FOUR |
||
1036 | } |
||
1037 | |||
1038 | input SomeInput { |
||
1039 | fooArg: String |
||
1040 | fieldA: String |
||
1041 | fieldB: String |
||
1042 | } |
||
1043 | |||
1044 | union SomeUnion = Foo | Biz | Boo | Joo |
||
1045 | '), |
||
1046 | $this->printTestSchemaChanges($extendedSchema) |
||
1047 | ); |
||
1048 | } |
||
1049 | |||
1050 | /** |
||
1051 | * @see it('extends interfaces by adding new fields') |
||
1052 | */ |
||
1053 | public function testExtendsInterfacesByAddingNewFields() |
||
1054 | { |
||
1055 | $extendedSchema = $this->extendTestSchema(' |
||
1056 | extend interface SomeInterface { |
||
1057 | newField: String |
||
1058 | } |
||
1059 | |||
1060 | extend type Bar { |
||
1061 | newField: String |
||
1062 | } |
||
1063 | |||
1064 | extend type Foo { |
||
1065 | newField: String |
||
1066 | } |
||
1067 | '); |
||
1068 | |||
1069 | self::assertEquals( |
||
1070 | $this->dedent(' |
||
1071 | type Bar implements SomeInterface { |
||
1072 | name: String |
||
1073 | some: SomeInterface |
||
1074 | foo: Foo |
||
1075 | newField: String |
||
1076 | } |
||
1077 | |||
1078 | type Foo implements SomeInterface { |
||
1079 | name: String |
||
1080 | some: SomeInterface |
||
1081 | tree: [Foo]! |
||
1082 | newField: String |
||
1083 | } |
||
1084 | |||
1085 | interface SomeInterface { |
||
1086 | name: String |
||
1087 | some: SomeInterface |
||
1088 | newField: String |
||
1089 | } |
||
1090 | '), |
||
1091 | $this->printTestSchemaChanges($extendedSchema) |
||
1092 | ); |
||
1093 | } |
||
1094 | |||
1095 | /** |
||
1096 | * @see it('allows extension of interface with missing Object fields') |
||
1097 | */ |
||
1098 | public function testAllowsExtensionOfInterfaceWithMissingObjectFields() |
||
1099 | { |
||
1100 | $extendedSchema = $this->extendTestSchema(' |
||
1101 | extend interface SomeInterface { |
||
1102 | newField: String |
||
1103 | } |
||
1104 | '); |
||
1105 | |||
1106 | $errors = $extendedSchema->validate(); |
||
1107 | self::assertGreaterThan(0, $errors); |
||
1108 | |||
1109 | self::assertEquals( |
||
1110 | $this->dedent(' |
||
1111 | interface SomeInterface { |
||
1112 | name: String |
||
1113 | some: SomeInterface |
||
1114 | newField: String |
||
1115 | } |
||
1116 | '), |
||
1117 | $this->printTestSchemaChanges($extendedSchema) |
||
1118 | ); |
||
1119 | } |
||
1120 | |||
1121 | /** |
||
1122 | * @see it('extends interfaces multiple times') |
||
1123 | */ |
||
1124 | public function testExtendsInterfacesMultipleTimes() |
||
1125 | { |
||
1126 | $extendedSchema = $this->extendTestSchema(' |
||
1127 | extend interface SomeInterface { |
||
1128 | newFieldA: Int |
||
1129 | } |
||
1130 | extend interface SomeInterface { |
||
1131 | newFieldB(test: Boolean): String |
||
1132 | } |
||
1133 | '); |
||
1134 | |||
1135 | self::assertEquals( |
||
1136 | $this->dedent(' |
||
1137 | interface SomeInterface { |
||
1138 | name: String |
||
1139 | some: SomeInterface |
||
1140 | newFieldA: Int |
||
1141 | newFieldB(test: Boolean): String |
||
1142 | } |
||
1143 | '), |
||
1144 | $this->printTestSchemaChanges($extendedSchema) |
||
1145 | ); |
||
1146 | } |
||
1147 | |||
1148 | /** |
||
1149 | * @see it('may extend mutations and subscriptions') |
||
1150 | */ |
||
1151 | public function testMayExtendMutationsAndSubscriptions() |
||
1152 | { |
||
1153 | $mutationSchema = new Schema([ |
||
1154 | 'query' => new ObjectType([ |
||
1155 | 'name' => 'Query', |
||
1156 | 'fields' => static function () { |
||
1157 | return [ 'queryField' => [ 'type' => Type::string() ] ]; |
||
1158 | }, |
||
1159 | ]), |
||
1160 | 'mutation' => new ObjectType([ |
||
1161 | 'name' => 'Mutation', |
||
1162 | 'fields' => static function () { |
||
1163 | return [ 'mutationField' => ['type' => Type::string() ] ]; |
||
1164 | }, |
||
1165 | ]), |
||
1166 | 'subscription' => new ObjectType([ |
||
1167 | 'name' => 'Subscription', |
||
1168 | 'fields' => static function () { |
||
1169 | return ['subscriptionField' => ['type' => Type::string()]]; |
||
1170 | }, |
||
1171 | ]), |
||
1172 | ]); |
||
1173 | |||
1174 | $ast = Parser::parse(' |
||
1175 | extend type Query { |
||
1176 | newQueryField: Int |
||
1177 | } |
||
1178 | |||
1179 | extend type Mutation { |
||
1180 | newMutationField: Int |
||
1181 | } |
||
1182 | |||
1183 | extend type Subscription { |
||
1184 | newSubscriptionField: Int |
||
1185 | } |
||
1186 | '); |
||
1187 | |||
1188 | $originalPrint = SchemaPrinter::doPrint($mutationSchema); |
||
1189 | $extendedSchema = SchemaExtender::extend($mutationSchema, $ast); |
||
1190 | self::assertNotEquals($mutationSchema, $extendedSchema); |
||
1191 | self::assertEquals(SchemaPrinter::doPrint($mutationSchema), $originalPrint); |
||
1192 | self::assertEquals(SchemaPrinter::doPrint($extendedSchema), $this->dedent(' |
||
1193 | type Mutation { |
||
1194 | mutationField: String |
||
1195 | newMutationField: Int |
||
1196 | } |
||
1197 | |||
1198 | type Query { |
||
1199 | queryField: String |
||
1200 | newQueryField: Int |
||
1201 | } |
||
1202 | |||
1203 | type Subscription { |
||
1204 | subscriptionField: String |
||
1205 | newSubscriptionField: Int |
||
1206 | } |
||
1207 | ')); |
||
1208 | } |
||
1209 | |||
1210 | /** |
||
1211 | * @see it('may extend directives with new simple directive') |
||
1212 | */ |
||
1213 | public function testMayExtendDirectivesWithNewSimpleDirective() |
||
1222 | } |
||
1223 | |||
1224 | /** |
||
1225 | * @see it('sets correct description when extending with a new directive') |
||
1226 | */ |
||
1227 | public function testSetsCorrectDescriptionWhenExtendingWithANewDirective() |
||
1228 | { |
||
1229 | $extendedSchema = $this->extendTestSchema(' |
||
1230 | """ |
||
1231 | new directive |
||
1232 | """ |
||
1233 | directive @new on QUERY |
||
1234 | '); |
||
1235 | |||
1236 | $newDirective = $extendedSchema->getDirective('new'); |
||
1237 | self::assertEquals('new directive', $newDirective->description); |
||
1238 | } |
||
1239 | |||
1240 | /** |
||
1241 | * @see it('sets correct description using legacy comments') |
||
1242 | */ |
||
1243 | public function testSetsCorrectDescriptionUsingLegacyComments() |
||
1255 | } |
||
1256 | |||
1257 | /** |
||
1258 | * @see it('may extend directives with new complex directive') |
||
1259 | */ |
||
1260 | public function testMayExtendDirectivesWithNewComplexDirective() |
||
1261 | { |
||
1262 | $extendedSchema = $this->extendTestSchema(' |
||
1263 | directive @profile(enable: Boolean! tag: String) on QUERY | FIELD |
||
1264 | '); |
||
1265 | |||
1266 | $extendedDirective = $extendedSchema->getDirective('profile'); |
||
1267 | self::assertContains('QUERY', $extendedDirective->locations); |
||
1268 | self::assertContains('FIELD', $extendedDirective->locations); |
||
1269 | |||
1270 | $args = $extendedDirective->args; |
||
1271 | self::assertCount(2, $args); |
||
1272 | |||
1273 | $arg0 = $args[0]; |
||
1274 | $arg1 = $args[1]; |
||
1275 | /** @var NonNull $arg0Type */ |
||
1276 | $arg0Type = $arg0->getType(); |
||
1277 | |||
1278 | self::assertEquals('enable', $arg0->name); |
||
1279 | self::assertTrue($arg0Type instanceof NonNull); |
||
1280 | self::assertTrue($arg0Type->getWrappedType() instanceof ScalarType); |
||
1281 | |||
1282 | self::assertEquals('tag', $arg1->name); |
||
1283 | self::assertTrue($arg1->getType() instanceof ScalarType); |
||
1284 | } |
||
1285 | |||
1286 | /** |
||
1287 | * @see it('Rejects invalid SDL') |
||
1288 | */ |
||
1289 | public function testRejectsInvalidSDL() |
||
1290 | { |
||
1291 | $sdl = ' |
||
1292 | extend schema @unknown |
||
1293 | '; |
||
1294 | |||
1295 | try { |
||
1296 | $this->extendTestSchema($sdl); |
||
1297 | self::fail(); |
||
1298 | } catch (Error $error) { |
||
1299 | self::assertEquals('Unknown directive "unknown".', $error->getMessage()); |
||
1300 | } |
||
1301 | } |
||
1302 | |||
1303 | /** |
||
1304 | * @see it('Allows to disable SDL validation') |
||
1305 | */ |
||
1306 | public function testAllowsToDisableSDLValidation() |
||
1307 | { |
||
1308 | $sdl = ' |
||
1309 | extend schema @unknown |
||
1310 | '; |
||
1311 | |||
1312 | $this->extendTestSchema($sdl, [ 'assumeValid' => true ]); |
||
1313 | $this->extendTestSchema($sdl, [ 'assumeValidSDL' => true ]); |
||
1314 | } |
||
1315 | |||
1316 | /** |
||
1317 | * @see it('does not allow replacing a default directive') |
||
1318 | */ |
||
1319 | public function testDoesNotAllowReplacingADefaultDirective() |
||
1320 | { |
||
1321 | $sdl = ' |
||
1322 | directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD |
||
1323 | '; |
||
1324 | |||
1325 | try { |
||
1326 | $this->extendTestSchema($sdl); |
||
1327 | self::fail(); |
||
1328 | } catch (Error $error) { |
||
1329 | self::assertEquals('Directive "include" already exists in the schema. It cannot be redefined.', $error->getMessage()); |
||
1330 | } |
||
1331 | } |
||
1332 | |||
1333 | /** |
||
1334 | * @see it('does not allow replacing a custom directive') |
||
1335 | */ |
||
1336 | public function testDoesNotAllowReplacingACustomDirective() |
||
1337 | { |
||
1338 | $extendedSchema = $this->extendTestSchema(' |
||
1339 | directive @meow(if: Boolean!) on FIELD | FRAGMENT_SPREAD |
||
1340 | '); |
||
1341 | |||
1342 | $replacementAST = Parser::parse(' |
||
1343 | directive @meow(if: Boolean!) on FIELD | QUERY |
||
1344 | '); |
||
1345 | |||
1346 | try { |
||
1347 | SchemaExtender::extend($extendedSchema, $replacementAST); |
||
1348 | self::fail(); |
||
1349 | } catch (Error $error) { |
||
1350 | self::assertEquals('Directive "meow" already exists in the schema. It cannot be redefined.', $error->getMessage()); |
||
1351 | } |
||
1352 | } |
||
1353 | |||
1354 | /** |
||
1355 | * @see it('does not allow replacing an existing type') |
||
1356 | */ |
||
1357 | public function testDoesNotAllowReplacingAnExistingType() |
||
1358 | { |
||
1359 | $existingTypeError = static function ($type) { |
||
1360 | return 'Type "' . $type . '" already exists in the schema. It cannot also be defined in this type definition.'; |
||
1361 | }; |
||
1362 | |||
1363 | $typeSDL = ' |
||
1364 | type Bar |
||
1365 | '; |
||
1366 | |||
1367 | try { |
||
1368 | $this->extendTestSchema($typeSDL); |
||
1369 | self::fail(); |
||
1370 | } catch (Error $error) { |
||
1371 | self::assertEquals($existingTypeError('Bar'), $error->getMessage()); |
||
1372 | } |
||
1373 | |||
1374 | $scalarSDL = ' |
||
1375 | scalar SomeScalar |
||
1376 | '; |
||
1377 | |||
1378 | try { |
||
1379 | $this->extendTestSchema($scalarSDL); |
||
1380 | self::fail(); |
||
1381 | } catch (Error $error) { |
||
1382 | self::assertEquals($existingTypeError('SomeScalar'), $error->getMessage()); |
||
1383 | } |
||
1384 | |||
1385 | $interfaceSDL = ' |
||
1386 | interface SomeInterface |
||
1387 | '; |
||
1388 | |||
1389 | try { |
||
1390 | $this->extendTestSchema($interfaceSDL); |
||
1391 | self::fail(); |
||
1392 | } catch (Error $error) { |
||
1393 | self::assertEquals($existingTypeError('SomeInterface'), $error->getMessage()); |
||
1394 | } |
||
1395 | |||
1396 | $enumSDL = ' |
||
1397 | enum SomeEnum |
||
1398 | '; |
||
1399 | |||
1400 | try { |
||
1401 | $this->extendTestSchema($enumSDL); |
||
1402 | self::fail(); |
||
1403 | } catch (Error $error) { |
||
1404 | self::assertEquals($existingTypeError('SomeEnum'), $error->getMessage()); |
||
1405 | } |
||
1406 | |||
1407 | $unionSDL = ' |
||
1408 | union SomeUnion |
||
1409 | '; |
||
1410 | |||
1411 | try { |
||
1412 | $this->extendTestSchema($unionSDL); |
||
1413 | self::fail(); |
||
1414 | } catch (Error $error) { |
||
1415 | self::assertEquals($existingTypeError('SomeUnion'), $error->getMessage()); |
||
1416 | } |
||
1417 | |||
1418 | $inputSDL = ' |
||
1419 | input SomeInput |
||
1420 | '; |
||
1421 | |||
1422 | try { |
||
1423 | $this->extendTestSchema($inputSDL); |
||
1424 | self::fail(); |
||
1425 | } catch (Error $error) { |
||
1426 | self::assertEquals($existingTypeError('SomeInput'), $error->getMessage()); |
||
1427 | } |
||
1428 | } |
||
1429 | |||
1430 | /** |
||
1431 | * @see it('does not allow replacing an existing field') |
||
1432 | */ |
||
1433 | public function testDoesNotAllowReplacingAnExistingField() |
||
1434 | { |
||
1435 | $existingFieldError = static function (string $type, string $field) { |
||
1436 | return 'Field "' . $type . '.' . $field . '" already exists in the schema. It cannot also be defined in this type extension.'; |
||
1437 | }; |
||
1438 | |||
1439 | $typeSDL = ' |
||
1440 | extend type Bar { |
||
1441 | foo: Foo |
||
1442 | } |
||
1443 | '; |
||
1444 | |||
1445 | try { |
||
1446 | $this->extendTestSchema($typeSDL); |
||
1447 | self::fail(); |
||
1448 | } catch (Error $error) { |
||
1449 | self::assertEquals($existingFieldError('Bar', 'foo'), $error->getMessage()); |
||
1450 | } |
||
1451 | |||
1452 | $interfaceSDL = ' |
||
1453 | extend interface SomeInterface { |
||
1454 | some: Foo |
||
1455 | } |
||
1456 | '; |
||
1457 | |||
1458 | try { |
||
1459 | $this->extendTestSchema($interfaceSDL); |
||
1460 | self::fail(); |
||
1461 | } catch (Error $error) { |
||
1462 | self::assertEquals($existingFieldError('SomeInterface', 'some'), $error->getMessage()); |
||
1463 | } |
||
1464 | |||
1465 | $inputSDL = ' |
||
1466 | extend input SomeInput { |
||
1467 | fooArg: String |
||
1468 | } |
||
1469 | '; |
||
1470 | |||
1471 | try { |
||
1472 | $this->extendTestSchema($inputSDL); |
||
1473 | self::fail(); |
||
1474 | } catch (Error $error) { |
||
1475 | self::assertEquals($existingFieldError('SomeInput', 'fooArg'), $error->getMessage()); |
||
1476 | } |
||
1477 | } |
||
1478 | |||
1479 | /** |
||
1480 | * @see it('does not allow replacing an existing enum value') |
||
1481 | */ |
||
1482 | public function testDoesNotAllowReplacingAnExistingEnumValue() |
||
1483 | { |
||
1484 | $sdl = ' |
||
1485 | extend enum SomeEnum { |
||
1486 | ONE |
||
1487 | } |
||
1488 | '; |
||
1489 | |||
1490 | try { |
||
1491 | $this->extendTestSchema($sdl); |
||
1492 | self::fail(); |
||
1493 | } catch (Error $error) { |
||
1494 | self::assertEquals('Enum value "SomeEnum.ONE" already exists in the schema. It cannot also be defined in this type extension.', $error->getMessage()); |
||
1495 | } |
||
1496 | } |
||
1497 | |||
1498 | /** |
||
1499 | * @see it('does not allow referencing an unknown type') |
||
1500 | */ |
||
1501 | public function testDoesNotAllowReferencingAnUnknownType() |
||
1502 | { |
||
1503 | $unknownTypeError = 'Unknown type: "Quix". Ensure that this type exists either in the original schema, or is added in a type definition.'; |
||
1504 | |||
1505 | $typeSDL = ' |
||
1506 | extend type Bar { |
||
1507 | quix: Quix |
||
1508 | } |
||
1509 | '; |
||
1510 | |||
1511 | try { |
||
1512 | $this->extendTestSchema($typeSDL); |
||
1513 | self::fail(); |
||
1514 | } catch (Error $error) { |
||
1515 | self::assertEquals($unknownTypeError, $error->getMessage()); |
||
1516 | } |
||
1517 | |||
1518 | $interfaceSDL = ' |
||
1519 | extend interface SomeInterface { |
||
1520 | quix: Quix |
||
1521 | } |
||
1522 | '; |
||
1523 | |||
1524 | try { |
||
1525 | $this->extendTestSchema($interfaceSDL); |
||
1526 | self::fail(); |
||
1527 | } catch (Error $error) { |
||
1528 | self::assertEquals($unknownTypeError, $error->getMessage()); |
||
1529 | } |
||
1530 | |||
1531 | $unionSDL = ' |
||
1532 | extend union SomeUnion = Quix |
||
1533 | '; |
||
1534 | |||
1535 | try { |
||
1536 | $this->extendTestSchema($unionSDL); |
||
1537 | self::fail(); |
||
1538 | } catch (Error $error) { |
||
1539 | self::assertEquals($unknownTypeError, $error->getMessage()); |
||
1540 | } |
||
1541 | |||
1542 | $inputSDL = ' |
||
1543 | extend input SomeInput { |
||
1544 | quix: Quix |
||
1545 | } |
||
1546 | '; |
||
1547 | |||
1548 | try { |
||
1549 | $this->extendTestSchema($inputSDL); |
||
1550 | self::fail(); |
||
1551 | } catch (Error $error) { |
||
1552 | self::assertEquals($unknownTypeError, $error->getMessage()); |
||
1553 | } |
||
1554 | } |
||
1555 | |||
1556 | /** |
||
1557 | * @see it('does not allow extending an unknown type') |
||
1558 | */ |
||
1559 | public function testDoesNotAllowExtendingAnUnknownType() |
||
1576 | } |
||
1577 | } |
||
1578 | } |
||
1579 | |||
1580 | /** |
||
1581 | * @see it('does not allow extending a mismatch type') |
||
1582 | */ |
||
1583 | public function testDoesNotAllowExtendingAMismatchType() |
||
1584 | { |
||
1585 | $typeSDL = ' |
||
1586 | extend type SomeInterface @foo |
||
1587 | '; |
||
1588 | |||
1589 | try { |
||
1590 | $this->extendTestSchema($typeSDL); |
||
1591 | self::fail(); |
||
1592 | } catch (Error $error) { |
||
1593 | self::assertEquals('Cannot extend non-object type "SomeInterface".', $error->getMessage()); |
||
1594 | } |
||
1595 | |||
1596 | $interfaceSDL = ' |
||
1597 | extend interface Foo @foo |
||
1598 | '; |
||
1599 | |||
1600 | try { |
||
1601 | $this->extendTestSchema($interfaceSDL); |
||
1602 | self::fail(); |
||
1603 | } catch (Error $error) { |
||
1604 | self::assertEquals('Cannot extend non-interface type "Foo".', $error->getMessage()); |
||
1605 | } |
||
1606 | |||
1607 | $enumSDL = ' |
||
1608 | extend enum Foo @foo |
||
1609 | '; |
||
1610 | |||
1611 | try { |
||
1612 | $this->extendTestSchema($enumSDL); |
||
1613 | self::fail(); |
||
1614 | } catch (Error $error) { |
||
1615 | self::assertEquals('Cannot extend non-enum type "Foo".', $error->getMessage()); |
||
1616 | } |
||
1617 | |||
1618 | $unionSDL = ' |
||
1619 | extend union Foo @foo |
||
1620 | '; |
||
1621 | |||
1622 | try { |
||
1623 | $this->extendTestSchema($unionSDL); |
||
1624 | self::fail(); |
||
1625 | } catch (Error $error) { |
||
1626 | self::assertEquals('Cannot extend non-union type "Foo".', $error->getMessage()); |
||
1627 | } |
||
1628 | |||
1629 | $inputSDL = ' |
||
1630 | extend input Foo @foo |
||
1631 | '; |
||
1632 | |||
1633 | try { |
||
1634 | $this->extendTestSchema($inputSDL); |
||
1635 | self::fail(); |
||
1636 | } catch (Error $error) { |
||
1637 | self::assertEquals('Cannot extend non-input object type "Foo".', $error->getMessage()); |
||
1638 | } |
||
1639 | } |
||
1640 | |||
1641 | /** |
||
1642 | * @see it('does not automatically include common root type names') |
||
1643 | */ |
||
1644 | public function testDoesNotAutomaticallyIncludeCommonRootTypeNames() |
||
1645 | { |
||
1646 | $schema = $this->extendTestSchema(' |
||
1647 | type Mutation { |
||
1648 | doSomething: String |
||
1649 | } |
||
1650 | '); |
||
1651 | |||
1652 | self::assertNull($schema->getMutationType()); |
||
1653 | } |
||
1654 | |||
1655 | /** |
||
1656 | * @see it('adds schema definition missing in the original schema') |
||
1657 | */ |
||
1658 | public function testAddsSchemaDefinitionMissingInTheOriginalSchema() |
||
1659 | { |
||
1660 | $schema = new Schema([ |
||
1661 | 'directives' => [$this->FooDirective], |
||
1662 | 'types' => [$this->FooType], |
||
1663 | ]); |
||
1664 | |||
1665 | self::assertNull($schema->getQueryType()); |
||
1666 | |||
1667 | $ast = Parser::parse(' |
||
1668 | schema @foo { |
||
1669 | query: Foo |
||
1670 | } |
||
1671 | '); |
||
1672 | |||
1673 | $schema = SchemaExtender::extend($schema, $ast); |
||
1674 | $queryType = $schema->getQueryType(); |
||
1675 | |||
1676 | self::assertEquals($queryType->name, 'Foo'); |
||
1677 | } |
||
1678 | |||
1679 | /** |
||
1680 | * @see it('adds new root types via schema extension') |
||
1681 | */ |
||
1682 | public function testAddsNewRootTypesViaSchemaExtension() |
||
1695 | } |
||
1696 | |||
1697 | /** |
||
1698 | * @see it('adds multiple new root types via schema extension') |
||
1699 | */ |
||
1700 | public function testAddsMultipleNewRootTypesViaSchemaExtension() |
||
1701 | { |
||
1702 | $schema = $this->extendTestSchema(' |
||
1703 | extend schema { |
||
1704 | mutation: Mutation |
||
1705 | subscription: Subscription |
||
1706 | } |
||
1707 | type Mutation { |
||
1708 | doSomething: String |
||
1709 | } |
||
1710 | type Subscription { |
||
1711 | hearSomething: String |
||
1712 | } |
||
1713 | '); |
||
1714 | $mutationType = $schema->getMutationType(); |
||
1715 | $subscriptionType = $schema->getSubscriptionType(); |
||
1716 | |||
1717 | self::assertEquals('Mutation', $mutationType->name); |
||
1718 | self::assertEquals('Subscription', $subscriptionType->name); |
||
1719 | } |
||
1720 | |||
1721 | /** |
||
1722 | * @see it('applies multiple schema extensions') |
||
1723 | */ |
||
1724 | public function testAppliesMultipleSchemaExtensions() |
||
1725 | { |
||
1726 | $schema = $this->extendTestSchema(' |
||
1727 | extend schema { |
||
1728 | mutation: Mutation |
||
1729 | } |
||
1730 | extend schema { |
||
1731 | subscription: Subscription |
||
1732 | } |
||
1733 | type Mutation { |
||
1734 | doSomething: String |
||
1735 | } |
||
1736 | type Subscription { |
||
1737 | hearSomething: String |
||
1738 | } |
||
1739 | '); |
||
1740 | |||
1741 | $mutationType = $schema->getMutationType(); |
||
1742 | $subscriptionType = $schema->getSubscriptionType(); |
||
1743 | |||
1744 | self::assertEquals('Mutation', $mutationType->name); |
||
1745 | self::assertEquals('Subscription', $subscriptionType->name); |
||
1746 | } |
||
1747 | |||
1748 | /** |
||
1749 | * @see it('schema extension AST are available from schema object') |
||
1750 | */ |
||
1751 | public function testSchemaExtensionASTAreAvailableFromSchemaObject() |
||
1752 | { |
||
1753 | $schema = $this->extendTestSchema(' |
||
1754 | extend schema { |
||
1755 | mutation: Mutation |
||
1756 | } |
||
1757 | extend schema { |
||
1758 | subscription: Subscription |
||
1759 | } |
||
1760 | type Mutation { |
||
1761 | doSomething: String |
||
1762 | } |
||
1763 | type Subscription { |
||
1764 | hearSomething: String |
||
1765 | } |
||
1766 | '); |
||
1767 | |||
1768 | $ast = Parser::parse(' |
||
1769 | extend schema @foo |
||
1770 | '); |
||
1771 | $schema = SchemaExtender::extend($schema, $ast); |
||
1772 | |||
1773 | $nodes = $schema->extensionASTNodes; |
||
1774 | self::assertEquals( |
||
1775 | $this->dedent(' |
||
1776 | extend schema { |
||
1777 | mutation: Mutation |
||
1778 | } |
||
1779 | |||
1780 | extend schema { |
||
1781 | subscription: Subscription |
||
1782 | } |
||
1783 | |||
1784 | extend schema @foo |
||
1785 | '), |
||
1786 | implode( |
||
1787 | "\n", |
||
1788 | array_map(static function ($node) { |
||
1789 | return Printer::doPrint($node) . "\n"; |
||
1790 | }, $nodes) |
||
1791 | ) |
||
1792 | ); |
||
1793 | } |
||
1794 | |||
1795 | /** |
||
1796 | * @see it('does not allow redefining an existing root type') |
||
1797 | */ |
||
1798 | public function testDoesNotAllowRedefiningAnExistingRootType() |
||
1815 | } |
||
1816 | } |
||
1817 | |||
1818 | /** |
||
1819 | * @see it('does not allow defining a root operation type twice') |
||
1820 | */ |
||
1821 | public function testDoesNotAllowDefiningARootOperationTypeTwice() |
||
1822 | { |
||
1823 | $sdl = ' |
||
1824 | extend schema { |
||
1825 | mutation: Mutation |
||
1826 | } |
||
1827 | extend schema { |
||
1828 | mutation: Mutation |
||
1829 | } |
||
1830 | type Mutation { |
||
1831 | doSomething: String |
||
1832 | } |
||
1833 | '; |
||
1834 | |||
1835 | try { |
||
1836 | $this->extendTestSchema($sdl); |
||
1837 | self::fail(); |
||
1838 | } catch (Error $error) { |
||
1839 | self::assertEquals('Must provide only one mutation type in schema.', $error->getMessage()); |
||
1840 | } |
||
1841 | } |
||
1842 | |||
1843 | /** |
||
1844 | * @see it('does not allow defining a root operation type with different types') |
||
1845 | */ |
||
1846 | public function testDoesNotAllowDefiningARootOperationTypeWithDifferentTypes() |
||
1847 | { |
||
1848 | $sdl = ' |
||
1849 | extend schema { |
||
1850 | mutation: Mutation |
||
1851 | } |
||
1852 | extend schema { |
||
1853 | mutation: SomethingElse |
||
1854 | } |
||
1855 | type Mutation { |
||
1856 | doSomething: String |
||
1857 | } |
||
1858 | type SomethingElse { |
||
1859 | doSomethingElse: String |
||
1860 | } |
||
1861 | '; |
||
1862 | |||
1863 | try { |
||
1864 | $this->extendTestSchema($sdl); |
||
1865 | self::fail(); |
||
1866 | } catch (Error $error) { |
||
1867 | self::assertEquals('Must provide only one mutation type in schema.', $error->getMessage()); |
||
1868 | } |
||
1869 | } |
||
1870 | |||
1871 | /** |
||
1872 | * @see https://github.com/webonyx/graphql-php/pull/381 |
||
1873 | */ |
||
1874 | public function testOriginalResolversArePreserved() |
||
1904 | } |
||
1905 | |||
1906 | /** |
||
1907 | * @see https://github.com/webonyx/graphql-php/issues/180 |
||
1908 | */ |
||
1909 | public function testShouldBeAbleToIntroduceNewTypesThroughExtension() |
||
1910 | { |
||
1947 | } |
||
1948 | } |
||
1949 |
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.