graphql-php/tests/Executor/UnionInterfaceTest.php

424 lines
12 KiB
PHP
Raw Normal View History

2015-07-15 20:05:46 +03:00
<?php
2018-09-01 18:07:06 +03:00
declare(strict_types=1);
namespace GraphQL\Tests\Executor;
2016-04-09 10:36:53 +03:00
use GraphQL\Executor\Executor;
use GraphQL\GraphQL;
2015-07-15 20:05:46 +03:00
use GraphQL\Language\Parser;
2018-09-01 18:07:06 +03:00
use GraphQL\Tests\Executor\TestClasses\Cat;
use GraphQL\Tests\Executor\TestClasses\Dog;
use GraphQL\Tests\Executor\TestClasses\Person;
2015-07-15 20:05:46 +03:00
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
2015-07-15 20:05:46 +03:00
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
2018-09-01 18:07:06 +03:00
use GraphQL\Type\Schema;
2018-07-29 18:43:10 +03:00
use PHPUnit\Framework\TestCase;
2015-07-15 20:05:46 +03:00
2018-07-29 18:43:10 +03:00
class UnionInterfaceTest extends TestCase
2015-07-15 20:05:46 +03:00
{
2018-09-01 18:07:06 +03:00
/** @var */
2015-07-15 20:05:46 +03:00
public $schema;
2018-09-01 18:07:06 +03:00
/** @var Cat */
2015-07-15 20:05:46 +03:00
public $garfield;
2018-09-01 18:07:06 +03:00
/** @var Dog */
2015-07-15 20:05:46 +03:00
public $odie;
2018-09-01 18:07:06 +03:00
/** @var Person */
2015-07-15 20:05:46 +03:00
public $liz;
2018-09-01 18:07:06 +03:00
/** @var Person */
2015-07-15 20:05:46 +03:00
public $john;
public function setUp()
{
$NamedType = new InterfaceType([
2018-09-01 18:07:06 +03:00
'name' => 'Named',
2015-07-15 20:05:46 +03:00
'fields' => [
2018-09-01 18:07:06 +03:00
'name' => ['type' => Type::string()],
],
2015-07-15 20:05:46 +03:00
]);
$DogType = new ObjectType([
2018-09-01 18:07:06 +03:00
'name' => 'Dog',
2015-07-15 20:05:46 +03:00
'interfaces' => [$NamedType],
2018-09-01 18:07:06 +03:00
'fields' => [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'isTypeOf' => function ($value) {
2015-07-15 20:05:46 +03:00
return $value instanceof Dog;
2018-09-01 18:07:06 +03:00
},
2015-07-15 20:05:46 +03:00
]);
$CatType = new ObjectType([
2018-09-01 18:07:06 +03:00
'name' => 'Cat',
2015-07-15 20:05:46 +03:00
'interfaces' => [$NamedType],
2018-09-01 18:07:06 +03:00
'fields' => [
'name' => ['type' => Type::string()],
'meows' => ['type' => Type::boolean()],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'isTypeOf' => function ($value) {
2015-07-15 20:05:46 +03:00
return $value instanceof Cat;
2018-09-01 18:07:06 +03:00
},
2015-07-15 20:05:46 +03:00
]);
$PetType = new UnionType([
2018-09-01 18:07:06 +03:00
'name' => 'Pet',
'types' => [$DogType, $CatType],
2015-07-15 20:05:46 +03:00
'resolveType' => function ($value) use ($DogType, $CatType) {
if ($value instanceof Dog) {
return $DogType;
}
if ($value instanceof Cat) {
return $CatType;
}
2018-09-01 18:07:06 +03:00
},
2015-07-15 20:05:46 +03:00
]);
$PersonType = new ObjectType([
2018-09-01 18:07:06 +03:00
'name' => 'Person',
2015-07-15 20:05:46 +03:00
'interfaces' => [$NamedType],
2018-09-01 18:07:06 +03:00
'fields' => [
'name' => ['type' => Type::string()],
'pets' => ['type' => Type::listOf($PetType)],
'friends' => ['type' => Type::listOf($NamedType)],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'isTypeOf' => function ($value) {
2015-07-15 20:05:46 +03:00
return $value instanceof Person;
2018-09-01 18:07:06 +03:00
},
2015-07-15 20:05:46 +03:00
]);
$this->schema = new Schema([
'query' => $PersonType,
2018-09-01 18:07:06 +03:00
'types' => [$PetType],
]);
2015-07-15 20:05:46 +03:00
$this->garfield = new Cat('Garfield', false);
2018-09-01 18:07:06 +03:00
$this->odie = new Dog('Odie', true);
$this->liz = new Person('Liz');
$this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]);
2015-07-15 20:05:46 +03:00
}
// Execute: Union and intersection types
/**
* @see it('can introspect on union and intersection types')
*/
public function testCanIntrospectOnUnionAndIntersectionTypes() : void
2015-07-15 20:05:46 +03:00
{
$ast = Parser::parse('
{
Named: __type(name: "Named") {
kind
name
fields { name }
interfaces { name }
possibleTypes { name }
enumValues { name }
inputFields { name }
}
Pet: __type(name: "Pet") {
kind
name
fields { name }
interfaces { name }
possibleTypes { name }
enumValues { name }
inputFields { name }
}
}
');
$expected = [
'data' => [
'Named' => [
2018-09-01 18:07:06 +03:00
'kind' => 'INTERFACE',
'name' => 'Named',
'fields' => [
['name' => 'name'],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'interfaces' => null,
2015-07-15 20:05:46 +03:00
'possibleTypes' => [
['name' => 'Person'],
2015-07-15 20:05:46 +03:00
['name' => 'Dog'],
2018-09-01 18:07:06 +03:00
['name' => 'Cat'],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'enumValues' => null,
'inputFields' => null,
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'Pet' => [
'kind' => 'UNION',
'name' => 'Pet',
'fields' => null,
'interfaces' => null,
2015-07-15 20:05:46 +03:00
'possibleTypes' => [
['name' => 'Dog'],
2018-09-01 18:07:06 +03:00
['name' => 'Cat'],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'enumValues' => null,
'inputFields' => null,
],
],
2015-07-15 20:05:46 +03:00
];
$this->assertEquals($expected, Executor::execute($this->schema, $ast)->toArray());
2015-07-15 20:05:46 +03:00
}
/**
* @see it('executes using union types')
*/
public function testExecutesUsingUnionTypes() : void
2015-07-15 20:05:46 +03:00
{
// NOTE: This is an *invalid* query, but it should be an *executable* query.
2018-09-01 18:07:06 +03:00
$ast = Parser::parse('
2015-07-15 20:05:46 +03:00
{
__typename
name
pets {
__typename
name
woofs
2015-07-15 20:05:46 +03:00
meows
}
}
');
$expected = [
'data' => [
'__typename' => 'Person',
2018-09-01 18:07:06 +03:00
'name' => 'John',
'pets' => [
2015-07-15 20:05:46 +03:00
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
2018-09-01 18:07:06 +03:00
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
],
],
2015-07-15 20:05:46 +03:00
];
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
2015-07-15 20:05:46 +03:00
}
/**
* @see it('executes union types with inline fragments')
*/
public function testExecutesUnionTypesWithInlineFragments() : void
2015-07-15 20:05:46 +03:00
{
// This is the valid version of the query in the above test.
2018-09-01 18:07:06 +03:00
$ast = Parser::parse('
2015-07-15 20:05:46 +03:00
{
__typename
name
pets {
__typename
... on Dog {
name
woofs
2015-07-15 20:05:46 +03:00
}
... on Cat {
name
meows
}
}
}
');
$expected = [
'data' => [
'__typename' => 'Person',
2018-09-01 18:07:06 +03:00
'name' => 'John',
'pets' => [
2015-07-15 20:05:46 +03:00
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
2018-09-01 18:07:06 +03:00
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
],
2015-07-15 20:05:46 +03:00
2018-09-01 18:07:06 +03:00
],
2015-07-15 20:05:46 +03:00
];
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
2015-07-15 20:05:46 +03:00
}
/**
* @see it('executes using interface types')
*/
public function testExecutesUsingInterfaceTypes() : void
2015-07-15 20:05:46 +03:00
{
// NOTE: This is an *invalid* query, but it should be an *executable* query.
2018-09-01 18:07:06 +03:00
$ast = Parser::parse('
2015-07-15 20:05:46 +03:00
{
__typename
name
friends {
__typename
name
woofs
2015-07-15 20:05:46 +03:00
meows
}
}
');
$expected = [
'data' => [
'__typename' => 'Person',
2018-09-01 18:07:06 +03:00
'name' => 'John',
'friends' => [
2015-07-15 20:05:46 +03:00
['__typename' => 'Person', 'name' => 'Liz'],
2018-09-01 18:07:06 +03:00
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
],
],
2015-07-15 20:05:46 +03:00
];
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
2015-07-15 20:05:46 +03:00
}
/**
* @see it('executes interface types with inline fragments')
*/
public function testExecutesInterfaceTypesWithInlineFragments() : void
2015-07-15 20:05:46 +03:00
{
// This is the valid version of the query in the above test.
2018-09-01 18:07:06 +03:00
$ast = Parser::parse('
2015-07-15 20:05:46 +03:00
{
__typename
name
friends {
__typename
name
... on Dog {
woofs
2015-07-15 20:05:46 +03:00
}
... on Cat {
meows
}
}
}
');
$expected = [
'data' => [
'__typename' => 'Person',
2018-09-01 18:07:06 +03:00
'name' => 'John',
'friends' => [
2015-07-15 20:05:46 +03:00
['__typename' => 'Person', 'name' => 'Liz'],
2018-09-01 18:07:06 +03:00
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
],
],
2015-07-15 20:05:46 +03:00
];
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray(true));
2015-07-15 20:05:46 +03:00
}
/**
* @see it('allows fragment conditions to be abstract types')
*/
public function testAllowsFragmentConditionsToBeAbstractTypes() : void
2015-07-15 20:05:46 +03:00
{
$ast = Parser::parse('
{
__typename
name
pets { ...PetFields }
friends { ...FriendFields }
}
fragment PetFields on Pet {
__typename
... on Dog {
name
woofs
2015-07-15 20:05:46 +03:00
}
... on Cat {
name
meows
}
}
fragment FriendFields on Named {
__typename
name
... on Dog {
woofs
2015-07-15 20:05:46 +03:00
}
... on Cat {
meows
}
}
');
$expected = [
'data' => [
'__typename' => 'Person',
2018-09-01 18:07:06 +03:00
'name' => 'John',
'pets' => [
2015-07-15 20:05:46 +03:00
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
2018-09-01 18:07:06 +03:00
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
2015-07-15 20:05:46 +03:00
],
2018-09-01 18:07:06 +03:00
'friends' => [
2015-07-15 20:05:46 +03:00
['__typename' => 'Person', 'name' => 'Liz'],
2018-09-01 18:07:06 +03:00
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
],
],
2015-07-15 20:05:46 +03:00
];
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
2015-07-15 20:05:46 +03:00
}
/**
* @see it('gets execution info in resolver')
*/
public function testGetsExecutionInfoInResolver() : void
{
2018-09-01 18:07:06 +03:00
$encounteredContext = null;
$encounteredSchema = null;
$encounteredRootValue = null;
2018-09-01 18:07:06 +03:00
$PersonType2 = null;
$NamedType2 = new InterfaceType([
2018-09-01 18:07:06 +03:00
'name' => 'Named',
'fields' => [
'name' => ['type' => Type::string()],
],
2018-09-01 18:07:06 +03:00
'resolveType' => function (
$obj,
$context,
ResolveInfo $info
) use (
&$encounteredContext,
&
$encounteredSchema,
&$encounteredRootValue,
&$PersonType2
) {
$encounteredContext = $context;
$encounteredSchema = $info->schema;
$encounteredRootValue = $info->rootValue;
2018-09-01 18:07:06 +03:00
return $PersonType2;
2018-09-01 18:07:06 +03:00
},
]);
$PersonType2 = new ObjectType([
2018-09-01 18:07:06 +03:00
'name' => 'Person',
'interfaces' => [$NamedType2],
2018-09-01 18:07:06 +03:00
'fields' => [
'name' => ['type' => Type::string()],
'friends' => ['type' => Type::listOf($NamedType2)],
],
]);
2018-09-01 18:07:06 +03:00
$schema2 = new Schema(['query' => $PersonType2]);
$john2 = new Person('John', [], [$this->liz]);
$context = ['authToken' => '123abc'];
$ast = Parser::parse('{ name, friends { name } }');
$this->assertEquals(
['data' => ['name' => 'John', 'friends' => [['name' => 'Liz']]]],
GraphQL::executeQuery($schema2, $ast, $john2, $context)->toArray()
);
$this->assertSame($context, $encounteredContext);
$this->assertSame($schema2, $encounteredSchema);
$this->assertSame($john2, $encounteredRootValue);
}
2015-07-15 20:05:46 +03:00
}