diff --git a/tests/Type/DefinitionTest.php b/tests/Type/DefinitionTest.php index d5b6b50..ec58783 100644 --- a/tests/Type/DefinitionTest.php +++ b/tests/Type/DefinitionTest.php @@ -1,11 +1,13 @@ objectType = new ObjectType(['name' => 'Object', 'fields' => ['tmp' => Type::string()]]); - $this->interfaceType = new InterfaceType(['name' => 'Interface']); - $this->unionType = new UnionType(['name' => 'Union', 'types' => [$this->objectType]]); - $this->enumType = new EnumType(['name' => 'Enum']); + $this->objectType = new ObjectType(['name' => 'Object', 'fields' => ['tmp' => Type::string()]]); + $this->interfaceType = new InterfaceType(['name' => 'Interface']); + $this->unionType = new UnionType(['name' => 'Union', 'types' => [$this->objectType]]); + $this->enumType = new EnumType(['name' => 'Enum']); $this->inputObjectType = new InputObjectType(['name' => 'InputObject']); $this->objectWithIsTypeOf = new ObjectType([ - 'name' => 'ObjectWithIsTypeOf', + 'name' => 'ObjectWithIsTypeOf', 'fields' => ['f' => ['type' => Type::string()]], ]); $this->scalarType = new CustomScalarType([ - 'name' => 'Scalar', - 'serialize' => function () {}, - 'parseValue' => function () {}, - 'parseLiteral' => function () {}, + 'name' => 'Scalar', + 'serialize' => function () { + }, + 'parseValue' => function () { + }, + 'parseLiteral' => function () { + }, ]); $this->blogImage = new ObjectType([ - 'name' => 'Image', + 'name' => 'Image', 'fields' => [ - 'url' => ['type' => Type::string()], - 'width' => ['type' => Type::int()], - 'height' => ['type' => Type::int()] - ] + 'url' => ['type' => Type::string()], + 'width' => ['type' => Type::int()], + 'height' => ['type' => Type::int()], + ], ]); $this->blogAuthor = new ObjectType([ - 'name' => 'Author', - 'fields' => function() { + 'name' => 'Author', + 'fields' => function () { return [ - 'id' => ['type' => Type::string()], - 'name' => ['type' => Type::string()], - 'pic' => [ 'type' => $this->blogImage, 'args' => [ - 'width' => ['type' => Type::int()], - 'height' => ['type' => Type::int()] - ]], + 'id' => ['type' => Type::string()], + 'name' => ['type' => Type::string()], + 'pic' => [ + 'type' => $this->blogImage, + 'args' => [ + 'width' => ['type' => Type::int()], + 'height' => ['type' => Type::int()], + ], + ], 'recentArticle' => $this->blogArticle, ]; }, ]); $this->blogArticle = new ObjectType([ - 'name' => 'Article', + 'name' => 'Article', 'fields' => [ - 'id' => ['type' => Type::string()], + 'id' => ['type' => Type::string()], 'isPublished' => ['type' => Type::boolean()], - 'author' => ['type' => $this->blogAuthor], - 'title' => ['type' => Type::string()], - 'body' => ['type' => Type::string()] - ] + 'author' => ['type' => $this->blogAuthor], + 'title' => ['type' => Type::string()], + 'body' => ['type' => Type::string()], + ], ]); $this->blogQuery = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'article' => ['type' => $this->blogArticle, 'args' => [ - 'id' => ['type' => Type::string()] - ]], - 'feed' => ['type' => new ListOfType($this->blogArticle)] - ] + 'article' => [ + 'type' => $this->blogArticle, + 'args' => [ + 'id' => ['type' => Type::string()], + ], + ], + 'feed' => ['type' => new ListOfType($this->blogArticle)], + ], ]); $this->blogMutation = new ObjectType([ - 'name' => 'Mutation', + 'name' => 'Mutation', 'fields' => [ - 'writeArticle' => ['type' => $this->blogArticle] - ] + 'writeArticle' => ['type' => $this->blogArticle], + ], ]); $this->blogSubscription = new ObjectType([ - 'name' => 'Subscription', + 'name' => 'Subscription', 'fields' => [ 'articleSubscribe' => [ - 'args' => [ 'id' => [ 'type' => Type::string() ]], - 'type' => $this->blogArticle - ] - ] + 'args' => ['id' => ['type' => Type::string()]], + 'type' => $this->blogArticle, + ], + ], ]); } @@ -175,7 +165,7 @@ class DefinitionTest extends TestCase public function testDefinesAQueryOnlySchema() : void { $blogSchema = new Schema([ - 'query' => $this->blogQuery + 'query' => $this->blogQuery, ]); $this->assertSame($blogSchema->getQueryType(), $this->blogQuery); @@ -187,7 +177,7 @@ class DefinitionTest extends TestCase /** @var ObjectType $articleFieldType */ $articleFieldType = $articleField->getType(); - $titleField = $articleFieldType->getField('title'); + $titleField = $articleFieldType->getField('title'); $this->assertInstanceOf('GraphQL\Type\Definition\FieldDefinition', $titleField); $this->assertSame('title', $titleField->name); @@ -219,8 +209,8 @@ class DefinitionTest extends TestCase public function testDefinesAMutationSchema() : void { $schema = new Schema([ - 'query' => $this->blogQuery, - 'mutation' => $this->blogMutation + 'query' => $this->blogQuery, + 'mutation' => $this->blogMutation, ]); $this->assertSame($this->blogMutation, $schema->getMutationType()); @@ -238,8 +228,8 @@ class DefinitionTest extends TestCase public function testDefinesSubscriptionSchema() : void { $schema = new Schema([ - 'query' => $this->blogQuery, - 'subscription' => $this->blogSubscription + 'query' => $this->blogQuery, + 'subscription' => $this->blogSubscription, ]); $this->assertEquals($this->blogSubscription, $schema->getSubscriptionType()); @@ -256,21 +246,24 @@ class DefinitionTest extends TestCase public function testDefinesEnumTypeWithDeprecatedValue() : void { $enumTypeWithDeprecatedValue = new EnumType([ - 'name' => 'EnumWithDeprecatedValue', + 'name' => 'EnumWithDeprecatedValue', 'values' => [ - 'foo' => ['deprecationReason' => 'Just because'] - ] + 'foo' => ['deprecationReason' => 'Just because'], + ], ]); $value = $enumTypeWithDeprecatedValue->getValues()[0]; - $this->assertArraySubset([ - 'name' => 'foo', - 'description' => null, - 'deprecationReason' => 'Just because', - 'value' => 'foo', - 'astNode' => null - ], (array) $value); + $this->assertArraySubset( + [ + 'name' => 'foo', + 'description' => null, + 'deprecationReason' => 'Just because', + 'value' => 'foo', + 'astNode' => null, + ], + (array) $value + ); $this->assertEquals(true, $value->isDeprecated()); } @@ -281,35 +274,35 @@ class DefinitionTest extends TestCase public function testDefinesAnEnumTypeWithAValueOfNullAndUndefined() : void { $EnumTypeWithNullishValue = new EnumType([ - 'name' => 'EnumWithNullishValue', + 'name' => 'EnumWithNullishValue', 'values' => [ - 'NULL' => ['value' => null], + 'NULL' => ['value' => null], 'UNDEFINED' => ['value' => null], - ] + ], ]); $expected = [ [ - 'name' => 'NULL', - 'description' => null, + 'name' => 'NULL', + 'description' => null, 'deprecationReason' => null, - 'value' => null, - 'astNode' => null, + 'value' => null, + 'astNode' => null, ], [ - 'name' => 'UNDEFINED', - 'description' => null, + 'name' => 'UNDEFINED', + 'description' => null, 'deprecationReason' => null, - 'value' => null, - 'astNode' => null, + 'value' => null, + 'astNode' => null, ], ]; $actual = $EnumTypeWithNullishValue->getValues(); $this->assertEquals(count($expected), count($actual)); - $this->assertArraySubset($expected[0], (array)$actual[0]); - $this->assertArraySubset($expected[1], (array)$actual[1]); + $this->assertArraySubset($expected[0], (array) $actual[0]); + $this->assertArraySubset($expected[1], (array) $actual[1]); } /** @@ -318,13 +311,13 @@ class DefinitionTest extends TestCase public function testDefinesAnObjectTypeWithDeprecatedField() : void { $TypeWithDeprecatedField = new ObjectType([ - 'name' => 'foo', - 'fields' => [ - 'bar' => [ - 'type' => Type::string(), - 'deprecationReason' => 'A terrible reason' - ] - ] + 'name' => 'foo', + 'fields' => [ + 'bar' => [ + 'type' => Type::string(), + 'deprecationReason' => 'A terrible reason', + ], + ], ]); $field = $TypeWithDeprecatedField->getField('bar'); @@ -342,26 +335,26 @@ class DefinitionTest extends TestCase public function testIncludesNestedInputObjectInTheMap() : void { $nestedInputObject = new InputObjectType([ - 'name' => 'NestedInputObject', - 'fields' => ['value' => ['type' => Type::string()]] + 'name' => 'NestedInputObject', + 'fields' => ['value' => ['type' => Type::string()]], ]); - $someInputObject = new InputObjectType([ - 'name' => 'SomeInputObject', - 'fields' => ['nested' => ['type' => $nestedInputObject]] + $someInputObject = new InputObjectType([ + 'name' => 'SomeInputObject', + 'fields' => ['nested' => ['type' => $nestedInputObject]], ]); - $someMutation = new ObjectType([ - 'name' => 'SomeMutation', + $someMutation = new ObjectType([ + 'name' => 'SomeMutation', 'fields' => [ 'mutateSomething' => [ 'type' => $this->blogArticle, - 'args' => ['input' => ['type' => $someInputObject]] - ] - ] + 'args' => ['input' => ['type' => $someInputObject]], + ], + ], ]); $schema = new Schema([ - 'query' => $this->blogQuery, - 'mutation' => $someMutation + 'query' => $this->blogQuery, + 'mutation' => $someMutation, ]); $this->assertSame($nestedInputObject, $schema->getType('NestedInputObject')); } @@ -372,28 +365,28 @@ class DefinitionTest extends TestCase public function testIncludesInterfaceSubtypesInTheTypeMap() : void { $someInterface = new InterfaceType([ - 'name' => 'SomeInterface', + 'name' => 'SomeInterface', 'fields' => [ - 'f' => ['type' => Type::int()] - ] + 'f' => ['type' => Type::int()], + ], ]); $someSubtype = new ObjectType([ - 'name' => 'SomeSubtype', - 'fields' => [ - 'f' => ['type' => Type::int()] + 'name' => 'SomeSubtype', + 'fields' => [ + 'f' => ['type' => Type::int()], ], 'interfaces' => [$someInterface], ]); $schema = new Schema([ 'query' => new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'iface' => ['type' => $someInterface] - ] + 'iface' => ['type' => $someInterface], + ], ]), - 'types' => [$someSubtype] + 'types' => [$someSubtype], ]); $this->assertSame($someSubtype, $schema->getType('SomeSubtype')); } @@ -406,28 +399,30 @@ class DefinitionTest extends TestCase $someInterface = null; $someSubtype = new ObjectType([ - 'name' => 'SomeSubtype', - 'fields' => [ - 'f' => ['type' => Type::int()] + 'name' => 'SomeSubtype', + 'fields' => [ + 'f' => ['type' => Type::int()], ], - 'interfaces' => function() use (&$someInterface) { return [$someInterface]; }, + 'interfaces' => function () use (&$someInterface) { + return [$someInterface]; + }, ]); $someInterface = new InterfaceType([ - 'name' => 'SomeInterface', + 'name' => 'SomeInterface', 'fields' => [ - 'f' => ['type' => Type::int()] - ] + 'f' => ['type' => Type::int()], + ], ]); $schema = new Schema([ 'query' => new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'iface' => ['type' => $someInterface] - ] + 'iface' => ['type' => $someInterface], + ], ]), - 'types' => [$someSubtype] + 'types' => [$someSubtype], ]); $this->assertSame($someSubtype, $schema->getType('SomeSubtype')); @@ -483,11 +478,15 @@ class DefinitionTest extends TestCase [$this->interfaceType, false], [$this->unionType, false], [$this->enumType, true], - [$this->inputObjectType, true] + [$this->inputObjectType, true], ]; foreach ($expected as $index => $entry) { - $this->assertSame($entry[1], Type::isInputType($entry[0]), "Type {$entry[0]} was detected incorrectly"); + $this->assertSame( + $entry[1], + Type::isInputType($entry[0]), + sprintf('Type %s was detected incorrectly', $entry[0]) + ); } } @@ -502,11 +501,15 @@ class DefinitionTest extends TestCase [$this->interfaceType, true], [$this->unionType, true], [$this->enumType, true], - [$this->inputObjectType, false] + [$this->inputObjectType, false], ]; foreach ($expected as $index => $entry) { - $this->assertSame($entry[1], Type::isOutputType($entry[0]), "Type {$entry[0]} was detected incorrectly"); + $this->assertSame( + $entry[1], + Type::isOutputType($entry[0]), + sprintf('Type %s was detected incorrectly', $entry[0]) + ); } } @@ -528,8 +531,10 @@ class DefinitionTest extends TestCase public function testAllowsThunkForUnionTypes() : void { $union = new UnionType([ - 'name' => 'ThunkUnion', - 'types' => function() {return [$this->objectType]; } + 'name' => 'ThunkUnion', + 'types' => function () { + return [$this->objectType]; + }, ]); $types = $union->getTypes(); @@ -541,52 +546,52 @@ class DefinitionTest extends TestCase { // See https://github.com/webonyx/graphql-php/issues/16 $node = new InterfaceType([ - 'name' => 'Node', + 'name' => 'Node', 'fields' => [ - 'id' => ['type' => Type::nonNull(Type::id())] - ] + 'id' => ['type' => Type::nonNull(Type::id())], + ], ]); - $blog = null; + $blog = null; $called = false; $user = new ObjectType([ - 'name' => 'User', - 'fields' => function() use (&$blog, &$called) { + 'name' => 'User', + 'fields' => function () use (&$blog, &$called) { $this->assertNotNull($blog, 'Blog type is expected to be defined at this point, but it is null'); $called = true; return [ - 'id' => ['type' => Type::nonNull(Type::id())], - 'blogs' => ['type' => Type::nonNull(Type::listOf(Type::nonNull($blog)))] + 'id' => ['type' => Type::nonNull(Type::id())], + 'blogs' => ['type' => Type::nonNull(Type::listOf(Type::nonNull($blog)))], ]; }, - 'interfaces' => function() use ($node) { + 'interfaces' => function () use ($node) { return [$node]; - } + }, ]); $blog = new ObjectType([ - 'name' => 'Blog', - 'fields' => function() use ($user) { + 'name' => 'Blog', + 'fields' => function () use ($user) { return [ - 'id' => ['type' => Type::nonNull(Type::id())], - 'owner' => ['type' => Type::nonNull($user)] + 'id' => ['type' => Type::nonNull(Type::id())], + 'owner' => ['type' => Type::nonNull($user)], ]; }, - 'interfaces' => function() use ($node) { + 'interfaces' => function () use ($node) { return [$node]; - } + }, ]); $schema = new Schema([ 'query' => new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'node' => ['type' => $node] - ] + 'node' => ['type' => $node], + ], ]), - 'types' => [$user, $blog] + 'types' => [$user, $blog], ]); $this->assertTrue($called); @@ -604,30 +609,32 @@ class DefinitionTest extends TestCase public function testInputObjectTypeAllowsRecursiveDefinitions() : void { - $called = false; + $called = false; $inputObject = new InputObjectType([ - 'name' => 'InputObject', - 'fields' => function() use (&$inputObject, &$called) { + 'name' => 'InputObject', + 'fields' => function () use (&$inputObject, &$called) { $called = true; + return [ - 'value' => ['type' => Type::string()], - 'nested' => ['type' => $inputObject ] + 'value' => ['type' => Type::string()], + 'nested' => ['type' => $inputObject], ]; - } + }, ]); + $someMutation = new ObjectType([ - 'name' => 'SomeMutation', + 'name' => 'SomeMutation', 'fields' => [ 'mutateSomething' => [ 'type' => $this->blogArticle, - 'args' => ['input' => ['type' => $inputObject]] - ] - ] + 'args' => ['input' => ['type' => $inputObject]], + ], + ], ]); $schema = new Schema([ - 'query' => $this->blogQuery, - 'mutation' => $someMutation + 'query' => $this->blogQuery, + 'mutation' => $someMutation, ]); $this->assertSame($inputObject, $schema->getType('InputObject')); @@ -639,28 +646,27 @@ class DefinitionTest extends TestCase public function testInterfaceTypeAllowsRecursiveDefinitions() : void { - $called = false; + $called = false; $interface = new InterfaceType([ - 'name' => 'SomeInterface', - 'fields' => function() use (&$interface, &$called) { + 'name' => 'SomeInterface', + 'fields' => function () use (&$interface, &$called) { $called = true; + return [ - 'value' => ['type' => Type::string()], - 'nested' => ['type' => $interface ] + 'value' => ['type' => Type::string()], + 'nested' => ['type' => $interface], ]; - } + }, ]); $query = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'test' => ['type' => $interface] - ] + 'test' => ['type' => $interface], + ], ]); - $schema = new Schema([ - 'query' => $query - ]); + $schema = new Schema(['query' => $query]); $this->assertSame($interface, $schema->getType('SomeInterface')); $this->assertTrue($called); @@ -672,33 +678,29 @@ class DefinitionTest extends TestCase public function testAllowsShorthandFieldDefinition() : void { $interface = new InterfaceType([ - 'name' => 'SomeInterface', - 'fields' => function() use (&$interface) { + 'name' => 'SomeInterface', + 'fields' => function () use (&$interface) { return [ - 'value' => Type::string(), - 'nested' => $interface, + 'value' => Type::string(), + 'nested' => $interface, 'withArg' => [ 'type' => Type::string(), 'args' => [ - 'arg1' => Type::int() - ] - ] + 'arg1' => Type::int(), + ], + ], ]; - } + }, ]); $query = new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'test' => $interface - ] + 'name' => 'Query', + 'fields' => ['test' => $interface], ]); - $schema = new Schema([ - 'query' => $query - ]); + $schema = new Schema(['query' => $query]); - $valueField = $schema->getType('SomeInterface')->getField('value'); + $valueField = $schema->getType('SomeInterface')->getField('value'); $nestedField = $schema->getType('SomeInterface')->getField('nested'); $this->assertEquals(Type::string(), $valueField->getType()); @@ -727,15 +729,18 @@ class DefinitionTest extends TestCase public function testAllowsOverridingInternalTypes() : void { $idType = new CustomScalarType([ - 'name' => 'ID', - 'serialize' => function() {}, - 'parseValue' => function() {}, - 'parseLiteral' => function() {} + 'name' => 'ID', + 'serialize' => function () { + }, + 'parseValue' => function () { + }, + 'parseLiteral' => function () { + }, ]); $schema = new Schema([ 'query' => new ObjectType(['name' => 'Query', 'fields' => []]), - 'types' => [$idType] + 'types' => [$idType], ]); $this->assertSame($idType, $schema->getType('ID')); @@ -749,7 +754,7 @@ class DefinitionTest extends TestCase public function testAcceptsAnObjectTypeWithAFieldFunction() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => function () { return [ 'f' => ['type' => Type::string()], @@ -766,10 +771,8 @@ class DefinitionTest extends TestCase public function testRejectsAnObjectTypeFieldWithUndefinedConfig() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', - 'fields' => [ - 'f' => null, - ], + 'name' => 'SomeObject', + 'fields' => ['f' => null], ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage( @@ -784,7 +787,7 @@ class DefinitionTest extends TestCase public function testRejectsAnObjectTypeWithIncorrectlyTypedFields() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => [['field' => Type::string()]], ]); $this->expectException(InvariantViolation::class); @@ -801,7 +804,7 @@ class DefinitionTest extends TestCase public function testRejectsAnObjectTypeWithAFieldFunctionThatReturnsIncorrectType() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => function () { return [['field' => Type::string()]]; }, @@ -823,7 +826,7 @@ class DefinitionTest extends TestCase { $this->expectNotToPerformAssertions(); $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => [ 'goodField' => [ 'type' => Type::string(), @@ -845,10 +848,10 @@ class DefinitionTest extends TestCase public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnField() : void { $OldObject = new ObjectType([ - 'name' => 'OldObject', + 'name' => 'OldObject', 'fields' => [ 'field' => [ - 'type' => Type::string(), + 'type' => Type::string(), 'isDeprecated' => true, ], ], @@ -869,9 +872,9 @@ class DefinitionTest extends TestCase public function testAcceptsAnObjectTypeWithArrayInterfaces() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => [$this->interfaceType], - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $this->assertSame($this->interfaceType, $objType->getInterfaces()[0]); } @@ -882,11 +885,11 @@ class DefinitionTest extends TestCase public function testAcceptsAnObjectTypeWithInterfacesAsAFunctionReturningAnArray() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => function () { return [$this->interfaceType]; }, - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $this->assertSame($this->interfaceType, $objType->getInterfaces()[0]); } @@ -897,9 +900,9 @@ class DefinitionTest extends TestCase public function testRejectsAnObjectTypeWithIncorrectlyTypedInterfaces() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => new \stdClass(), - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage( @@ -914,11 +917,11 @@ class DefinitionTest extends TestCase public function testRejectsAnObjectTypeWithInterfacesAsAFunctionReturningAnIncorrectType() : void { $objType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => function () { return new \stdClass(); }, - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage( @@ -929,30 +932,6 @@ class DefinitionTest extends TestCase // Type System: Object fields must have valid resolve values - private function schemaWithObjectWithFieldResolver($resolveValue) - { - $BadResolverType = new ObjectType([ - 'name' => 'BadResolver', - 'fields' => [ - 'badField' => [ - 'type' => Type::string(), - 'resolve' => $resolveValue, - ], - ], - ]); - - $schema = new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'f' => ['type' => $BadResolverType], - ], - ]), - ]); - $schema->assertValid(); - return $schema; - } - /** * @see it('accepts a lambda as an Object field resolver') */ @@ -960,7 +939,33 @@ class DefinitionTest extends TestCase { $this->expectNotToPerformAssertions(); // should not throw: - $this->schemaWithObjectWithFieldResolver(function () {}); + $this->schemaWithObjectWithFieldResolver(function () { + }); + } + + private function schemaWithObjectWithFieldResolver($resolveValue) + { + $BadResolverType = new ObjectType([ + 'name' => 'BadResolver', + 'fields' => [ + 'badField' => [ + 'type' => Type::string(), + 'resolve' => $resolveValue, + ], + ], + ]); + + $schema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'f' => ['type' => $BadResolverType], + ], + ]), + ]); + $schema->assertValid(); + + return $schema; } /** @@ -987,21 +992,8 @@ class DefinitionTest extends TestCase $this->schemaWithObjectWithFieldResolver(0); } - // Type System: Interface types must be resolvable - private function schemaWithFieldType($type) - { - $schema = new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => ['field' => ['type' => $type]], - ]), - 'types' => [$type], - ]); - $schema->assertValid(); - return $schema; - } /** * @see it('accepts an Interface type defining resolveType') */ @@ -1009,20 +1001,34 @@ class DefinitionTest extends TestCase { $this->expectNotToPerformAssertions(); $AnotherInterfaceType = new InterfaceType([ - 'name' => 'AnotherInterface', + 'name' => 'AnotherInterface', 'fields' => ['f' => ['type' => Type::string()]], ]); // Should not throw: $this->schemaWithFieldType( new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => [$AnotherInterfaceType], - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]) ); } + private function schemaWithFieldType($type) + { + $schema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => ['field' => ['type' => $type]], + ]), + 'types' => [$type], + ]); + $schema->assertValid(); + + return $schema; + } + /** * @see it('accepts an Interface with implementing type defining isTypeOf') */ @@ -1030,16 +1036,16 @@ class DefinitionTest extends TestCase { $this->expectNotToPerformAssertions(); $InterfaceTypeWithoutResolveType = new InterfaceType([ - 'name' => 'InterfaceTypeWithoutResolveType', + 'name' => 'InterfaceTypeWithoutResolveType', 'fields' => ['f' => ['type' => Type::string()]], ]); // Should not throw: $this->schemaWithFieldType( new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => [$InterfaceTypeWithoutResolveType], - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]) ); } @@ -1051,16 +1057,16 @@ class DefinitionTest extends TestCase { $this->expectNotToPerformAssertions(); $AnotherInterfaceType = new InterfaceType([ - 'name' => 'AnotherInterface', + 'name' => 'AnotherInterface', 'fields' => ['f' => ['type' => Type::string()]], ]); // Should not throw: $this->schemaWithFieldType( new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'interfaces' => [$AnotherInterfaceType], - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]) ); } @@ -1076,23 +1082,15 @@ class DefinitionTest extends TestCase ); $type = new InterfaceType([ - 'name' => 'AnotherInterface', + 'name' => 'AnotherInterface', 'resolveType' => new \stdClass(), - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $type->assertValid(); } // Type System: Union types must be resolvable - private function ObjectWithIsTypeOf() - { - return new ObjectType([ - 'name' => 'ObjectWithIsTypeOf', - 'fields' => ['f' => ['type' => Type::string()]], - ]); - } - /** * @see it('accepts a Union type defining resolveType') */ @@ -1102,7 +1100,7 @@ class DefinitionTest extends TestCase // Should not throw: $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', + 'name' => 'SomeUnion', 'types' => [$this->objectType], ]) ); @@ -1117,7 +1115,7 @@ class DefinitionTest extends TestCase // Should not throw: $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', + 'name' => 'SomeUnion', 'types' => [$this->objectWithIsTypeOf], ]) ); @@ -1132,7 +1130,7 @@ class DefinitionTest extends TestCase // Should not throw: $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', + 'name' => 'SomeUnion', 'types' => [$this->objectWithIsTypeOf], ]) ); @@ -1149,15 +1147,13 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', + 'name' => 'SomeUnion', 'resolveType' => new \stdClass(), - 'types' => [$this->objectWithIsTypeOf], + 'types' => [$this->objectWithIsTypeOf], ]) ); } - // Type System: Scalar types must be serializable - /** * @see it('accepts a Scalar type defining serialize') */ @@ -1167,7 +1163,7 @@ class DefinitionTest extends TestCase // Should not throw $this->schemaWithFieldType( new CustomScalarType([ - 'name' => 'SomeScalar', + 'name' => 'SomeScalar', 'serialize' => function () { return null; }, @@ -1175,6 +1171,8 @@ class DefinitionTest extends TestCase ); } + // Type System: Scalar types must be serializable + /** * @see it('rejects a Scalar type not defining serialize') */ @@ -1187,9 +1185,7 @@ class DefinitionTest extends TestCase 'functions are also provided.' ); $this->schemaWithFieldType( - new CustomScalarType([ - 'name' => 'SomeScalar', - ]) + new CustomScalarType(['name' => 'SomeScalar']) ); } @@ -1206,7 +1202,7 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new CustomScalarType([ - 'name' => 'SomeScalar', + 'name' => 'SomeScalar', 'serialize' => new \stdClass(), ]) ); @@ -1221,10 +1217,10 @@ class DefinitionTest extends TestCase // Should not throw: $this->schemaWithFieldType( new CustomScalarType([ - 'name' => 'SomeScalar', - 'serialize' => function () { + 'name' => 'SomeScalar', + 'serialize' => function () { }, - 'parseValue' => function () { + 'parseValue' => function () { }, 'parseLiteral' => function () { }, @@ -1243,8 +1239,8 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new CustomScalarType([ - 'name' => 'SomeScalar', - 'serialize' => function () { + 'name' => 'SomeScalar', + 'serialize' => function () { }, 'parseValue' => function () { }, @@ -1263,8 +1259,8 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new CustomScalarType([ - 'name' => 'SomeScalar', - 'serialize' => function () { + 'name' => 'SomeScalar', + 'serialize' => function () { }, 'parseLiteral' => function () { }, @@ -1283,17 +1279,15 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new CustomScalarType([ - 'name' => 'SomeScalar', - 'serialize' => function () { + 'name' => 'SomeScalar', + 'serialize' => function () { }, - 'parseValue' => new \stdClass(), + 'parseValue' => new \stdClass(), 'parseLiteral' => new \stdClass(), ]) ); } - // Type System: Object types must be assertable - /** * @see it('accepts an Object type with an isTypeOf function') */ @@ -1303,12 +1297,14 @@ class DefinitionTest extends TestCase // Should not throw $this->schemaWithFieldType( new ObjectType([ - 'name' => 'AnotherObject', + 'name' => 'AnotherObject', 'fields' => ['f' => ['type' => Type::string()]], ]) ); } + // Type System: Object types must be assertable + /** * @see it('rejects an Object type with an incorrect type for isTypeOf') */ @@ -1320,15 +1316,13 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new ObjectType([ - 'name' => 'AnotherObject', + 'name' => 'AnotherObject', 'isTypeOf' => new \stdClass(), - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]) ); } - // Type System: Union types must be array - /** * @see it('accepts a Union type with array types') */ @@ -1338,12 +1332,14 @@ class DefinitionTest extends TestCase // Should not throw: $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', + 'name' => 'SomeUnion', 'types' => [$this->objectType], ]) ); } + // Type System: Union types must be array + /** * @see it('accepts a Union type with function returning an array of types') */ @@ -1352,7 +1348,7 @@ class DefinitionTest extends TestCase $this->expectNotToPerformAssertions(); $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', + 'name' => 'SomeUnion', 'types' => function () { return [$this->objectType]; }, @@ -1370,9 +1366,7 @@ class DefinitionTest extends TestCase 'Must provide Array of types or a callable which returns such an array for Union SomeUnion' ); $this->schemaWithFieldType( - new UnionType([ - 'name' => 'SomeUnion', - ]) + new UnionType(['name' => 'SomeUnion']) ); } @@ -1387,21 +1381,19 @@ class DefinitionTest extends TestCase ); $this->schemaWithFieldType( new UnionType([ - 'name' => 'SomeUnion', - 'types' => (object)[ 'test' => $this->objectType, ], + 'name' => 'SomeUnion', + 'types' => (object) ['test' => $this->objectType], ]) ); } - // Type System: Input Objects must have fields - /** * @see it('accepts an Input Object type with fields') */ public function testAcceptsAnInputObjectTypeWithFields() : void { $inputObjType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => [ 'f' => ['type' => Type::string()], ], @@ -1410,13 +1402,15 @@ class DefinitionTest extends TestCase $this->assertSame(Type::string(), $inputObjType->getField('f')->getType()); } + // Type System: Input Objects must have fields + /** * @see it('accepts an Input Object type with a field function') */ public function testAcceptsAnInputObjectTypeWithAFieldFunction() : void { $inputObjType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => function () { return [ 'f' => ['type' => Type::string()], @@ -1433,12 +1427,12 @@ class DefinitionTest extends TestCase public function testRejectsAnInputObjectTypeWithIncorrectFields() : void { $inputObjType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => [], ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage( - 'SomeInputObject fields must be an associative array with field names as keys or a callable '. + 'SomeInputObject fields must be an associative array with field names as keys or a callable ' . 'which returns such an array.' ); $inputObjType->assertValid(); @@ -1450,7 +1444,7 @@ class DefinitionTest extends TestCase public function testRejectsAnInputObjectTypeWithFieldsFunctionThatReturnsIncorrectType() : void { $inputObjType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => function () { return []; }, @@ -1463,18 +1457,16 @@ class DefinitionTest extends TestCase $inputObjType->assertValid(); } - // Type System: Input Object fields must not have resolvers - /** * @see it('rejects an Input Object type with resolvers') */ public function testRejectsAnInputObjectTypeWithResolvers() : void { $inputObjType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => [ 'f' => [ - 'type' => Type::string(), + 'type' => Type::string(), 'resolve' => function () { return 0; }, @@ -1489,16 +1481,18 @@ class DefinitionTest extends TestCase $inputObjType->assertValid(); } + // Type System: Input Object fields must not have resolvers + /** * @see it('rejects an Input Object type with resolver constant') */ public function testRejectsAnInputObjectTypeWithResolverConstant() : void { $inputObjType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => [ 'f' => [ - 'type' => Type::string(), + 'type' => Type::string(), 'resolve' => new \stdClass(), ], ], @@ -1511,15 +1505,13 @@ class DefinitionTest extends TestCase $inputObjType->assertValid(); } - // Type System: Enum types must be well defined - /** * @see it('accepts a well defined Enum type with empty value definition') */ public function testAcceptsAWellDefinedEnumTypeWithEmptyValueDefinition() : void { $enumType = new EnumType([ - 'name' => 'SomeEnum', + 'name' => 'SomeEnum', 'values' => [ 'FOO' => [], 'BAR' => [], @@ -1529,13 +1521,15 @@ class DefinitionTest extends TestCase $this->assertEquals('BAR', $enumType->getValue('BAR')->value); } + // Type System: Enum types must be well defined + /** * @see it('accepts a well defined Enum type with internal value definition') */ public function testAcceptsAWellDefinedEnumTypeWithInternalValueDefinition() : void { $enumType = new EnumType([ - 'name' => 'SomeEnum', + 'name' => 'SomeEnum', 'values' => [ 'FOO' => ['value' => 10], 'BAR' => ['value' => 20], @@ -1551,7 +1545,7 @@ class DefinitionTest extends TestCase public function testRejectsAnEnumTypeWithIncorrectlyTypedValues() : void { $enumType = new EnumType([ - 'name' => 'SomeEnum', + 'name' => 'SomeEnum', 'values' => [['FOO' => 10]], ]); $this->expectException(InvariantViolation::class); @@ -1567,11 +1561,9 @@ class DefinitionTest extends TestCase public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnEnum() : void { $enumType = new EnumType([ - 'name' => 'SomeEnum', + 'name' => 'SomeEnum', 'values' => [ - 'FOO' => [ - 'isDeprecated' => true, - ], + 'FOO' => ['isDeprecated' => true], ], ]); $this->expectException(InvariantViolation::class); @@ -1582,7 +1574,6 @@ class DefinitionTest extends TestCase $enumType->assertValid(); } - /** * Type System: List must accept only types */ @@ -1606,27 +1597,26 @@ class DefinitionTest extends TestCase try { Type::listOf($type); } catch (\Throwable $e) { - $this->fail("List is expected to accept type: " . get_class($type) . ", but got error: ". $e->getMessage()); + $this->fail('List is expected to accept type: ' . get_class($type) . ', but got error: ' . $e->getMessage()); } } foreach ($badTypes as $badType) { $typeStr = Utils::printSafe($badType); try { Type::listOf($badType); - $this->fail("List should not accept $typeStr"); + $this->fail(sprintf('List should not accept %s', $typeStr)); } catch (InvariantViolation $e) { - $this->assertEquals("Expected $typeStr to be a GraphQL type.", $e->getMessage()); + $this->assertEquals(sprintf('Expected %s to be a GraphQL type.', $typeStr), $e->getMessage()); } } } - /** * Type System: NonNull must only accept non-nullable types */ public function testNonNullMustOnlyAcceptNonNullableTypes() : void { - $nullableTypes = [ + $nullableTypes = [ Type::string(), $this->scalarType, $this->objectType, @@ -1648,67 +1638,67 @@ class DefinitionTest extends TestCase try { Type::nonNull($type); } catch (\Throwable $e) { - $this->fail("NonNull is expected to accept type: " . get_class($type) . ", but got error: ". $e->getMessage()); + $this->fail('NonNull is expected to accept type: ' . get_class($type) . ', but got error: ' . $e->getMessage()); } } foreach ($notNullableTypes as $badType) { $typeStr = Utils::printSafe($badType); try { Type::nonNull($badType); - $this->fail("Nulls should not accept $typeStr"); + $this->fail(sprintf('Nulls should not accept %s', $typeStr)); } catch (InvariantViolation $e) { - $this->assertEquals("Expected $typeStr to be a GraphQL nullable type.", $e->getMessage()); + $this->assertEquals(sprintf('Expected %s to be a GraphQL nullable type.', $typeStr), $e->getMessage()); } } } - // Type System: A Schema must contain uniquely named types - /** * @see it('rejects a Schema which redefines a built-in type') */ public function testRejectsASchemaWhichRedefinesABuiltInType() : void { $FakeString = new CustomScalarType([ - 'name' => 'String', + 'name' => 'String', 'serialize' => function () { }, ]); $QueryType = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ 'normal' => ['type' => Type::string()], - 'fake' => ['type' => $FakeString], + 'fake' => ['type' => $FakeString], ], ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage( - 'Schema must contain unique named types but contains multiple types named "String" '. + 'Schema must contain unique named types but contains multiple types named "String" ' . '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).' ); $schema = new Schema(['query' => $QueryType]); $schema->assertValid(); } + // Type System: A Schema must contain uniquely named types + /** * @see it('rejects a Schema which defines an object type twice') */ public function testRejectsASchemaWhichDefinesAnObjectTypeTwice() : void { $A = new ObjectType([ - 'name' => 'SameName', + 'name' => 'SameName', 'fields' => ['f' => ['type' => Type::string()]], ]); $B = new ObjectType([ - 'name' => 'SameName', + 'name' => 'SameName', 'fields' => ['f' => ['type' => Type::string()]], ]); $QueryType = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ 'a' => ['type' => $A], 'b' => ['type' => $B], @@ -1719,7 +1709,7 @@ class DefinitionTest extends TestCase 'Schema must contain unique named types but contains multiple types named "SameName" ' . '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).' ); - $schema = new Schema([ 'query' => $QueryType ]); + $schema = new Schema(['query' => $QueryType]); $schema->assertValid(); } @@ -1729,24 +1719,24 @@ class DefinitionTest extends TestCase public function testRejectsASchemaWhichHaveSameNamedObjectsImplementingAnInterface() : void { $AnotherInterface = new InterfaceType([ - 'name' => 'AnotherInterface', + 'name' => 'AnotherInterface', 'fields' => ['f' => ['type' => Type::string()]], ]); $FirstBadObject = new ObjectType([ - 'name' => 'BadObject', + 'name' => 'BadObject', 'interfaces' => [$AnotherInterface], - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $SecondBadObject = new ObjectType([ - 'name' => 'BadObject', + 'name' => 'BadObject', 'interfaces' => [$AnotherInterface], - 'fields' => ['f' => ['type' => Type::string()]], + 'fields' => ['f' => ['type' => Type::string()]], ]); $QueryType = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ 'iface' => ['type' => $AnotherInterface], ], @@ -1763,4 +1753,12 @@ class DefinitionTest extends TestCase ]); $schema->assertValid(); } + + public function objectWithIsTypeOf() : ObjectType + { + return new ObjectType([ + 'name' => 'ObjectWithIsTypeOf', + 'fields' => ['f' => ['type' => Type::string()]], + ]); + } } diff --git a/tests/Type/EnumTypeTest.php b/tests/Type/EnumTypeTest.php index f8ab00a..55e508d 100644 --- a/tests/Type/EnumTypeTest.php +++ b/tests/Type/EnumTypeTest.php @@ -1,68 +1,77 @@ 'Color', + 'name' => 'Color', 'values' => [ - 'RED' => ['value' => 0], + 'RED' => ['value' => 0], 'GREEN' => ['value' => 1], - 'BLUE' => ['value' => 2], - ] + 'BLUE' => ['value' => 2], + ], ]); $simpleEnum = new EnumType([ - 'name' => 'SimpleEnum', + 'name' => 'SimpleEnum', 'values' => [ - 'ONE', 'TWO', 'THREE' - ] + 'ONE', + 'TWO', + 'THREE', + ], ]); - $Complex1 = ['someRandomFunction' => function() {}]; + $Complex1 = [ + 'someRandomFunction' => function () { + }, + ]; $Complex2 = new \ArrayObject(['someRandomValue' => 123]); $ComplexEnum = new EnumType([ - 'name' => 'Complex', + 'name' => 'Complex', 'values' => [ 'ONE' => ['value' => $Complex1], - 'TWO' => ['value' => $Complex2] - ] + 'TWO' => ['value' => $Complex2], + ], ]); $QueryType = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'colorEnum' => [ - 'type' => $ColorType, - 'args' => [ - 'fromEnum' => ['type' => $ColorType], - 'fromInt' => ['type' => Type::int()], + 'colorEnum' => [ + 'type' => $ColorType, + 'args' => [ + 'fromEnum' => ['type' => $ColorType], + 'fromInt' => ['type' => Type::int()], 'fromString' => ['type' => Type::string()], ], 'resolve' => function ($value, $args) { @@ -75,28 +84,28 @@ class EnumTypeTest extends TestCase if (isset($args['fromEnum'])) { return $args['fromEnum']; } - } + }, ], - 'simpleEnum' => [ - 'type' => $simpleEnum, - 'args' => [ - 'fromName' => ['type' => Type::string()], - 'fromValue' => ['type' => Type::string()] + 'simpleEnum' => [ + 'type' => $simpleEnum, + 'args' => [ + 'fromName' => ['type' => Type::string()], + 'fromValue' => ['type' => Type::string()], ], - 'resolve' => function($value, $args) { + 'resolve' => function ($value, $args) { if (isset($args['fromName'])) { return $args['fromName']; } if (isset($args['fromValue'])) { return $args['fromValue']; } - } + }, ], - 'colorInt' => [ - 'type' => Type::int(), - 'args' => [ + 'colorInt' => [ + 'type' => Type::int(), + 'args' => [ 'fromEnum' => ['type' => $ColorType], - 'fromInt' => ['type' => Type::int()], + 'fromInt' => ['type' => Type::int()], ], 'resolve' => function ($value, $args) { if (isset($args['fromInt'])) { @@ -105,75 +114,76 @@ class EnumTypeTest extends TestCase if (isset($args['fromEnum'])) { return $args['fromEnum']; } - } + }, ], 'complexEnum' => [ - 'type' => $ComplexEnum, - 'args' => [ - 'fromEnum' => [ - 'type' => $ComplexEnum, + 'type' => $ComplexEnum, + 'args' => [ + 'fromEnum' => [ + 'type' => $ComplexEnum, // Note: defaultValue is provided an *internal* representation for // Enums, rather than the string name. - 'defaultValue' => $Complex1 + 'defaultValue' => $Complex1, ], 'provideGoodValue' => [ 'type' => Type::boolean(), ], - 'provideBadValue' => [ - 'type' => Type::boolean() - ] + 'provideBadValue' => [ + 'type' => Type::boolean(), + ], ], - 'resolve' => function($value, $args) use ($Complex1, $Complex2) { - if (!empty($args['provideGoodValue'])) { + 'resolve' => function ($value, $args) use ($Complex1, $Complex2) { + if (! empty($args['provideGoodValue'])) { // Note: this is one of the references of the internal values which // ComplexEnum allows. return $Complex2; } - if (!empty($args['provideBadValue'])) { + if (! empty($args['provideBadValue'])) { // Note: similar shape, but not the same *reference* // as Complex2 above. Enum internal values require === equality. return new \ArrayObject(['someRandomValue' => 123]); } + return $args['fromEnum']; - } - ] - ] + }, + ], + ], ]); $MutationType = new ObjectType([ - 'name' => 'Mutation', + 'name' => 'Mutation', 'fields' => [ 'favoriteEnum' => [ - 'type' => $ColorType, - 'args' => ['color' => ['type' => $ColorType]], + 'type' => $ColorType, + 'args' => ['color' => ['type' => $ColorType]], 'resolve' => function ($value, $args) { - return isset($args['color']) ? $args['color'] : null; - } - ] - ] + return $args['color'] ?? null; + }, + ], + ], ]); $SubscriptionType = new ObjectType([ - 'name' => 'Subscription', + 'name' => 'Subscription', 'fields' => [ 'subscribeToEnum' => [ - 'type' => $ColorType, - 'args' => ['color' => ['type' => $ColorType]], + 'type' => $ColorType, + 'args' => ['color' => ['type' => $ColorType]], 'resolve' => function ($value, $args) { - return isset($args['color']) ? $args['color'] : null; - } - ] - ] + return $args['color'] ?? null; + }, + ], + ], ]); - $this->Complex1 = $Complex1; - $this->Complex2 = $Complex2; + $this->Complex1 = $Complex1; + $this->Complex2 = $Complex2; $this->ComplexEnum = $ComplexEnum; $this->schema = new Schema([ - 'query' => $QueryType, - 'mutation' => $MutationType, - 'subscription' => $SubscriptionType + 'query' => $QueryType, + 'mutation' => $MutationType, + 'subscription' => $SubscriptionType, ]); } @@ -221,12 +231,34 @@ class EnumTypeTest extends TestCase '{ colorEnum(fromEnum: "GREEN") }', null, [ - 'message' => "Expected type Color, found \"GREEN\"; Did you mean the enum value GREEN?", - 'locations' => [new SourceLocation(1, 23)] + 'message' => 'Expected type Color, found "GREEN"; Did you mean the enum value GREEN?', + 'locations' => [new SourceLocation(1, 23)], ] ); } + private function expectFailure($query, $vars, $err) + { + $result = GraphQL::executeQuery($this->schema, $query, null, null, $vars); + $this->assertEquals(1, count($result->errors)); + + if (is_array($err)) { + $this->assertEquals( + $err['message'], + $result->errors[0]->getMessage() + ); + $this->assertEquals( + $err['locations'], + $result->errors[0]->getLocations() + ); + } else { + $this->assertEquals( + $err, + $result->errors[0]->getMessage() + ); + } + } + /** * @see it('does not accept valuesNotInTheEnum') */ @@ -236,8 +268,8 @@ class EnumTypeTest extends TestCase '{ colorEnum(fromEnum: GREENISH) }', null, [ - 'message' => "Expected type Color, found GREENISH; Did you mean the enum value GREEN?", - 'locations' => [new SourceLocation(1, 23)] + 'message' => 'Expected type Color, found GREENISH; Did you mean the enum value GREEN?', + 'locations' => [new SourceLocation(1, 23)], ] ); } @@ -251,8 +283,8 @@ class EnumTypeTest extends TestCase '{ colorEnum(fromEnum: green) }', null, [ - 'message' => "Expected type Color, found green; Did you mean the enum value GREEN?", - 'locations' => [new SourceLocation(1, 23)] + 'message' => 'Expected type Color, found green; Did you mean the enum value GREEN?', + 'locations' => [new SourceLocation(1, 23)], ] ); } @@ -266,9 +298,9 @@ class EnumTypeTest extends TestCase '{ colorEnum(fromString: "GREEN") }', null, [ - 'message' => 'Expected a value of type "Color" but received: GREEN', + 'message' => 'Expected a value of type "Color" but received: GREEN', 'locations' => [new SourceLocation(1, 3)], - 'path' => ['colorEnum'], + 'path' => ['colorEnum'], ] ); } @@ -281,7 +313,7 @@ class EnumTypeTest extends TestCase $this->expectFailure( '{ colorEnum(fromEnum: 1) }', null, - "Expected type Color, found 1." + 'Expected type Color, found 1.' ); } @@ -293,7 +325,7 @@ class EnumTypeTest extends TestCase $this->expectFailure( '{ colorEnum(fromInt: GREEN) }', null, - "Expected type Int, found GREEN." + 'Expected type Int, found GREEN.' ); } @@ -381,7 +413,7 @@ class EnumTypeTest extends TestCase $this->expectFailure( 'query test($color: Int!) { colorEnum(fromEnum: $color) }', ['color' => 2], - 'Variable "$color" of type "Int!" used in position ' . 'expecting type "Color".' + 'Variable "$color" of type "Int!" used in position expecting type "Color".' ); } @@ -392,10 +424,13 @@ class EnumTypeTest extends TestCase { $this->assertEquals( ['data' => ['colorEnum' => 'RED', 'colorInt' => 0]], - GraphQL::executeQuery($this->schema, "{ + GraphQL::executeQuery( + $this->schema, + '{ colorEnum(fromEnum: RED) colorInt(fromEnum: RED) - }")->toArray() + }' + )->toArray() ); } @@ -406,10 +441,13 @@ class EnumTypeTest extends TestCase { $this->assertEquals( ['data' => ['colorEnum' => null, 'colorInt' => null]], - GraphQL::executeQuery($this->schema, "{ + GraphQL::executeQuery( + $this->schema, + '{ colorEnum colorInt - }")->toArray() + }' + )->toArray() ); } @@ -419,7 +457,7 @@ class EnumTypeTest extends TestCase public function testPresentsGetValuesAPIForComplexEnums() : void { $ComplexEnum = $this->ComplexEnum; - $values = $ComplexEnum->getValues(); + $values = $ComplexEnum->getValues(); $this->assertEquals(2, count($values)); $this->assertEquals('ONE', $values[0]->name); @@ -446,25 +484,29 @@ class EnumTypeTest extends TestCase */ public function testMayBeInternallyRepresentedWithComplexValues() : void { - $result = GraphQL::executeQuery($this->schema, '{ + $result = GraphQL::executeQuery( + $this->schema, + '{ first: complexEnum second: complexEnum(fromEnum: TWO) good: complexEnum(provideGoodValue: true) bad: complexEnum(provideBadValue: true) - }')->toArray(true); + }' + )->toArray(true); $expected = [ - 'data' => [ - 'first' => 'ONE', + 'data' => [ + 'first' => 'ONE', 'second' => 'TWO', - 'good' => 'TWO', - 'bad' => null + 'good' => 'TWO', + 'bad' => null, ], 'errors' => [[ 'debugMessage' => 'Expected a value of type "Complex" but received: instance of ArrayObject', - 'locations' => [['line' => 5, 'column' => 9]] - ]] + 'locations' => [['line' => 5, 'column' => 9]], + ], + ], ]; $this->assertArraySubset($expected, $result); @@ -489,35 +531,14 @@ class EnumTypeTest extends TestCase $this->assertArraySubset( [ - 'data' => ['first' => 'ONE', 'second' => 'TWO', 'third' => null], + 'data' => ['first' => 'ONE', 'second' => 'TWO', 'third' => null], 'errors' => [[ 'debugMessage' => 'Expected a value of type "SimpleEnum" but received: WRONG', - 'locations' => [['line' => 4, 'column' => 13]] - ]] + 'locations' => [['line' => 4, 'column' => 13]], + ], + ], ], GraphQL::executeQuery($this->schema, $q)->toArray(true) ); } - - private function expectFailure($query, $vars, $err) - { - $result = GraphQL::executeQuery($this->schema, $query, null, null, $vars); - $this->assertEquals(1, count($result->errors)); - - if (is_array($err)) { - $this->assertEquals( - $err['message'], - $result->errors[0]->getMessage() - ); - $this->assertEquals( - $err['locations'], - $result->errors[0]->getLocations() - ); - } else { - $this->assertEquals( - $err, - $result->errors[0]->getMessage() - ); - } - } } diff --git a/tests/Type/IntrospectionTest.php b/tests/Type/IntrospectionTest.php index b44a168..cd710cc 100644 --- a/tests/Type/IntrospectionTest.php +++ b/tests/Type/IntrospectionTest.php @@ -1,1067 +1,1027 @@ new ObjectType([ - 'name' => 'QueryRoot', - 'fields' => ['a' => Type::string()] - ]) + 'name' => 'QueryRoot', + 'fields' => ['a' => Type::string()], + ]), ]); - $request = Introspection::getIntrospectionQuery(['descriptions' => false]); - $expected = array ( + $request = Introspection::getIntrospectionQuery(['descriptions' => false]); + $expected = [ 'data' => - array ( + [ '__schema' => - array ( - 'mutationType' => NULL, - 'subscriptionType' => NULL, - 'queryType' => - array ( - 'name' => 'QueryRoot', - ), - 'types' => - array ( - array ( - 'kind' => 'OBJECT', - 'name' => 'QueryRoot', - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - 'fields' => array ( - array ( - 'name' => 'a', - 'args' => array(), - 'type' => array( - 'kind' => 'SCALAR', - 'name' => 'String', - 'ofType' => null - ), - 'isDeprecated' => false, + [ + 'mutationType' => null, + 'subscriptionType' => null, + 'queryType' => + ['name' => 'QueryRoot'], + 'types' => + [ + [ + 'kind' => 'OBJECT', + 'name' => 'QueryRoot', + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + 'fields' => [ + [ + 'name' => 'a', + 'args' => [], + 'type' => [ + 'kind' => 'SCALAR', + 'name' => 'String', + 'ofType' => null, + ], + 'isDeprecated' => false, 'deprecationReason' => null, - ) - ) - ), - array ( - 'kind' => 'SCALAR', - 'name' => 'String', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'SCALAR', - 'name' => 'ID', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'SCALAR', - 'name' => 'Float', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'SCALAR', - 'name' => 'Int', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'SCALAR', - 'name' => 'Boolean', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'OBJECT', - 'name' => '__Schema', - 'fields' => - array ( + ], + ], + ], + [ + 'kind' => 'SCALAR', + 'name' => 'String', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'SCALAR', + 'name' => 'ID', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'SCALAR', + 'name' => 'Float', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'SCALAR', + 'name' => 'Int', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'SCALAR', + 'name' => 'Boolean', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'OBJECT', + 'name' => '__Schema', + 'fields' => + [ 0 => - array ( - 'name' => 'types', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'types', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', - 'name' => '__Type' - ), - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + 'name' => '__Type', + ], + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'queryType', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'queryType', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - array ( - 'name' => 'mutationType', - 'args' => - array ( - ), - 'type' => - array ( + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + [ + 'name' => 'mutationType', + 'args' => + [], + 'type' => + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - array ( - 'name' => 'subscriptionType', - 'args' => - array ( - ), - 'type' => - array ( + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + [ + 'name' => 'subscriptionType', + 'args' => + [], + 'type' => + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - array ( - 'name' => 'directives', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + [ + 'name' => 'directives', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Directive', - ), - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - ), - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'OBJECT', - 'name' => '__Type', - 'fields' => - array ( + ], + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'OBJECT', + 'name' => '__Type', + 'fields' => + [ 0 => - array ( - 'name' => 'kind', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'kind', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'ENUM', 'name' => '__TypeKind', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'name', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'name', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'description', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'description', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'fields', - 'args' => - array ( + [ + 'name' => 'fields', + 'args' => + [ 0 => - array ( - 'name' => 'includeDeprecated', - 'type' => - array ( + [ + 'name' => 'includeDeprecated', + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), + ], 'defaultValue' => 'false', - ), - ), - 'type' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + ], + ], + 'type' => + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Field', - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 4 => - array ( - 'name' => 'interfaces', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'name' => 'interfaces', + 'args' => + [], + 'type' => + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 5 => - array ( - 'name' => 'possibleTypes', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'name' => 'possibleTypes', + 'args' => + [], + 'type' => + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 6 => - array ( - 'name' => 'enumValues', - 'args' => - array ( + [ + 'name' => 'enumValues', + 'args' => + [ 0 => - array ( - 'name' => 'includeDeprecated', - 'type' => - array ( + [ + 'name' => 'includeDeprecated', + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), + ], 'defaultValue' => 'false', - ), - ), - 'type' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + ], + ], + 'type' => + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__EnumValue', - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 7 => - array ( - 'name' => 'inputFields', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'name' => 'inputFields', + 'args' => + [], + 'type' => + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__InputValue', - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 8 => - array ( - 'name' => 'ofType', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'ofType', + 'args' => + [], + 'type' => + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - ), - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'ENUM', - 'name' => '__TypeKind', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => - array ( + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'ENUM', + 'name' => '__TypeKind', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => + [ 0 => - array ( - 'name' => 'SCALAR', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'SCALAR', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'OBJECT', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'OBJECT', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'INTERFACE', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'INTERFACE', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'UNION', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'UNION', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 4 => - array ( - 'name' => 'ENUM', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'ENUM', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 5 => - array ( - 'name' => 'INPUT_OBJECT', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'INPUT_OBJECT', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 6 => - array ( - 'name' => 'LIST', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + [ + 'name' => 'LIST', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 7 => - array ( - 'name' => 'NON_NULL', - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - ), - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'OBJECT', - 'name' => '__Field', - 'fields' => - array ( + [ + 'name' => 'NON_NULL', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'possibleTypes' => null, + ], + [ + 'kind' => 'OBJECT', + 'name' => '__Field', + 'fields' => + [ 0 => - array ( - 'name' => 'name', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'name', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'description', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'description', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'args', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'args', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__InputValue', - ), - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'type', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'type', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 4 => - array ( - 'name' => 'isDeprecated', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'isDeprecated', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 5 => - array ( - 'name' => 'deprecationReason', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'deprecationReason', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - ), - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'OBJECT', - 'name' => '__InputValue', - 'fields' => - array ( + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'OBJECT', + 'name' => '__InputValue', + 'fields' => + [ 0 => - array ( - 'name' => 'name', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'name', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'description', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'description', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'type', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'type', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__Type', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'defaultValue', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'defaultValue', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - ), - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'OBJECT', - 'name' => '__EnumValue', - 'fields' => - array ( + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'OBJECT', + 'name' => '__EnumValue', + 'fields' => + [ 0 => - array ( - 'name' => 'name', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'name', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'description', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'description', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'isDeprecated', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'isDeprecated', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'deprecationReason', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'deprecationReason', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), - ), - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'OBJECT', - 'name' => '__Directive', - 'fields' => - array ( + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'OBJECT', + 'name' => '__Directive', + 'fields' => + [ 0 => - array ( - 'name' => 'name', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'name', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'description', - 'args' => - array ( - ), - 'type' => - array ( + [ + 'name' => 'description', + 'args' => + [], + 'type' => + [ 'kind' => 'SCALAR', 'name' => 'String', - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'locations', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'locations', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'ENUM', 'name' => '__DirectiveLocation', - ), - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'args', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'args', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( - 'kind' => 'LIST', - 'name' => NULL, + [ + 'kind' => 'LIST', + 'name' => null, 'ofType' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'OBJECT', 'name' => '__InputValue', - ), - ), - ), - ), - 'isDeprecated' => false, - 'deprecationReason' => NULL, - ), + ], + ], + ], + ], + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 4 => - array ( - 'name' => 'onOperation', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'onOperation', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - 'isDeprecated' => true, + ], + ], + 'isDeprecated' => true, 'deprecationReason' => 'Use `locations`.', - ), + ], 5 => - array ( - 'name' => 'onFragment', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'onFragment', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - 'isDeprecated' => true, + ], + ], + 'isDeprecated' => true, 'deprecationReason' => 'Use `locations`.', - ), + ], 6 => - array ( - 'name' => 'onField', - 'args' => - array ( - ), - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'name' => 'onField', + 'args' => + [], + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - 'isDeprecated' => true, + ], + ], + 'isDeprecated' => true, 'deprecationReason' => 'Use `locations`.', - ), - ), - 'inputFields' => NULL, - 'interfaces' => - array ( - ), - 'enumValues' => NULL, - 'possibleTypes' => NULL, - ), - array ( - 'kind' => 'ENUM', - 'name' => '__DirectiveLocation', - 'fields' => NULL, - 'inputFields' => NULL, - 'interfaces' => NULL, - 'enumValues' => - array ( + ], + ], + 'inputFields' => null, + 'interfaces' => + [], + 'enumValues' => null, + 'possibleTypes' => null, + ], + [ + 'kind' => 'ENUM', + 'name' => '__DirectiveLocation', + 'fields' => null, + 'inputFields' => null, + 'interfaces' => null, + 'enumValues' => + [ 0 => - array ( - 'name' => 'QUERY', - 'isDeprecated' => false, - 'deprecationReason' => null - ), + [ + 'name' => 'QUERY', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 1 => - array ( - 'name' => 'MUTATION', - 'isDeprecated' => false, - 'deprecationReason' => null - ), + [ + 'name' => 'MUTATION', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 2 => - array ( - 'name' => 'SUBSCRIPTION', - 'isDeprecated' => false, - 'deprecationReason' => null - ), + [ + 'name' => 'SUBSCRIPTION', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 3 => - array ( - 'name' => 'FIELD', - 'isDeprecated' => false, - 'deprecationReason' => null - ), + [ + 'name' => 'FIELD', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 4 => - array ( - 'name' => 'FRAGMENT_DEFINITION', - 'isDeprecated' => false, - 'deprecationReason' => null - ), + [ + 'name' => 'FRAGMENT_DEFINITION', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 5 => - array ( - 'name' => 'FRAGMENT_SPREAD', - 'isDeprecated' => false, - 'deprecationReason' => null - ), + [ + 'name' => 'FRAGMENT_SPREAD', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], 6 => - array ( - 'name' => 'INLINE_FRAGMENT', - 'isDeprecated' => false, - 'deprecationReason' => null - ), - ), - 'possibleTypes' => NULL, - ), - ), - 'directives' => - array ( + [ + 'name' => 'INLINE_FRAGMENT', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + 'possibleTypes' => null, + ], + ], + 'directives' => + [ 0 => - array ( - 'name' => 'include', + [ + 'name' => 'include', 'locations' => - array ( + [ 0 => 'FIELD', 1 => 'FRAGMENT_SPREAD', 2 => 'INLINE_FRAGMENT', - ), - 'args' => - array ( + ], + 'args' => + [ 0 => - array ( - 'defaultValue' => NULL, - 'name' => 'if', - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'defaultValue' => null, + 'name' => 'if', + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - ), - ), - ), + ], + ], + ], + ], + ], 1 => - array ( - 'name' => 'skip', + [ + 'name' => 'skip', 'locations' => - array ( + [ 0 => 'FIELD', 1 => 'FRAGMENT_SPREAD', 2 => 'INLINE_FRAGMENT', - ), - 'args' => - array ( + ], + 'args' => + [ 0 => - array ( - 'defaultValue' => NULL, - 'name' => 'if', - 'type' => - array ( - 'kind' => 'NON_NULL', - 'name' => NULL, + [ + 'defaultValue' => null, + 'name' => 'if', + 'type' => + [ + 'kind' => 'NON_NULL', + 'name' => null, 'ofType' => - array ( + [ 'kind' => 'SCALAR', 'name' => 'Boolean', - ), - ), - ), - ), - ), - ), - ), - ) - ); + ], + ], + ], + ], + ], + ], + ], + ], + ]; $actual = GraphQL::executeQuery($emptySchema, $request)->toArray(); @@ -1072,31 +1032,31 @@ class IntrospectionTest extends TestCase /** * @see it('introspects on input object') */ - function testIntrospectsOnInputObject() + public function testIntrospectsOnInputObject() : void { $TestInputObject = new InputObjectType([ - 'name' => 'TestInputObject', + 'name' => 'TestInputObject', 'fields' => [ 'a' => ['type' => Type::string(), 'defaultValue' => "tes\t de\fault"], 'b' => ['type' => Type::listOf(Type::string())], - 'c' => ['type' => Type::string(), 'defaultValue' => null ] - ] + 'c' => ['type' => Type::string(), 'defaultValue' => null], + ], ]); $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ 'field' => [ - 'type' => Type::string(), - 'args' => ['complex' => ['type' => $TestInputObject]], + 'type' => Type::string(), + 'args' => ['complex' => ['type' => $TestInputObject]], 'resolve' => function ($_, $args) { return json_encode($args['complex']); - } - ] - ] + }, + ], + ], ]); - $schema = new Schema(['query' => $TestType]); + $schema = new Schema(['query' => $TestType]); $request = ' { __type(name: "TestInputObject") { @@ -1128,39 +1088,38 @@ class IntrospectionTest extends TestCase } '; - $expectedFragment = [ - 'kind' => 'INPUT_OBJECT', - 'name' => 'TestInputObject', + 'kind' => 'INPUT_OBJECT', + 'name' => 'TestInputObject', 'inputFields' => [ [ - 'name' => 'a', - 'type' => [ - 'kind' => 'SCALAR', - 'name' => 'String', - 'ofType' => null + 'name' => 'a', + 'type' => [ + 'kind' => 'SCALAR', + 'name' => 'String', + 'ofType' => null, ], - 'defaultValue' => '"tes\t de\fault"' + 'defaultValue' => '"tes\t de\fault"', ], [ - 'name' => 'b', - 'type' => [ - 'kind' => 'LIST', - 'name' => null, - 'ofType' => ['kind' => 'SCALAR', 'name' => 'String', 'ofType' => null] + 'name' => 'b', + 'type' => [ + 'kind' => 'LIST', + 'name' => null, + 'ofType' => ['kind' => 'SCALAR', 'name' => 'String', 'ofType' => null], ], - 'defaultValue' => null + 'defaultValue' => null, ], [ - 'name' => 'c', - 'type' => [ - 'kind' => 'SCALAR', - 'name' => 'String', - 'ofType' => null + 'name' => 'c', + 'type' => [ + 'kind' => 'SCALAR', + 'name' => 'String', + 'ofType' => null, ], - 'defaultValue' => 'null' // defaultValue was set (even if it was set to null) - ] - ] + 'defaultValue' => 'null',// defaultValue was set (even if it was set to null) + ], + ], ]; $result = GraphQL::executeQuery($schema, $request)->toArray(); @@ -1174,15 +1133,15 @@ class IntrospectionTest extends TestCase public function testSupportsTheTypeRootField() : void { $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ 'testField' => [ 'type' => Type::string(), - ] - ] + ], + ], ]); - $schema = new Schema(['query' => $TestType]); + $schema = new Schema(['query' => $TestType]); $request = ' { __type(name: "TestType") { @@ -1191,11 +1150,11 @@ class IntrospectionTest extends TestCase } '; - $expected = ['data' => [ - '__type' => [ - 'name' => 'TestType' - ] - ]]; + $expected = [ + 'data' => [ + '__type' => ['name' => 'TestType'], + ], + ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); } @@ -1205,21 +1164,20 @@ class IntrospectionTest extends TestCase */ public function testIdentifiesDeprecatedFields() : void { - $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ 'nonDeprecated' => [ 'type' => Type::string(), ], - 'deprecated' => [ - 'type' => Type::string(), - 'deprecationReason' => 'Removed in 1.0' - ] - ] + 'deprecated' => [ + 'type' => Type::string(), + 'deprecationReason' => 'Removed in 1.0', + ], + ], ]); - $schema = new Schema(['query' => $TestType]); + $schema = new Schema(['query' => $TestType]); $request = ' { __type(name: "TestType") { @@ -1236,21 +1194,21 @@ class IntrospectionTest extends TestCase $expected = [ 'data' => [ '__type' => [ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ [ - 'name' => 'nonDeprecated', - 'isDeprecated' => false, - 'deprecationReason' => null + 'name' => 'nonDeprecated', + 'isDeprecated' => false, + 'deprecationReason' => null, ], [ - 'name' => 'deprecated', - 'isDeprecated' => true, - 'deprecationReason' => 'Removed in 1.0' - ] - ] - ] - ] + 'name' => 'deprecated', + 'isDeprecated' => true, + 'deprecationReason' => 'Removed in 1.0', + ], + ], + ], + ], ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); } @@ -1261,19 +1219,19 @@ class IntrospectionTest extends TestCase public function testRespectsTheIncludeDeprecatedParameterForFields() : void { $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ 'nonDeprecated' => [ 'type' => Type::string(), ], - 'deprecated' => [ - 'type' => Type::string(), - 'deprecationReason' => 'Removed in 1.0' - ] - ] + 'deprecated' => [ + 'type' => Type::string(), + 'deprecationReason' => 'Removed in 1.0', + ], + ], ]); - $schema = new Schema(['query' => $TestType]); + $schema = new Schema(['query' => $TestType]); $request = ' { __type(name: "TestType") { @@ -1294,27 +1252,19 @@ class IntrospectionTest extends TestCase $expected = [ 'data' => [ '__type' => [ - 'name' => 'TestType', - 'trueFields' => [ - [ - 'name' => 'nonDeprecated', - ], - [ - 'name' => 'deprecated', - ] + 'name' => 'TestType', + 'trueFields' => [ + ['name' => 'nonDeprecated'], + ['name' => 'deprecated'], ], - 'falseFields' => [ - [ - 'name' => 'nonDeprecated', - ] + 'falseFields' => [ + ['name' => 'nonDeprecated'], ], 'omittedFields' => [ - [ - 'name' => 'nonDeprecated', - ] + ['name' => 'nonDeprecated'], ], - ] - ] + ], + ], ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); @@ -1326,24 +1276,22 @@ class IntrospectionTest extends TestCase public function testIdentifiesDeprecatedEnumValues() : void { $TestEnum = new EnumType([ - 'name' => 'TestEnum', + 'name' => 'TestEnum', 'values' => [ - 'NONDEPRECATED' => ['value' => 0], - 'DEPRECATED' => ['value' => 1, 'deprecationReason' => 'Removed in 1.0'], - 'ALSONONDEPRECATED' => ['value' => 2] - ] + 'NONDEPRECATED' => ['value' => 0], + 'DEPRECATED' => ['value' => 1, 'deprecationReason' => 'Removed in 1.0'], + 'ALSONONDEPRECATED' => ['value' => 2], + ], ]); $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ - 'testEnum' => [ - 'type' => $TestEnum, - ], - ] + 'testEnum' => ['type' => $TestEnum], + ], ]); - $schema = new Schema(['query' => $TestType]); + $schema = new Schema(['query' => $TestType]); $request = ' { __type(name: "TestEnum") { @@ -1360,26 +1308,26 @@ class IntrospectionTest extends TestCase $expected = [ 'data' => [ '__type' => [ - 'name' => 'TestEnum', + 'name' => 'TestEnum', 'enumValues' => [ [ - 'name' => 'NONDEPRECATED', - 'isDeprecated' => false, - 'deprecationReason' => null + 'name' => 'NONDEPRECATED', + 'isDeprecated' => false, + 'deprecationReason' => null, ], [ - 'name' => 'DEPRECATED', - 'isDeprecated' => true, - 'deprecationReason' => 'Removed in 1.0' + 'name' => 'DEPRECATED', + 'isDeprecated' => true, + 'deprecationReason' => 'Removed in 1.0', ], [ - 'name' => 'ALSONONDEPRECATED', - 'isDeprecated' => false, - 'deprecationReason' => null - ] - ] - ] - ] + 'name' => 'ALSONONDEPRECATED', + 'isDeprecated' => false, + 'deprecationReason' => null, + ], + ], + ], + ], ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); } @@ -1390,25 +1338,23 @@ class IntrospectionTest extends TestCase public function testRespectsTheIncludeDeprecatedParameterForEnumValues() : void { $TestEnum = new EnumType([ - 'name' => 'TestEnum', + 'name' => 'TestEnum', 'values' => [ - 'NONDEPRECATED' => ['value' => 0], - 'DEPRECATED' => ['value' => 1, 'deprecationReason' => 'Removed in 1.0'], - 'ALSONONDEPRECATED' => ['value' => 2] - ] + 'NONDEPRECATED' => ['value' => 0], + 'DEPRECATED' => ['value' => 1, 'deprecationReason' => 'Removed in 1.0'], + 'ALSONONDEPRECATED' => ['value' => 2], + ], ]); $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ - 'testEnum' => [ - 'type' => $TestEnum, - ], - ] + 'testEnum' => ['type' => $TestEnum], + ], ]); - $schema = new Schema(['query' => $TestType]); - $request = ' + $schema = new Schema(['query' => $TestType]); + $request = ' { __type(name: "TestEnum") { name @@ -1427,22 +1373,22 @@ class IntrospectionTest extends TestCase $expected = [ 'data' => [ '__type' => [ - 'name' => 'TestEnum', - 'trueValues' => [ + 'name' => 'TestEnum', + 'trueValues' => [ ['name' => 'NONDEPRECATED'], ['name' => 'DEPRECATED'], - ['name' => 'ALSONONDEPRECATED'] + ['name' => 'ALSONONDEPRECATED'], ], - 'falseValues' => [ + 'falseValues' => [ ['name' => 'NONDEPRECATED'], - ['name' => 'ALSONONDEPRECATED'] + ['name' => 'ALSONONDEPRECATED'], ], 'omittedValues' => [ ['name' => 'NONDEPRECATED'], - ['name' => 'ALSONONDEPRECATED'] + ['name' => 'ALSONONDEPRECATED'], ], - ] - ] + ], + ], ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); } @@ -1453,16 +1399,16 @@ class IntrospectionTest extends TestCase public function testFailsAsExpectedOnTheTypeRootFieldWithoutAnArg() : void { $TestType = new ObjectType([ - 'name' => 'TestType', + 'name' => 'TestType', 'fields' => [ 'testField' => [ 'type' => Type::string(), - ] - ] + ], + ], ]); - $schema = new Schema(['query' => $TestType]); - $request = ' + $schema = new Schema(['query' => $TestType]); + $request = ' { __type { name @@ -1472,9 +1418,10 @@ class IntrospectionTest extends TestCase $expected = [ 'errors' => [ FormattedError::create( - ProvidedNonNullArguments::missingFieldArgMessage('__type', 'name', 'String!'), [new SourceLocation(3, 9)] - ) - ] + ProvidedNonNullArguments::missingFieldArgMessage('__type', 'name', 'String!'), + [new SourceLocation(3, 9)] + ), + ], ]; $this->assertArraySubset($expected, GraphQL::executeQuery($schema, $request)->toArray()); } @@ -1485,12 +1432,12 @@ class IntrospectionTest extends TestCase public function testExposesDescriptionsOnTypesAndFields() : void { $QueryRoot = new ObjectType([ - 'name' => 'QueryRoot', - 'fields' => ['a' => Type::string()] + 'name' => 'QueryRoot', + 'fields' => ['a' => Type::string()], ]); - $schema = new Schema(['query' => $QueryRoot]); - $request = ' + $schema = new Schema(['query' => $QueryRoot]); + $request = ' { schemaType: __type(name: "__Schema") { name, @@ -1505,36 +1452,36 @@ class IntrospectionTest extends TestCase $expected = [ 'data' => [ 'schemaType' => [ - 'name' => '__Schema', + 'name' => '__Schema', 'description' => 'A GraphQL Schema defines the capabilities of a ' . 'GraphQL server. It exposes all available types and ' . 'directives on the server, as well as the entry ' . 'points for query, mutation, and subscription operations.', - 'fields' => [ + 'fields' => [ [ - 'name' => 'types', - 'description' => 'A list of all types supported by this server.' + 'name' => 'types', + 'description' => 'A list of all types supported by this server.', ], [ - 'name' => 'queryType', - 'description' => 'The type that query operations will be rooted at.' + 'name' => 'queryType', + 'description' => 'The type that query operations will be rooted at.', ], [ - 'name' => 'mutationType', + 'name' => 'mutationType', 'description' => 'If this server supports mutation, the type that ' . - 'mutation operations will be rooted at.' + 'mutation operations will be rooted at.', ], [ - 'name' => 'subscriptionType', - 'description' => 'If this server support subscription, the type that subscription operations will be rooted at.' + 'name' => 'subscriptionType', + 'description' => 'If this server support subscription, the type that subscription operations will be rooted at.', ], [ - 'name' => 'directives', - 'description' => 'A list of all directives supported by this server.' - ] - ] - ] - ] + 'name' => 'directives', + 'description' => 'A list of all directives supported by this server.', + ], + ], + ], + ], ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); } @@ -1545,12 +1492,12 @@ class IntrospectionTest extends TestCase public function testExposesDescriptionsOnEnums() : void { $QueryRoot = new ObjectType([ - 'name' => 'QueryRoot', - 'fields' => ['a' => Type::string()] + 'name' => 'QueryRoot', + 'fields' => ['a' => Type::string()], ]); - $schema = new Schema(['query' => $QueryRoot]); - $request = ' + $schema = new Schema(['query' => $QueryRoot]); + $request = ' { typeKindType: __type(name: "__TypeKind") { name, @@ -1565,51 +1512,51 @@ class IntrospectionTest extends TestCase $expected = [ 'data' => [ 'typeKindType' => [ - 'name' => '__TypeKind', + 'name' => '__TypeKind', 'description' => 'An enum describing what kind of type a given `__Type` is.', - 'enumValues' => [ + 'enumValues' => [ [ 'description' => 'Indicates this type is a scalar.', - 'name' => 'SCALAR' + 'name' => 'SCALAR', ], [ 'description' => 'Indicates this type is an object. ' . '`fields` and `interfaces` are valid fields.', - 'name' => 'OBJECT' + 'name' => 'OBJECT', ], [ 'description' => 'Indicates this type is an interface. ' . '`fields` and `possibleTypes` are valid fields.', - 'name' => 'INTERFACE' + 'name' => 'INTERFACE', ], [ 'description' => 'Indicates this type is a union. ' . '`possibleTypes` is a valid field.', - 'name' => 'UNION' + 'name' => 'UNION', ], [ 'description' => 'Indicates this type is an enum. ' . '`enumValues` is a valid field.', - 'name' => 'ENUM' + 'name' => 'ENUM', ], [ 'description' => 'Indicates this type is an input object. ' . '`inputFields` is a valid field.', - 'name' => 'INPUT_OBJECT' + 'name' => 'INPUT_OBJECT', ], [ 'description' => 'Indicates this type is a list. ' . '`ofType` is a valid field.', - 'name' => 'LIST' + 'name' => 'LIST', ], [ 'description' => 'Indicates this type is a non-null. ' . '`ofType` is a valid field.', - 'name' => 'NON_NULL' - ] - ] - ] - ] + 'name' => 'NON_NULL', + ], + ], + ], + ], ]; $this->assertEquals($expected, GraphQL::executeQuery($schema, $request)->toArray()); diff --git a/tests/Type/ObjectIdStub.php b/tests/Type/ObjectIdStub.php index b0453ab..3049569 100644 --- a/tests/Type/ObjectIdStub.php +++ b/tests/Type/ObjectIdStub.php @@ -1,11 +1,12 @@ node = new InterfaceType([ - 'name' => 'Node', + 'name' => 'Node', 'fields' => [ - 'id' => Type::string() - ] + 'id' => Type::string(), + ], ]); $this->content = new InterfaceType([ - 'name' => 'Content', - 'fields' => function() { + 'name' => 'Content', + 'fields' => function () { return [ - 'title' => Type::string(), - 'body' => Type::string(), - 'author' => $this->user, - 'comments' => Type::listOf($this->comment), - 'categories' => Type::listOf($this->category) + 'title' => Type::string(), + 'body' => Type::string(), + 'author' => $this->user, + 'comments' => Type::listOf($this->comment), + 'categories' => Type::listOf($this->category), ]; - } + }, ]); $this->blogStory = new ObjectType([ - 'name' => 'BlogStory', + 'name' => 'BlogStory', 'interfaces' => [ $this->node, - $this->content + $this->content, ], - 'fields' => function() { - return [ - $this->node->getField('id'), - $this->content->getField('title'), - $this->content->getField('body'), - $this->content->getField('author'), - $this->content->getField('comments'), - $this->content->getField('categories') - ]; - }, - ]); - - $this->link = new ObjectType([ - 'name' => 'Link', - 'interfaces' => [ - $this->node, - $this->content - ], - 'fields' => function() { + 'fields' => function () { return [ $this->node->getField('id'), $this->content->getField('title'), @@ -135,143 +98,166 @@ class ResolutionTest extends TestCase $this->content->getField('author'), $this->content->getField('comments'), $this->content->getField('categories'), - 'url' => Type::string() ]; }, ]); + new ObjectType([ + 'name' => 'Link', + 'interfaces' => [ + $this->node, + $this->content, + ], + 'fields' => function () { + return [ + 'id' => $this->node->getField('id'), + 'title' => $this->content->getField('title'), + 'body' => $this->content->getField('body'), + 'author' => $this->content->getField('author'), + 'comments' => $this->content->getField('comments'), + 'categories' => $this->content->getField('categories'), + 'url' => Type::string(), + ]; + }, + + ]); + + $this->videoMetadata = new ObjectType([ + 'name' => 'VideoMetadata', + 'fields' => [ + 'lat' => Type::float(), + 'lng' => Type::float(), + ], + ]); + $this->video = new ObjectType([ - 'name' => 'Video', + 'name' => 'Video', 'interfaces' => [ $this->node, - $this->content + $this->content, ], - 'fields' => function() { + 'fields' => function () { return [ - $this->node->getField('id'), - $this->content->getField('title'), - $this->content->getField('body'), - $this->content->getField('author'), - $this->content->getField('comments'), - $this->content->getField('categories'), - 'streamUrl' => Type::string(), + 'id' => $this->node->getField('id'), + 'title' => $this->content->getField('title'), + 'body' => $this->content->getField('body'), + 'author' => $this->content->getField('author'), + 'comments' => $this->content->getField('comments'), + 'categories' => $this->content->getField('categories'), + 'streamUrl' => Type::string(), 'downloadUrl' => Type::string(), - 'metadata' => $this->videoMetadata = new ObjectType([ - 'name' => 'VideoMetadata', - 'fields' => [ - 'lat' => Type::float(), - 'lng' => Type::float() - ] - ]) + 'metadata' => $this->videoMetadata, ]; - } + }, ]); $this->comment = new ObjectType([ - 'name' => 'Comment', + 'name' => 'Comment', 'interfaces' => [ - $this->node + $this->node, ], - 'fields' => function() { + 'fields' => function () { return [ - $this->node->getField('id'), - 'author' => $this->user, - 'text' => Type::string(), + 'id' => $this->node->getField('id'), + 'author' => $this->user, + 'text' => Type::string(), 'replies' => Type::listOf($this->comment), - 'parent' => $this->comment, - 'content' => $this->content + 'parent' => $this->comment, + 'content' => $this->content, ]; - } + }, ]); $this->user = new ObjectType([ - 'name' => 'User', + 'name' => 'User', 'interfaces' => [ - $this->node + $this->node, ], - 'fields' => function() { + 'fields' => function () { return [ - $this->node->getField('id'), + 'id' => $this->node->getField('id'), 'name' => Type::string(), ]; - } + }, ]); $this->category = new ObjectType([ - 'name' => 'Category', + 'name' => 'Category', 'interfaces' => [ - $this->node + $this->node, ], - 'fields' => function() { + 'fields' => function () { return [ - $this->node->getField('id'), - 'name' => Type::string() + 'id' => $this->node->getField('id'), + 'name' => Type::string(), ]; - } + }, ]); $this->mention = new UnionType([ - 'name' => 'Mention', + 'name' => 'Mention', 'types' => [ $this->user, - $this->category - ] + $this->category, + ], ]); $this->query = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'viewer' => $this->user, + 'viewer' => $this->user, 'latestContent' => $this->content, - 'node' => $this->node, - 'mentions' => Type::listOf($this->mention) - ] + 'node' => $this->node, + 'mentions' => Type::listOf($this->mention), + ], + ]); + + $this->postStoryMutationInput = new InputObjectType([ + 'name' => 'PostStoryMutationInput', + 'fields' => [ + 'title' => Type::string(), + 'body' => Type::string(), + 'author' => Type::id(), + 'category' => Type::id(), + ], ]); $this->mutation = new ObjectType([ - 'name' => 'Mutation', + 'name' => 'Mutation', 'fields' => [ - 'postStory' => [ + 'postStory' => [ 'type' => $this->postStoryMutation = new ObjectType([ - 'name' => 'PostStoryMutation', + 'name' => 'PostStoryMutation', 'fields' => [ - 'story' => $this->blogStory - ] + 'story' => $this->blogStory, + ], ]), 'args' => [ - 'input' => Type::nonNull($this->postStoryMutationInput = new InputObjectType([ - 'name' => 'PostStoryMutationInput', - 'fields' => [ - 'title' => Type::string(), - 'body' => Type::string(), - 'author' => Type::id(), - 'category' => Type::id() - ] - ])), - 'clientRequestId' => Type::string() - ] + 'input' => Type::nonNull($this->postStoryMutationInput), + 'clientRequestId' => Type::string(), + ], ], 'postComment' => [ 'type' => $this->postCommentMutation = new ObjectType([ - 'name' => 'PostCommentMutation', + 'name' => 'PostCommentMutation', 'fields' => [ - 'comment' => $this->comment - ] + 'comment' => $this->comment, + ], ]), 'args' => [ - 'input' => Type::nonNull($this->postCommentMutationInput = new InputObjectType([ - 'name' => 'PostCommentMutationInput', + 'input' => Type::nonNull($this->postCommentMutationInput = new InputObjectType([ + 'name' => 'PostCommentMutationInput', 'fields' => [ - 'text' => Type::nonNull(Type::string()), - 'author' => Type::nonNull(Type::id()), + 'text' => Type::nonNull(Type::string()), + 'author' => Type::nonNull(Type::id()), 'content' => Type::id(), - 'parent' => Type::id() - ] + 'parent' => Type::id(), + ], ])), - 'clientRequestId' => Type::string() - ] - ] - ] + 'clientRequestId' => Type::string(), + ], + ], + ], ]); } @@ -279,25 +265,25 @@ class ResolutionTest extends TestCase { // Has internal types by default: $eagerTypeResolution = new EagerResolution([]); - $expectedTypeMap = [ - 'ID' => Type::id(), - 'String' => Type::string(), - 'Float' => Type::float(), - 'Int' => Type::int(), - 'Boolean' => Type::boolean() + $expectedTypeMap = [ + 'ID' => Type::id(), + 'String' => Type::string(), + 'Float' => Type::float(), + 'Int' => Type::int(), + 'Boolean' => Type::boolean(), ]; $this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap()); $expectedDescriptor = [ - 'version' => '1.0', - 'typeMap' => [ - 'ID' => 1, - 'String' => 1, - 'Float' => 1, - 'Int' => 1, + 'version' => '1.0', + 'typeMap' => [ + 'ID' => 1, + 'String' => 1, + 'Float' => 1, + 'Int' => 1, 'Boolean' => 1, ], - 'possibleTypeMap' => [] + 'possibleTypeMap' => [], ]; $this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor()); @@ -321,72 +307,76 @@ class ResolutionTest extends TestCase $this->assertSame($this->postStoryMutation, $eagerTypeResolution->resolveType('PostStoryMutation')); $this->assertSame($this->postStoryMutationInput, $eagerTypeResolution->resolveType('PostStoryMutationInput')); $this->assertSame($this->postCommentMutation, $eagerTypeResolution->resolveType('PostCommentMutation')); - $this->assertSame($this->postCommentMutationInput, $eagerTypeResolution->resolveType('PostCommentMutationInput')); + $this->assertSame( + $this->postCommentMutationInput, + $eagerTypeResolution->resolveType('PostCommentMutationInput') + ); $this->assertEquals([$this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->content)); - $this->assertEquals([$this->user, $this->comment, $this->category, $this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->node)); + $this->assertEquals( + [$this->user, $this->comment, $this->category, $this->blogStory], + $eagerTypeResolution->resolvePossibleTypes($this->node) + ); $this->assertEquals([$this->user, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->mention)); $expectedTypeMap = [ - 'Query' => $this->query, - 'Mutation' => $this->mutation, - 'User' => $this->user, - 'Node' => $this->node, - 'String' => Type::string(), - 'Content' => $this->content, - 'Comment' => $this->comment, - 'Mention' => $this->mention, - 'BlogStory' => $this->blogStory, - 'Category' => $this->category, - 'PostStoryMutationInput' => $this->postStoryMutationInput, - 'ID' => Type::id(), - 'PostStoryMutation' => $this->postStoryMutation, + 'Query' => $this->query, + 'Mutation' => $this->mutation, + 'User' => $this->user, + 'Node' => $this->node, + 'String' => Type::string(), + 'Content' => $this->content, + 'Comment' => $this->comment, + 'Mention' => $this->mention, + 'BlogStory' => $this->blogStory, + 'Category' => $this->category, + 'PostStoryMutationInput' => $this->postStoryMutationInput, + 'ID' => Type::id(), + 'PostStoryMutation' => $this->postStoryMutation, 'PostCommentMutationInput' => $this->postCommentMutationInput, - 'PostCommentMutation' => $this->postCommentMutation, - 'Float' => Type::float(), - 'Int' => Type::int(), - 'Boolean' => Type::boolean() + 'PostCommentMutation' => $this->postCommentMutation, + 'Float' => Type::float(), + 'Int' => Type::int(), + 'Boolean' => Type::boolean(), ]; $this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap()); $expectedDescriptor = [ - 'version' => '1.0', - 'typeMap' => [ - 'Query' => 1, - 'Mutation' => 1, - 'User' => 1, - 'Node' => 1, - 'String' => 1, - 'Content' => 1, - 'Comment' => 1, - 'Mention' => 1, - 'BlogStory' => 1, - 'Category' => 1, - 'PostStoryMutationInput' => 1, - 'ID' => 1, - 'PostStoryMutation' => 1, + 'version' => '1.0', + 'typeMap' => [ + 'Query' => 1, + 'Mutation' => 1, + 'User' => 1, + 'Node' => 1, + 'String' => 1, + 'Content' => 1, + 'Comment' => 1, + 'Mention' => 1, + 'BlogStory' => 1, + 'Category' => 1, + 'PostStoryMutationInput' => 1, + 'ID' => 1, + 'PostStoryMutation' => 1, 'PostCommentMutationInput' => 1, - 'PostCommentMutation' => 1, - 'Float' => 1, - 'Int' => 1, - 'Boolean' => 1 + 'PostCommentMutation' => 1, + 'Float' => 1, + 'Int' => 1, + 'Boolean' => 1, ], 'possibleTypeMap' => [ - 'Node' => [ - 'User' => 1, - 'Comment' => 1, - 'Category' => 1, - 'BlogStory' => 1 - ], - 'Content' => [ - 'BlogStory' => 1 + 'Node' => [ + 'User' => 1, + 'Comment' => 1, + 'Category' => 1, + 'BlogStory' => 1, ], + 'Content' => ['BlogStory' => 1], 'Mention' => [ - 'User' => 1, - 'Category' => 1 - ] - ] + 'User' => 1, + 'Category' => 1, + ], + ], ]; $this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor()); @@ -402,7 +392,10 @@ class ResolutionTest extends TestCase $this->assertEquals(null, $eagerTypeResolution->resolveType('VideoMetadata')); $this->assertEquals([$this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->content)); - $this->assertEquals([$this->user, $this->comment, $this->category, $this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->node)); + $this->assertEquals( + [$this->user, $this->comment, $this->category, $this->blogStory], + $eagerTypeResolution->resolvePossibleTypes($this->node) + ); $this->assertEquals([$this->user, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->mention)); $eagerTypeResolution = new EagerResolution([null, $this->video, null]); @@ -410,52 +403,53 @@ class ResolutionTest extends TestCase $this->assertEquals($this->video, $eagerTypeResolution->resolveType('Video')); $this->assertEquals([$this->video], $eagerTypeResolution->resolvePossibleTypes($this->content)); - $this->assertEquals([$this->video, $this->user, $this->comment, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->node)); + $this->assertEquals( + [$this->video, $this->user, $this->comment, $this->category], + $eagerTypeResolution->resolvePossibleTypes($this->node) + ); $this->assertEquals([], $eagerTypeResolution->resolvePossibleTypes($this->mention)); $expectedTypeMap = [ - 'Video' => $this->video, - 'Node' => $this->node, - 'String' => Type::string(), - 'Content' => $this->content, - 'User' => $this->user, - 'Comment' => $this->comment, - 'Category' => $this->category, + 'Video' => $this->video, + 'Node' => $this->node, + 'String' => Type::string(), + 'Content' => $this->content, + 'User' => $this->user, + 'Comment' => $this->comment, + 'Category' => $this->category, 'VideoMetadata' => $this->videoMetadata, - 'Float' => Type::float(), - 'ID' => Type::id(), - 'Int' => Type::int(), - 'Boolean' => Type::boolean() + 'Float' => Type::float(), + 'ID' => Type::id(), + 'Int' => Type::int(), + 'Boolean' => Type::boolean(), ]; $this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap()); $expectedDescriptor = [ - 'version' => '1.0', - 'typeMap' => [ - 'Video' => 1, - 'Node' => 1, - 'String' => 1, - 'Content' => 1, - 'User' => 1, - 'Comment' => 1, - 'Category' => 1, + 'version' => '1.0', + 'typeMap' => [ + 'Video' => 1, + 'Node' => 1, + 'String' => 1, + 'Content' => 1, + 'User' => 1, + 'Comment' => 1, + 'Category' => 1, 'VideoMetadata' => 1, - 'Float' => 1, - 'ID' => 1, - 'Int' => 1, - 'Boolean' => 1 + 'Float' => 1, + 'ID' => 1, + 'Int' => 1, + 'Boolean' => 1, ], 'possibleTypeMap' => [ - 'Node' => [ - 'Video' => 1, - 'User' => 1, - 'Comment' => 1, - 'Category' => 1 + 'Node' => [ + 'Video' => 1, + 'User' => 1, + 'Comment' => 1, + 'Category' => 1, ], - 'Content' => [ - 'Video' => 1 - ] - ] + 'Content' => ['Video' => 1], + ], ]; $this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor()); } @@ -463,11 +457,11 @@ class ResolutionTest extends TestCase public function testLazyResolutionFollowsEagerResolution() : void { // Lazy resolution should work the same way as eager resolution works, except that it should load types on demand - $eager = new EagerResolution([]); + $eager = new EagerResolution([]); $emptyDescriptor = $eager->getDescriptor(); - $typeLoader = function($name) { - throw new \Exception("This should be never called for empty descriptor"); + $typeLoader = function ($name) { + throw new \Exception('This should be never called for empty descriptor'); }; $lazy = new LazyResolution($emptyDescriptor, $typeLoader); @@ -478,11 +472,12 @@ class ResolutionTest extends TestCase $eager = new EagerResolution([$this->query, $this->mutation]); - $called = 0; + $called = 0; $descriptor = $eager->getDescriptor(); - $typeLoader = function($name) use (&$called) { + $typeLoader = function ($name) use (&$called) { $called++; $prop = lcfirst($name); + return $this->{$prop}; }; @@ -507,7 +502,10 @@ class ResolutionTest extends TestCase $this->assertSame($eager->resolveType('PostStoryMutation'), $lazy->resolveType('PostStoryMutation')); $this->assertSame($eager->resolveType('PostStoryMutationInput'), $lazy->resolveType('PostStoryMutationInput')); $this->assertSame($eager->resolveType('PostCommentMutation'), $lazy->resolveType('PostCommentMutation')); - $this->assertSame($eager->resolveType('PostCommentMutationInput'), $lazy->resolveType('PostCommentMutationInput')); + $this->assertSame( + $eager->resolveType('PostCommentMutationInput'), + $lazy->resolveType('PostCommentMutationInput') + ); $this->assertSame(13, $called); $this->assertEquals($eager->resolvePossibleTypes($this->content), $lazy->resolvePossibleTypes($this->content)); @@ -515,8 +513,8 @@ class ResolutionTest extends TestCase $this->assertEquals($eager->resolvePossibleTypes($this->mention), $lazy->resolvePossibleTypes($this->mention)); $called = 0; - $eager = new EagerResolution([$this->video]); - $lazy = new LazyResolution($eager->getDescriptor(), $typeLoader); + $eager = new EagerResolution([$this->video]); + $lazy = new LazyResolution($eager->getDescriptor(), $typeLoader); $this->assertEquals($eager->resolveType('VideoMetadata'), $lazy->resolveType('VideoMetadata')); $this->assertEquals($eager->resolveType('Video'), $lazy->resolveType('Video')); @@ -527,40 +525,6 @@ class ResolutionTest extends TestCase $this->assertEquals($eager->resolvePossibleTypes($this->mention), $lazy->resolvePossibleTypes($this->mention)); } - private function createLazy(){ - - $descriptor = [ - 'version' => '1.0', - 'typeMap' => [ - 'null' => 1, - 'int' => 1 - ], - 'possibleTypeMap' => [ - 'a' => [ - 'null' => 1, - ], - 'b' => [ - 'int' => 1 - ] - ] - ]; - - $invalidTypeLoader = function($name) { - switch ($name) { - case 'null': - return null; - case 'int': - return 7; - } - }; - - $lazy = new LazyResolution($descriptor, $invalidTypeLoader); - $value = $lazy->resolveType('null'); - $this->assertEquals(null, $value); - - return $lazy; - } - public function testLazyThrowsOnInvalidLoadedType() : void { $lazy = $this->createLazy(); @@ -569,9 +533,39 @@ class ResolutionTest extends TestCase $lazy->resolveType('int'); } + private function createLazy() + { + $descriptor = [ + 'version' => '1.0', + 'typeMap' => [ + 'null' => 1, + 'int' => 1, + ], + 'possibleTypeMap' => [ + 'a' => ['null' => 1], + 'b' => ['int' => 1], + ], + ]; + + $invalidTypeLoader = function ($name) { + switch ($name) { + case 'null': + return null; + case 'int': + return 7; + } + }; + + $lazy = new LazyResolution($descriptor, $invalidTypeLoader); + $value = $lazy->resolveType('null'); + $this->assertEquals(null, $value); + + return $lazy; + } + public function testLazyThrowsOnInvalidLoadedPossibleType() : void { - $tmp = new InterfaceType(['name' => 'a', 'fields' => []]); + $tmp = new InterfaceType(['name' => 'a', 'fields' => []]); $lazy = $this->createLazy(); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage('Lazy Type Resolution Error: Implementation null of interface a is expected to be instance of ObjectType, but got NULL'); @@ -580,7 +574,7 @@ class ResolutionTest extends TestCase public function testLazyThrowsOnInvalidLoadedPossibleTypeWithInteger() : void { - $tmp = new InterfaceType(['name' => 'b', 'fields' => []]); + $tmp = new InterfaceType(['name' => 'b', 'fields' => []]); $lazy = $this->createLazy(); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage('Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer'); diff --git a/tests/Type/ResolveInfoTest.php b/tests/Type/ResolveInfoTest.php index 768f555..5c5b5f1 100644 --- a/tests/Type/ResolveInfoTest.php +++ b/tests/Type/ResolveInfoTest.php @@ -1,11 +1,14 @@ 'Image', + 'name' => 'Image', 'fields' => [ - 'url' => ['type' => Type::string()], - 'width' => ['type' => Type::int()], - 'height' => ['type' => Type::int()] - ] + 'url' => ['type' => Type::string()], + 'width' => ['type' => Type::int()], + 'height' => ['type' => Type::int()], + ], ]); $article = null; $author = new ObjectType([ - 'name' => 'Author', - 'fields' => function() use ($image, &$article) { + 'name' => 'Author', + 'fields' => function () use ($image, &$article) { return [ - 'id' => ['type' => Type::string()], - 'name' => ['type' => Type::string()], - 'pic' => [ 'type' => $image, 'args' => [ - 'width' => ['type' => Type::int()], - 'height' => ['type' => Type::int()] - ]], + 'id' => ['type' => Type::string()], + 'name' => ['type' => Type::string()], + 'pic' => [ + 'type' => $image, + 'args' => [ + 'width' => ['type' => Type::int()], + 'height' => ['type' => Type::int()], + ], + ], 'recentArticle' => ['type' => $article], ]; }, ]); $reply = new ObjectType([ - 'name' => 'Reply', + 'name' => 'Reply', 'fields' => [ 'author' => ['type' => $author], - 'body' => ['type' => Type::string()] - ] + 'body' => ['type' => Type::string()], + ], ]); $article = new ObjectType([ - 'name' => 'Article', + 'name' => 'Article', 'fields' => [ - 'id' => ['type' => Type::string()], + 'id' => ['type' => Type::string()], 'isPublished' => ['type' => Type::boolean()], - 'author' => ['type' => $author], - 'title' => ['type' => Type::string()], - 'body' => ['type' => Type::string()], - 'image' => ['type' => $image], - 'replies' => ['type' => Type::listOf($reply)] - ] + 'author' => ['type' => $author], + 'title' => ['type' => Type::string()], + 'body' => ['type' => Type::string()], + 'image' => ['type' => $image], + 'replies' => ['type' => Type::listOf($reply)], + ], ]); - $doc = ' + $doc = ' query Test { article { author { @@ -100,59 +106,70 @@ class ResolveInfoTest extends TestCase } '; $expectedDefaultSelection = [ - 'author' => true, - 'image' => true, - 'replies' => true + 'author' => true, + 'image' => true, + 'replies' => true, ]; - $expectedDeepSelection = [ - 'author' => [ + $expectedDeepSelection = [ + 'author' => [ 'name' => true, - 'pic' => [ - 'url' => true, - 'width' => true - ] + 'pic' => [ + 'url' => true, + 'width' => true, + ], ], - 'image' => [ - 'width' => true, + 'image' => [ + 'width' => true, 'height' => true, - 'url' => true + 'url' => true, ], 'replies' => [ - 'body' => true, + 'body' => true, 'author' => [ - 'id' => true, - 'name' => true, - 'pic' => [ - 'url' => true, - 'width' => true, - 'height' => true + 'id' => true, + 'name' => true, + 'pic' => [ + 'url' => true, + 'width' => true, + 'height' => true, ], 'recentArticle' => [ - 'id' => true, + 'id' => true, 'title' => true, - 'body' => true - ] - ] - ] + 'body' => true, + ], + ], + ], ]; - $hasCalled = false; + $hasCalled = false; $actualDefaultSelection = null; - $actualDeepSelection = null; + $actualDeepSelection = null; $blogQuery = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ 'article' => [ - 'type' => $article, - 'resolve' => function($value, $args, $context, ResolveInfo $info) use (&$hasCalled, &$actualDefaultSelection, &$actualDeepSelection) { - $hasCalled = true; + 'type' => $article, + 'resolve' => function ( + $value, + $args, + $context, + ResolveInfo $info + ) use ( + &$hasCalled, + & + $actualDefaultSelection, + &$actualDeepSelection + ) { + $hasCalled = true; $actualDefaultSelection = $info->getFieldSelection(); - $actualDeepSelection = $info->getFieldSelection(5); + $actualDeepSelection = $info->getFieldSelection(5); + return null; - } - ] - ] + }, + ], + ], ]); $schema = new Schema(['query' => $blogQuery]); @@ -167,50 +184,53 @@ class ResolveInfoTest extends TestCase public function testMergedFragmentsFieldSelection() : void { $image = new ObjectType([ - 'name' => 'Image', + 'name' => 'Image', 'fields' => [ - 'url' => ['type' => Type::string()], - 'width' => ['type' => Type::int()], - 'height' => ['type' => Type::int()] - ] + 'url' => ['type' => Type::string()], + 'width' => ['type' => Type::int()], + 'height' => ['type' => Type::int()], + ], ]); $article = null; $author = new ObjectType([ - 'name' => 'Author', - 'fields' => function() use ($image, &$article) { + 'name' => 'Author', + 'fields' => function () use ($image, &$article) { return [ - 'id' => ['type' => Type::string()], - 'name' => ['type' => Type::string()], - 'pic' => [ 'type' => $image, 'args' => [ - 'width' => ['type' => Type::int()], - 'height' => ['type' => Type::int()] - ]], + 'id' => ['type' => Type::string()], + 'name' => ['type' => Type::string()], + 'pic' => [ + 'type' => $image, + 'args' => [ + 'width' => ['type' => Type::int()], + 'height' => ['type' => Type::int()], + ], + ], 'recentArticle' => ['type' => $article], ]; }, ]); $reply = new ObjectType([ - 'name' => 'Reply', + 'name' => 'Reply', 'fields' => [ 'author' => ['type' => $author], - 'body' => ['type' => Type::string()] - ] + 'body' => ['type' => Type::string()], + ], ]); $article = new ObjectType([ - 'name' => 'Article', + 'name' => 'Article', 'fields' => [ - 'id' => ['type' => Type::string()], + 'id' => ['type' => Type::string()], 'isPublished' => ['type' => Type::boolean()], - 'author' => ['type' => $author], - 'title' => ['type' => Type::string()], - 'body' => ['type' => Type::string()], - 'image' => ['type' => $image], - 'replies' => ['type' => Type::listOf($reply)] - ] + 'author' => ['type' => $author], + 'title' => ['type' => Type::string()], + 'body' => ['type' => Type::string()], + 'image' => ['type' => $image], + 'replies' => ['type' => Type::listOf($reply)], + ], ]); $doc = ' @@ -264,53 +284,63 @@ class ResolveInfoTest extends TestCase '; $expectedDeepSelection = [ - 'author' => [ + 'author' => [ 'name' => true, - 'pic' => [ - 'url' => true, - 'width' => true - ] + 'pic' => [ + 'url' => true, + 'width' => true, + ], ], - 'image' => [ - 'width' => true, + 'image' => [ + 'width' => true, 'height' => true, - 'url' => true + 'url' => true, ], 'replies' => [ - 'body' => true, //this would be missing if not for the fix https://github.com/webonyx/graphql-php/pull/98 + 'body' => true, //this would be missing if not for the fix https://github.com/webonyx/graphql-php/pull/98 'author' => [ - 'id' => true, - 'name' => true, - 'pic' => [ - 'url' => true, - 'width' => true, - 'height' => true + 'id' => true, + 'name' => true, + 'pic' => [ + 'url' => true, + 'width' => true, + 'height' => true, ], 'recentArticle' => [ - 'id' => true, + 'id' => true, 'title' => true, - 'body' => true - ] - ] - ] + 'body' => true, + ], + ], + ], ]; - $hasCalled = false; + $hasCalled = false; $actualDefaultSelection = null; - $actualDeepSelection = null; + $actualDeepSelection = null; $blogQuery = new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ 'article' => [ - 'type' => $article, - 'resolve' => function($value, $args, $context, ResolveInfo $info) use (&$hasCalled, &$actualDeepSelection) { - $hasCalled = true; + 'type' => $article, + 'resolve' => function ( + $value, + $args, + $context, + ResolveInfo $info + ) use ( + &$hasCalled, + & + $actualDeepSelection + ) { + $hasCalled = true; $actualDeepSelection = $info->getFieldSelection(5); + return null; - } - ] - ] + }, + ], + ], ]); $schema = new Schema(['query' => $blogQuery]); @@ -320,6 +350,4 @@ class ResolveInfoTest extends TestCase $this->assertEquals(['data' => ['article' => null]], $result); $this->assertEquals($expectedDeepSelection, $actualDeepSelection); } - - } diff --git a/tests/Type/ScalarSerializationTest.php b/tests/Type/ScalarSerializationTest.php index e26f0a1..fa89e01 100644 --- a/tests/Type/ScalarSerializationTest.php +++ b/tests/Type/ScalarSerializationTest.php @@ -1,4 +1,7 @@ expectException(Error::class); $this->expectExceptionMessage('Int cannot represent non-integer value: 1.1'); $intType->serialize(1.1); - } public function testSerializesOutputIntCannotRepresentNegativeFloat() : void @@ -51,7 +52,6 @@ class ScalarSerializationTest extends TestCase $this->expectException(Error::class); $this->expectExceptionMessage('Int cannot represent non-integer value: -1.1'); $intType->serialize(-1.1); - } public function testSerializesOutputIntCannotRepresentNumericString() : void @@ -60,7 +60,6 @@ class ScalarSerializationTest extends TestCase $this->expectException(Error::class); $this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: Int cannot represent non-integer value: "-1.1"'); $intType->serialize('Int cannot represent non-integer value: "-1.1"'); - } public function testSerializesOutputIntCannotRepresentBiggerThan32Bits() : void @@ -71,7 +70,6 @@ class ScalarSerializationTest extends TestCase $this->expectException(Error::class); $this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: 9876504321'); $intType->serialize(9876504321); - } public function testSerializesOutputIntCannotRepresentLowerThan32Bits() : void @@ -104,7 +102,6 @@ class ScalarSerializationTest extends TestCase $this->expectException(Error::class); $this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: one'); $intType->serialize('one'); - } public function testSerializesOutputIntCannotRepresentEmptyString() : void @@ -196,7 +193,6 @@ class ScalarSerializationTest extends TestCase $this->assertSame(false, $boolType->serialize(0)); $this->assertSame(true, $boolType->serialize(true)); $this->assertSame(false, $boolType->serialize(false)); - // TODO: how should it behave on '0'? } diff --git a/tests/Type/SchemaTest.php b/tests/Type/SchemaTest.php index 7224622..ea07e65 100644 --- a/tests/Type/SchemaTest.php +++ b/tests/Type/SchemaTest.php @@ -1,4 +1,7 @@ interfaceType = new InterfaceType([ - 'name' => 'Interface', + 'name' => 'Interface', 'fields' => ['fieldName' => ['type' => Type::string()]], ]); $this->implementingType = new ObjectType([ - 'name' => 'Object', + 'name' => 'Object', 'interfaces' => [$this->interfaceType], - 'fields' => ['fieldName' => ['type' => Type::string(), 'resolve' => function () { + 'fields' => [ + 'fieldName' => [ + 'type' => Type::string(), + 'resolve' => function () { return ''; - }]], + }, + ], + ], ]); $this->directiveInputType = new InputObjectType([ - 'name' => 'DirInput', + 'name' => 'DirInput', 'fields' => [ 'field' => [ 'type' => Type::string(), @@ -50,7 +63,7 @@ class SchemaTest extends TestCase ]); $this->wrappedDirectiveInputType = new InputObjectType([ - 'name' => 'WrappedDirInput', + 'name' => 'WrappedDirInput', 'fields' => [ 'field' => [ 'type' => Type::string(), @@ -59,10 +72,10 @@ class SchemaTest extends TestCase ]); $this->directive = new Directive([ - 'name' => 'dir', + 'name' => 'dir', 'locations' => ['OBJECT'], - 'args' => [ - 'arg' => [ + 'args' => [ + 'arg' => [ 'type' => $this->directiveInputType, ], 'argList' => [ @@ -72,11 +85,11 @@ class SchemaTest extends TestCase ]); $this->schema = new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', + 'query' => new ObjectType([ + 'name' => 'Query', 'fields' => [ 'getObject' => [ - 'type' => $this->interfaceType, + 'type' => $this->interfaceType, 'resolve' => function () { return []; }, diff --git a/tests/Type/TestClasses.php b/tests/Type/TestClasses.php deleted file mode 100644 index b9c277c..0000000 --- a/tests/Type/TestClasses.php +++ /dev/null @@ -1,32 +0,0 @@ - [ - 'a' => Type::string() - ] - ]; - parent::__construct($config); - } -} - -// Note: named OtherCustom vs OtherCustomType intentionally -class OtherCustom extends ObjectType -{ - public function __construct() - { - $config = [ - 'fields' => [ - 'b' => Type::string() - ] - ]; - parent::__construct($config); - } -} diff --git a/tests/Type/TestClasses/MyCustomType.php b/tests/Type/TestClasses/MyCustomType.php new file mode 100644 index 0000000..7ad0f5e --- /dev/null +++ b/tests/Type/TestClasses/MyCustomType.php @@ -0,0 +1,21 @@ + [ + 'a' => Type::string(), + ], + ]; + parent::__construct($config); + } +} diff --git a/tests/Type/TestClasses/OtherCustom.php b/tests/Type/TestClasses/OtherCustom.php new file mode 100644 index 0000000..50f4daf --- /dev/null +++ b/tests/Type/TestClasses/OtherCustom.php @@ -0,0 +1,24 @@ + [ + 'b' => Type::string(), + ], + ]; + parent::__construct($config); + } +} diff --git a/tests/Type/TypeLoaderTest.php b/tests/Type/TypeLoaderTest.php index 1893ca7..3024568 100644 --- a/tests/Type/TypeLoaderTest.php +++ b/tests/Type/TypeLoaderTest.php @@ -1,6 +1,8 @@ calls = []; $this->node = new InterfaceType([ - 'name' => 'Node', - 'fields' => function() { + 'name' => 'Node', + 'fields' => function () { $this->calls[] = 'Node.fields'; + return [ - 'id' => Type::string() + 'id' => Type::string(), ]; }, - 'resolveType' => function() {} + 'resolveType' => function () { + }, ]); $this->content = new InterfaceType([ - 'name' => 'Content', - 'fields' => function() { + 'name' => 'Content', + 'fields' => function () { $this->calls[] = 'Content.fields'; + return [ 'title' => Type::string(), - 'body' => Type::string(), + 'body' => Type::string(), ]; }, - 'resolveType' => function() {} + 'resolveType' => function () { + }, ]); $this->blogStory = new ObjectType([ - 'name' => 'BlogStory', + 'name' => 'BlogStory', 'interfaces' => [ $this->node, - $this->content + $this->content, ], - 'fields' => function() { + 'fields' => function () { $this->calls[] = 'BlogStory.fields'; + return [ $this->node->getField('id'), $this->content->getField('title'), @@ -101,53 +91,56 @@ class TypeLoaderTest extends TestCase ]); $this->query = new ObjectType([ - 'name' => 'Query', - 'fields' => function() { + 'name' => 'Query', + 'fields' => function () { $this->calls[] = 'Query.fields'; + return [ 'latestContent' => $this->content, - 'node' => $this->node, + 'node' => $this->node, ]; - } + }, ]); $this->mutation = new ObjectType([ - 'name' => 'Mutation', - 'fields' => function() { + 'name' => 'Mutation', + 'fields' => function () { $this->calls[] = 'Mutation.fields'; + return [ 'postStory' => [ 'type' => $this->postStoryMutation, 'args' => [ - 'input' => Type::nonNull($this->postStoryMutationInput), - 'clientRequestId' => Type::string() - ] - ] + 'input' => Type::nonNull($this->postStoryMutationInput), + 'clientRequestId' => Type::string(), + ], + ], ]; - } + }, ]); $this->postStoryMutation = new ObjectType([ - 'name' => 'PostStoryMutation', + 'name' => 'PostStoryMutation', 'fields' => [ - 'story' => $this->blogStory - ] + 'story' => $this->blogStory, + ], ]); $this->postStoryMutationInput = new InputObjectType([ - 'name' => 'PostStoryMutationInput', + 'name' => 'PostStoryMutationInput', 'fields' => [ - 'title' => Type::string(), - 'body' => Type::string(), - 'author' => Type::id(), - 'category' => Type::id() - ] + 'title' => Type::string(), + 'body' => Type::string(), + 'author' => Type::id(), + 'category' => Type::id(), + ], ]); - $this->typeLoader = function($name) { + $this->typeLoader = function ($name) { $this->calls[] = $name; - $prop = lcfirst($name); - return isset($this->{$prop}) ? $this->{$prop} : null; + $prop = lcfirst($name); + + return $this->{$prop} ?? null; }; } @@ -155,11 +148,12 @@ class TypeLoaderTest extends TestCase { $this->expectNotToPerformAssertions(); new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => ['a' => Type::string()] + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => ['a' => Type::string()], ]), - 'typeLoader' => function() {} + 'typeLoader' => function () { + }, ]); } @@ -169,20 +163,20 @@ class TypeLoaderTest extends TestCase $this->expectExceptionMessage('Schema type loader must be callable if provided but got: []'); new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => ['a' => Type::string()] + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => ['a' => Type::string()], ]), - 'typeLoader' => [] + 'typeLoader' => [], ]); } public function testWorksWithoutTypeLoader() : void { $schema = new Schema([ - 'query' => $this->query, + 'query' => $this->query, 'mutation' => $this->mutation, - 'types' => [$this->blogStory] + 'types' => [$this->blogStory], ]); $expected = [ @@ -203,12 +197,12 @@ class TypeLoaderTest extends TestCase $this->assertSame($this->postStoryMutationInput, $schema->getType('PostStoryMutationInput')); $expectedTypeMap = [ - 'Query' => $this->query, - 'Mutation' => $this->mutation, - 'Node' => $this->node, - 'String' => Type::string(), - 'Content' => $this->content, - 'BlogStory' => $this->blogStory, + 'Query' => $this->query, + 'Mutation' => $this->mutation, + 'Node' => $this->node, + 'String' => Type::string(), + 'Content' => $this->content, + 'BlogStory' => $this->blogStory, 'PostStoryMutationInput' => $this->postStoryMutationInput, ]; @@ -218,9 +212,9 @@ class TypeLoaderTest extends TestCase public function testWorksWithTypeLoader() : void { $schema = new Schema([ - 'query' => $this->query, - 'mutation' => $this->mutation, - 'typeLoader' => $this->typeLoader + 'query' => $this->query, + 'mutation' => $this->mutation, + 'typeLoader' => $this->typeLoader, ]); $this->assertEquals([], $this->calls); @@ -244,8 +238,8 @@ class TypeLoaderTest extends TestCase public function testOnlyCallsLoaderOnce() : void { $schema = new Schema([ - 'query' => $this->query, - 'typeLoader' => $this->typeLoader + 'query' => $this->query, + 'typeLoader' => $this->typeLoader, ]); $schema->getType('Node'); @@ -258,8 +252,9 @@ class TypeLoaderTest extends TestCase public function testFailsOnNonExistentType() : void { $schema = new Schema([ - 'query' => $this->query, - 'typeLoader' => function() {} + 'query' => $this->query, + 'typeLoader' => function () { + }, ]); $this->expectException(InvariantViolation::class); @@ -271,10 +266,10 @@ class TypeLoaderTest extends TestCase public function testFailsOnNonType() : void { $schema = new Schema([ - 'query' => $this->query, - 'typeLoader' => function() { + 'query' => $this->query, + 'typeLoader' => function () { return new \stdClass(); - } + }, ]); $this->expectException(InvariantViolation::class); @@ -286,10 +281,10 @@ class TypeLoaderTest extends TestCase public function testFailsOnInvalidLoad() : void { $schema = new Schema([ - 'query' => $this->query, - 'typeLoader' => function() { + 'query' => $this->query, + 'typeLoader' => function () { return $this->content; - } + }, ]); $this->expectException(InvariantViolation::class); @@ -301,10 +296,10 @@ class TypeLoaderTest extends TestCase public function testPassesThroughAnExceptionInLoader() : void { $schema = new Schema([ - 'query' => $this->query, - 'typeLoader' => function() { - throw new \Exception("This is the exception we are looking for"); - } + 'query' => $this->query, + 'typeLoader' => function () { + throw new \Exception('This is the exception we are looking for'); + }, ]); $this->expectException(\Throwable::class); @@ -316,14 +311,14 @@ class TypeLoaderTest extends TestCase public function testReturnsIdenticalResults() : void { $withoutLoader = new Schema([ - 'query' => $this->query, - 'mutation' => $this->mutation + 'query' => $this->query, + 'mutation' => $this->mutation, ]); $withLoader = new Schema([ - 'query' => $this->query, - 'mutation' => $this->mutation, - 'typeLoader' => $this->typeLoader + 'query' => $this->query, + 'mutation' => $this->mutation, + 'typeLoader' => $this->typeLoader, ]); $this->assertSame($withoutLoader->getQueryType(), $withLoader->getQueryType()); @@ -335,9 +330,9 @@ class TypeLoaderTest extends TestCase public function testSkipsLoaderForInternalTypes() : void { $schema = new Schema([ - 'query' => $this->query, - 'mutation' => $this->mutation, - 'typeLoader' => $this->typeLoader + 'query' => $this->query, + 'mutation' => $this->mutation, + 'typeLoader' => $this->typeLoader, ]); $type = $schema->getType('ID'); diff --git a/tests/Type/ValidationTest.php b/tests/Type/ValidationTest.php index d388bb5..b96f46d 100644 --- a/tests/Type/ValidationTest.php +++ b/tests/Type/ValidationTest.php @@ -1,43 +1,63 @@ Number = 1; $this->SomeScalarType = new CustomScalarType([ - 'name' => 'SomeScalar', - 'serialize' => function() {}, - 'parseValue' => function() {}, - 'parseLiteral' => function() {} + 'name' => 'SomeScalar', + 'serialize' => function () { + }, + 'parseValue' => function () { + }, + 'parseLiteral' => function () { + }, ]); $this->SomeObjectType = new ObjectType([ - 'name' => 'SomeObject', - 'fields' => [ 'f' => [ 'type' => Type::string() ] ], - 'interfaces' => function() {return [$this->SomeInterfaceType];} + 'name' => 'SomeObject', + 'fields' => ['f' => ['type' => Type::string()]], + 'interfaces' => function () { + return [$this->SomeInterfaceType]; + }, ]); + $this->SomeUnionType = new UnionType([ - 'name' => 'SomeUnion', - 'types' => [ $this->SomeObjectType ] + 'name' => 'SomeUnion', + 'types' => [$this->SomeObjectType], ]); $this->SomeInterfaceType = new InterfaceType([ - 'name' => 'SomeInterface', - 'fields' => [ 'f' => ['type' => Type::string() ]] + 'name' => 'SomeInterface', + 'fields' => ['f' => ['type' => Type::string()]], ]); $this->SomeEnumType = new EnumType([ - 'name' => 'SomeEnum', + 'name' => 'SomeEnum', 'values' => [ - 'ONLY' => [] - ] + 'ONLY' => [], + ], ]); $this->SomeInputObjectType = new InputObjectType([ - 'name' => 'SomeInputObject', + 'name' => 'SomeInputObject', 'fields' => [ - 'val' => [ 'type' => Type::string(), 'defaultValue' => 'hello' ] - ] + 'val' => ['type' => Type::string(), 'defaultValue' => 'hello'], + ], ]); $this->outputTypes = $this->withModifiers([ @@ -86,11 +112,11 @@ class ValidationTest extends TestCase $this->SomeEnumType, $this->SomeObjectType, $this->SomeUnionType, - $this->SomeInterfaceType + $this->SomeInterfaceType, ]); - $this->notOutputTypes = $this->withModifiers([ - $this->SomeInputObjectType, + $this->notOutputTypes = $this->withModifiers([ + $this->SomeInputObjectType, ]); $this->notOutputTypes[] = $this->Number; @@ -112,61 +138,75 @@ class ValidationTest extends TestCase Warning::suppress(Warning::WARNING_NOT_A_TYPE); } + private function withModifiers($types) + { + return array_merge( + $types, + Utils::map( + $types, + function ($type) { + return Type::listOf($type); + } + ), + Utils::map( + $types, + function ($type) { + return Type::nonNull($type); + } + ), + Utils::map( + $types, + function ($type) { + return Type::nonNull(Type::listOf($type)); + } + ) + ); + } + public function tearDown() { parent::tearDown(); Warning::enable(Warning::WARNING_NOT_A_TYPE); } - /** - * @param InvariantViolation[]|Error[] $array - * @param array $messages - */ - private function assertContainsValidationMessage($array, $messages) { - $this->assertCount( - count($messages), - $array, - 'For messages: ' . $messages[0]['message'] . "\n" . - "Received: \n" . join("\n", array_map(function($error) { return $error->getMessage(); }, $array)) - ); - foreach ($array as $index => $error) { - if(!isset($messages[$index]) || !$error instanceof Error) { - $this->fail('Received unexpected error: ' . $error->getMessage()); - } - $this->assertEquals($messages[$index]['message'], $error->getMessage()); - $errorLocations = []; - foreach ($error->getLocations() as $location) { - $errorLocations[] = $location->toArray(); - } - $this->assertEquals( - isset($messages[$index]['locations']) ? $messages[$index]['locations'] : [], - $errorLocations - ); - } - } - public function testRejectsTypesWithoutNames() : void { - $this->assertEachCallableThrows([ - function() { - return new ObjectType([]); - }, - function() { - return new EnumType([]); - }, - function() { - return new InputObjectType([]); - }, - function() { - return new UnionType([]); - }, - function() { - return new InterfaceType([]); - } - ], 'Must provide name.'); + $this->assertEachCallableThrows( + [ + function () { + return new ObjectType([]); + }, + function () { + return new EnumType([]); + }, + function () { + return new InputObjectType([]); + }, + function () { + return new UnionType([]); + }, + function () { + return new InterfaceType([]); + }, + ], + 'Must provide name.' + ); } - // DESCRIBE: Type System: A Schema must have Object root types + /** + * DESCRIBE: Type System: A Schema must have Object root types + */ + private function assertEachCallableThrows($closures, $expectedError) + { + foreach ($closures as $index => $factory) { + try { + $factory(); + $this->fail('Expected exception not thrown for entry ' . $index); + } catch (InvariantViolation $e) { + $this->assertEquals($expectedError, $e->getMessage(), 'Error in callable #' . $index); + } + } + } /** * @see it('accepts a Schema whose query type is an object type') @@ -273,7 +313,6 @@ class ValidationTest extends TestCase [['message' => 'Query root type must be provided.']] ); - $schemaWithDef = BuildSchema::build(' schema { mutation: MutationRoot @@ -287,12 +326,50 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schemaWithDef->validate(), [[ - 'message' => 'Query root type must be provided.', + 'message' => 'Query root type must be provided.', 'locations' => [['line' => 2, 'column' => 7]], - ]] + ], + ] ); } + /** + * @param InvariantViolation[]|Error[] $array + * @param string[][] $messages + */ + private function assertContainsValidationMessage($array, $messages) + { + $this->assertCount( + count($messages), + $array, + sprintf('For messages: %s', $messages[0]['message']) . "\n" . + "Received: \n" . + implode( + "\n", + array_map( + function ($error) { + return $error->getMessage(); + }, + $array + ) + ) + ); + foreach ($array as $index => $error) { + if (! isset($messages[$index]) || ! $error instanceof Error) { + $this->fail('Received unexpected error: ' . $error->getMessage()); + } + $this->assertEquals($messages[$index]['message'], $error->getMessage()); + $errorLocations = []; + foreach ($error->getLocations() as $location) { + $errorLocations[] = $location->toArray(); + } + $this->assertEquals( + $messages[$index]['locations'] ?? [], + $errorLocations + ); + } + } + /** * @see it('rejects a Schema whose query root type is not an Object type') */ @@ -307,12 +384,12 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Query root type must be Object type, it cannot be Query.', + 'message' => 'Query root type must be Object type, it cannot be Query.', 'locations' => [['line' => 2, 'column' => 7]], - ]] + ], + ] ); - $schemaWithDef = BuildSchema::build(' schema { query: SomeInputObject @@ -326,9 +403,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schemaWithDef->validate(), [[ - 'message' => 'Query root type must be Object type, it cannot be SomeInputObject.', + 'message' => 'Query root type must be Object type, it cannot be SomeInputObject.', 'locations' => [['line' => 3, 'column' => 16]], - ]] + ], + ] ); } @@ -350,9 +428,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Mutation root type must be Object type if provided, it cannot be Mutation.', + 'message' => 'Mutation root type must be Object type if provided, it cannot be Mutation.', 'locations' => [['line' => 6, 'column' => 7]], - ]] + ], + ] ); $schemaWithDef = BuildSchema::build(' @@ -373,12 +452,15 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schemaWithDef->validate(), [[ - 'message' => 'Mutation root type must be Object type if provided, it cannot be SomeInputObject.', + 'message' => 'Mutation root type must be Object type if provided, it cannot be SomeInputObject.', 'locations' => [['line' => 4, 'column' => 19]], - ]] + ], + ] ); } + // DESCRIBE: Type System: Objects must have fields + /** * @see it('rejects a Schema whose subscription type is an input type') */ @@ -397,9 +479,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Subscription root type must be Object type if provided, it cannot be Subscription.', + 'message' => 'Subscription root type must be Object type if provided, it cannot be Subscription.', 'locations' => [['line' => 6, 'column' => 7]], - ]] + ], + ] ); $schemaWithDef = BuildSchema::build(' @@ -420,12 +503,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schemaWithDef->validate(), [[ - 'message' => 'Subscription root type must be Object type if provided, it cannot be SomeInputObject.', + 'message' => 'Subscription root type must be Object type if provided, it cannot be SomeInputObject.', 'locations' => [['line' => 4, 'column' => 23]], - ]] + ], + ] ); - - } /** @@ -434,8 +516,8 @@ class ValidationTest extends TestCase public function testRejectsASchemaWhoseDirectivesAreIncorrectlyTyped() : void { $schema = new Schema([ - 'query' => $this->SomeObjectType, - 'directives' => ['somedirective'] + 'query' => $this->SomeObjectType, + 'directives' => ['somedirective'], ]); $this->assertContainsValidationMessage( @@ -444,8 +526,6 @@ class ValidationTest extends TestCase ); } - // DESCRIBE: Type System: Objects must have fields - /** * @see it('accepts an Object type with fields object') */ @@ -480,14 +560,15 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Type IncompleteObject must define one or more fields.', + 'message' => 'Type IncompleteObject must define one or more fields.', 'locations' => [['line' => 6, 'column' => 7]], - ]] + ], + ] ); $manualSchema = $this->schemaWithFieldType( new ObjectType([ - 'name' => 'IncompleteObject', + 'name' => 'IncompleteObject', 'fields' => [], ]) ); @@ -499,8 +580,10 @@ class ValidationTest extends TestCase $manualSchema2 = $this->schemaWithFieldType( new ObjectType([ - 'name' => 'IncompleteObject', - 'fields' => function () { return []; }, + 'name' => 'IncompleteObject', + 'fields' => function () { + return []; + }, ]) ); @@ -510,6 +593,20 @@ class ValidationTest extends TestCase ); } + /** + * DESCRIBE: Type System: Fields args must be properly named + */ + private function schemaWithFieldType($type) : Schema + { + return new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => ['f' => ['type' => $type]], + ]), + 'types' => [$type], + ]); + } + /** * @see it('rejects an Object type with incorrectly named fields') */ @@ -517,9 +614,9 @@ class ValidationTest extends TestCase { $schema = $this->schemaWithFieldType( new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => [ - 'bad-name-with-dashes' => ['type' => Type::string()] + 'bad-name-with-dashes' => ['type' => Type::string()], ], ]) ); @@ -528,42 +625,44 @@ class ValidationTest extends TestCase $schema->validate(), [[ 'message' => 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but ' . - '"bad-name-with-dashes" does not.', - ]] + '"bad-name-with-dashes" does not.', + ], + ] ); } + /** + * DESCRIBE: Type System: Union types must be valid + */ public function testAcceptsShorthandNotationForFields() : void { $this->expectNotToPerformAssertions(); $schema = $this->schemaWithFieldType( new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => [ - 'field' => Type::string() - ] + 'field' => Type::string(), + ], ]) ); $schema->assertValid(); } - // DESCRIBE: Type System: Fields args must be properly named - /** * @see it('accepts field args with valid names') */ public function testAcceptsFieldArgsWithValidNames() : void { $schema = $this->schemaWithFieldType(new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => [ 'goodField' => [ 'type' => Type::string(), 'args' => [ - 'goodArg' => ['type' => Type::string()] - ] - ] - ] + 'goodArg' => ['type' => Type::string()], + ], + ], + ], ])); $this->assertEquals([], $schema->validate()); } @@ -574,17 +673,17 @@ class ValidationTest extends TestCase public function testRejectsFieldArgWithInvalidNames() : void { $QueryType = new ObjectType([ - 'name' => 'SomeObject', + 'name' => 'SomeObject', 'fields' => [ 'badField' => [ 'type' => Type::string(), 'args' => [ - 'bad-name-with-dashes' => ['type' => Type::string()] - ] - ] - ] + 'bad-name-with-dashes' => ['type' => Type::string()], + ], + ], + ], ]); - $schema = new Schema(['query' => $QueryType]); + $schema = new Schema(['query' => $QueryType]); $this->assertContainsValidationMessage( $schema->validate(), @@ -592,8 +691,6 @@ class ValidationTest extends TestCase ); } - // DESCRIBE: Type System: Union types must be valid - /** * @see it('accepts a Union type with member types') */ @@ -620,6 +717,8 @@ class ValidationTest extends TestCase $this->assertEquals([], $schema->validate()); } + // DESCRIBE: Type System: Input Objects must have fields + /** * @see it('rejects a Union type with empty types') */ @@ -635,9 +734,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Union type BadUnion must define one or more member types.', + 'message' => 'Union type BadUnion must define one or more member types.', 'locations' => [['line' => 6, 'column' => 7]], - ]] + ], + ] ); } @@ -667,9 +767,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Union type BadUnion can only include type TypeA once.', + 'message' => 'Union type BadUnion can only include type TypeA once.', 'locations' => [['line' => 15, 'column' => 11], ['line' => 17, 'column' => 11]], - ]] + ], + ] ); } @@ -699,11 +800,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Union type BadUnion can only include Object types, ' . - 'it cannot include String.', + 'message' => 'Union type BadUnion can only include Object types, ' . + 'it cannot include String.', 'locations' => [['line' => 16, 'column' => 11]], - ]] - + ], + ] ); $badUnionMemberTypes = [ @@ -716,7 +817,7 @@ class ValidationTest extends TestCase $this->SomeInputObjectType, ]; - foreach($badUnionMemberTypes as $memberType) { + foreach ($badUnionMemberTypes as $memberType) { $badSchema = $this->schemaWithFieldType( new UnionType(['name' => 'BadUnion', 'types' => [$memberType]]) ); @@ -724,13 +825,14 @@ class ValidationTest extends TestCase $badSchema->validate(), [[ 'message' => 'Union type BadUnion can only include Object types, ' . - "it cannot include ". Utils::printSafe($memberType) . ".", - ]] + 'it cannot include ' . Utils::printSafe($memberType) . '.', + ], + ] ); } } - // DESCRIBE: Type System: Input Objects must have fields + // DESCRIBE: Type System: Enum types must be well defined /** * @see it('accepts an Input Object type with fields') @@ -764,9 +866,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Input Object type SomeInputObject must define one or more fields.', + 'message' => 'Input Object type SomeInputObject must define one or more fields.', 'locations' => [['line' => 6, 'column' => 7]], - ]] + ], + ] ); } @@ -794,18 +897,19 @@ class ValidationTest extends TestCase '); $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => 'The type of SomeInputObject.badObject must be Input Type but got: SomeObject.', - 'locations' => [['line' => 13, 'column' => 20]], - ],[ - 'message' => 'The type of SomeInputObject.badUnion must be Input Type but got: SomeUnion.', - 'locations' => [['line' => 14, 'column' => 19]], - ]] + [ + [ + 'message' => 'The type of SomeInputObject.badObject must be Input Type but got: SomeObject.', + 'locations' => [['line' => 13, 'column' => 20]], + ], + [ + 'message' => 'The type of SomeInputObject.badUnion must be Input Type but got: SomeUnion.', + 'locations' => [['line' => 14, 'column' => 19]], + ], + ] ); } - // DESCRIBE: Type System: Enum types must be well defined - /** * @see it('rejects an Enum type without values') */ @@ -821,9 +925,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Enum type SomeEnum must define one or more values.', + 'message' => 'Enum type SomeEnum must define one or more values.', 'locations' => [['line' => 6, 'column' => 7]], - ]] + ], + ] ); } @@ -845,38 +950,32 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Enum type SomeEnum can include value SOME_VALUE only once.', + 'message' => 'Enum type SomeEnum can include value SOME_VALUE only once.', 'locations' => [['line' => 7, 'column' => 9], ['line' => 8, 'column' => 9]], - ]] + ], + ] ); } public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnEnum() : void { $enum = new EnumType([ - 'name' => 'SomeEnum', + 'name' => 'SomeEnum', 'values' => [ - 'value' => ['isDeprecated' => true] - ] + 'value' => ['isDeprecated' => true], + ], ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage('SomeEnum.value should provide "deprecationReason" instead of "isDeprecated".'); $enum->assertValid(); } - private function schemaWithEnum($name) - { - return $this->schemaWithFieldType( - new EnumType([ - 'name' => 'SomeEnum', - 'values' => [ - $name => [] - ] - ]) - ); - } - - public function invalidEnumValueName() + /** + * DESCRIBE: Type System: Object fields must have output types + * + * @return string[][] + */ + public function invalidEnumValueName() : array { return [ ['#value', 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "#value" does not.'], @@ -889,7 +988,7 @@ class ValidationTest extends TestCase } /** - * @see it('rejects an Enum type with incorrectly named values') + * @see it('rejects an Enum type with incorrectly named values') * @dataProvider invalidEnumValueName */ public function testRejectsAnEnumTypeWithIncorrectlyNamedValues($name, $expectedMessage) : void @@ -898,13 +997,22 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => $expectedMessage, - ]] + [['message' => $expectedMessage], + ] ); } - // DESCRIBE: Type System: Object fields must have output types + private function schemaWithEnum($name) + { + return $this->schemaWithFieldType( + new EnumType([ + 'name' => 'SomeEnum', + 'values' => [ + $name => [], + ], + ]) + ); + } /** * @see it('accepts an output type as an Object field type') @@ -917,6 +1025,29 @@ class ValidationTest extends TestCase } } + /** + * DESCRIBE: Type System: Objects can only implement unique interfaces + */ + private function schemaWithObjectFieldOfType($fieldType) : Schema + { + $BadObjectType = new ObjectType([ + 'name' => 'BadObject', + 'fields' => [ + 'badField' => ['type' => $fieldType], + ], + ]); + + return new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'f' => ['type' => $BadObjectType], + ], + ]), + 'types' => [$this->SomeObjectType], + ]); + } + /** * @see it('rejects an empty Object field type') */ @@ -926,9 +1057,8 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => 'The type of BadObject.badField must be Output Type but got: null.', - ]] + [['message' => 'The type of BadObject.badField must be Output Type but got: null.'], + ] ); } @@ -944,7 +1074,8 @@ class ValidationTest extends TestCase $schema->validate(), [[ 'message' => 'The type of BadObject.badField must be Output Type but got: ' . Utils::printSafe($type) . '.', - ]] + ], + ] ); } } @@ -966,29 +1097,28 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'The type of Query.field must be Output Type but got: [SomeInputObject].', + 'message' => 'The type of Query.field must be Output Type but got: [SomeInputObject].', 'locations' => [['line' => 3, 'column' => 16]], - ]] + ], + ] ); } - // DESCRIBE: Type System: Objects can only implement unique interfaces + // DESCRIBE: Type System: Interface fields must have output types /** * @see it('rejects an Object implementing a non-type values') */ public function testRejectsAnObjectImplementingANonTypeValues() : void { - $schema = new Schema([ + $schema = new Schema([ 'query' => new ObjectType([ - 'name' => 'BadObject', + 'name' => 'BadObject', 'interfaces' => [null], - 'fields' => ['a' => Type::string()] + 'fields' => ['a' => Type::string()], ]), ]); - $expected = [ - 'message' => 'Type BadObject must only implement Interface types, it cannot implement null.' - ]; + $expected = ['message' => 'Type BadObject must only implement Interface types, it cannot implement null.']; $this->assertContainsValidationMessage( $schema->validate(), @@ -1017,9 +1147,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Type BadObject must only implement Interface types, it cannot implement SomeInputObject.', + 'message' => 'Type BadObject must only implement Interface types, it cannot implement SomeInputObject.', 'locations' => [['line' => 10, 'column' => 33]], - ]] + ], + ] ); } @@ -1044,9 +1175,10 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Type AnotherObject can only implement AnotherInterface once.', + 'message' => 'Type AnotherObject can only implement AnotherInterface once.', 'locations' => [['line' => 10, 'column' => 37], ['line' => 10, 'column' => 56]], - ]] + ], + ] ); } @@ -1075,13 +1207,14 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Type AnotherObject can only implement AnotherInterface once.', + 'message' => 'Type AnotherObject can only implement AnotherInterface once.', 'locations' => [['line' => 10, 'column' => 37], ['line' => 14, 'column' => 38]], - ]] + ], + ] ); } - // DESCRIBE: Type System: Interface fields must have output types + // DESCRIBE: Type System: Field arguments must have input types /** * @see it('accepts an output type as an Interface field type') @@ -1094,6 +1227,25 @@ class ValidationTest extends TestCase } } + private function schemaWithInterfaceFieldOfType($fieldType) + { + $BadInterfaceType = new InterfaceType([ + 'name' => 'BadInterface', + 'fields' => [ + 'badField' => ['type' => $fieldType], + ], + ]); + + return new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'f' => ['type' => $BadInterfaceType], + ], + ]), + ]); + } + /** * @see it('rejects an empty Interface field type') */ @@ -1102,9 +1254,8 @@ class ValidationTest extends TestCase $schema = $this->schemaWithInterfaceFieldOfType(null); $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => 'The type of BadInterface.badField must be Output Type but got: null.', - ]] + [['message' => 'The type of BadInterface.badField must be Output Type but got: null.'], + ] ); } @@ -1120,11 +1271,14 @@ class ValidationTest extends TestCase $schema->validate(), [[ 'message' => 'The type of BadInterface.badField must be Output Type but got: ' . Utils::printSafe($type) . '.', - ]] + ], + ] ); } } + // DESCRIBE: Type System: Input Object fields must have input types + /** * @see it('rejects a non-output type as an Interface field type with locations') */ @@ -1146,14 +1300,13 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'The type of SomeInterface.field must be Output Type but got: SomeInputObject.', + 'message' => 'The type of SomeInterface.field must be Output Type but got: SomeInputObject.', 'locations' => [['line' => 7, 'column' => 16]], - ]] + ], + ] ); } - // DESCRIBE: Type System: Field arguments must have input types - /** * @see it('accepts an input type as a field arg type') */ @@ -1165,6 +1318,30 @@ class ValidationTest extends TestCase } } + private function schemaWithArgOfType($argType) + { + $BadObjectType = new ObjectType([ + 'name' => 'BadObject', + 'fields' => [ + 'badField' => [ + 'type' => Type::string(), + 'args' => [ + 'badArg' => ['type' => $argType], + ], + ], + ], + ]); + + return new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'f' => ['type' => $BadObjectType], + ], + ]), + ]); + } + /** * @see it('rejects an empty field arg type') */ @@ -1173,12 +1350,13 @@ class ValidationTest extends TestCase $schema = $this->schemaWithArgOfType(null); $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => 'The type of BadObject.badField(badArg:) must be Input Type but got: null.', - ]] + [['message' => 'The type of BadObject.badField(badArg:) must be Input Type but got: null.'], + ] ); } + // DESCRIBE: Objects must adhere to Interface they implement + /** * @see it('rejects a non-input type as a field arg type') */ @@ -1190,7 +1368,8 @@ class ValidationTest extends TestCase $schema->validate(), [[ 'message' => 'The type of BadObject.badField(badArg:) must be Input Type but got: ' . Utils::printSafe($type) . '.', - ]] + ], + ] ); } } @@ -1212,14 +1391,13 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'The type of Query.test(arg:) must be Input Type but got: SomeObject.', + 'message' => 'The type of Query.test(arg:) must be Input Type but got: SomeObject.', 'locations' => [['line' => 3, 'column' => 19]], - ]] + ], + ] ); } - // DESCRIBE: Type System: Input Object fields must have input types - /** * @see it('accepts an input type as an input field type') */ @@ -1231,6 +1409,30 @@ class ValidationTest extends TestCase } } + private function schemaWithInputFieldOfType($inputFieldType) + { + $BadInputObjectType = new InputObjectType([ + 'name' => 'BadInputObject', + 'fields' => [ + 'badField' => ['type' => $inputFieldType], + ], + ]); + + return new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'f' => [ + 'type' => Type::string(), + 'args' => [ + 'badArg' => ['type' => $BadInputObjectType], + ], + ], + ], + ]), + ]); + } + /** * @see it('rejects an empty input field type') */ @@ -1239,9 +1441,8 @@ class ValidationTest extends TestCase $schema = $this->schemaWithInputFieldOfType(null); $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => 'The type of BadInputObject.badField must be Input Type but got: null.', - ]] + [['message' => 'The type of BadInputObject.badField must be Input Type but got: null.'], + ] ); } @@ -1256,7 +1457,8 @@ class ValidationTest extends TestCase $schema->validate(), [[ 'message' => 'The type of BadInputObject.badField must be Input Type but got: ' . Utils::printSafe($type) . '.', - ]] + ], + ] ); } } @@ -1282,14 +1484,13 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'The type of SomeInputObject.foo must be Input Type but got: SomeObject.', + 'message' => 'The type of SomeInputObject.foo must be Input Type but got: SomeObject.', 'locations' => [['line' => 7, 'column' => 14]], - ]] + ], + ] ); } - // DESCRIBE: Objects must adhere to Interface they implement - /** * @see it('accepts an Object which implements an Interface') */ @@ -1335,10 +1536,10 @@ class ValidationTest extends TestCase } '); - $this->assertEquals( - [], - $schema->validate() - ); + $this->assertEquals( + [], + $schema->validate() + ); } /** @@ -1388,10 +1589,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field AnotherInterface.field expected but ' . - 'AnotherObject does not provide it.', + 'message' => 'Interface field AnotherInterface.field expected but ' . + 'AnotherObject does not provide it.', 'locations' => [['line' => 7, 'column' => 9], ['line' => 10, 'column' => 7]], - ]] + ], + ] ); } @@ -1417,10 +1619,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field AnotherInterface.field expects type String but ' . + 'message' => 'Interface field AnotherInterface.field expects type String but ' . 'AnotherObject.field is type Int.', 'locations' => [['line' => 7, 'column' => 31], ['line' => 11, 'column' => 31]], - ]] + ], + ] ); } @@ -1449,10 +1652,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field AnotherInterface.field expects type A but ' . + 'message' => 'Interface field AnotherInterface.field expects type A but ' . 'AnotherObject.field is type B.', 'locations' => [['line' => 10, 'column' => 16], ['line' => 14, 'column' => 16]], - ]] + ], + ] ); } @@ -1503,7 +1707,7 @@ class ValidationTest extends TestCase } '); - $this->assertEquals([],$schema->validate()); + $this->assertEquals([], $schema->validate()); } /** @@ -1528,10 +1732,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field argument AnotherInterface.field(input:) expected ' . - 'but AnotherObject.field does not provide it.', + 'message' => 'Interface field argument AnotherInterface.field(input:) expected ' . + 'but AnotherObject.field does not provide it.', 'locations' => [['line' => 7, 'column' => 15], ['line' => 11, 'column' => 9]], - ]] + ], + ] ); } @@ -1557,10 +1762,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field argument AnotherInterface.field(input:) expects ' . - 'type String but AnotherObject.field(input:) is type Int.', + 'message' => 'Interface field argument AnotherInterface.field(input:) expects ' . + 'type String but AnotherObject.field(input:) is type Int.', 'locations' => [['line' => 7, 'column' => 22], ['line' => 11, 'column' => 22]], - ]] + ], + ] ); } @@ -1585,15 +1791,18 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), - [[ - 'message' => 'Interface field AnotherInterface.field expects type String but ' . - 'AnotherObject.field is type Int.', - 'locations' => [['line' => 7, 'column' => 31], ['line' => 11, 'column' => 28]], - ], [ - 'message' => 'Interface field argument AnotherInterface.field(input:) expects ' . - 'type String but AnotherObject.field(input:) is type Int.', - 'locations' => [['line' => 7, 'column' => 22], ['line' => 11, 'column' => 22]], - ]] + [ + [ + 'message' => 'Interface field AnotherInterface.field expects type String but ' . + 'AnotherObject.field is type Int.', + 'locations' => [['line' => 7, 'column' => 31], ['line' => 11, 'column' => 28]], + ], + [ + 'message' => 'Interface field argument AnotherInterface.field(input:) expects ' . + 'type String but AnotherObject.field(input:) is type Int.', + 'locations' => [['line' => 7, 'column' => 22], ['line' => 11, 'column' => 22]], + ], + ] ); } @@ -1619,11 +1828,12 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Object field argument AnotherObject.field(anotherInput:) is of ' . - 'required type String! but is not also provided by the Interface ' . - 'field AnotherInterface.field.', + 'message' => 'Object field argument AnotherObject.field(anotherInput:) is of ' . + 'required type String! but is not also provided by the Interface ' . + 'field AnotherInterface.field.', 'locations' => [['line' => 11, 'column' => 44], ['line' => 7, 'column' => 9]], - ]] + ], + ] ); } @@ -1671,10 +1881,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field AnotherInterface.field expects type [String] ' . - 'but AnotherObject.field is type String.', + 'message' => 'Interface field AnotherInterface.field expects type [String] ' . + 'but AnotherObject.field is type String.', 'locations' => [['line' => 7, 'column' => 16], ['line' => 11, 'column' => 16]], - ]] + ], + ] ); } @@ -1700,10 +1911,11 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field AnotherInterface.field expects type String but ' . - 'AnotherObject.field is type [String].', + 'message' => 'Interface field AnotherInterface.field expects type String but ' . + 'AnotherObject.field is type [String].', 'locations' => [['line' => 7, 'column' => 16], ['line' => 11, 'column' => 16]], - ]] + ], + ] ); } @@ -1751,24 +1963,25 @@ class ValidationTest extends TestCase $this->assertContainsValidationMessage( $schema->validate(), [[ - 'message' => 'Interface field AnotherInterface.field expects type String! ' . - 'but AnotherObject.field is type String.', + 'message' => 'Interface field AnotherInterface.field expects type String! ' . + 'but AnotherObject.field is type String.', 'locations' => [['line' => 7, 'column' => 16], ['line' => 11, 'column' => 16]], - ]] + ], + ] ); } public function testRejectsDifferentInstancesOfTheSameType() : void { // Invalid: always creates new instance vs returning one from registry - $typeLoader = function($name) use (&$typeLoader) { + $typeLoader = function ($name) use (&$typeLoader) { switch ($name) { case 'Query': return new ObjectType([ - 'name' => 'Query', + 'name' => 'Query', 'fields' => [ - 'test' => Type::string() - ] + 'test' => Type::string(), + ], ]); default: return null; @@ -1776,141 +1989,14 @@ class ValidationTest extends TestCase }; $schema = new Schema([ - 'query' => $typeLoader('Query'), - 'typeLoader' => $typeLoader + 'query' => $typeLoader('Query'), + 'typeLoader' => $typeLoader, ]); $this->expectException(InvariantViolation::class); $this->expectExceptionMessage( - 'Type loader returns different instance for Query than field/argument definitions. '. + 'Type loader returns different instance for Query than field/argument definitions. ' . 'Make sure you always return the same instance for the same type name.' ); $schema->assertValid(); } - - - private function assertEachCallableThrows($closures, $expectedError) - { - foreach ($closures as $index => $factory) { - try { - $factory(); - $this->fail('Expected exception not thrown for entry ' . $index); - } catch (InvariantViolation $e) { - $this->assertEquals($expectedError, $e->getMessage(), 'Error in callable #' . $index); - } - } - } - - private function schemaWithFieldType($type) - { - return new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => ['f' => ['type' => $type]] - ]), - 'types' => [$type], - ]); - } - - private function schemaWithObjectFieldOfType($fieldType) - { - $BadObjectType = new ObjectType([ - 'name' => 'BadObject', - 'fields' => [ - 'badField' => ['type' => $fieldType] - ] - ]); - - return new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'f' => ['type' => $BadObjectType] - ] - ]), - 'types' => [$this->SomeObjectType] - ]); - } - - private function withModifiers($types) - { - return array_merge( - $types, - Utils::map($types, function ($type) { - return Type::listOf($type); - }), - Utils::map($types, function ($type) { - return Type::nonNull($type); - }), - Utils::map($types, function ($type) { - return Type::nonNull(Type::listOf($type)); - }) - ); - } - - private function schemaWithInterfaceFieldOfType($fieldType) - { - $BadInterfaceType = new InterfaceType([ - 'name' => 'BadInterface', - 'fields' => [ - 'badField' => ['type' => $fieldType] - ] - ]); - - return new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'f' => ['type' => $BadInterfaceType] - ] - ]), - ]); - } - - private function schemaWithArgOfType($argType) - { - $BadObjectType = new ObjectType([ - 'name' => 'BadObject', - 'fields' => [ - 'badField' => [ - 'type' => Type::string(), - 'args' => [ - 'badArg' => ['type' => $argType] - ] - ] - ] - ]); - - return new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'f' => ['type' => $BadObjectType] - ] - ]) - ]); - } - - private function schemaWithInputFieldOfType($inputFieldType) - { - $BadInputObjectType = new InputObjectType([ - 'name' => 'BadInputObject', - 'fields' => [ - 'badField' => ['type' => $inputFieldType] - ] - ]); - - return new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'f' => [ - 'type' => Type::string(), - 'args' => [ - 'badArg' => ['type' => $BadInputObjectType] - ] - ] - ] - ]) - ]); - } }