mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-29 08:26:02 +03:00
2cbccb87db
ref: graphql/graphql-js#1000 BREAKING CHANGE: SchemaBuilder::build() and buildAST() and constructor removed the typedecorator, as not needed anymore as library can now resolve union and interfaces from generated schemas.
1176 lines
24 KiB
PHP
1176 lines
24 KiB
PHP
<?php
|
|
namespace GraphQL\Tests\Utils;
|
|
|
|
use GraphQL\GraphQL;
|
|
use GraphQL\Language\AST\EnumTypeDefinitionNode;
|
|
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
|
|
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
|
|
use GraphQL\Language\Parser;
|
|
use GraphQL\Language\Printer;
|
|
use GraphQL\Type\Definition\EnumType;
|
|
use GraphQL\Type\Definition\ObjectType;
|
|
use GraphQL\Utils\BuildSchema;
|
|
use GraphQL\Utils\SchemaPrinter;
|
|
use GraphQL\Type\Definition\Directive;
|
|
|
|
class BuildSchemaTest extends \PHPUnit_Framework_TestCase
|
|
{
|
|
// Describe: Schema Builder
|
|
|
|
private function cycleOutput($body, $options = [])
|
|
{
|
|
$ast = Parser::parse($body);
|
|
$schema = BuildSchema::buildAST($ast, $options);
|
|
return "\n" . SchemaPrinter::doPrint($schema, $options);
|
|
}
|
|
|
|
/**
|
|
* @it can use built schema for limited execution
|
|
*/
|
|
public function testUseBuiltSchemaForLimitedExecution()
|
|
{
|
|
$schema = BuildSchema::buildAST(Parser::parse('
|
|
schema { query: Query }
|
|
type Query {
|
|
str: String
|
|
}
|
|
'));
|
|
|
|
$result = GraphQL::executeQuery($schema, '{ str }', ['str' => 123]);
|
|
$this->assertEquals(['str' => 123], $result->toArray(true)['data']);
|
|
}
|
|
|
|
/**
|
|
* @it can build a schema directly from the source
|
|
*/
|
|
public function testBuildSchemaDirectlyFromSource()
|
|
{
|
|
$schema = BuildSchema::build("
|
|
schema { query: Query }
|
|
type Query {
|
|
add(x: Int, y: Int): Int
|
|
}
|
|
");
|
|
|
|
$result = GraphQL::executeQuery(
|
|
$schema,
|
|
'{ add(x: 34, y: 55) }',
|
|
[
|
|
'add' => function ($root, $args) {
|
|
return $args['x'] + $args['y'];
|
|
}
|
|
]
|
|
);
|
|
$this->assertEquals(['data' => ['add' => 89]], $result->toArray(true));
|
|
}
|
|
|
|
/**
|
|
* @it Simple Type
|
|
*/
|
|
public function testSimpleType()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: HelloScalars
|
|
}
|
|
|
|
type HelloScalars {
|
|
str: String
|
|
int: Int
|
|
float: Float
|
|
id: ID
|
|
bool: Boolean
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it With directives
|
|
*/
|
|
public function testWithDirectives()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
directive @foo(arg: Int) on FIELD
|
|
|
|
type Hello {
|
|
str: String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Supports descriptions
|
|
*/
|
|
public function testSupportsDescriptions()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
"""This is a directive"""
|
|
directive @foo(
|
|
"""It has an argument"""
|
|
arg: Int
|
|
) on FIELD
|
|
|
|
"""With an enum"""
|
|
enum Color {
|
|
RED
|
|
|
|
"""Not a creative color"""
|
|
GREEN
|
|
BLUE
|
|
}
|
|
|
|
"""What a great type"""
|
|
type Hello {
|
|
"""And a field to boot"""
|
|
str: String
|
|
}
|
|
';
|
|
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($body, $output);
|
|
}
|
|
|
|
/**
|
|
* @it Supports descriptions
|
|
*/
|
|
public function testSupportsOptionForCommentDescriptions()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
# This is a directive
|
|
directive @foo(
|
|
# It has an argument
|
|
arg: Int
|
|
) on FIELD
|
|
|
|
# With an enum
|
|
enum Color {
|
|
RED
|
|
|
|
# Not a creative color
|
|
GREEN
|
|
BLUE
|
|
}
|
|
|
|
# What a great type
|
|
type Hello {
|
|
# And a field to boot
|
|
str: String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body, [ 'commentDescriptions' => true ]);
|
|
$this->assertEquals($body, $output);
|
|
}
|
|
|
|
/**
|
|
* @it Maintains @skip & @include
|
|
*/
|
|
public function testMaintainsSkipAndInclude()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello {
|
|
str: String
|
|
}
|
|
';
|
|
$schema = BuildSchema::buildAST(Parser::parse($body));
|
|
$this->assertEquals(count($schema->getDirectives()), 3);
|
|
$this->assertEquals($schema->getDirective('skip'), Directive::skipDirective());
|
|
$this->assertEquals($schema->getDirective('include'), Directive::includeDirective());
|
|
$this->assertEquals($schema->getDirective('deprecated'), Directive::deprecatedDirective());
|
|
}
|
|
|
|
/**
|
|
* @it Overriding directives excludes specified
|
|
*/
|
|
public function testOverridingDirectivesExcludesSpecified()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
directive @skip on FIELD
|
|
directive @include on FIELD
|
|
directive @deprecated on FIELD_DEFINITION
|
|
|
|
type Hello {
|
|
str: String
|
|
}
|
|
';
|
|
$schema = BuildSchema::buildAST(Parser::parse($body));
|
|
$this->assertEquals(count($schema->getDirectives()), 3);
|
|
$this->assertNotEquals($schema->getDirective('skip'), Directive::skipDirective());
|
|
$this->assertNotEquals($schema->getDirective('include'), Directive::includeDirective());
|
|
$this->assertNotEquals($schema->getDirective('deprecated'), Directive::deprecatedDirective());
|
|
}
|
|
|
|
/**
|
|
* @it Type modifiers
|
|
*/
|
|
public function testTypeModifiers()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: HelloScalars
|
|
}
|
|
|
|
type HelloScalars {
|
|
nonNullStr: String!
|
|
listOfStrs: [String]
|
|
listOfNonNullStrs: [String!]
|
|
nonNullListOfStrs: [String]!
|
|
nonNullListOfNonNullStrs: [String!]!
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Recursive type
|
|
*/
|
|
public function testRecursiveType()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Recurse
|
|
}
|
|
|
|
type Recurse {
|
|
str: String
|
|
recurse: Recurse
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Two types circular
|
|
*/
|
|
public function testTwoTypesCircular()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: TypeOne
|
|
}
|
|
|
|
type TypeOne {
|
|
str: String
|
|
typeTwo: TypeTwo
|
|
}
|
|
|
|
type TypeTwo {
|
|
str: String
|
|
typeOne: TypeOne
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Single argument field
|
|
*/
|
|
public function testSingleArgumentField()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello {
|
|
str(int: Int): String
|
|
floatToStr(float: Float): String
|
|
idToStr(id: ID): String
|
|
booleanToStr(bool: Boolean): String
|
|
strToStr(bool: String): String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple type with multiple arguments
|
|
*/
|
|
public function testSimpleTypeWithMultipleArguments()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello {
|
|
str(int: Int, bool: Boolean): String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple type with interface
|
|
*/
|
|
public function testSimpleTypeWithInterface()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello implements WorldInterface {
|
|
str: String
|
|
}
|
|
|
|
interface WorldInterface {
|
|
str: String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple output enum
|
|
*/
|
|
public function testSimpleOutputEnum()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: OutputEnumRoot
|
|
}
|
|
|
|
enum Hello {
|
|
WORLD
|
|
}
|
|
|
|
type OutputEnumRoot {
|
|
hello: Hello
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Multiple value enum
|
|
*/
|
|
public function testMultipleValueEnum()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: OutputEnumRoot
|
|
}
|
|
|
|
enum Hello {
|
|
WO
|
|
RLD
|
|
}
|
|
|
|
type OutputEnumRoot {
|
|
hello: Hello
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple Union
|
|
*/
|
|
public function testSimpleUnion()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Root
|
|
}
|
|
|
|
union Hello = World
|
|
|
|
type Root {
|
|
hello: Hello
|
|
}
|
|
|
|
type World {
|
|
str: String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Multiple Union
|
|
*/
|
|
public function testMultipleUnion()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Root
|
|
}
|
|
|
|
union Hello = WorldOne | WorldTwo
|
|
|
|
type Root {
|
|
hello: Hello
|
|
}
|
|
|
|
type WorldOne {
|
|
str: String
|
|
}
|
|
|
|
type WorldTwo {
|
|
str: String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Specifying Union type using __typename
|
|
*/
|
|
public function testSpecifyingUnionTypeUsingTypename()
|
|
{
|
|
$schema = BuildSchema::buildAST(Parser::parse('
|
|
schema {
|
|
query: Root
|
|
}
|
|
|
|
type Root {
|
|
fruits: [Fruit]
|
|
}
|
|
|
|
union Fruit = Apple | Banana
|
|
|
|
type Apple {
|
|
color: String
|
|
}
|
|
|
|
type Banana {
|
|
length: Int
|
|
}
|
|
'));
|
|
$query = '
|
|
{
|
|
fruits {
|
|
... on Apple {
|
|
color
|
|
}
|
|
... on Banana {
|
|
length
|
|
}
|
|
}
|
|
}
|
|
';
|
|
$root = [
|
|
'fruits' => [
|
|
[
|
|
'color' => 'green',
|
|
'__typename' => 'Apple',
|
|
],
|
|
[
|
|
'length' => 5,
|
|
'__typename' => 'Banana',
|
|
]
|
|
]
|
|
];
|
|
$expected = [
|
|
'data' => [
|
|
'fruits' => [
|
|
['color' => 'green'],
|
|
['length' => 5],
|
|
]
|
|
]
|
|
];
|
|
|
|
$result = GraphQL::executeQuery($schema, $query, $root);
|
|
$this->assertEquals($expected, $result->toArray(true));
|
|
}
|
|
|
|
/**
|
|
* @it Specifying Interface type using __typename
|
|
*/
|
|
public function testSpecifyingInterfaceUsingTypename()
|
|
{
|
|
$schema = BuildSchema::buildAST(Parser::parse('
|
|
schema {
|
|
query: Root
|
|
}
|
|
|
|
type Root {
|
|
characters: [Character]
|
|
}
|
|
|
|
interface Character {
|
|
name: String!
|
|
}
|
|
|
|
type Human implements Character {
|
|
name: String!
|
|
totalCredits: Int
|
|
}
|
|
|
|
type Droid implements Character {
|
|
name: String!
|
|
primaryFunction: String
|
|
}
|
|
'));
|
|
$query = '
|
|
{
|
|
characters {
|
|
name
|
|
... on Human {
|
|
totalCredits
|
|
}
|
|
... on Droid {
|
|
primaryFunction
|
|
}
|
|
}
|
|
}
|
|
';
|
|
$root = [
|
|
'characters' => [
|
|
[
|
|
'name' => 'Han Solo',
|
|
'totalCredits' => 10,
|
|
'__typename' => 'Human',
|
|
],
|
|
[
|
|
'name' => 'R2-D2',
|
|
'primaryFunction' => 'Astromech',
|
|
'__typename' => 'Droid',
|
|
]
|
|
]
|
|
];
|
|
$expected = [
|
|
'data' => [
|
|
'characters' => [
|
|
['name' => 'Han Solo', 'totalCredits' => 10],
|
|
['name' => 'R2-D2', 'primaryFunction' => 'Astromech'],
|
|
]
|
|
]
|
|
];
|
|
|
|
$result = GraphQL::executeQuery($schema, $query, $root);
|
|
$this->assertEquals($expected, $result->toArray(true));
|
|
}
|
|
|
|
/**
|
|
* @it CustomScalar
|
|
*/
|
|
public function testCustomScalar()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Root
|
|
}
|
|
|
|
scalar CustomScalar
|
|
|
|
type Root {
|
|
customScalar: CustomScalar
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it CustomScalar
|
|
*/
|
|
public function testInputObject()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Root
|
|
}
|
|
|
|
input Input {
|
|
int: Int
|
|
}
|
|
|
|
type Root {
|
|
field(in: Input): String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple argument field with default
|
|
*/
|
|
public function testSimpleArgumentFieldWithDefault()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello {
|
|
str(int: Int = 2): String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Custom scalar argument field with default
|
|
*/
|
|
public function testCustomScalarArgumentFieldWithDefault()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
scalar CustomScalar
|
|
|
|
type Hello {
|
|
str(int: CustomScalar = 2): String
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple type with mutation
|
|
*/
|
|
public function testSimpleTypeWithMutation()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: HelloScalars
|
|
mutation: Mutation
|
|
}
|
|
|
|
type HelloScalars {
|
|
str: String
|
|
int: Int
|
|
bool: Boolean
|
|
}
|
|
|
|
type Mutation {
|
|
addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Simple type with subscription
|
|
*/
|
|
public function testSimpleTypeWithSubscription()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: HelloScalars
|
|
subscription: Subscription
|
|
}
|
|
|
|
type HelloScalars {
|
|
str: String
|
|
int: Int
|
|
bool: Boolean
|
|
}
|
|
|
|
type Subscription {
|
|
subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Unreferenced type implementing referenced interface
|
|
*/
|
|
public function testUnreferencedTypeImplementingReferencedInterface()
|
|
{
|
|
$body = '
|
|
type Concrete implements Iface {
|
|
key: String
|
|
}
|
|
|
|
interface Iface {
|
|
key: String
|
|
}
|
|
|
|
type Query {
|
|
iface: Iface
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Unreferenced type implementing referenced union
|
|
*/
|
|
public function testUnreferencedTypeImplementingReferencedUnion()
|
|
{
|
|
$body = '
|
|
type Concrete {
|
|
key: String
|
|
}
|
|
|
|
type Query {
|
|
union: Union
|
|
}
|
|
|
|
union Union = Concrete
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
}
|
|
|
|
/**
|
|
* @it Supports @deprecated
|
|
*/
|
|
public function testSupportsDeprecated()
|
|
{
|
|
$body = '
|
|
enum MyEnum {
|
|
VALUE
|
|
OLD_VALUE @deprecated
|
|
OTHER_VALUE @deprecated(reason: "Terrible reasons")
|
|
}
|
|
|
|
type Query {
|
|
field1: String @deprecated
|
|
field2: Int @deprecated(reason: "Because I said so")
|
|
enum: MyEnum
|
|
}
|
|
';
|
|
$output = $this->cycleOutput($body);
|
|
$this->assertEquals($output, $body);
|
|
|
|
$ast = Parser::parse($body);
|
|
$schema = BuildSchema::buildAST($ast);
|
|
|
|
/** @var EnumType $myEnum */
|
|
$myEnum = $schema->getType('MyEnum');
|
|
|
|
$value = $myEnum->getValue('VALUE');
|
|
$this->assertFalse($value->isDeprecated());
|
|
|
|
$oldValue = $myEnum->getValue('OLD_VALUE');
|
|
$this->assertTrue($oldValue->isDeprecated());
|
|
$this->assertEquals('No longer supported', $oldValue->deprecationReason);
|
|
|
|
$otherValue = $myEnum->getValue('OTHER_VALUE');
|
|
$this->assertTrue($otherValue->isDeprecated());
|
|
$this->assertEquals('Terrible reasons', $otherValue->deprecationReason);
|
|
|
|
$rootFields = $schema->getType('Query')->getFields();
|
|
$this->assertEquals($rootFields['field1']->isDeprecated(), true);
|
|
$this->assertEquals($rootFields['field1']->deprecationReason, 'No longer supported');
|
|
|
|
$this->assertEquals($rootFields['field2']->isDeprecated(), true);
|
|
$this->assertEquals($rootFields['field2']->deprecationReason, 'Because I said so');
|
|
}
|
|
|
|
/**
|
|
* @it Correctly assign AST nodes
|
|
*/
|
|
public function testCorrectlyAssignASTNodes()
|
|
{
|
|
|
|
$schema = BuildSchema::build('
|
|
schema {
|
|
query: Query
|
|
}
|
|
|
|
type Query {
|
|
testField(testArg: TestInput): TestUnion
|
|
}
|
|
|
|
input TestInput {
|
|
testInputField: TestEnum
|
|
}
|
|
|
|
enum TestEnum {
|
|
TEST_VALUE
|
|
}
|
|
|
|
union TestUnion = TestType
|
|
|
|
interface TestInterface {
|
|
interfaceField: String
|
|
}
|
|
|
|
type TestType implements TestInterface {
|
|
interfaceField: String
|
|
}
|
|
|
|
directive @test(arg: Int) on FIELD
|
|
');
|
|
/** @var ObjectType $query */
|
|
$query = $schema->getType('Query');
|
|
$testInput = $schema->getType('TestInput');
|
|
$testEnum = $schema->getType('TestEnum');
|
|
$testUnion = $schema->getType('TestUnion');
|
|
$testInterface = $schema->getType('TestInterface');
|
|
$testType = $schema->getType('TestType');
|
|
$testDirective = $schema->getDirective('test');
|
|
|
|
$restoredIDL = SchemaPrinter::doPrint(BuildSchema::build(
|
|
Printer::doPrint($schema->getAstNode()) . "\n" .
|
|
Printer::doPrint($query->astNode) . "\n" .
|
|
Printer::doPrint($testInput->astNode) . "\n" .
|
|
Printer::doPrint($testEnum->astNode) . "\n" .
|
|
Printer::doPrint($testUnion->astNode) . "\n" .
|
|
Printer::doPrint($testInterface->astNode) . "\n" .
|
|
Printer::doPrint($testType->astNode) . "\n" .
|
|
Printer::doPrint($testDirective->astNode)
|
|
));
|
|
|
|
$this->assertEquals($restoredIDL, SchemaPrinter::doPrint($schema));
|
|
|
|
$testField = $query->getField('testField');
|
|
$this->assertEquals('testField(testArg: TestInput): TestUnion', Printer::doPrint($testField->astNode));
|
|
$this->assertEquals('testArg: TestInput', Printer::doPrint($testField->args[0]->astNode));
|
|
$this->assertEquals('testInputField: TestEnum', Printer::doPrint($testInput->getField('testInputField')->astNode));
|
|
$this->assertEquals('TEST_VALUE', Printer::doPrint($testEnum->getValue('TEST_VALUE')->astNode));
|
|
$this->assertEquals('interfaceField: String', Printer::doPrint($testInterface->getField('interfaceField')->astNode));
|
|
$this->assertEquals('interfaceField: String', Printer::doPrint($testType->getField('interfaceField')->astNode));
|
|
$this->assertEquals('arg: Int', Printer::doPrint($testDirective->args[0]->astNode));
|
|
}
|
|
|
|
// Describe: Failures
|
|
|
|
/**
|
|
* @it Requires a schema definition or Query type
|
|
*/
|
|
public function testRequiresSchemaDefinitionOrQueryType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Must provide schema definition with query type or a type named Query.');
|
|
$body = '
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Allows only a single schema definition
|
|
*/
|
|
public function testAllowsOnlySingleSchemaDefinition()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Must provide only one schema definition.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Requires a query type
|
|
*/
|
|
public function testRequiresQueryType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Must provide schema definition with query type or a type named Query.');
|
|
$body = '
|
|
schema {
|
|
mutation: Hello
|
|
}
|
|
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Allows only a single query type
|
|
*/
|
|
public function testAllowsOnlySingleQueryType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Must provide only one query type in schema.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
query: Yellow
|
|
}
|
|
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
|
|
type Yellow {
|
|
isColor: Boolean
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Allows only a single mutation type
|
|
*/
|
|
public function testAllowsOnlySingleMutationType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Must provide only one mutation type in schema.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
mutation: Hello
|
|
mutation: Yellow
|
|
}
|
|
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
|
|
type Yellow {
|
|
isColor: Boolean
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Allows only a single subscription type
|
|
*/
|
|
public function testAllowsOnlySingleSubscriptionType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Must provide only one subscription type in schema.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
subscription: Hello
|
|
subscription: Yellow
|
|
}
|
|
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
|
|
type Yellow {
|
|
isColor: Boolean
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Unknown type referenced
|
|
*/
|
|
public function testUnknownTypeReferenced()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Type "Bar" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello {
|
|
bar: Bar
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
$schema = BuildSchema::buildAST($doc);
|
|
$schema->getTypeMap();
|
|
}
|
|
|
|
/**
|
|
* @it Unknown type in interface list
|
|
*/
|
|
public function testUnknownTypeInInterfaceList()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Type "Bar" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
type Hello implements Bar { }
|
|
';
|
|
$doc = Parser::parse($body);
|
|
$schema = BuildSchema::buildAST($doc);
|
|
$schema->getTypeMap();
|
|
}
|
|
|
|
/**
|
|
* @it Unknown type in union list
|
|
*/
|
|
public function testUnknownTypeInUnionList()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Type "Bar" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
}
|
|
|
|
union TestUnion = Bar
|
|
type Hello { testUnion: TestUnion }
|
|
';
|
|
$doc = Parser::parse($body);
|
|
$schema = BuildSchema::buildAST($doc);
|
|
$schema->getTypeMap();
|
|
}
|
|
|
|
/**
|
|
* @it Unknown query type
|
|
*/
|
|
public function testUnknownQueryType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Specified query type "Wat" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Wat
|
|
}
|
|
|
|
type Hello {
|
|
str: String
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Unknown mutation type
|
|
*/
|
|
public function testUnknownMutationType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Specified mutation type "Wat" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
mutation: Wat
|
|
}
|
|
|
|
type Hello {
|
|
str: String
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Unknown subscription type
|
|
*/
|
|
public function testUnknownSubscriptionType()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Specified subscription type "Awesome" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Hello
|
|
mutation: Wat
|
|
subscription: Awesome
|
|
}
|
|
|
|
type Hello {
|
|
str: String
|
|
}
|
|
|
|
type Wat {
|
|
str: String
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Does not consider operation names
|
|
*/
|
|
public function testDoesNotConsiderOperationNames()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Specified query type "Foo" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Foo
|
|
}
|
|
|
|
query Foo { field }
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Does not consider fragment names
|
|
*/
|
|
public function testDoesNotConsiderFragmentNames()
|
|
{
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Specified query type "Foo" not found in document.');
|
|
$body = '
|
|
schema {
|
|
query: Foo
|
|
}
|
|
|
|
fragment Foo on Type { field }
|
|
';
|
|
$doc = Parser::parse($body);
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
|
|
/**
|
|
* @it Forbids duplicate type definitions
|
|
*/
|
|
public function testForbidsDuplicateTypeDefinitions()
|
|
{
|
|
$body = '
|
|
schema {
|
|
query: Repeated
|
|
}
|
|
|
|
type Repeated {
|
|
id: Int
|
|
}
|
|
|
|
type Repeated {
|
|
id: String
|
|
}
|
|
';
|
|
$doc = Parser::parse($body);
|
|
|
|
$this->setExpectedException('GraphQL\Error\Error', 'Type "Repeated" was defined more than once.');
|
|
BuildSchema::buildAST($doc);
|
|
}
|
|
}
|