graphql-php/tests/Executor/AbstractPromiseTest.php

661 lines
18 KiB
PHP

<?php
namespace GraphQL\Tests\Executor;
use GraphQL\Deferred;
use GraphQL\Error\UserError;
use GraphQL\Error\Warning;
use GraphQL\GraphQL;
use GraphQL\Schema;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
require_once __DIR__ . '/TestClasses.php';
class AbstractPromiseTest extends \PHPUnit_Framework_TestCase
{
// DESCRIBE: Execute: Handles execution of abstract types with promises
/**
* @it isTypeOf used to resolve runtime type for Interface
*/
public function testIsTypeOfUsedToResolveRuntimeTypeForInterface()
{
$PetType = new InterfaceType([
'name' => 'Pet',
'fields' => [
'name' => [ 'type' => Type::string() ]
]
]);
$DogType = new ObjectType([
'name' => 'Dog',
'interfaces' => [ $PetType ],
'isTypeOf' => function($obj) {
return new Deferred(function() use ($obj) {
return $obj instanceof Dog;
});
},
'fields' => [
'name' => [ 'type' => Type::string() ],
'woofs' => [ 'type' => Type::boolean() ],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'interfaces' => [ $PetType ],
'isTypeOf' => function($obj) {
return new Deferred(function() use ($obj) {
return $obj instanceof Cat;
});
},
'fields' => [
'name' => [ 'type' => Type::string() ],
'meows' => [ 'type' => Type::boolean() ],
]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function() {
return [
new Dog('Odie', true),
new Cat('Garfield', false)
];
}
]
]
]),
'types' => [ $CatType, $DogType ]
]);
$query = '{
pets {
name
... on Dog {
woofs
}
... on Cat {
meows
}
}
}';
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
$result = GraphQL::execute($schema, $query);
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
$expected = [
'data' => [
'pets' => [
[ 'name' => 'Odie', 'woofs' => true ],
[ 'name' => 'Garfield', 'meows' => false ]
]
]
];
$this->assertEquals($expected, $result);
}
/**
* @it isTypeOf can be rejected
*/
public function testIsTypeOfCanBeRejected()
{
$PetType = new InterfaceType([
'name' => 'Pet',
'fields' => [
'name' => ['type' => Type::string()]
]
]);
$DogType = new ObjectType([
'name' => 'Dog',
'interfaces' => [$PetType],
'isTypeOf' => function () {
return new Deferred(function () {
throw new UserError('We are testing this error');
});
},
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'interfaces' => [$PetType],
'isTypeOf' => function ($obj) {
return new Deferred(function () use ($obj) {
return $obj instanceof Cat;
});
},
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function () {
return [
new Dog('Odie', true),
new Cat('Garfield', false)
];
}
]
]
]),
'types' => [$CatType, $DogType]
]);
$query = '{
pets {
name
... on Dog {
woofs
}
... on Cat {
meows
}
}
}';
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
$result = GraphQL::execute($schema, $query);
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
$expected = [
'data' => [
'pets' => [null, null]
],
'errors' => [
[
'message' => 'We are testing this error',
'locations' => [['line' => 2, 'column' => 7]],
'path' => ['pets', 0],
],
[
'message' => 'We are testing this error',
'locations' => [['line' => 2, 'column' => 7]],
'path' => ['pets', 1]
]
]
];
$this->assertArraySubset($expected, $result);
}
/**
* @it isTypeOf used to resolve runtime type for Union
*/
public function testIsTypeOfUsedToResolveRuntimeTypeForUnion()
{
$DogType = new ObjectType([
'name' => 'Dog',
'isTypeOf' => function ($obj) {
return new Deferred(function () use ($obj) {
return $obj instanceof Dog;
});
},
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'isTypeOf' => function ($obj) {
return new Deferred(function () use ($obj) {
return $obj instanceof Cat;
});
},
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
]
]);
$PetType = new UnionType([
'name' => 'Pet',
'types' => [$DogType, $CatType]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function () {
return [new Dog('Odie', true), new Cat('Garfield', false)];
}
]
]
])
]);
$query = '{
pets {
... on Dog {
name
woofs
}
... on Cat {
name
meows
}
}
}';
$result = GraphQL::execute($schema, $query);
$expected = [
'data' => [
'pets' => [
['name' => 'Odie', 'woofs' => true],
['name' => 'Garfield', 'meows' => false]
]
]
];
$this->assertEquals($expected, $result);
}
/**
* @it resolveType on Interface yields useful error
*/
public function testResolveTypeOnInterfaceYieldsUsefulError()
{
$PetType = new InterfaceType([
'name' => 'Pet',
'resolveType' => function ($obj) use (&$DogType, &$CatType, &$HumanType) {
return new Deferred(function () use ($obj, $DogType, $CatType, $HumanType) {
if ($obj instanceof Dog) {
return $DogType;
}
if ($obj instanceof Cat) {
return $CatType;
}
if ($obj instanceof Human) {
return $HumanType;
}
return null;
});
},
'fields' => [
'name' => ['type' => Type::string()]
]
]);
$HumanType = new ObjectType([
'name' => 'Human',
'fields' => [
'name' => ['type' => Type::string()],
]
]);
$DogType = new ObjectType([
'name' => 'Dog',
'interfaces' => [$PetType],
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'interfaces' => [$PetType],
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function () {
return new Deferred(function () {
return [
new Dog('Odie', true),
new Cat('Garfield', false),
new Human('Jon')
];
});
}
]
]
]),
'types' => [$CatType, $DogType]
]);
$query = '{
pets {
name
... on Dog {
woofs
}
... on Cat {
meows
}
}
}';
$result = GraphQL::executeAndReturnResult($schema, $query)->toArray(true);
$expected = [
'data' => [
'pets' => [
['name' => 'Odie', 'woofs' => true],
['name' => 'Garfield', 'meows' => false],
null
]
],
'errors' => [
[
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
'locations' => [['line' => 2, 'column' => 7]],
'path' => ['pets', 2]
],
]
];
$this->assertArraySubset($expected, $result);
}
/**
* @it resolveType on Union yields useful error
*/
public function testResolveTypeOnUnionYieldsUsefulError()
{
$HumanType = new ObjectType([
'name' => 'Human',
'fields' => [
'name' => ['type' => Type::string()],
]
]);
$DogType = new ObjectType([
'name' => 'Dog',
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
]
]);
$PetType = new UnionType([
'name' => 'Pet',
'resolveType' => function ($obj) use ($DogType, $CatType, $HumanType) {
return new Deferred(function () use ($obj, $DogType, $CatType, $HumanType) {
if ($obj instanceof Dog) {
return $DogType;
}
if ($obj instanceof Cat) {
return $CatType;
}
if ($obj instanceof Human) {
return $HumanType;
}
return null;
});
},
'types' => [$DogType, $CatType]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function () {
return [
new Dog('Odie', true),
new Cat('Garfield', false),
new Human('Jon')
];
}
]
]
])
]);
$query = '{
pets {
... on Dog {
name
woofs
}
... on Cat {
name
meows
}
}
}';
$result = GraphQL::executeAndReturnResult($schema, $query)->toArray(true);
$expected = [
'data' => [
'pets' => [
['name' => 'Odie', 'woofs' => true],
['name' => 'Garfield', 'meows' => false],
null
]
],
'errors' => [
[
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
'locations' => [['line' => 2, 'column' => 7]],
'path' => ['pets', 2]
]
]
];
$this->assertArraySubset($expected, $result);
}
/**
* @it resolveType allows resolving with type name
*/
public function testResolveTypeAllowsResolvingWithTypeName()
{
$PetType = new InterfaceType([
'name' => 'Pet',
'resolveType' => function ($obj) {
return new Deferred(function () use ($obj) {
if ($obj instanceof Dog) {
return 'Dog';
}
if ($obj instanceof Cat) {
return 'Cat';
}
return null;
});
},
'fields' => [
'name' => ['type' => Type::string()]
]
]);
$DogType = new ObjectType([
'name' => 'Dog',
'interfaces' => [$PetType],
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'interfaces' => [$PetType],
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function () {
return [
new Dog('Odie', true),
new Cat('Garfield', false)
];
}
]
]
]),
'types' => [$CatType, $DogType]
]);
$query = '{
pets {
name
... on Dog {
woofs
}
... on Cat {
meows
}
}
}';
$result = GraphQL::execute($schema, $query);
$expected = [
'data' => [
'pets' => [
['name' => 'Odie', 'woofs' => true],
['name' => 'Garfield', 'meows' => false],
]
]
];
$this->assertEquals($expected, $result);
}
/**
* @it resolveType can be caught
*/
public function testResolveTypeCanBeCaught()
{
$PetType = new InterfaceType([
'name' => 'Pet',
'resolveType' => function () {
return new Deferred(function () {
throw new UserError('We are testing this error');
});
},
'fields' => [
'name' => ['type' => Type::string()]
]
]);
$DogType = new ObjectType([
'name' => 'Dog',
'interfaces' => [$PetType],
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
]
]);
$CatType = new ObjectType([
'name' => 'Cat',
'interfaces' => [$PetType],
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
]
]);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($PetType),
'resolve' => function () {
return [
new Dog('Odie', true),
new Cat('Garfield', false)
];
}
]
]
]),
'types' => [$CatType, $DogType]
]);
$query = '{
pets {
name
... on Dog {
woofs
}
... on Cat {
meows
}
}
}';
$result = GraphQL::execute($schema, $query);
$expected = [
'data' => [
'pets' => [null, null]
],
'errors' => [
[
'message' => 'We are testing this error',
'locations' => [['line' => 2, 'column' => 7]],
'path' => ['pets', 0]
],
[
'message' => 'We are testing this error',
'locations' => [['line' => 2, 'column' => 7]],
'path' => ['pets', 1]
]
]
];
$this->assertArraySubset($expected, $result);
}
}