mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-25 14:26:08 +03:00
Fix CS in tests/Executor
This commit is contained in:
parent
ec54d6152b
commit
b02d25e62c
@ -1,23 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Error\Warning;
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Human;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DESCRIBE: Execute: Handles execution of abstract types with promises
|
||||||
|
*/
|
||||||
class AbstractPromiseTest extends TestCase
|
class AbstractPromiseTest extends TestCase
|
||||||
{
|
{
|
||||||
// DESCRIBE: Execute: Handles execution of abstract types with promises
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('isTypeOf used to resolve runtime type for Interface')
|
* @see it('isTypeOf used to resolve runtime type for Interface')
|
||||||
*/
|
*/
|
||||||
@ -26,8 +30,8 @@ class AbstractPromiseTest extends TestCase
|
|||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -41,7 +45,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -55,7 +59,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -67,13 +71,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [ $CatType, $DogType ]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -94,9 +98,9 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
[ 'name' => 'Garfield', 'meows' => false ]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
@ -107,12 +111,11 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testIsTypeOfCanBeRejected() : void
|
public function testIsTypeOfCanBeRejected() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -126,7 +129,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -140,7 +143,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -152,13 +155,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -177,7 +180,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [null, null]
|
'pets' => [null, null],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
@ -188,9 +191,9 @@ class AbstractPromiseTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'We are testing this error',
|
'message' => 'We are testing this error',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 1]
|
'path' => ['pets', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -201,7 +204,6 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testIsTypeOfUsedToResolveRuntimeTypeForUnion() : void
|
public function testIsTypeOfUsedToResolveRuntimeTypeForUnion() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'isTypeOf' => function ($obj) {
|
'isTypeOf' => function ($obj) {
|
||||||
@ -212,7 +214,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -225,12 +227,12 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -241,10 +243,10 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'type' => Type::listOf($PetType),
|
'type' => Type::listOf($PetType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -266,9 +268,9 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
@ -292,19 +294,20 @@ class AbstractPromiseTest extends TestCase
|
|||||||
if ($obj instanceof Human) {
|
if ($obj instanceof Human) {
|
||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$HumanType = new ObjectType([
|
$HumanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -313,7 +316,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -322,7 +325,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -336,14 +339,14 @@ class AbstractPromiseTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -365,16 +368,16 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -385,12 +388,11 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testResolveTypeOnUnionYieldsUsefulError() : void
|
public function testResolveTypeOnUnionYieldsUsefulError() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$HumanType = new ObjectType([
|
$HumanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -398,7 +400,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -406,7 +408,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
@ -422,10 +424,11 @@ class AbstractPromiseTest extends TestCase
|
|||||||
if ($obj instanceof Human) {
|
if ($obj instanceof Human) {
|
||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -438,12 +441,12 @@ class AbstractPromiseTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -466,16 +469,16 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -496,22 +499,22 @@ class AbstractPromiseTest extends TestCase
|
|||||||
if ($obj instanceof Cat) {
|
if ($obj instanceof Cat) {
|
||||||
return 'Cat';
|
return 'Cat';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [$PetType],
|
'interfaces' => [$PetType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -520,7 +523,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -532,13 +535,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -560,8 +563,8 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
}
|
}
|
||||||
@ -571,7 +574,6 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testResolveTypeCanBeCaught() : void
|
public function testResolveTypeCanBeCaught() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'resolveType' => function () {
|
'resolveType' => function () {
|
||||||
@ -580,8 +582,8 @@ class AbstractPromiseTest extends TestCase
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -590,7 +592,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -599,7 +601,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -611,13 +613,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -636,20 +638,20 @@ class AbstractPromiseTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [null, null]
|
'pets' => [null, null],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'We are testing this error',
|
'message' => 'We are testing this error',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 0]
|
'path' => ['pets', 0],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'We are testing this error',
|
'message' => 'We are testing this error',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 1]
|
'path' => ['pets', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Human;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute: Handles execution of abstract types
|
||||||
|
*/
|
||||||
class AbstractTest extends TestCase
|
class AbstractTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: Handles execution of abstract types
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('isTypeOf used to resolve runtime type for Interface')
|
* @see it('isTypeOf used to resolve runtime type for Interface')
|
||||||
*/
|
*/
|
||||||
@ -27,19 +32,21 @@ class AbstractTest extends TestCase
|
|||||||
$petType = new InterfaceType([
|
$petType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Added to interface type when defined
|
// Added to interface type when defined
|
||||||
$dogType = new ObjectType([
|
$dogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [$petType],
|
'interfaces' => [$petType],
|
||||||
'isTypeOf' => function($obj) { return $obj instanceof Dog; },
|
'isTypeOf' => function ($obj) {
|
||||||
|
return $obj instanceof Dog;
|
||||||
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$catType = new ObjectType([
|
$catType = new ObjectType([
|
||||||
@ -51,7 +58,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -62,11 +69,11 @@ class AbstractTest extends TestCase
|
|||||||
'type' => Type::listOf($petType),
|
'type' => Type::listOf($petType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$catType, $dogType]
|
'types' => [$catType, $dogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -84,8 +91,8 @@ class AbstractTest extends TestCase
|
|||||||
$expected = new ExecutionResult([
|
$expected = new ExecutionResult([
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$result = Executor::execute($schema, Parser::parse($query));
|
$result = Executor::execute($schema, Parser::parse($query));
|
||||||
@ -99,11 +106,13 @@ class AbstractTest extends TestCase
|
|||||||
{
|
{
|
||||||
$dogType = new ObjectType([
|
$dogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'isTypeOf' => function($obj) { return $obj instanceof Dog; },
|
'isTypeOf' => function ($obj) {
|
||||||
|
return $obj instanceof Dog;
|
||||||
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$catType = new ObjectType([
|
$catType = new ObjectType([
|
||||||
@ -114,12 +123,12 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$petType = new UnionType([
|
$petType = new UnionType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'types' => [$dogType, $catType]
|
'types' => [$dogType, $catType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -130,10 +139,10 @@ class AbstractTest extends TestCase
|
|||||||
'type' => Type::listOf($petType),
|
'type' => Type::listOf($petType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -151,8 +160,8 @@ class AbstractTest extends TestCase
|
|||||||
$expected = new ExecutionResult([
|
$expected = new ExecutionResult([
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($schema, Parser::parse($query)));
|
$this->assertEquals($expected, Executor::execute($schema, Parser::parse($query)));
|
||||||
@ -161,7 +170,7 @@ class AbstractTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @see it('resolveType on Interface yields useful error')
|
* @see it('resolveType on Interface yields useful error')
|
||||||
*/
|
*/
|
||||||
function testResolveTypeOnInterfaceYieldsUsefulError()
|
public function testResolveTypeOnInterfaceYieldsUsefulError() : void
|
||||||
{
|
{
|
||||||
$DogType = null;
|
$DogType = null;
|
||||||
$CatType = null;
|
$CatType = null;
|
||||||
@ -179,18 +188,19 @@ class AbstractTest extends TestCase
|
|||||||
if ($obj instanceof Human) {
|
if ($obj instanceof Human) {
|
||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$HumanType = new ObjectType([
|
$HumanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -199,7 +209,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -208,7 +218,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -221,16 +231,15 @@ class AbstractTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
pets {
|
pets {
|
||||||
name
|
name
|
||||||
@ -248,14 +257,15 @@ class AbstractTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 11]],
|
'locations' => [['line' => 2, 'column' => 11]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$actual = GraphQL::executeQuery($schema, $query)->toArray(true);
|
$actual = GraphQL::executeQuery($schema, $query)->toArray(true);
|
||||||
|
|
||||||
@ -271,7 +281,7 @@ class AbstractTest extends TestCase
|
|||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -279,7 +289,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -287,7 +297,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
@ -303,7 +313,7 @@ class AbstractTest extends TestCase
|
|||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -316,12 +326,12 @@ class AbstractTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -341,18 +351,23 @@ class AbstractTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie',
|
[
|
||||||
'woofs' => true],
|
'name' => 'Odie',
|
||||||
['name' => 'Garfield',
|
'woofs' => true,
|
||||||
'meows' => false],
|
],
|
||||||
null
|
[
|
||||||
]
|
'name' => 'Garfield',
|
||||||
|
'meows' => false,
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 11]],
|
'locations' => [['line' => 2, 'column' => 11]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
}
|
}
|
||||||
@ -420,13 +435,18 @@ class AbstractTest extends TestCase
|
|||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'resolveType' => function ($obj) {
|
'resolveType' => function ($obj) {
|
||||||
if ($obj instanceof Dog) return 'Dog';
|
if ($obj instanceof Dog) {
|
||||||
if ($obj instanceof Cat) return 'Cat';
|
return 'Dog';
|
||||||
|
}
|
||||||
|
if ($obj instanceof Cat) {
|
||||||
|
return 'Cat';
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -435,7 +455,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -444,7 +464,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -456,13 +476,13 @@ class AbstractTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [ $CatType, $DogType ]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -479,14 +499,17 @@ class AbstractTest extends TestCase
|
|||||||
|
|
||||||
$result = GraphQL::executeQuery($schema, $query)->toArray();
|
$result = GraphQL::executeQuery($schema, $query)->toArray();
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $result);
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHintsOnConflictingTypeInstancesInResolveType() : void
|
public function testHintsOnConflictingTypeInstancesInResolveType() : void
|
||||||
@ -495,35 +518,33 @@ class AbstractTest extends TestCase
|
|||||||
return new ObjectType([
|
return new ObjectType([
|
||||||
'name' => 'Test',
|
'name' => 'Test',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => Type::string()
|
'a' => Type::string(),
|
||||||
],
|
],
|
||||||
'interfaces' => function () use ($iface) {
|
'interfaces' => function () use ($iface) {
|
||||||
return [$iface];
|
return [$iface];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
$iface = new InterfaceType([
|
$iface = new InterfaceType([
|
||||||
'name' => 'Node',
|
'name' => 'Node',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => Type::string()
|
'a' => Type::string(),
|
||||||
],
|
],
|
||||||
'resolveType' => function () use (&$createTest) {
|
'resolveType' => function () use (&$createTest) {
|
||||||
return $createTest();
|
return $createTest();
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'node' => $iface,
|
'node' => $iface,
|
||||||
'test' => $createTest()
|
'test' => $createTest(),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $query]);
|
||||||
'query' => $query,
|
|
||||||
]);
|
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
|
|
||||||
$query = '
|
$query = '
|
||||||
|
@ -1,33 +1,44 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function in_array;
|
||||||
|
|
||||||
class DeferredFieldsTest extends TestCase
|
class DeferredFieldsTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var ObjectType */
|
||||||
private $userType;
|
private $userType;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $storyType;
|
private $storyType;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $categoryType;
|
private $categoryType;
|
||||||
|
|
||||||
|
/** @var */
|
||||||
private $path;
|
private $path;
|
||||||
|
|
||||||
|
/** @var mixed[][] */
|
||||||
private $storyDataSource;
|
private $storyDataSource;
|
||||||
|
|
||||||
|
/** @var mixed[][] */
|
||||||
private $userDataSource;
|
private $userDataSource;
|
||||||
|
|
||||||
|
/** @var mixed[][] */
|
||||||
private $categoryDataSource;
|
private $categoryDataSource;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $queryType;
|
private $queryType;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -54,7 +65,7 @@ class DeferredFieldsTest extends TestCase
|
|||||||
$this->categoryDataSource = [
|
$this->categoryDataSource = [
|
||||||
['id' => 1, 'name' => 'Category #1', 'topStoryId' => 8],
|
['id' => 1, 'name' => 'Category #1', 'topStoryId' => 8],
|
||||||
['id' => 2, 'name' => 'Category #2', 'topStoryId' => 3],
|
['id' => 2, 'name' => 'Category #2', 'topStoryId' => 3],
|
||||||
['id' => 3, 'name' => 'Category #3', 'topStoryId' => 9]
|
['id' => 3, 'name' => 'Category #3', 'topStoryId' => 9],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->path = [];
|
$this->path = [];
|
||||||
@ -66,8 +77,9 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($user, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($user, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $user['name'];
|
return $user['name'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'bestFriend' => [
|
'bestFriend' => [
|
||||||
'type' => $this->userType,
|
'type' => $this->userType,
|
||||||
@ -76,14 +88,18 @@ class DeferredFieldsTest extends TestCase
|
|||||||
|
|
||||||
return new Deferred(function () use ($user) {
|
return new Deferred(function () use ($user) {
|
||||||
$this->path[] = 'deferred-for-best-friend-of-' . $user['id'];
|
$this->path[] = 'deferred-for-best-friend-of-' . $user['id'];
|
||||||
return Utils::find($this->userDataSource, function($entry) use ($user) {
|
|
||||||
|
return Utils::find(
|
||||||
|
$this->userDataSource,
|
||||||
|
function ($entry) use ($user) {
|
||||||
return $entry['id'] === $user['bestFriendId'];
|
return $entry['id'] === $user['bestFriendId'];
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->storyType = new ObjectType([
|
$this->storyType = new ObjectType([
|
||||||
@ -93,8 +109,9 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($entry, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($entry, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $entry['title'];
|
return $entry['title'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'author' => [
|
'author' => [
|
||||||
'type' => $this->userType,
|
'type' => $this->userType,
|
||||||
@ -103,13 +120,17 @@ class DeferredFieldsTest extends TestCase
|
|||||||
|
|
||||||
return new Deferred(function () use ($story) {
|
return new Deferred(function () use ($story) {
|
||||||
$this->path[] = 'deferred-for-story-' . $story['id'] . '-author';
|
$this->path[] = 'deferred-for-story-' . $story['id'] . '-author';
|
||||||
return Utils::find($this->userDataSource, function($entry) use ($story) {
|
|
||||||
|
return Utils::find(
|
||||||
|
$this->userDataSource,
|
||||||
|
function ($entry) use ($story) {
|
||||||
return $entry['id'] === $story['authorId'];
|
return $entry['id'] === $story['authorId'];
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
]
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->categoryType = new ObjectType([
|
$this->categoryType = new ObjectType([
|
||||||
@ -119,18 +140,23 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $category['name'];
|
return $category['name'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
'stories' => [
|
'stories' => [
|
||||||
'type' => Type::listOf($this->storyType),
|
'type' => Type::listOf($this->storyType),
|
||||||
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
return Utils::filter($this->storyDataSource, function($story) use ($category) {
|
|
||||||
|
return Utils::filter(
|
||||||
|
$this->storyDataSource,
|
||||||
|
function ($story) use ($category) {
|
||||||
return in_array($category['id'], $story['categoryIds']);
|
return in_array($category['id'], $story['categoryIds']);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'topStory' => [
|
'topStory' => [
|
||||||
'type' => $this->storyType,
|
'type' => $this->storyType,
|
||||||
@ -139,13 +165,17 @@ class DeferredFieldsTest extends TestCase
|
|||||||
|
|
||||||
return new Deferred(function () use ($category) {
|
return new Deferred(function () use ($category) {
|
||||||
$this->path[] = 'deferred-for-category-' . $category['id'] . '-topStory';
|
$this->path[] = 'deferred-for-category-' . $category['id'] . '-topStory';
|
||||||
return Utils::find($this->storyDataSource, function($story) use ($category) {
|
|
||||||
|
return Utils::find(
|
||||||
|
$this->storyDataSource,
|
||||||
|
function ($story) use ($category) {
|
||||||
return $story['id'] === $category['topStoryId'];
|
return $story['id'] === $category['topStoryId'];
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
]
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->queryType = new ObjectType([
|
$this->queryType = new ObjectType([
|
||||||
@ -155,26 +185,32 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'type' => Type::listOf($this->storyType),
|
'type' => Type::listOf($this->storyType),
|
||||||
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
return Utils::filter($this->storyDataSource, function($story) {
|
|
||||||
|
return Utils::filter(
|
||||||
|
$this->storyDataSource,
|
||||||
|
function ($story) {
|
||||||
return $story['id'] % 2 === 1;
|
return $story['id'] % 2 === 1;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'featuredCategory' => [
|
'featuredCategory' => [
|
||||||
'type' => $this->categoryType,
|
'type' => $this->categoryType,
|
||||||
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $this->categoryDataSource[0];
|
return $this->categoryDataSource[0];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'categories' => [
|
'categories' => [
|
||||||
'type' => Type::listOf($this->categoryType),
|
'type' => Type::listOf($this->categoryType),
|
||||||
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $this->categoryDataSource;
|
return $this->categoryDataSource;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
@ -202,7 +238,7 @@ class DeferredFieldsTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->queryType
|
'query' => $this->queryType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
@ -220,9 +256,9 @@ class DeferredFieldsTest extends TestCase
|
|||||||
['title' => 'Story #4', 'author' => ['name' => 'Joe']],
|
['title' => 'Story #4', 'author' => ['name' => 'Joe']],
|
||||||
['title' => 'Story #6', 'author' => ['name' => 'Jane']],
|
['title' => 'Story #6', 'author' => ['name' => 'Jane']],
|
||||||
['title' => 'Story #8', 'author' => ['name' => 'John']],
|
['title' => 'Story #8', 'author' => ['name' => 'John']],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
@ -292,7 +328,7 @@ class DeferredFieldsTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->queryType
|
'query' => $this->queryType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$author1 = ['name' => 'John', 'bestFriend' => ['name' => 'Dirk']];
|
$author1 = ['name' => 'John', 'bestFriend' => ['name' => 'Dirk']];
|
||||||
@ -306,8 +342,8 @@ class DeferredFieldsTest extends TestCase
|
|||||||
['name' => 'Category #1', 'topStory' => ['title' => 'Story #8', 'author' => $author1]],
|
['name' => 'Category #1', 'topStory' => ['title' => 'Story #8', 'author' => $author1]],
|
||||||
['name' => 'Category #2', 'topStory' => ['title' => 'Story #3', 'author' => $author3]],
|
['name' => 'Category #2', 'topStory' => ['title' => 'Story #3', 'author' => $author3]],
|
||||||
['name' => 'Category #3', 'topStory' => ['title' => 'Story #9', 'author' => $author2]],
|
['name' => 'Category #3', 'topStory' => ['title' => 'Story #9', 'author' => $author2]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
@ -359,8 +395,9 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return 'sync';
|
return 'sync';
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'deferred' => [
|
'deferred' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
@ -369,16 +406,18 @@ class DeferredFieldsTest extends TestCase
|
|||||||
|
|
||||||
return new Deferred(function () use ($info) {
|
return new Deferred(function () use ($info) {
|
||||||
$this->path[] = ['!dfd for: ', $info->path];
|
$this->path[] = ['!dfd for: ', $info->path];
|
||||||
|
|
||||||
return 'deferred';
|
return 'deferred';
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'nest' => [
|
'nest' => [
|
||||||
'type' => $complexType,
|
'type' => $complexType,
|
||||||
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'type' => $complexType,
|
'type' => $complexType,
|
||||||
@ -387,17 +426,16 @@ class DeferredFieldsTest extends TestCase
|
|||||||
|
|
||||||
return new Deferred(function () use ($info) {
|
return new Deferred(function () use ($info) {
|
||||||
$this->path[] = ['!dfd nest for: ', $info->path];
|
$this->path[] = ['!dfd nest for: ', $info->path];
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $complexType]);
|
||||||
'query' => $complexType
|
|
||||||
]);
|
|
||||||
|
|
||||||
$query = Parser::parse('
|
$query = Parser::parse('
|
||||||
{
|
{
|
||||||
@ -435,26 +473,26 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'deferred' => 'deferred',
|
'deferred' => 'deferred',
|
||||||
'nest' => [
|
'nest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred',
|
'deferred' => 'deferred',
|
||||||
'nest' => [
|
'nest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Language\Source;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe: Execute: handles directives
|
||||||
|
*/
|
||||||
class DirectivesTest extends TestCase
|
class DirectivesTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: Execute: handles directives
|
/** @var Schema */
|
||||||
|
private static $schema;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
|
private static $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('basic query works')
|
* @see it('basic query works')
|
||||||
@ -20,10 +31,50 @@ class DirectivesTest extends TestCase
|
|||||||
$this->assertEquals(['data' => ['a' => 'a', 'b' => 'b']], $this->executeTestQuery('{ a, b }'));
|
$this->assertEquals(['data' => ['a' => 'a', 'b' => 'b']], $this->executeTestQuery('{ a, b }'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Source|string $doc
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function executeTestQuery($doc) : array
|
||||||
|
{
|
||||||
|
return Executor::execute(self::getSchema(), Parser::parse($doc), self::getData())->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getSchema() : Schema
|
||||||
|
{
|
||||||
|
if (! self::$schema) {
|
||||||
|
self::$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'TestType',
|
||||||
|
'fields' => [
|
||||||
|
'a' => ['type' => Type::string()],
|
||||||
|
'b' => ['type' => Type::string()],
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private static function getData() : array
|
||||||
|
{
|
||||||
|
return self::$data ?: (self::$data = [
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function testWorksOnScalars() : void
|
public function testWorksOnScalars() : void
|
||||||
{
|
{
|
||||||
// if true includes scalar
|
// if true includes scalar
|
||||||
$this->assertEquals(['data' => ['a' => 'a', 'b' => 'b']], $this->executeTestQuery('{ a, b @include(if: true) }'));
|
$this->assertEquals(
|
||||||
|
['data' => ['a' => 'a', 'b' => 'b']],
|
||||||
|
$this->executeTestQuery('{ a, b @include(if: true) }')
|
||||||
|
);
|
||||||
|
|
||||||
// if false omits on scalar
|
// if false omits on scalar
|
||||||
$this->assertEquals(['data' => ['a' => 'a']], $this->executeTestQuery('{ a, b @include(if: false) }'));
|
$this->assertEquals(['data' => ['a' => 'a']], $this->executeTestQuery('{ a, b @include(if: false) }'));
|
||||||
@ -200,37 +251,4 @@ class DirectivesTest extends TestCase
|
|||||||
$this->executeTestQuery('{ a, b @include(if: false) @skip(if: false) }')
|
$this->executeTestQuery('{ a, b @include(if: false) @skip(if: false) }')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $schema;
|
|
||||||
|
|
||||||
private static $data;
|
|
||||||
|
|
||||||
private static function getSchema()
|
|
||||||
{
|
|
||||||
if (!self::$schema) {
|
|
||||||
self::$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'TestType',
|
|
||||||
'fields' => [
|
|
||||||
'a' => ['type' => Type::string()],
|
|
||||||
'b' => ['type' => Type::string()]
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return self::$schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getData()
|
|
||||||
{
|
|
||||||
return self::$data ?: (self::$data = [
|
|
||||||
'a' => 'a',
|
|
||||||
'b' => 'b'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executeTestQuery($doc)
|
|
||||||
{
|
|
||||||
return Executor::execute(self::getSchema(), Parser::parse($doc), self::getData())->toArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
|
@ -1,44 +1,62 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Error\Warning;
|
use GraphQL\Error\Warning;
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
use GraphQL\Type\Definition\CustomScalarType;
|
use GraphQL\Type\Definition\CustomScalarType;
|
||||||
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\ScalarType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\Error\Error;
|
use PHPUnit\Framework\Error\Error;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
|
||||||
class ExecutorLazySchemaTest extends TestCase
|
class ExecutorLazySchemaTest extends TestCase
|
||||||
{
|
{
|
||||||
public $SomeScalarType;
|
/** @var ScalarType */
|
||||||
|
public $someScalarType;
|
||||||
|
|
||||||
public $SomeObjectType;
|
/** @var ObjectType */
|
||||||
|
public $someObjectType;
|
||||||
|
|
||||||
public $OtherObjectType;
|
/** @var ObjectType */
|
||||||
|
public $otherObjectType;
|
||||||
|
|
||||||
public $DeeperObjectType;
|
/** @var ObjectType */
|
||||||
|
public $deeperObjectType;
|
||||||
|
|
||||||
public $SomeUnionType;
|
/** @var UnionType */
|
||||||
|
public $someUnionType;
|
||||||
|
|
||||||
public $SomeInterfaceType;
|
/** @var InterfaceType */
|
||||||
|
public $someInterfaceType;
|
||||||
|
|
||||||
public $SomeEnumType;
|
/** @var EnumType */
|
||||||
|
public $someEnumType;
|
||||||
|
|
||||||
public $SomeInputObjectType;
|
/** @var InputObjectType */
|
||||||
|
public $someInputObjectType;
|
||||||
|
|
||||||
public $QueryType;
|
/** @var ObjectType */
|
||||||
|
public $queryType;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
public $calls = [];
|
public $calls = [];
|
||||||
|
|
||||||
|
/** @var bool[] */
|
||||||
public $loadedTypes = [];
|
public $loadedTypes = [];
|
||||||
|
|
||||||
public function testWarnsAboutSlowIsTypeOfForLazySchema() : void
|
public function testWarnsAboutSlowIsTypeOfForLazySchema() : void
|
||||||
@ -48,22 +66,24 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => function () {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Added to interface type when defined
|
// Added to interface type when defined
|
||||||
$dogType = new ObjectType([
|
$dogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [$petType],
|
'interfaces' => [$petType],
|
||||||
'isTypeOf' => function($obj) { return $obj instanceof Dog; },
|
'isTypeOf' => function ($obj) {
|
||||||
|
return $obj instanceof Dog;
|
||||||
|
},
|
||||||
'fields' => function () {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$catType = new ObjectType([
|
$catType = new ObjectType([
|
||||||
@ -77,7 +97,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -88,9 +108,9 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'type' => Type::listOf($petType),
|
'type' => Type::listOf($petType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$catType, $dogType],
|
'types' => [$catType, $dogType],
|
||||||
'typeLoader' => function ($name) use ($dogType, $petType, $catType) {
|
'typeLoader' => function ($name) use ($dogType, $petType, $catType) {
|
||||||
@ -102,7 +122,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
case 'Cat':
|
case 'Cat':
|
||||||
return $catType;
|
return $catType;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -120,7 +140,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$expected = new ExecutionResult([
|
$expected = new ExecutionResult([
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -135,10 +155,11 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'GraphQL Interface Type `Pet` returned `null` from it`s `resolveType` function for value: instance of ' .
|
'GraphQL Interface Type `Pet` returned `null` from it`s `resolveType` function for value: instance of ' .
|
||||||
'GraphQL\Tests\Executor\Dog. Switching to slow resolution method using `isTypeOf` of all possible '.
|
'GraphQL\Tests\Executor\TestClasses\Dog. Switching to slow resolution method using `isTypeOf` of all possible ' .
|
||||||
'implementations. It requires full schema scan and degrades query performance significantly. ' .
|
'implementations. It requires full schema scan and degrades query performance significantly. ' .
|
||||||
'Make sure your `resolveType` always returns valid implementation or throws.',
|
'Make sure your `resolveType` always returns valid implementation or throws.',
|
||||||
$result->errors[0]->getMessage());
|
$result->errors[0]->getMessage()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHintsOnConflictingTypeInstancesInDefinitions() : void
|
public function testHintsOnConflictingTypeInstancesInDefinitions() : void
|
||||||
@ -154,23 +175,25 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
'test' => Type::string(),
|
'test' => Type::string(),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => function () use ($typeLoader) {
|
'fields' => function () use ($typeLoader) {
|
||||||
return [
|
return [
|
||||||
'test' => $typeLoader('Test')
|
'test' => $typeLoader('Test'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'typeLoader' => $typeLoader
|
'typeLoader' => $typeLoader,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '
|
$query = '
|
||||||
@ -203,7 +226,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'query' => $this->loadType('Query'),
|
'query' => $this->loadType('Query'),
|
||||||
'typeLoader' => function ($name) {
|
'typeLoader' => function ($name) {
|
||||||
return $this->loadType($name, true);
|
return $this->loadType($name, true);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{ object { string } }';
|
$query = '{ object { string } }';
|
||||||
@ -219,19 +242,126 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$expectedExecutorCalls = [
|
$expectedExecutorCalls = [
|
||||||
'Query.fields',
|
'Query.fields',
|
||||||
'SomeObject',
|
'SomeObject',
|
||||||
'SomeObject.fields'
|
'SomeObject.fields',
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray(true));
|
$this->assertEquals($expected, $result->toArray(true));
|
||||||
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loadType($name, $isExecutorCall = false)
|
||||||
|
{
|
||||||
|
if ($isExecutorCall) {
|
||||||
|
$this->calls[] = $name;
|
||||||
|
}
|
||||||
|
$this->loadedTypes[$name] = true;
|
||||||
|
|
||||||
|
switch ($name) {
|
||||||
|
case 'Query':
|
||||||
|
return $this->queryType ?: $this->queryType = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'Query.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'object' => ['type' => $this->loadType('SomeObject')],
|
||||||
|
'other' => ['type' => $this->loadType('OtherObject')],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeObject':
|
||||||
|
return $this->someObjectType ?: $this->someObjectType = new ObjectType([
|
||||||
|
'name' => 'SomeObject',
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'SomeObject.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'string' => ['type' => Type::string()],
|
||||||
|
'object' => ['type' => $this->someObjectType],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
'interfaces' => function () {
|
||||||
|
$this->calls[] = 'SomeObject.interfaces';
|
||||||
|
|
||||||
|
return [
|
||||||
|
$this->loadType('SomeInterface'),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'OtherObject':
|
||||||
|
return $this->otherObjectType ?: $this->otherObjectType = new ObjectType([
|
||||||
|
'name' => 'OtherObject',
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'OtherObject.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'union' => ['type' => $this->loadType('SomeUnion')],
|
||||||
|
'iface' => ['type' => Type::nonNull($this->loadType('SomeInterface'))],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'DeeperObject':
|
||||||
|
return $this->deeperObjectType ?: $this->deeperObjectType = new ObjectType([
|
||||||
|
'name' => 'DeeperObject',
|
||||||
|
'fields' => function () {
|
||||||
|
return [
|
||||||
|
'scalar' => ['type' => $this->loadType('SomeScalar')],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeScalar':
|
||||||
|
return $this->someScalarType ?: $this->someScalarType = new CustomScalarType([
|
||||||
|
'name' => 'SomeScalar',
|
||||||
|
'serialize' => function ($value) {
|
||||||
|
return $value;
|
||||||
|
},
|
||||||
|
'parseValue' => function ($value) {
|
||||||
|
return $value;
|
||||||
|
},
|
||||||
|
'parseLiteral' => function () {
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeUnion':
|
||||||
|
return $this->someUnionType ?: $this->someUnionType = new UnionType([
|
||||||
|
'name' => 'SomeUnion',
|
||||||
|
'resolveType' => function () {
|
||||||
|
$this->calls[] = 'SomeUnion.resolveType';
|
||||||
|
|
||||||
|
return $this->loadType('DeeperObject');
|
||||||
|
},
|
||||||
|
'types' => function () {
|
||||||
|
$this->calls[] = 'SomeUnion.types';
|
||||||
|
|
||||||
|
return [$this->loadType('DeeperObject')];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeInterface':
|
||||||
|
return $this->someInterfaceType ?: $this->someInterfaceType = new InterfaceType([
|
||||||
|
'name' => 'SomeInterface',
|
||||||
|
'resolveType' => function () {
|
||||||
|
$this->calls[] = 'SomeInterface.resolveType';
|
||||||
|
|
||||||
|
return $this->loadType('SomeObject');
|
||||||
|
},
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'SomeInterface.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'string' => ['type' => Type::string()],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function testDeepQuery() : void
|
public function testDeepQuery() : void
|
||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->loadType('Query'),
|
'query' => $this->loadType('Query'),
|
||||||
'typeLoader' => function ($name) {
|
'typeLoader' => function ($name) {
|
||||||
return $this->loadType($name, true);
|
return $this->loadType($name, true);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{ object { object { object { string } } } }';
|
$query = '{ object { object { object { string } } } }';
|
||||||
@ -242,12 +372,12 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['object' => ['object' => ['object' => ['string' => 'test']]]]
|
'data' => ['object' => ['object' => ['object' => ['string' => 'test']]]],
|
||||||
];
|
];
|
||||||
$expectedLoadedTypes = [
|
$expectedLoadedTypes = [
|
||||||
'Query' => true,
|
'Query' => true,
|
||||||
'SomeObject' => true,
|
'SomeObject' => true,
|
||||||
'OtherObject' => true
|
'OtherObject' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray(true));
|
$this->assertEquals($expected, $result->toArray(true));
|
||||||
@ -256,7 +386,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$expectedExecutorCalls = [
|
$expectedExecutorCalls = [
|
||||||
'Query.fields',
|
'Query.fields',
|
||||||
'SomeObject',
|
'SomeObject',
|
||||||
'SomeObject.fields'
|
'SomeObject.fields',
|
||||||
];
|
];
|
||||||
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
||||||
}
|
}
|
||||||
@ -267,7 +397,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'query' => $this->loadType('Query'),
|
'query' => $this->loadType('Query'),
|
||||||
'typeLoader' => function ($name) {
|
'typeLoader' => function ($name) {
|
||||||
return $this->loadType($name, true);
|
return $this->loadType($name, true);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '
|
$query = '
|
||||||
@ -313,98 +443,4 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
];
|
];
|
||||||
$this->assertEquals($expectedCalls, $this->calls);
|
$this->assertEquals($expectedCalls, $this->calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadType($name, $isExecutorCall = false)
|
|
||||||
{
|
|
||||||
if ($isExecutorCall) {
|
|
||||||
$this->calls[] = $name;
|
|
||||||
}
|
|
||||||
$this->loadedTypes[$name] = true;
|
|
||||||
|
|
||||||
switch ($name) {
|
|
||||||
case 'Query':
|
|
||||||
return $this->QueryType ?: $this->QueryType = new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'Query.fields';
|
|
||||||
return [
|
|
||||||
'object' => ['type' => $this->loadType('SomeObject')],
|
|
||||||
'other' => ['type' => $this->loadType('OtherObject')],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'SomeObject':
|
|
||||||
return $this->SomeObjectType ?: $this->SomeObjectType = new ObjectType([
|
|
||||||
'name' => 'SomeObject',
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'SomeObject.fields';
|
|
||||||
return [
|
|
||||||
'string' => ['type' => Type::string()],
|
|
||||||
'object' => ['type' => $this->SomeObjectType]
|
|
||||||
];
|
|
||||||
},
|
|
||||||
'interfaces' => function() {
|
|
||||||
$this->calls[] = 'SomeObject.interfaces';
|
|
||||||
return [
|
|
||||||
$this->loadType('SomeInterface')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'OtherObject':
|
|
||||||
return $this->OtherObjectType ?: $this->OtherObjectType = new ObjectType([
|
|
||||||
'name' => 'OtherObject',
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'OtherObject.fields';
|
|
||||||
return [
|
|
||||||
'union' => ['type' => $this->loadType('SomeUnion')],
|
|
||||||
'iface' => ['type' => Type::nonNull($this->loadType('SomeInterface'))],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'DeeperObject':
|
|
||||||
return $this->DeeperObjectType ?: $this->DeeperObjectType = new ObjectType([
|
|
||||||
'name' => 'DeeperObject',
|
|
||||||
'fields' => function() {
|
|
||||||
return [
|
|
||||||
'scalar' => ['type' => $this->loadType('SomeScalar')],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'SomeScalar';
|
|
||||||
return $this->SomeScalarType ?: $this->SomeScalarType = new CustomScalarType([
|
|
||||||
'name' => 'SomeScalar',
|
|
||||||
'serialize' => function($value) {return $value;},
|
|
||||||
'parseValue' => function($value) {return $value;},
|
|
||||||
'parseLiteral' => function() {}
|
|
||||||
]);
|
|
||||||
case 'SomeUnion':
|
|
||||||
return $this->SomeUnionType ?: $this->SomeUnionType = new UnionType([
|
|
||||||
'name' => 'SomeUnion',
|
|
||||||
'resolveType' => function() {
|
|
||||||
$this->calls[] = 'SomeUnion.resolveType';
|
|
||||||
return $this->loadType('DeeperObject');
|
|
||||||
},
|
|
||||||
'types' => function() {
|
|
||||||
$this->calls[] = 'SomeUnion.types';
|
|
||||||
return [ $this->loadType('DeeperObject') ];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'SomeInterface':
|
|
||||||
return $this->SomeInterfaceType ?: $this->SomeInterfaceType = new InterfaceType([
|
|
||||||
'name' => 'SomeInterface',
|
|
||||||
'resolveType' => function() {
|
|
||||||
$this->calls[] = 'SomeInterface.resolveType';
|
|
||||||
return $this->loadType('SomeObject');
|
|
||||||
},
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'SomeInterface.fields';
|
|
||||||
return [
|
|
||||||
'string' => ['type' => Type::string() ]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
class ExecutorSchemaTest extends TestCase
|
class ExecutorSchemaTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: Handles execution with a complex schema
|
// Execute: Handles execution with a complex schema
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('executes using a schema')
|
* @see it('executes using a schema')
|
||||||
*/
|
*/
|
||||||
@ -24,7 +27,7 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'url' => ['type' => Type::string()],
|
'url' => ['type' => Type::string()],
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()],
|
'height' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogAuthor = new ObjectType([
|
$BlogAuthor = new ObjectType([
|
||||||
@ -38,11 +41,11 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'type' => $BlogImage,
|
'type' => $BlogImage,
|
||||||
'resolve' => function ($obj, $args) {
|
'resolve' => function ($obj, $args) {
|
||||||
return $obj['pic']($args['width'], $args['height']);
|
return $obj['pic']($args['width'], $args['height']);
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'recentArticle' => $BlogArticle
|
'recentArticle' => $BlogArticle,
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogArticle = new ObjectType([
|
$BlogArticle = new ObjectType([
|
||||||
@ -53,8 +56,8 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'author' => ['type' => $BlogAuthor],
|
'author' => ['type' => $BlogAuthor],
|
||||||
'title' => ['type' => Type::string()],
|
'title' => ['type' => Type::string()],
|
||||||
'body' => ['type' => Type::string()],
|
'body' => ['type' => Type::string()],
|
||||||
'keywords' => ['type' => Type::listOf(Type::string())]
|
'keywords' => ['type' => Type::listOf(Type::string())],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogQuery = new ObjectType([
|
$BlogQuery = new ObjectType([
|
||||||
@ -65,7 +68,7 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'args' => ['id' => ['type' => Type::id()]],
|
'args' => ['id' => ['type' => Type::id()]],
|
||||||
'resolve' => function ($_, $args) {
|
'resolve' => function ($_, $args) {
|
||||||
return $this->article($args['id']);
|
return $this->article($args['id']);
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'feed' => [
|
'feed' => [
|
||||||
'type' => Type::listOf($BlogArticle),
|
'type' => Type::listOf($BlogArticle),
|
||||||
@ -80,16 +83,15 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
$this->article(7),
|
$this->article(7),
|
||||||
$this->article(8),
|
$this->article(8),
|
||||||
$this->article(9),
|
$this->article(9),
|
||||||
$this->article(10)
|
$this->article(10),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogSchema = new Schema(['query' => $BlogQuery]);
|
$BlogSchema = new Schema(['query' => $BlogQuery]);
|
||||||
|
|
||||||
|
|
||||||
$request = '
|
$request = '
|
||||||
{
|
{
|
||||||
feed {
|
feed {
|
||||||
@ -127,26 +129,46 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'feed' => [
|
'feed' => [
|
||||||
['id' => '1',
|
[
|
||||||
'title' => 'My Article 1'],
|
'id' => '1',
|
||||||
['id' => '2',
|
'title' => 'My Article 1',
|
||||||
'title' => 'My Article 2'],
|
],
|
||||||
['id' => '3',
|
[
|
||||||
'title' => 'My Article 3'],
|
'id' => '2',
|
||||||
['id' => '4',
|
'title' => 'My Article 2',
|
||||||
'title' => 'My Article 4'],
|
],
|
||||||
['id' => '5',
|
[
|
||||||
'title' => 'My Article 5'],
|
'id' => '3',
|
||||||
['id' => '6',
|
'title' => 'My Article 3',
|
||||||
'title' => 'My Article 6'],
|
],
|
||||||
['id' => '7',
|
[
|
||||||
'title' => 'My Article 7'],
|
'id' => '4',
|
||||||
['id' => '8',
|
'title' => 'My Article 4',
|
||||||
'title' => 'My Article 8'],
|
],
|
||||||
['id' => '9',
|
[
|
||||||
'title' => 'My Article 9'],
|
'id' => '5',
|
||||||
['id' => '10',
|
'title' => 'My Article 5',
|
||||||
'title' => 'My Article 10']
|
],
|
||||||
|
[
|
||||||
|
'id' => '6',
|
||||||
|
'title' => 'My Article 6',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '7',
|
||||||
|
'title' => 'My Article 7',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '8',
|
||||||
|
'title' => 'My Article 8',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '9',
|
||||||
|
'title' => 'My Article 9',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '10',
|
||||||
|
'title' => 'My Article 10',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'article' => [
|
'article' => [
|
||||||
'id' => '1',
|
'id' => '1',
|
||||||
@ -159,18 +181,18 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'pic' => [
|
'pic' => [
|
||||||
'url' => 'cdn://123',
|
'url' => 'cdn://123',
|
||||||
'width' => 640,
|
'width' => 640,
|
||||||
'height' => 480
|
'height' => 480,
|
||||||
],
|
],
|
||||||
'recentArticle' => [
|
'recentArticle' => [
|
||||||
'id' => '1',
|
'id' => '1',
|
||||||
'isPublished' => true,
|
'isPublished' => true,
|
||||||
'title' => 'My Article 1',
|
'title' => 'My Article 1',
|
||||||
'body' => 'This is a post',
|
'body' => 'This is a post',
|
||||||
'keywords' => ['foo', 'bar', '1', 'true', null]
|
'keywords' => ['foo', 'bar', '1', 'true', null],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($BlogSchema, Parser::parse($request))->toArray());
|
$this->assertEquals($expected, Executor::execute($BlogSchema, Parser::parse($request))->toArray());
|
||||||
@ -187,22 +209,24 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'title' => 'My Article ' . $id,
|
'title' => 'My Article ' . $id,
|
||||||
'body' => 'This is a post',
|
'body' => 'This is a post',
|
||||||
'hidden' => 'This data is not exposed in the schema',
|
'hidden' => 'This data is not exposed in the schema',
|
||||||
'keywords' => ['foo', 'bar', 1, true, null]
|
'keywords' => ['foo', 'bar', 1, true, null],
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
$getPic = function ($uid, $width, $height) {
|
$getPic = function ($uid, $width, $height) {
|
||||||
return [
|
return [
|
||||||
'url' => "cdn://$uid",
|
'url' => sprintf('cdn://%s', $uid),
|
||||||
'width' => $width,
|
'width' => $width,
|
||||||
'height' => $height
|
'height' => $height,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
$johnSmith = [
|
$johnSmith = [
|
||||||
'id' => 123,
|
'id' => 123,
|
||||||
'name' => 'John Smith',
|
'name' => 'John Smith',
|
||||||
'pic' => function($width, $height) use ($getPic) {return $getPic(123, $width, $height);},
|
'pic' => function ($width, $height) use ($getPic) {
|
||||||
|
return $getPic(123, $width, $height);
|
||||||
|
},
|
||||||
'recentArticle' => $article(1),
|
'recentArticle' => $article(1),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\NotSpecial;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Special;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function array_keys;
|
||||||
|
use function count;
|
||||||
|
use function json_encode;
|
||||||
|
|
||||||
class ExecutorTest extends TestCase
|
class ExecutorTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -40,11 +45,21 @@ class ExecutorTest extends TestCase
|
|||||||
};
|
};
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'a' => function () { return 'Apple';},
|
'a' => function () {
|
||||||
'b' => function () {return 'Banana';},
|
return 'Apple';
|
||||||
'c' => function () {return 'Cookie';},
|
},
|
||||||
'd' => function () {return 'Donut';},
|
'b' => function () {
|
||||||
'e' => function () {return 'Egg';},
|
return 'Banana';
|
||||||
|
},
|
||||||
|
'c' => function () {
|
||||||
|
return 'Cookie';
|
||||||
|
},
|
||||||
|
'd' => function () {
|
||||||
|
return 'Donut';
|
||||||
|
},
|
||||||
|
'e' => function () {
|
||||||
|
return 'Egg';
|
||||||
|
},
|
||||||
'f' => 'Fish',
|
'f' => 'Fish',
|
||||||
'pic' => function ($size = 50) {
|
'pic' => function ($size = 50) {
|
||||||
return 'Pic of size: ' . $size;
|
return 'Pic of size: ' . $size;
|
||||||
@ -54,21 +69,25 @@ class ExecutorTest extends TestCase
|
|||||||
},
|
},
|
||||||
'deep' => function () use (&$deepData) {
|
'deep' => function () use (&$deepData) {
|
||||||
return $deepData;
|
return $deepData;
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Required for that & reference above
|
||||||
$deepData = [
|
$deepData = [
|
||||||
'a' => function () { return 'Already Been Done'; },
|
'a' => function () {
|
||||||
'b' => function () { return 'Boring'; },
|
return 'Already Been Done';
|
||||||
|
},
|
||||||
|
'b' => function () {
|
||||||
|
return 'Boring';
|
||||||
|
},
|
||||||
'c' => function () {
|
'c' => function () {
|
||||||
return ['Contrived', null, 'Confusing'];
|
return ['Contrived', null, 'Confusing'];
|
||||||
},
|
},
|
||||||
'deeper' => function () use (&$data) {
|
'deeper' => function () use (&$data) {
|
||||||
return [$data, null, $data];
|
return [$data, null, $data];
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
$doc = '
|
$doc = '
|
||||||
query Example($size: Int) {
|
query Example($size: Int) {
|
||||||
a,
|
a,
|
||||||
@ -109,9 +128,7 @@ class ExecutorTest extends TestCase
|
|||||||
'e' => 'Egg',
|
'e' => 'Egg',
|
||||||
'f' => 'Fish',
|
'f' => 'Fish',
|
||||||
'pic' => 'Pic of size: 100',
|
'pic' => 'Pic of size: 100',
|
||||||
'promise' => [
|
'promise' => ['a' => 'Apple'],
|
||||||
'a' => 'Apple'
|
|
||||||
],
|
|
||||||
'deep' => [
|
'deep' => [
|
||||||
'a' => 'Already Been Done',
|
'a' => 'Already Been Done',
|
||||||
'b' => 'Boring',
|
'b' => 'Boring',
|
||||||
@ -119,10 +136,10 @@ class ExecutorTest extends TestCase
|
|||||||
'deeper' => [
|
'deeper' => [
|
||||||
['a' => 'Apple', 'b' => 'Banana'],
|
['a' => 'Apple', 'b' => 'Banana'],
|
||||||
null,
|
null,
|
||||||
[ 'a' => 'Apple', 'b' => 'Banana' ]
|
['a' => 'Apple', 'b' => 'Banana'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$deepDataType = null;
|
$deepDataType = null;
|
||||||
@ -141,26 +158,30 @@ class ExecutorTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($obj, $args) {
|
'resolve' => function ($obj, $args) {
|
||||||
return $obj['pic']($args['size']);
|
return $obj['pic']($args['size']);
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'promise' => ['type' => $dataType],
|
'promise' => ['type' => $dataType],
|
||||||
'deep' => ['type' => $deepDataType],
|
'deep' => ['type' => $deepDataType],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Required for that & reference above
|
||||||
$deepDataType = new ObjectType([
|
$deepDataType = new ObjectType([
|
||||||
'name' => 'DeepDataType',
|
'name' => 'DeepDataType',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
'b' => ['type' => Type::string()],
|
'b' => ['type' => Type::string()],
|
||||||
'c' => ['type' => Type::listOf(Type::string())],
|
'c' => ['type' => Type::listOf(Type::string())],
|
||||||
'deeper' => [ 'type' => Type::listOf($dataType) ]
|
'deeper' => ['type' => Type::listOf($dataType)],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$schema = new Schema(['query' => $dataType]);
|
$schema = new Schema(['query' => $dataType]);
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($schema, $ast, $data, null, ['size' => 100], 'Example')->toArray());
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($schema, $ast, $data, null, ['size' => 100], 'Example')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,24 +207,34 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => function () use (&$Type) {
|
'fields' => function () use (&$Type) {
|
||||||
return [
|
return [
|
||||||
'a' => ['type' => Type::string(), 'resolve' => function () {
|
'a' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function () {
|
||||||
return 'Apple';
|
return 'Apple';
|
||||||
}],
|
},
|
||||||
'b' => ['type' => Type::string(), 'resolve' => function () {
|
],
|
||||||
|
'b' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function () {
|
||||||
return 'Banana';
|
return 'Banana';
|
||||||
}],
|
},
|
||||||
'c' => ['type' => Type::string(), 'resolve' => function () {
|
],
|
||||||
|
'c' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function () {
|
||||||
return 'Cherry';
|
return 'Cherry';
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
'deep' => [
|
'deep' => [
|
||||||
'type' => $Type,
|
'type' => $Type,
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [];
|
return [];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $Type]);
|
$schema = new Schema(['query' => $Type]);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
@ -215,10 +246,10 @@ class ExecutorTest extends TestCase
|
|||||||
'c' => 'Cherry',
|
'c' => 'Cherry',
|
||||||
'deeper' => [
|
'deeper' => [
|
||||||
'b' => 'Banana',
|
'b' => 'Banana',
|
||||||
'c' => 'Cherry'
|
'c' => 'Cherry',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($schema, $ast)->toArray());
|
$this->assertEquals($expected, Executor::execute($schema, $ast)->toArray());
|
||||||
@ -241,17 +272,18 @@ class ExecutorTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($val, $args, $ctx, $_info) use (&$info) {
|
'resolve' => function ($val, $args, $ctx, $_info) use (&$info) {
|
||||||
$info = $_info;
|
$info = $_info;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$rootValue = ['root' => 'val'];
|
$rootValue = ['root' => 'val'];
|
||||||
|
|
||||||
Executor::execute($schema, $ast, $rootValue, null, ['var' => '123']);
|
Executor::execute($schema, $ast, $rootValue, null, ['var' => '123']);
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'fieldName',
|
'fieldName',
|
||||||
'fieldNodes',
|
'fieldNodes',
|
||||||
'returnType',
|
'returnType',
|
||||||
@ -262,7 +294,9 @@ class ExecutorTest extends TestCase
|
|||||||
'rootValue',
|
'rootValue',
|
||||||
'operation',
|
'operation',
|
||||||
'variableValues',
|
'variableValues',
|
||||||
], array_keys((array) $info));
|
],
|
||||||
|
array_keys((array) $info)
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals('test', $info->fieldName);
|
$this->assertEquals('test', $info->fieldName);
|
||||||
$this->assertEquals(1, count($info->fieldNodes));
|
$this->assertEquals(1, count($info->fieldNodes));
|
||||||
@ -286,9 +320,7 @@ class ExecutorTest extends TestCase
|
|||||||
|
|
||||||
$gotHere = false;
|
$gotHere = false;
|
||||||
|
|
||||||
$data = [
|
$data = ['contextThing' => 'thing'];
|
||||||
'contextThing' => 'thing',
|
|
||||||
];
|
|
||||||
|
|
||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -300,10 +332,10 @@ class ExecutorTest extends TestCase
|
|||||||
'resolve' => function ($context) use ($doc, &$gotHere) {
|
'resolve' => function ($context) use ($doc, &$gotHere) {
|
||||||
$this->assertEquals('thing', $context['contextThing']);
|
$this->assertEquals('thing', $context['contextThing']);
|
||||||
$gotHere = true;
|
$gotHere = true;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Executor::execute($schema, $ast, $data, null, [], 'Example');
|
Executor::execute($schema, $ast, $data, null, [], 'Example');
|
||||||
@ -331,17 +363,17 @@ class ExecutorTest extends TestCase
|
|||||||
'b' => [
|
'b' => [
|
||||||
'args' => [
|
'args' => [
|
||||||
'numArg' => ['type' => Type::int()],
|
'numArg' => ['type' => Type::int()],
|
||||||
'stringArg' => ['type' => Type::string()]
|
'stringArg' => ['type' => Type::string()],
|
||||||
],
|
],
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($_, $args) use (&$gotHere) {
|
'resolve' => function ($_, $args) use (&$gotHere) {
|
||||||
$this->assertEquals(123, $args['numArg']);
|
$this->assertEquals(123, $args['numArg']);
|
||||||
$this->assertEquals('foo', $args['stringArg']);
|
$this->assertEquals('foo', $args['stringArg']);
|
||||||
$gotHere = true;
|
$gotHere = true;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
Executor::execute($schema, $docAst, null, null, [], 'Example');
|
Executor::execute($schema, $docAst, null, null, [], 'Example');
|
||||||
$this->assertSame($gotHere, true);
|
$this->assertSame($gotHere, true);
|
||||||
@ -387,14 +419,18 @@ class ExecutorTest extends TestCase
|
|||||||
'sync0',
|
'sync0',
|
||||||
new UserError('Error getting syncReturnErrorList1'),
|
new UserError('Error getting syncReturnErrorList1'),
|
||||||
'sync2',
|
'sync2',
|
||||||
new UserError('Error getting syncReturnErrorList3')
|
new UserError('Error getting syncReturnErrorList3'),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
'async' => function () {
|
'async' => function () {
|
||||||
return new Deferred(function() { return 'async'; });
|
return new Deferred(function () {
|
||||||
|
return 'async';
|
||||||
|
});
|
||||||
},
|
},
|
||||||
'asyncReject' => function () {
|
'asyncReject' => function () {
|
||||||
return new Deferred(function() { throw new UserError('Error getting asyncReject'); });
|
return new Deferred(function () {
|
||||||
|
throw new UserError('Error getting asyncReject');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
'asyncRawReject' => function () {
|
'asyncRawReject' => function () {
|
||||||
return new Deferred(function () {
|
return new Deferred(function () {
|
||||||
@ -442,8 +478,8 @@ class ExecutorTest extends TestCase
|
|||||||
'asyncError' => ['type' => Type::string()],
|
'asyncError' => ['type' => Type::string()],
|
||||||
'asyncRawError' => ['type' => Type::string()],
|
'asyncRawError' => ['type' => Type::string()],
|
||||||
'asyncReturnError' => ['type' => Type::string()],
|
'asyncReturnError' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
@ -465,59 +501,59 @@ class ExecutorTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'Error getting syncError',
|
'message' => 'Error getting syncError',
|
||||||
'locations' => [['line' => 3, 'column' => 7]],
|
'locations' => [['line' => 3, 'column' => 7]],
|
||||||
'path' => ['syncError']
|
'path' => ['syncError'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting syncRawError',
|
'message' => 'Error getting syncRawError',
|
||||||
'locations' => [['line' => 4, 'column' => 7]],
|
'locations' => [['line' => 4, 'column' => 7]],
|
||||||
'path'=> [ 'syncRawError' ]
|
'path' => ['syncRawError'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting syncReturnError',
|
'message' => 'Error getting syncReturnError',
|
||||||
'locations' => [['line' => 5, 'column' => 7]],
|
'locations' => [['line' => 5, 'column' => 7]],
|
||||||
'path' => ['syncReturnError']
|
'path' => ['syncReturnError'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting syncReturnErrorList1',
|
'message' => 'Error getting syncReturnErrorList1',
|
||||||
'locations' => [['line' => 6, 'column' => 7]],
|
'locations' => [['line' => 6, 'column' => 7]],
|
||||||
'path' => ['syncReturnErrorList', 1]
|
'path' => ['syncReturnErrorList', 1],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting syncReturnErrorList3',
|
'message' => 'Error getting syncReturnErrorList3',
|
||||||
'locations' => [['line' => 6, 'column' => 7]],
|
'locations' => [['line' => 6, 'column' => 7]],
|
||||||
'path' => ['syncReturnErrorList', 3]
|
'path' => ['syncReturnErrorList', 3],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting asyncReject',
|
'message' => 'Error getting asyncReject',
|
||||||
'locations' => [['line' => 8, 'column' => 7]],
|
'locations' => [['line' => 8, 'column' => 7]],
|
||||||
'path' => ['asyncReject']
|
'path' => ['asyncReject'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting asyncRawReject',
|
'message' => 'Error getting asyncRawReject',
|
||||||
'locations' => [['line' => 9, 'column' => 7]],
|
'locations' => [['line' => 9, 'column' => 7]],
|
||||||
'path' => ['asyncRawReject']
|
'path' => ['asyncRawReject'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'An unknown error occurred.',
|
'message' => 'An unknown error occurred.',
|
||||||
'locations' => [['line' => 10, 'column' => 7]],
|
'locations' => [['line' => 10, 'column' => 7]],
|
||||||
'path' => ['asyncEmptyReject']
|
'path' => ['asyncEmptyReject'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting asyncError',
|
'message' => 'Error getting asyncError',
|
||||||
'locations' => [['line' => 11, 'column' => 7]],
|
'locations' => [['line' => 11, 'column' => 7]],
|
||||||
'path' => ['asyncError']
|
'path' => ['asyncError'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting asyncRawError',
|
'message' => 'Error getting asyncRawError',
|
||||||
'locations' => [['line' => 12, 'column' => 7]],
|
'locations' => [['line' => 12, 'column' => 7]],
|
||||||
'path' => [ 'asyncRawError' ]
|
'path' => ['asyncRawError'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'Error getting asyncReturnError',
|
'message' => 'Error getting asyncReturnError',
|
||||||
'locations' => [['line' => 13, 'column' => 7]],
|
'locations' => [['line' => 13, 'column' => 7]],
|
||||||
'path' => ['asyncReturnError']
|
'path' => ['asyncReturnError'],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = Executor::execute($schema, $docAst, $data)->toArray();
|
$result = Executor::execute($schema, $docAst, $data)->toArray();
|
||||||
@ -538,8 +574,8 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$ex = Executor::execute($schema, $ast, $data);
|
$ex = Executor::execute($schema, $ast, $data);
|
||||||
@ -560,8 +596,8 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$ex = Executor::execute($schema, $ast, $data);
|
$ex = Executor::execute($schema, $ast, $data);
|
||||||
@ -581,8 +617,8 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$result = Executor::execute($schema, $ast, $data, null, null, 'OtherExample');
|
$result = Executor::execute($schema, $ast, $data, null, null, 'OtherExample');
|
||||||
@ -602,17 +638,15 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$result = Executor::execute($schema, $ast, $data);
|
$result = Executor::execute($schema, $ast, $data);
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
['message' => 'Must provide an operation.'],
|
||||||
'message' => 'Must provide an operation.',
|
],
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result->toArray());
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
@ -631,18 +665,16 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$result = Executor::execute($schema, $ast, $data);
|
$result = Executor::execute($schema, $ast, $data);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
['message' => 'Must provide operation name if query contains multiple operations.'],
|
||||||
'message' => 'Must provide operation name if query contains multiple operations.',
|
],
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result->toArray());
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
@ -660,11 +692,10 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$result = Executor::execute(
|
$result = Executor::execute(
|
||||||
$schema,
|
$schema,
|
||||||
$ast,
|
$ast,
|
||||||
@ -676,10 +707,8 @@ class ExecutorTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
['message' => 'Unknown operation named "UnknownExample".'],
|
||||||
'message' => 'Unknown operation named "UnknownExample".',
|
],
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -699,14 +728,14 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Q',
|
'name' => 'Q',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'mutation' => new ObjectType([
|
'mutation' => new ObjectType([
|
||||||
'name' => 'M',
|
'name' => 'M',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'c' => ['type' => Type::string()],
|
'c' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryResult = Executor::execute($schema, $ast, $data, null, [], 'Q');
|
$queryResult = Executor::execute($schema, $ast, $data, null, [], 'Q');
|
||||||
@ -726,14 +755,14 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Q',
|
'name' => 'Q',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'mutation' => new ObjectType([
|
'mutation' => new ObjectType([
|
||||||
'name' => 'M',
|
'name' => 'M',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'c' => ['type' => Type::string()],
|
'c' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
$mutationResult = Executor::execute($schema, $ast, $data, null, [], 'M');
|
$mutationResult = Executor::execute($schema, $ast, $data, null, [], 'M');
|
||||||
$this->assertEquals(['data' => ['c' => 'd']], $mutationResult->toArray());
|
$this->assertEquals(['data' => ['c' => 'd']], $mutationResult->toArray());
|
||||||
@ -752,14 +781,14 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Q',
|
'name' => 'Q',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'subscription' => new ObjectType([
|
'subscription' => new ObjectType([
|
||||||
'name' => 'S',
|
'name' => 'S',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$subscriptionResult = Executor::execute($schema, $ast, $data, null, [], 'S');
|
$subscriptionResult = Executor::execute($schema, $ast, $data, null, [], 'S');
|
||||||
@ -780,13 +809,17 @@ class ExecutorTest extends TestCase
|
|||||||
return 'a';
|
return 'a';
|
||||||
},
|
},
|
||||||
'b' => function () {
|
'b' => function () {
|
||||||
return new Deferred(function () { return 'b'; });
|
return new Deferred(function () {
|
||||||
|
return 'b';
|
||||||
|
});
|
||||||
},
|
},
|
||||||
'c' => function () {
|
'c' => function () {
|
||||||
return 'c';
|
return 'c';
|
||||||
},
|
},
|
||||||
'd' => function () {
|
'd' => function () {
|
||||||
return new Deferred(function () { return 'd'; });
|
return new Deferred(function () {
|
||||||
|
return 'd';
|
||||||
|
});
|
||||||
},
|
},
|
||||||
'e' => function () {
|
'e' => function () {
|
||||||
return 'e';
|
return 'e';
|
||||||
@ -803,7 +836,7 @@ class ExecutorTest extends TestCase
|
|||||||
'c' => ['type' => Type::string()],
|
'c' => ['type' => Type::string()],
|
||||||
'd' => ['type' => Type::string()],
|
'd' => ['type' => Type::string()],
|
||||||
'e' => ['type' => Type::string()],
|
'e' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$schema = new Schema(['query' => $queryType]);
|
$schema = new Schema(['query' => $queryType]);
|
||||||
|
|
||||||
@ -814,7 +847,7 @@ class ExecutorTest extends TestCase
|
|||||||
'c' => 'c',
|
'c' => 'c',
|
||||||
'd' => 'd',
|
'd' => 'd',
|
||||||
'e' => 'e',
|
'e' => 'e',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($schema, $ast, $data)->toArray());
|
$this->assertEquals($expected, Executor::execute($schema, $ast, $data)->toArray());
|
||||||
@ -844,8 +877,8 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryResult = Executor::execute($schema, $ast, $data, null, [], 'Q');
|
$queryResult = Executor::execute($schema, $ast, $data, null, [], 'Q');
|
||||||
@ -866,14 +899,14 @@ class ExecutorTest extends TestCase
|
|||||||
'name' => 'Q',
|
'name' => 'Q',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::string()],
|
'a' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'mutation' => new ObjectType([
|
'mutation' => new ObjectType([
|
||||||
'name' => 'M',
|
'name' => 'M',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'c' => ['type' => Type::string()],
|
'c' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
$mutationResult = Executor::execute($schema, $ast);
|
$mutationResult = Executor::execute($schema, $ast);
|
||||||
$this->assertEquals(['data' => []], $mutationResult->toArray());
|
$this->assertEquals(['data' => []], $mutationResult->toArray());
|
||||||
@ -890,25 +923,25 @@ class ExecutorTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'field' => [
|
'field' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($data, $args) {return $args ? json_encode($args) : '';},
|
'resolve' => function ($data, $args) {
|
||||||
|
return $args ? json_encode($args) : '';
|
||||||
|
},
|
||||||
'args' => [
|
'args' => [
|
||||||
'a' => ['type' => Type::boolean()],
|
'a' => ['type' => Type::boolean()],
|
||||||
'b' => ['type' => Type::boolean()],
|
'b' => ['type' => Type::boolean()],
|
||||||
'c' => ['type' => Type::boolean()],
|
'c' => ['type' => Type::boolean()],
|
||||||
'd' => ['type' => Type::int()],
|
'd' => ['type' => Type::int()],
|
||||||
'e' => ['type' => Type::int()]
|
'e' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = Parser::parse('{ field(a: true, c: false, e: 0) }');
|
$query = Parser::parse('{ field(a: true, c: false, e: 0) }');
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['field' => '{"a":true,"c":false,"e":0}'],
|
||||||
'field' => '{"a":true,"c":false,"e":0}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
@ -925,8 +958,8 @@ class ExecutorTest extends TestCase
|
|||||||
return $obj instanceof Special;
|
return $obj instanceof Special;
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'value' => ['type' => Type::string()]
|
'value' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -937,31 +970,37 @@ class ExecutorTest extends TestCase
|
|||||||
'type' => Type::listOf($SpecialType),
|
'type' => Type::listOf($SpecialType),
|
||||||
'resolve' => function ($rootValue) {
|
'resolve' => function ($rootValue) {
|
||||||
return $rootValue['specials'];
|
return $rootValue['specials'];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = Parser::parse('{ specials { value } }');
|
$query = Parser::parse('{ specials { value } }');
|
||||||
$value = [
|
$value = [
|
||||||
'specials' => [ new Special('foo'), new NotSpecial('bar') ]
|
'specials' => [new Special('foo'), new NotSpecial('bar')],
|
||||||
];
|
];
|
||||||
$result = Executor::execute($schema, $query, $value);
|
$result = Executor::execute($schema, $query, $value);
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'specials' => [
|
'specials' => [
|
||||||
['value' => 'foo'],
|
['value' => 'foo'],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
], $result->data);
|
],
|
||||||
|
$result->data
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals(1, count($result->errors));
|
$this->assertEquals(1, count($result->errors));
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
'message' => 'Expected value of type "SpecialType" but got: instance of GraphQL\Tests\Executor\NotSpecial.',
|
[
|
||||||
|
'message' => 'Expected value of type "SpecialType" but got: instance of GraphQL\Tests\Executor\TestClasses\NotSpecial.',
|
||||||
'locations' => [['line' => 1, 'column' => 3]],
|
'locations' => [['line' => 1, 'column' => 3]],
|
||||||
'path' => ['specials', 1]
|
'path' => ['specials', 1],
|
||||||
], $result->errors[0]->toSerializableArray());
|
],
|
||||||
|
$result->errors[0]->toSerializableArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -979,18 +1018,15 @@ class ExecutorTest extends TestCase
|
|||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'foo' => ['type' => Type::string()]
|
'foo' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['foo' => null],
|
||||||
'foo' => null,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result->toArray());
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
@ -1007,9 +1043,9 @@ class ExecutorTest extends TestCase
|
|||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'foo' => ['type' => Type::string()]
|
'foo' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// For the purposes of test, just return the name of the field!
|
// For the purposes of test, just return the name of the field!
|
||||||
@ -1028,7 +1064,7 @@ class ExecutorTest extends TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['foo' => 'foo']
|
'data' => ['foo' => 'foo'],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
@ -1042,7 +1078,9 @@ class ExecutorTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'field' => [
|
'field' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($data, $args) {return $args ? json_encode($args) : '';},
|
'resolve' => function ($data, $args) {
|
||||||
|
return $args ? json_encode($args) : '';
|
||||||
|
},
|
||||||
'args' => [
|
'args' => [
|
||||||
'a' => ['type' => Type::boolean(), 'defaultValue' => 1],
|
'a' => ['type' => Type::boolean(), 'defaultValue' => 1],
|
||||||
'b' => ['type' => Type::boolean(), 'defaultValue' => null],
|
'b' => ['type' => Type::boolean(), 'defaultValue' => null],
|
||||||
@ -1051,25 +1089,25 @@ class ExecutorTest extends TestCase
|
|||||||
'e' => ['type' => Type::int(), 'defaultValue' => '0'],
|
'e' => ['type' => Type::int(), 'defaultValue' => '0'],
|
||||||
'f' => ['type' => Type::int(), 'defaultValue' => 'some-string'],
|
'f' => ['type' => Type::int(), 'defaultValue' => 'some-string'],
|
||||||
'g' => ['type' => Type::boolean()],
|
'g' => ['type' => Type::boolean()],
|
||||||
'h' => ['type' => new InputObjectType([
|
'h' => [
|
||||||
|
'type' => new InputObjectType([
|
||||||
'name' => 'ComplexType',
|
'name' => 'ComplexType',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => ['type' => Type::int()],
|
'a' => ['type' => Type::int()],
|
||||||
'b' => ['type' => Type::string()]
|
'b' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]), 'defaultValue' => ['a' => 1, 'b' => 'test']]
|
]), 'defaultValue' => ['a' => 1, 'b' => 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
],
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = Parser::parse('{ field }');
|
$query = Parser::parse('{ field }');
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['field' => '{"a":1,"b":null,"c":0,"d":false,"e":"0","f":"some-string","h":{"a":1,"b":"test"}}'],
|
||||||
'field' => '{"a":1,"b":null,"c":0,"d":false,"e":"0","f":"some-string","h":{"a":1,"b":"test"}}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
@ -1085,41 +1123,41 @@ class ExecutorTest extends TestCase
|
|||||||
$a = new ObjectType([
|
$a = new ObjectType([
|
||||||
'name' => 'A',
|
'name' => 'A',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => Type::id()
|
'id' => Type::id(),
|
||||||
],
|
],
|
||||||
'interfaces' => function () use (&$iface) {
|
'interfaces' => function () use (&$iface) {
|
||||||
return [$iface];
|
return [$iface];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$b = new ObjectType([
|
$b = new ObjectType([
|
||||||
'name' => 'B',
|
'name' => 'B',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => Type::id()
|
'id' => Type::id(),
|
||||||
],
|
],
|
||||||
'interfaces' => function () use (&$iface) {
|
'interfaces' => function () use (&$iface) {
|
||||||
return [$iface];
|
return [$iface];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$iface = new InterfaceType([
|
$iface = new InterfaceType([
|
||||||
'name' => 'Iface',
|
'name' => 'Iface',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => Type::id()
|
'id' => Type::id(),
|
||||||
],
|
],
|
||||||
'resolveType' => function ($v) use ($a, $b) {
|
'resolveType' => function ($v) use ($a, $b) {
|
||||||
return $v['type'] === 'A' ? $a : $b;
|
return $v['type'] === 'A' ? $a : $b;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'ab' => Type::listOf($iface)
|
'ab' => Type::listOf($iface),
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$a, $b]
|
'types' => [$a, $b],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@ -1127,8 +1165,8 @@ class ExecutorTest extends TestCase
|
|||||||
['id' => 1, 'type' => 'A'],
|
['id' => 1, 'type' => 'A'],
|
||||||
['id' => 2, 'type' => 'A'],
|
['id' => 2, 'type' => 'A'],
|
||||||
['id' => 3, 'type' => 'B'],
|
['id' => 3, 'type' => 'B'],
|
||||||
['id' => 4, 'type' => 'B']
|
['id' => 4, 'type' => 'B'],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$query = Parser::parse('
|
$query = Parser::parse('
|
||||||
@ -1143,15 +1181,18 @@ class ExecutorTest extends TestCase
|
|||||||
|
|
||||||
$result = Executor::execute($schema, $query, $data, null);
|
$result = Executor::execute($schema, $query, $data, null);
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'data' => [
|
'data' => [
|
||||||
'ab' => [
|
'ab' => [
|
||||||
['id' => '1'],
|
['id' => '1'],
|
||||||
['id' => '2'],
|
['id' => '2'],
|
||||||
new \stdClass(),
|
new \stdClass(),
|
||||||
new \stdClass()
|
new \stdClass(),
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $result->toArray());
|
],
|
||||||
|
$result->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,58 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: Ivo Meißner
|
* @author: Ivo Meißner
|
||||||
* Date: 03.05.16
|
* Date: 03.05.16
|
||||||
* Time: 13:14
|
* Time: 13:14
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class LazyInterfaceTest extends TestCase
|
class LazyInterfaceTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var Schema */
|
||||||
* @var Schema
|
|
||||||
*/
|
|
||||||
protected $schema;
|
protected $schema;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
protected $lazyInterface;
|
protected $lazyInterface;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
protected $testObject;
|
protected $testObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles execution of a lazily created interface
|
||||||
|
*/
|
||||||
|
public function testReturnsFragmentsWithLazyCreatedInterface() : void
|
||||||
|
{
|
||||||
|
$request = '
|
||||||
|
{
|
||||||
|
lazyInterface {
|
||||||
|
... on TestObject {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
';
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => [
|
||||||
|
'lazyInterface' => ['name' => 'testname'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, Executor::execute($this->schema, Parser::parse($request))->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup schema
|
* Setup schema
|
||||||
*/
|
*/
|
||||||
@ -44,10 +66,10 @@ class LazyInterfaceTest extends TestCase
|
|||||||
'type' => $this->getLazyInterfaceType(),
|
'type' => $this->getLazyInterfaceType(),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [];
|
return [];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->schema = new Schema(['query' => $query, 'types' => [$this->getTestObjectType()]]);
|
$this->schema = new Schema(['query' => $query, 'types' => [$this->getTestObjectType()]]);
|
||||||
@ -64,7 +86,7 @@ class LazyInterfaceTest extends TestCase
|
|||||||
$this->lazyInterface = new InterfaceType([
|
$this->lazyInterface = new InterfaceType([
|
||||||
'name' => 'LazyInterface',
|
'name' => 'LazyInterface',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => Type::string()
|
'a' => Type::string(),
|
||||||
],
|
],
|
||||||
'resolveType' => function () {
|
'resolveType' => function () {
|
||||||
return $this->getTestObjectType();
|
return $this->getTestObjectType();
|
||||||
@ -89,39 +111,13 @@ class LazyInterfaceTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return 'testname';
|
return 'testname';
|
||||||
}
|
},
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'interfaces' => [$this->getLazyInterfaceType()]
|
],
|
||||||
|
'interfaces' => [$this->getLazyInterfaceType()],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->testObject;
|
return $this->testObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles execution of a lazily created interface
|
|
||||||
*/
|
|
||||||
public function testReturnsFragmentsWithLazyCreatedInterface() : void
|
|
||||||
{
|
|
||||||
$request = '
|
|
||||||
{
|
|
||||||
lazyInterface {
|
|
||||||
... on TestObject {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
';
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'data' => [
|
|
||||||
'lazyInterface' => [
|
|
||||||
'name' => 'testname'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, Parser::parse($request))->toArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class ListsTest extends TestCase
|
class ListsTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: Execute: Handles list nullability
|
// Describe: Execute: Handles list nullability
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T]
|
* [T]
|
||||||
*/
|
*/
|
||||||
@ -41,6 +40,40 @@ class ListsTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkHandlesNullableLists($testData, $expected)
|
||||||
|
{
|
||||||
|
$testType = Type::listOf(Type::int());
|
||||||
|
$this->check($testType, $testData, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function check($testType, $testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$data = ['test' => $testData];
|
||||||
|
$dataType = null;
|
||||||
|
|
||||||
|
$dataType = new ObjectType([
|
||||||
|
'name' => 'DataType',
|
||||||
|
'fields' => function () use (&$testType, &$dataType, $data) {
|
||||||
|
return [
|
||||||
|
'test' => ['type' => $testType],
|
||||||
|
'nest' => [
|
||||||
|
'type' => $dataType,
|
||||||
|
'resolve' => function () use ($data) {
|
||||||
|
return $data;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$schema = new Schema(['query' => $dataType]);
|
||||||
|
|
||||||
|
$ast = Parser::parse('{ nest { test } }');
|
||||||
|
|
||||||
|
$result = Executor::execute($schema, $ast, $data);
|
||||||
|
$this->assertArraySubset($expected, $result->toArray($debug));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T]
|
* [T]
|
||||||
*/
|
*/
|
||||||
@ -83,9 +116,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -103,16 +136,23 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})],
|
}),
|
||||||
|
],
|
||||||
['data' => ['nest' => ['test' => [1, 2]]]]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
[
|
[
|
||||||
new Deferred(function() {return 1;}),
|
new Deferred(function () {
|
||||||
new Deferred(function() {return null;}),
|
return 1;
|
||||||
new Deferred(function() {return 2;})
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return 2;
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
@ -137,7 +177,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -146,9 +186,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test', 1]
|
'path' => ['nest', 'test', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -178,14 +218,20 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkHandlesNonNullableLists($testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$testType = Type::nonNull(Type::listOf(Type::int()));
|
||||||
|
$this->check($testType, $testData, $expected, $debug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T]!
|
* [T]!
|
||||||
*/
|
*/
|
||||||
@ -215,9 +261,9 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -235,9 +281,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -255,7 +301,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
['data' => ['nest' => ['test' => [1, 2]]]]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
@ -271,7 +317,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
@ -288,7 +334,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -297,9 +343,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test', 1]
|
'path' => ['nest', 'test', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -323,9 +369,9 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -337,6 +383,12 @@ class ListsTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkHandlesListOfNonNulls($testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$testType = Type::listOf(Type::nonNull(Type::int()));
|
||||||
|
$this->check($testType, $testData, $expected, $debug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T!]
|
* [T!]
|
||||||
*/
|
*/
|
||||||
@ -360,9 +412,9 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -388,9 +440,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -408,7 +460,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
['data' => ['nest' => ['test' => [1, 2]]]]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
@ -416,9 +468,15 @@ class ListsTest extends TestCase
|
|||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
[
|
[
|
||||||
new Deferred(function() {return 1;}),
|
new Deferred(function () {
|
||||||
new Deferred(function() {return null;}),
|
return 1;
|
||||||
new Deferred(function() {return 2;})
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return 2;
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
['data' => ['nest' => ['test' => null]]]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
@ -435,7 +493,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -444,9 +502,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test', 1]
|
'path' => ['nest', 'test', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -462,7 +520,6 @@ class ListsTest extends TestCase
|
|||||||
['data' => ['nest' => ['test' => [1, 2]]]]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
[1, null, 2],
|
[1, null, 2],
|
||||||
@ -471,9 +528,9 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10 ]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -486,14 +543,20 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkHandlesNonNullListOfNonNulls($testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$testType = Type::nonNull(Type::listOf(Type::nonNull(Type::int())));
|
||||||
|
$this->check($testType, $testData, $expected, $debug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T!]!
|
* [T!]!
|
||||||
*/
|
*/
|
||||||
@ -517,9 +580,9 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -534,9 +597,9 @@ class ListsTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -554,9 +617,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -574,7 +637,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
['data' => ['nest' => ['test' => [1, 2]]]]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
@ -591,16 +654,16 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'data' => ['nest' => null],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -617,7 +680,7 @@ class ListsTest extends TestCase
|
|||||||
}),
|
}),
|
||||||
new Deferred(function () {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -626,66 +689,10 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkHandlesNullableLists($testData, $expected)
|
|
||||||
{
|
|
||||||
$testType = Type::listOf(Type::int());
|
|
||||||
$this->check($testType, $testData, $expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkHandlesNonNullableLists($testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$testType = Type::nonNull(Type::listOf(Type::int()));
|
|
||||||
$this->check($testType, $testData, $expected, $debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkHandlesListOfNonNulls($testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$testType = Type::listOf(Type::nonNull(Type::int()));
|
|
||||||
$this->check($testType, $testData, $expected, $debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkHandlesNonNullListOfNonNulls($testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$testType = Type::nonNull(Type::listOf(Type::nonNull(Type::int())));
|
|
||||||
$this->check($testType, $testData, $expected, $debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function check($testType, $testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$data = ['test' => $testData];
|
|
||||||
$dataType = null;
|
|
||||||
|
|
||||||
$dataType = new ObjectType([
|
|
||||||
'name' => 'DataType',
|
|
||||||
'fields' => function () use (&$testType, &$dataType, $data) {
|
|
||||||
return [
|
|
||||||
'test' => [
|
|
||||||
'type' => $testType
|
|
||||||
],
|
|
||||||
'nest' => [
|
|
||||||
'type' => $dataType,
|
|
||||||
'resolve' => function () use ($data) {
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
$schema = new Schema([
|
|
||||||
'query' => $dataType
|
|
||||||
]);
|
|
||||||
|
|
||||||
$ast = Parser::parse('{ nest { test } }');
|
|
||||||
|
|
||||||
$result = Executor::execute($schema, $ast, $data);
|
|
||||||
$this->assertArraySubset($expected, $result->toArray($debug));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Tests\Executor\TestClasses\Root;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class MutationsTest extends TestCase
|
class MutationsTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: Handles mutation execution ordering
|
// Execute: Handles mutation execution ordering
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('evaluates mutations serially')
|
* @see it('evaluates mutations serially')
|
||||||
*/
|
*/
|
||||||
@ -42,26 +41,69 @@ class MutationsTest extends TestCase
|
|||||||
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'first' => [
|
'first' => ['theNumber' => 1],
|
||||||
'theNumber' => 1
|
'second' => ['theNumber' => 2],
|
||||||
|
'third' => ['theNumber' => 3],
|
||||||
|
'fourth' => ['theNumber' => 4],
|
||||||
|
'fifth' => ['theNumber' => 5],
|
||||||
],
|
],
|
||||||
'second' => [
|
|
||||||
'theNumber' => 2
|
|
||||||
],
|
|
||||||
'third' => [
|
|
||||||
'theNumber' => 3
|
|
||||||
],
|
|
||||||
'fourth' => [
|
|
||||||
'theNumber' => 4
|
|
||||||
],
|
|
||||||
'fifth' => [
|
|
||||||
'theNumber' => 5
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $mutationResult->toArray());
|
$this->assertEquals($expected, $mutationResult->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function schema() : Schema
|
||||||
|
{
|
||||||
|
$numberHolderType = new ObjectType([
|
||||||
|
'fields' => [
|
||||||
|
'theNumber' => ['type' => Type::int()],
|
||||||
|
],
|
||||||
|
'name' => 'NumberHolder',
|
||||||
|
]);
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'fields' => [
|
||||||
|
'numberHolder' => ['type' => $numberHolderType],
|
||||||
|
],
|
||||||
|
'name' => 'Query',
|
||||||
|
]),
|
||||||
|
'mutation' => new ObjectType([
|
||||||
|
'fields' => [
|
||||||
|
'immediatelyChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
return $obj->immediatelyChangeTheNumber($args['newNumber']);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'promiseToChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
return $obj->promiseToChangeTheNumber($args['newNumber']);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'failToChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
$obj->failToChangeTheNumber();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'promiseAndFailToChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
return $obj->promiseAndFailToChangeTheNumber();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'name' => 'Mutation',
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('evaluates mutations correctly in the presense of a failed mutation')
|
* @see it('evaluates mutations correctly in the presense of a failed mutation')
|
||||||
*/
|
*/
|
||||||
@ -91,143 +133,24 @@ class MutationsTest extends TestCase
|
|||||||
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'first' => [
|
'first' => ['theNumber' => 1],
|
||||||
'theNumber' => 1
|
'second' => ['theNumber' => 2],
|
||||||
],
|
|
||||||
'second' => [
|
|
||||||
'theNumber' => 2
|
|
||||||
],
|
|
||||||
'third' => null,
|
'third' => null,
|
||||||
'fourth' => [
|
'fourth' => ['theNumber' => 4],
|
||||||
'theNumber' => 4
|
'fifth' => ['theNumber' => 5],
|
||||||
],
|
|
||||||
'fifth' => [
|
|
||||||
'theNumber' => 5
|
|
||||||
],
|
|
||||||
'sixth' => null,
|
'sixth' => null,
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot change the number',
|
'debugMessage' => 'Cannot change the number',
|
||||||
'locations' => [['line' => 8, 'column' => 7]]
|
'locations' => [['line' => 8, 'column' => 7]],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot change the number',
|
'debugMessage' => 'Cannot change the number',
|
||||||
'locations' => [['line' => 17, 'column' => 7]]
|
'locations' => [['line' => 17, 'column' => 7]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $mutationResult->toArray(true));
|
$this->assertArraySubset($expected, $mutationResult->toArray(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function schema()
|
|
||||||
{
|
|
||||||
$numberHolderType = new ObjectType([
|
|
||||||
'fields' => [
|
|
||||||
'theNumber' => ['type' => Type::int()],
|
|
||||||
],
|
|
||||||
'name' => 'NumberHolder',
|
|
||||||
]);
|
|
||||||
$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'fields' => [
|
|
||||||
'numberHolder' => ['type' => $numberHolderType],
|
|
||||||
],
|
|
||||||
'name' => 'Query',
|
|
||||||
]),
|
|
||||||
'mutation' => new ObjectType([
|
|
||||||
'fields' => [
|
|
||||||
'immediatelyChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->immediatelyChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
'promiseToChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->promiseToChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
'failToChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->failToChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
'promiseAndFailToChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->promiseAndFailToChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'name' => 'Mutation',
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumberHolder
|
|
||||||
{
|
|
||||||
public $theNumber;
|
|
||||||
|
|
||||||
public function __construct($originalNumber)
|
|
||||||
{
|
|
||||||
$this->theNumber = $originalNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Root {
|
|
||||||
public $numberHolder;
|
|
||||||
|
|
||||||
public function __construct($originalNumber)
|
|
||||||
{
|
|
||||||
$this->numberHolder = new NumberHolder($originalNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $newNumber
|
|
||||||
* @return NumberHolder
|
|
||||||
*/
|
|
||||||
public function immediatelyChangeTheNumber($newNumber)
|
|
||||||
{
|
|
||||||
$this->numberHolder->theNumber = $newNumber;
|
|
||||||
return $this->numberHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $newNumber
|
|
||||||
*
|
|
||||||
* @return Deferred
|
|
||||||
*/
|
|
||||||
public function promiseToChangeTheNumber($newNumber)
|
|
||||||
{
|
|
||||||
return new Deferred(function () use ($newNumber) {
|
|
||||||
return $this->immediatelyChangeTheNumber($newNumber);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function failToChangeTheNumber()
|
|
||||||
{
|
|
||||||
throw new \Exception('Cannot change the number');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Deferred
|
|
||||||
*/
|
|
||||||
public function promiseAndFailToChangeTheNumber()
|
|
||||||
{
|
|
||||||
return new Deferred(function () {
|
|
||||||
throw new \Exception("Cannot change the number");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
|
use GraphQL\Error\FormattedError;
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class NonNullTest extends TestCase
|
class NonNullTest extends TestCase
|
||||||
@ -27,8 +29,13 @@ class NonNullTest extends TestCase
|
|||||||
/** @var \Exception */
|
/** @var \Exception */
|
||||||
public $promiseNonNullError;
|
public $promiseNonNullError;
|
||||||
|
|
||||||
|
/** @var callable[] */
|
||||||
public $throwingData;
|
public $throwingData;
|
||||||
|
|
||||||
|
/** @var callable[] */
|
||||||
public $nullingData;
|
public $nullingData;
|
||||||
|
|
||||||
|
/** @var Schema */
|
||||||
public $schema;
|
public $schema;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -121,7 +128,7 @@ class NonNullTest extends TestCase
|
|||||||
'promiseNest' => $dataType,
|
'promiseNest' => $dataType,
|
||||||
'promiseNonNullNest' => Type::nonNull($dataType),
|
'promiseNonNullNest' => Type::nonNull($dataType),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->schema = new Schema(['query' => $dataType]);
|
$this->schema = new Schema(['query' => $dataType]);
|
||||||
@ -143,17 +150,18 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['sync' => null],
|
||||||
'sync' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create(
|
FormattedError::create(
|
||||||
$this->syncError->getMessage(),
|
$this->syncError->getMessage(),
|
||||||
[new SourceLocation(3, 9)]
|
[new SourceLocation(3, 9)]
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsANullableFieldThatThrowsInAPromise() : void
|
public function testNullsANullableFieldThatThrowsInAPromise() : void
|
||||||
@ -167,18 +175,19 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promise' => null],
|
||||||
'promise' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create(
|
FormattedError::create(
|
||||||
$this->promiseError->getMessage(),
|
$this->promiseError->getMessage(),
|
||||||
[new SourceLocation(3, 9)]
|
[new SourceLocation(3, 9)]
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
||||||
@ -195,14 +204,15 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsAsynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
public function testNullsAsynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
||||||
@ -218,15 +228,16 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
||||||
@ -242,15 +253,16 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
||||||
@ -266,15 +278,16 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -353,10 +366,13 @@ class NonNullTest extends TestCase
|
|||||||
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(17, 11)]),
|
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(17, 11)]),
|
||||||
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(20, 13)]),
|
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(20, 13)]),
|
||||||
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(24, 13)]),
|
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(24, 13)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsTheFirstNullableObjectAfterAFieldThrowsInALongChainOfFieldsThatAreNonNull() : void
|
public function testNullsTheFirstNullableObjectAfterAFieldThrowsInALongChainOfFieldsThatAreNonNull() : void
|
||||||
@ -424,10 +440,13 @@ class NonNullTest extends TestCase
|
|||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(19, 19)]),
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(19, 19)]),
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(30, 19)]),
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(30, 19)]),
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(41, 19)]),
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(41, 19)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsANullableFieldThatSynchronouslyReturnsNull() : void
|
public function testNullsANullableFieldThatSynchronouslyReturnsNull() : void
|
||||||
@ -441,11 +460,12 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['sync' => null],
|
||||||
'sync' => null,
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray());
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsANullableFieldThatReturnsNullInAPromise() : void
|
public function testNullsANullableFieldThatReturnsNullInAPromise() : void
|
||||||
@ -459,12 +479,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promise' => null],
|
||||||
'promise' => null,
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullSynchronously() : void
|
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullSynchronously() : void
|
||||||
@ -480,17 +501,18 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray(true));
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray(true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullInAPromise() : void
|
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullInAPromise() : void
|
||||||
@ -506,15 +528,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -536,15 +556,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -566,15 +584,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -628,7 +644,7 @@ class NonNullTest extends TestCase
|
|||||||
'promiseNest' => [
|
'promiseNest' => [
|
||||||
'sync' => null,
|
'sync' => null,
|
||||||
'promise' => null,
|
'promise' => null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'promiseNest' => [
|
'promiseNest' => [
|
||||||
'sync' => null,
|
'sync' => null,
|
||||||
@ -640,9 +656,9 @@ class NonNullTest extends TestCase
|
|||||||
'promiseNest' => [
|
'promiseNest' => [
|
||||||
'sync' => null,
|
'sync' => null,
|
||||||
'promise' => null,
|
'promise' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$actual = Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray();
|
$actual = Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray();
|
||||||
@ -714,7 +730,7 @@ class NonNullTest extends TestCase
|
|||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.', 'locations' => [['line' => 19, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.', 'locations' => [['line' => 19, 'column' => 19]]],
|
||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [['line' => 30, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [['line' => 30, 'column' => 19]]],
|
||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [['line' => 41, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [['line' => 41, 'column' => 19]]],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -734,8 +750,8 @@ class NonNullTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(2, 17)])
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(2, 17)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$actual = Executor::execute($this->schema, Parser::parse($doc), $this->throwingData)->toArray();
|
$actual = Executor::execute($this->schema, Parser::parse($doc), $this->throwingData)->toArray();
|
||||||
$this->assertArraySubset($expected, $actual);
|
$this->assertArraySubset($expected, $actual);
|
||||||
@ -752,10 +768,13 @@ class NonNullTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(2, 17)]),
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(2, 17)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsTheTopLevelIfSyncNonNullableFieldReturnsNull() : void
|
public function testNullsTheTopLevelIfSyncNonNullableFieldReturnsNull() : void
|
||||||
@ -769,9 +788,9 @@ class NonNullTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]]
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
$expected,
|
$expected,
|
||||||
@ -791,9 +810,9 @@ class NonNullTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]]
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor\Promise;
|
namespace GraphQL\Tests\Executor\Promise;
|
||||||
|
|
||||||
|
|
||||||
use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter;
|
use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter;
|
||||||
use GraphQL\Executor\Promise\Promise;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use React\Promise\Deferred;
|
use React\Promise\Deferred;
|
||||||
use React\Promise\FulfilledPromise;
|
use React\Promise\FulfilledPromise;
|
||||||
use React\Promise\LazyPromise;
|
use React\Promise\LazyPromise;
|
||||||
use React\Promise\Promise as ReactPromise;
|
use React\Promise\Promise as ReactPromise;
|
||||||
use React\Promise\RejectedPromise;
|
use React\Promise\RejectedPromise;
|
||||||
|
use function class_exists;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group ReactPromise
|
* @group ReactPromise
|
||||||
@ -20,19 +20,29 @@ class ReactPromiseAdapterTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
if(! class_exists('React\Promise\Promise')) {
|
if (class_exists('React\Promise\Promise')) {
|
||||||
$this->markTestSkipped('react/promise package must be installed to run GraphQL\Tests\Executor\Promise\ReactPromiseAdapterTest');
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->markTestSkipped('react/promise package must be installed to run GraphQL\Tests\Executor\Promise\ReactPromiseAdapterTest');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsThenableReturnsTrueWhenAReactPromiseIsGiven() : void
|
public function testIsThenableReturnsTrueWhenAReactPromiseIsGiven() : void
|
||||||
{
|
{
|
||||||
$reactAdapter = new ReactPromiseAdapter();
|
$reactAdapter = new ReactPromiseAdapter();
|
||||||
|
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new ReactPromise(function() {})));
|
$this->assertSame(
|
||||||
|
true,
|
||||||
|
$reactAdapter->isThenable(new ReactPromise(function () {
|
||||||
|
}))
|
||||||
|
);
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new FulfilledPromise()));
|
$this->assertSame(true, $reactAdapter->isThenable(new FulfilledPromise()));
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new RejectedPromise()));
|
$this->assertSame(true, $reactAdapter->isThenable(new RejectedPromise()));
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new LazyPromise(function() {})));
|
$this->assertSame(
|
||||||
|
true,
|
||||||
|
$reactAdapter->isThenable(new LazyPromise(function () {
|
||||||
|
}))
|
||||||
|
);
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(false));
|
$this->assertSame(false, $reactAdapter->isThenable(false));
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(true));
|
$this->assertSame(false, $reactAdapter->isThenable(true));
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(1));
|
$this->assertSame(false, $reactAdapter->isThenable(1));
|
||||||
@ -62,9 +72,12 @@ class ReactPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
$result = null;
|
$result = null;
|
||||||
|
|
||||||
$resultPromise = $reactAdapter->then($promise, function ($value) use (&$result) {
|
$resultPromise = $reactAdapter->then(
|
||||||
|
$promise,
|
||||||
|
function ($value) use (&$result) {
|
||||||
$result = $value;
|
$result = $value;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertSame(1, $result);
|
$this->assertSame(1, $result);
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $resultPromise);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $resultPromise);
|
||||||
@ -117,9 +130,12 @@ class ReactPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
$exception = null;
|
$exception = null;
|
||||||
|
|
||||||
$rejectedPromise->then(null, function ($error) use (&$exception) {
|
$rejectedPromise->then(
|
||||||
|
null,
|
||||||
|
function ($error) use (&$exception) {
|
||||||
$exception = $error;
|
$exception = $error;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf('\Exception', $exception);
|
$this->assertInstanceOf('\Exception', $exception);
|
||||||
$this->assertEquals('I am a bad promise', $exception->getMessage());
|
$this->assertEquals('I am a bad promise', $exception->getMessage());
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor\Promise;
|
namespace GraphQL\Tests\Executor\Promise;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
@ -10,9 +13,7 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class SyncPromiseAdapterTest extends TestCase
|
class SyncPromiseAdapterTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var SyncPromiseAdapter */
|
||||||
* @var SyncPromiseAdapter
|
|
||||||
*/
|
|
||||||
private $promises;
|
private $promises;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -22,7 +23,11 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testIsThenable() : void
|
public function testIsThenable() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals(true, $this->promises->isThenable(new Deferred(function() {})));
|
$this->assertEquals(
|
||||||
|
true,
|
||||||
|
$this->promises->isThenable(new Deferred(function () {
|
||||||
|
}))
|
||||||
|
);
|
||||||
$this->assertEquals(false, $this->promises->isThenable(false));
|
$this->assertEquals(false, $this->promises->isThenable(false));
|
||||||
$this->assertEquals(false, $this->promises->isThenable(true));
|
$this->assertEquals(false, $this->promises->isThenable(true));
|
||||||
$this->assertEquals(false, $this->promises->isThenable(1));
|
$this->assertEquals(false, $this->promises->isThenable(1));
|
||||||
@ -35,7 +40,8 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testConvert() : void
|
public function testConvert() : void
|
||||||
{
|
{
|
||||||
$dfd = new Deferred(function() {});
|
$dfd = new Deferred(function () {
|
||||||
|
});
|
||||||
$result = $this->promises->convertThenable($dfd);
|
$result = $this->promises->convertThenable($dfd);
|
||||||
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $result);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $result);
|
||||||
@ -48,7 +54,8 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testThen() : void
|
public function testThen() : void
|
||||||
{
|
{
|
||||||
$dfd = new Deferred(function() {});
|
$dfd = new Deferred(function () {
|
||||||
|
});
|
||||||
$promise = $this->promises->convertThenable($dfd);
|
$promise = $this->promises->convertThenable($dfd);
|
||||||
|
|
||||||
$result = $this->promises->then($promise);
|
$result = $this->promises->then($promise);
|
||||||
@ -59,7 +66,8 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testCreatePromise() : void
|
public function testCreatePromise() : void
|
||||||
{
|
{
|
||||||
$promise = $this->promises->create(function($resolve, $reject) {});
|
$promise = $this->promises->create(function ($resolve, $reject) {
|
||||||
|
});
|
||||||
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
||||||
@ -71,6 +79,42 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$this->assertValidPromise($promise, null, 'A', SyncPromise::FULFILLED);
|
$this->assertValidPromise($promise, null, 'A', SyncPromise::FULFILLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertValidPromise($promise, $expectedNextReason, $expectedNextValue, $expectedNextState)
|
||||||
|
{
|
||||||
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
||||||
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
||||||
|
|
||||||
|
$actualNextValue = null;
|
||||||
|
$actualNextReason = null;
|
||||||
|
$onFulfilledCalled = false;
|
||||||
|
$onRejectedCalled = false;
|
||||||
|
|
||||||
|
$promise->then(
|
||||||
|
function ($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
||||||
|
$onFulfilledCalled = true;
|
||||||
|
$actualNextValue = $nextValue;
|
||||||
|
},
|
||||||
|
function (\Throwable $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
||||||
|
$onRejectedCalled = true;
|
||||||
|
$actualNextReason = $reason->getMessage();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame($onFulfilledCalled, false);
|
||||||
|
$this->assertSame($onRejectedCalled, false);
|
||||||
|
|
||||||
|
SyncPromise::runQueue();
|
||||||
|
|
||||||
|
if ($expectedNextState !== SyncPromise::PENDING) {
|
||||||
|
$this->assertSame(! $expectedNextReason, $onFulfilledCalled);
|
||||||
|
$this->assertSame(! ! $expectedNextReason, $onRejectedCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertSame($expectedNextValue, $actualNextValue);
|
||||||
|
$this->assertSame($expectedNextReason, $actualNextReason);
|
||||||
|
$this->assertSame($expectedNextState, $promise->adoptedPromise->state);
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreateFulfilledPromise() : void
|
public function testCreateFulfilledPromise() : void
|
||||||
{
|
{
|
||||||
$promise = $this->promises->createFulfilled('test');
|
$promise = $this->promises->createFulfilled('test');
|
||||||
@ -105,7 +149,7 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
new Promise($promise2, $this->promises),
|
new Promise($promise2, $this->promises),
|
||||||
3,
|
3,
|
||||||
new Promise($promise3, $this->promises),
|
new Promise($promise3, $this->promises),
|
||||||
[]
|
[],
|
||||||
];
|
];
|
||||||
|
|
||||||
$promise = $this->promises->all($data);
|
$promise = $this->promises->all($data);
|
||||||
@ -114,7 +158,12 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$promise1->resolve('value1');
|
$promise1->resolve('value1');
|
||||||
$this->assertValidPromise($promise, null, null, SyncPromise::PENDING);
|
$this->assertValidPromise($promise, null, null, SyncPromise::PENDING);
|
||||||
$promise2->resolve('value2');
|
$promise2->resolve('value2');
|
||||||
$this->assertValidPromise($promise, null, ['1', 'value1', 'value2', 3, 'value2-value3', []], SyncPromise::FULFILLED);
|
$this->assertValidPromise(
|
||||||
|
$promise,
|
||||||
|
null,
|
||||||
|
['1', 'value1', 'value2', 3, 'value2-value3', []],
|
||||||
|
SyncPromise::FULFILLED
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWait() : void
|
public function testWait() : void
|
||||||
@ -123,10 +172,12 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
$deferred1 = new Deferred(function () use (&$called) {
|
$deferred1 = new Deferred(function () use (&$called) {
|
||||||
$called[] = 1;
|
$called[] = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
$deferred2 = new Deferred(function () use (&$called) {
|
$deferred2 = new Deferred(function () use (&$called) {
|
||||||
$called[] = 2;
|
$called[] = 2;
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -136,14 +187,17 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$p3 = $p2->then(function () use (&$called) {
|
$p3 = $p2->then(function () use (&$called) {
|
||||||
$dfd = new Deferred(function () use (&$called) {
|
$dfd = new Deferred(function () use (&$called) {
|
||||||
$called[] = 3;
|
$called[] = 3;
|
||||||
|
|
||||||
return 3;
|
return 3;
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this->promises->convertThenable($dfd);
|
return $this->promises->convertThenable($dfd);
|
||||||
});
|
});
|
||||||
|
|
||||||
$p4 = $p3->then(function () use (&$called) {
|
$p4 = $p3->then(function () use (&$called) {
|
||||||
return new Deferred(function () use (&$called) {
|
return new Deferred(function () use (&$called) {
|
||||||
$called[] = 4;
|
$called[] = 4;
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -162,40 +216,4 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$this->assertEquals([1, 2, 3, 4], $called);
|
$this->assertEquals([1, 2, 3, 4], $called);
|
||||||
$this->assertValidPromise($all, null, [0, 1, 2, 3, 4], SyncPromise::FULFILLED);
|
$this->assertValidPromise($all, null, [0, 1, 2, 3, 4], SyncPromise::FULFILLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertValidPromise($promise, $expectedNextReason, $expectedNextValue, $expectedNextState)
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
|
||||||
|
|
||||||
$actualNextValue = null;
|
|
||||||
$actualNextReason = null;
|
|
||||||
$onFulfilledCalled = false;
|
|
||||||
$onRejectedCalled = false;
|
|
||||||
|
|
||||||
$promise->then(
|
|
||||||
function($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
|
||||||
$onFulfilledCalled = true;
|
|
||||||
$actualNextValue = $nextValue;
|
|
||||||
},
|
|
||||||
function(\Exception $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
|
||||||
$onRejectedCalled = true;
|
|
||||||
$actualNextReason = $reason->getMessage();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertSame($onFulfilledCalled, false);
|
|
||||||
$this->assertSame($onRejectedCalled, false);
|
|
||||||
|
|
||||||
SyncPromise::runQueue();
|
|
||||||
|
|
||||||
if ($expectedNextState !== SyncPromise::PENDING) {
|
|
||||||
$this->assertSame(!$expectedNextReason, $onFulfilledCalled);
|
|
||||||
$this->assertSame(!!$expectedNextReason, $onRejectedCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertSame($expectedNextValue, $actualNextValue);
|
|
||||||
$this->assertSame($expectedNextReason, $actualNextReason);
|
|
||||||
$this->assertSame($expectedNextState, $promise->adoptedPromise->state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor\Promise;
|
namespace GraphQL\Tests\Executor\Promise;
|
||||||
|
|
||||||
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
||||||
use PHPUnit\Framework\Error\Error;
|
use PHPUnit\Framework\Error\Error;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function uniqid;
|
||||||
|
|
||||||
class SyncPromiseTest extends TestCase
|
class SyncPromiseTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -12,14 +16,17 @@ class SyncPromiseTest extends TestCase
|
|||||||
$onFulfilledReturnsNull = function () {
|
$onFulfilledReturnsNull = function () {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
$onFulfilledReturnsSameValue = function ($value) {
|
$onFulfilledReturnsSameValue = function ($value) {
|
||||||
return $value;
|
return $value;
|
||||||
};
|
};
|
||||||
|
|
||||||
$onFulfilledReturnsOtherValue = function ($value) {
|
$onFulfilledReturnsOtherValue = function ($value) {
|
||||||
return 'other-' . $value;
|
return 'other-' . $value;
|
||||||
};
|
};
|
||||||
|
|
||||||
$onFulfilledThrows = function ($value) {
|
$onFulfilledThrows = function ($value) {
|
||||||
throw new \Exception("onFulfilled throws this!");
|
throw new \Exception('onFulfilled throws this!');
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -28,7 +35,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
[uniqid(), $onFulfilledReturnsNull, null, null, SyncPromise::FULFILLED],
|
[uniqid(), $onFulfilledReturnsNull, null, null, SyncPromise::FULFILLED],
|
||||||
['test-value', $onFulfilledReturnsSameValue, 'test-value', null, SyncPromise::FULFILLED],
|
['test-value', $onFulfilledReturnsSameValue, 'test-value', null, SyncPromise::FULFILLED],
|
||||||
['test-value-2', $onFulfilledReturnsOtherValue, 'other-test-value-2', null, SyncPromise::FULFILLED],
|
['test-value-2', $onFulfilledReturnsOtherValue, 'other-test-value-2', null, SyncPromise::FULFILLED],
|
||||||
['test-value-3', $onFulfilledThrows, null, "onFulfilled throws this!", SyncPromise::REJECTED],
|
['test-value-3', $onFulfilledThrows, null, 'onFulfilled throws this!', SyncPromise::REJECTED],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +48,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -63,8 +69,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -85,21 +90,27 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
$promise->resolve($resolvedValue);
|
$promise->resolve($resolvedValue);
|
||||||
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
||||||
|
|
||||||
$nextPromise = $promise->then(null, function() {});
|
$nextPromise = $promise->then(
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
|
}
|
||||||
|
);
|
||||||
$this->assertSame($promise, $nextPromise);
|
$this->assertSame($promise, $nextPromise);
|
||||||
|
|
||||||
$onRejectedCalled = false;
|
$onRejectedCalled = false;
|
||||||
$nextPromise = $promise->then($onFulfilled, function () use (&$onRejectedCalled) {
|
$nextPromise = $promise->then(
|
||||||
|
$onFulfilled,
|
||||||
|
function () use (&$onRejectedCalled) {
|
||||||
$onRejectedCalled = true;
|
$onRejectedCalled = true;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if ($onFulfilled) {
|
if ($onFulfilled) {
|
||||||
$this->assertNotSame($promise, $nextPromise);
|
$this->assertNotSame($promise, $nextPromise);
|
||||||
@ -124,19 +135,57 @@ class SyncPromiseTest extends TestCase
|
|||||||
$this->assertValidPromise($nextPromise3, $expectedNextReason, $expectedNextValue, $expectedNextState);
|
$this->assertValidPromise($nextPromise3, $expectedNextReason, $expectedNextValue, $expectedNextState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertValidPromise(
|
||||||
|
SyncPromise $promise,
|
||||||
|
$expectedNextReason,
|
||||||
|
$expectedNextValue,
|
||||||
|
$expectedNextState
|
||||||
|
) {
|
||||||
|
$actualNextValue = null;
|
||||||
|
$actualNextReason = null;
|
||||||
|
$onFulfilledCalled = false;
|
||||||
|
$onRejectedCalled = false;
|
||||||
|
|
||||||
|
$promise->then(
|
||||||
|
function ($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
||||||
|
$onFulfilledCalled = true;
|
||||||
|
$actualNextValue = $nextValue;
|
||||||
|
},
|
||||||
|
function (\Throwable $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
||||||
|
$onRejectedCalled = true;
|
||||||
|
$actualNextReason = $reason->getMessage();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($onFulfilledCalled, false);
|
||||||
|
$this->assertEquals($onRejectedCalled, false);
|
||||||
|
|
||||||
|
SyncPromise::runQueue();
|
||||||
|
|
||||||
|
$this->assertEquals(! $expectedNextReason, $onFulfilledCalled);
|
||||||
|
$this->assertEquals(! ! $expectedNextReason, $onRejectedCalled);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedNextValue, $actualNextValue);
|
||||||
|
$this->assertEquals($expectedNextReason, $actualNextReason);
|
||||||
|
$this->assertEquals($expectedNextState, $promise->state);
|
||||||
|
}
|
||||||
|
|
||||||
public function getRejectedPromiseData()
|
public function getRejectedPromiseData()
|
||||||
{
|
{
|
||||||
$onRejectedReturnsNull = function () {
|
$onRejectedReturnsNull = function () {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
$onRejectedReturnsSomeValue = function ($reason) {
|
$onRejectedReturnsSomeValue = function ($reason) {
|
||||||
return 'some-value';
|
return 'some-value';
|
||||||
};
|
};
|
||||||
|
|
||||||
$onRejectedThrowsSameReason = function ($reason) {
|
$onRejectedThrowsSameReason = function ($reason) {
|
||||||
throw $reason;
|
throw $reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
$onRejectedThrowsOtherReason = function ($value) {
|
$onRejectedThrowsOtherReason = function ($value) {
|
||||||
throw new \Exception("onRejected throws other!");
|
throw new \Exception('onRejected throws other!');
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -158,8 +207,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -169,7 +217,6 @@ class SyncPromiseTest extends TestCase
|
|||||||
$this->expectException(\Throwable::class);
|
$this->expectException(\Throwable::class);
|
||||||
$this->expectExceptionMessage('Cannot change rejection reason');
|
$this->expectExceptionMessage('Cannot change rejection reason');
|
||||||
$promise->reject(new \Exception('other-reason'));
|
$promise->reject(new \Exception('other-reason'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,8 +228,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -203,8 +249,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -214,18 +259,22 @@ class SyncPromiseTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
$promise->reject(new \Exception('other-reason'));
|
$promise->reject(new \Exception('other-reason'));
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals('Cannot change rejection reason', $e->getMessage());
|
$this->assertEquals('Cannot change rejection reason', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$promise->resolve('anything');
|
$promise->resolve('anything');
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals('Cannot resolve rejected promise', $e->getMessage());
|
$this->assertEquals('Cannot resolve rejected promise', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$nextPromise = $promise->then(function() {}, null);
|
$nextPromise = $promise->then(
|
||||||
|
function () {
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
$this->assertSame($promise, $nextPromise);
|
$this->assertSame($promise, $nextPromise);
|
||||||
|
|
||||||
$onFulfilledCalled = false;
|
$onFulfilledCalled = false;
|
||||||
@ -266,7 +315,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
$promise->resolve($promise);
|
$promise->resolve($promise);
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals('Cannot resolve promise with self', $e->getMessage());
|
$this->assertEquals('Cannot resolve promise with self', $e->getMessage());
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
}
|
}
|
||||||
@ -299,24 +348,25 @@ class SyncPromiseTest extends TestCase
|
|||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$promise->reject(new \Exception("Rejected Reason"));
|
$promise->reject(new \Exception('Rejected Reason'));
|
||||||
$this->assertValidPromise($promise, "Rejected Reason", null, SyncPromise::REJECTED);
|
$this->assertValidPromise($promise, 'Rejected Reason', null, SyncPromise::REJECTED);
|
||||||
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$promise2 = $promise->then(null, function() {
|
$promise2 = $promise->then(
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
return 'value';
|
return 'value';
|
||||||
});
|
}
|
||||||
$promise->reject(new \Exception("Rejected Again"));
|
);
|
||||||
|
$promise->reject(new \Exception('Rejected Again'));
|
||||||
$this->assertValidPromise($promise2, null, 'value', SyncPromise::FULFILLED);
|
$this->assertValidPromise($promise2, null, 'value', SyncPromise::FULFILLED);
|
||||||
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$promise2 = $promise->then();
|
$promise2 = $promise->then();
|
||||||
$promise->reject(new \Exception("Rejected Once Again"));
|
$promise->reject(new \Exception('Rejected Once Again'));
|
||||||
$this->assertValidPromise($promise2, "Rejected Once Again", null, SyncPromise::REJECTED);
|
$this->assertValidPromise($promise2, 'Rejected Once Again', null, SyncPromise::REJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPendingPromiseThen() : void
|
public function testPendingPromiseThen() : void
|
||||||
@ -334,8 +384,10 @@ class SyncPromiseTest extends TestCase
|
|||||||
$onRejectedCount = 0;
|
$onRejectedCount = 0;
|
||||||
$onFulfilled = function ($value) use (&$onFulfilledCount) {
|
$onFulfilled = function ($value) use (&$onFulfilledCount) {
|
||||||
$onFulfilledCount++;
|
$onFulfilledCount++;
|
||||||
|
|
||||||
return $onFulfilledCount;
|
return $onFulfilledCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
$onRejected = function ($reason) use (&$onRejectedCount) {
|
$onRejected = function ($reason) use (&$onRejectedCount) {
|
||||||
$onRejectedCount++;
|
$onRejectedCount++;
|
||||||
throw $reason;
|
throw $reason;
|
||||||
@ -367,35 +419,4 @@ class SyncPromiseTest extends TestCase
|
|||||||
$this->assertValidPromise($nextPromise3, null, 2, SyncPromise::FULFILLED);
|
$this->assertValidPromise($nextPromise3, null, 2, SyncPromise::FULFILLED);
|
||||||
$this->assertValidPromise($nextPromise4, null, 3, SyncPromise::FULFILLED);
|
$this->assertValidPromise($nextPromise4, null, 3, SyncPromise::FULFILLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertValidPromise(SyncPromise $promise, $expectedNextReason, $expectedNextValue, $expectedNextState)
|
|
||||||
{
|
|
||||||
$actualNextValue = null;
|
|
||||||
$actualNextReason = null;
|
|
||||||
$onFulfilledCalled = false;
|
|
||||||
$onRejectedCalled = false;
|
|
||||||
|
|
||||||
$promise->then(
|
|
||||||
function($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
|
||||||
$onFulfilledCalled = true;
|
|
||||||
$actualNextValue = $nextValue;
|
|
||||||
},
|
|
||||||
function(\Exception $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
|
||||||
$onRejectedCalled = true;
|
|
||||||
$actualNextReason = $reason->getMessage();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals($onFulfilledCalled, false);
|
|
||||||
$this->assertEquals($onRejectedCalled, false);
|
|
||||||
|
|
||||||
SyncPromise::runQueue();
|
|
||||||
|
|
||||||
$this->assertEquals(!$expectedNextReason, $onFulfilledCalled);
|
|
||||||
$this->assertEquals(!!$expectedNextReason, $onRejectedCalled);
|
|
||||||
|
|
||||||
$this->assertEquals($expectedNextValue, $actualNextValue);
|
|
||||||
$this->assertEquals($expectedNextReason, $actualNextReason);
|
|
||||||
$this->assertEquals($expectedNextState, $promise->state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Adder;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function json_encode;
|
||||||
|
use function uniqid;
|
||||||
|
|
||||||
class ResolveTest extends TestCase
|
class ResolveTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: resolve function
|
// Execute: resolve function
|
||||||
|
|
||||||
private function buildSchema($testField)
|
|
||||||
{
|
|
||||||
return new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => [
|
|
||||||
'test' => $testField
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('default function accesses properties')
|
* @see it('default function accesses properties')
|
||||||
*/
|
*/
|
||||||
@ -32,9 +24,7 @@ class ResolveTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = $this->buildSchema(['type' => Type::string()]);
|
$schema = $this->buildSchema(['type' => Type::string()]);
|
||||||
|
|
||||||
$source = [
|
$source = ['test' => 'testValue'];
|
||||||
'test' => 'testValue'
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['data' => ['test' => 'testValue']],
|
['data' => ['test' => 'testValue']],
|
||||||
@ -42,6 +32,16 @@ class ResolveTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildSchema($testField)
|
||||||
|
{
|
||||||
|
return new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => ['test' => $testField],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('default function calls methods')
|
* @see it('default function calls methods')
|
||||||
*/
|
*/
|
||||||
@ -53,7 +53,7 @@ class ResolveTest extends TestCase
|
|||||||
$source = [
|
$source = [
|
||||||
'test' => function () use ($_secret) {
|
'test' => function () use ($_secret) {
|
||||||
return $_secret;
|
return $_secret;
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['data' => ['test' => $_secret]],
|
['data' => ['test' => $_secret]],
|
||||||
@ -92,7 +92,7 @@ class ResolveTest extends TestCase
|
|||||||
],
|
],
|
||||||
'resolve' => function ($source, $args) {
|
'resolve' => function ($source, $args) {
|
||||||
return json_encode([$source, $args]);
|
return json_encode([$source, $args]);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Error\FormattedError;
|
use GraphQL\Error\FormattedError;
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
@ -36,7 +38,7 @@ class SyncTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($rootValue) {
|
'resolve' => function ($rootValue) {
|
||||||
return $rootValue;
|
return $rootValue;
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'asyncField' => [
|
'asyncField' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
@ -44,9 +46,9 @@ class SyncTest extends TestCase
|
|||||||
return new Deferred(function () use ($rootValue) {
|
return new Deferred(function () use ($rootValue) {
|
||||||
return $rootValue;
|
return $rootValue;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'mutation' => new ObjectType([
|
'mutation' => new ObjectType([
|
||||||
'name' => 'Mutation',
|
'name' => 'Mutation',
|
||||||
@ -55,11 +57,12 @@ class SyncTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($rootValue) {
|
'resolve' => function ($rootValue) {
|
||||||
return $rootValue;
|
return $rootValue;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->promiseAdapter = new SyncPromiseAdapter();
|
$this->promiseAdapter = new SyncPromiseAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +82,26 @@ class SyncTest extends TestCase
|
|||||||
$this->assertSync(['errors' => [['message' => 'Must provide an operation.']]], $result);
|
$this->assertSync(['errors' => [['message' => 'Must provide an operation.']]], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function execute($schema, $doc, $rootValue = null)
|
||||||
|
{
|
||||||
|
return Executor::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function assertSync($expectedFinalArray, $actualResult)
|
||||||
|
{
|
||||||
|
$message = 'Failed assertion that execution was synchronous';
|
||||||
|
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
||||||
|
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
||||||
|
$this->assertEquals(SyncPromise::FULFILLED, $actualResult->adoptedPromise->state, $message);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $actualResult->adoptedPromise->result, $message);
|
||||||
|
$this->assertArraySubset(
|
||||||
|
$expectedFinalArray,
|
||||||
|
$actualResult->adoptedPromise->result->toArray(),
|
||||||
|
false,
|
||||||
|
$message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not return a Promise if fields are all synchronous')
|
* @see it('does not return a Promise if fields are all synchronous')
|
||||||
*/
|
*/
|
||||||
@ -93,6 +116,8 @@ class SyncTest extends TestCase
|
|||||||
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: graphqlSync
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not return a Promise if mutation fields are all synchronous')
|
* @see it('does not return a Promise if mutation fields are all synchronous')
|
||||||
*/
|
*/
|
||||||
@ -121,7 +146,16 @@ class SyncTest extends TestCase
|
|||||||
$this->assertAsync(['data' => ['syncField' => 'rootValue', 'asyncField' => 'rootValue']], $result);
|
$this->assertAsync(['data' => ['syncField' => 'rootValue', 'asyncField' => 'rootValue']], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: graphqlSync
|
private function assertAsync($expectedFinalArray, $actualResult)
|
||||||
|
{
|
||||||
|
$message = 'Failed assertion that execution was asynchronous';
|
||||||
|
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
||||||
|
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
||||||
|
$this->assertEquals(SyncPromise::PENDING, $actualResult->adoptedPromise->state, $message);
|
||||||
|
$resolvedResult = $this->promiseAdapter->wait($actualResult);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $resolvedResult, $message);
|
||||||
|
$this->assertArraySubset($expectedFinalArray, $resolvedResult->toArray(), false, $message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not return a Promise for syntax errors')
|
* @see it('does not return a Promise for syntax errors')
|
||||||
@ -133,12 +167,22 @@ class SyncTest extends TestCase
|
|||||||
$this->schema,
|
$this->schema,
|
||||||
$doc
|
$doc
|
||||||
);
|
);
|
||||||
$this->assertSync([
|
$this->assertSync(
|
||||||
|
[
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['message' => 'Syntax Error: Expected Name, found {',
|
[
|
||||||
'locations' => [['line' => 1, 'column' => 29]]]
|
'message' => 'Syntax Error: Expected Name, found {',
|
||||||
]
|
'locations' => [['line' => 1, 'column' => 29]],
|
||||||
], $result);
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function graphqlSync($schema, $doc, $rootValue = null)
|
||||||
|
{
|
||||||
|
return GraphQL::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,9 +197,12 @@ class SyncTest extends TestCase
|
|||||||
$doc
|
$doc
|
||||||
);
|
);
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => Utils::map($validationErrors, function ($e) {
|
'errors' => Utils::map(
|
||||||
|
$validationErrors,
|
||||||
|
function ($e) {
|
||||||
return FormattedError::createFromException($e);
|
return FormattedError::createFromException($e);
|
||||||
})
|
}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
$this->assertSync($expected, $result);
|
$this->assertSync($expected, $result);
|
||||||
}
|
}
|
||||||
@ -173,35 +220,4 @@ class SyncTest extends TestCase
|
|||||||
);
|
);
|
||||||
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function graphqlSync($schema, $doc, $rootValue = null)
|
|
||||||
{
|
|
||||||
return GraphQL::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function execute($schema, $doc, $rootValue = null)
|
|
||||||
{
|
|
||||||
return Executor::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertSync($expectedFinalArray, $actualResult)
|
|
||||||
{
|
|
||||||
$message = 'Failed assertion that execution was synchronous';
|
|
||||||
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
|
||||||
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
|
||||||
$this->assertEquals(SyncPromise::FULFILLED, $actualResult->adoptedPromise->state, $message);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $actualResult->adoptedPromise->result, $message);
|
|
||||||
$this->assertArraySubset($expectedFinalArray, $actualResult->adoptedPromise->result->toArray(), $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertAsync($expectedFinalArray, $actualResult)
|
|
||||||
{
|
|
||||||
$message = 'Failed assertion that execution was asynchronous';
|
|
||||||
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
|
||||||
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
|
||||||
$this->assertEquals(SyncPromise::PENDING, $actualResult->adoptedPromise->state, $message);
|
|
||||||
$resolvedResult = $this->promiseAdapter->wait($actualResult);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $resolvedResult, $message);
|
|
||||||
$this->assertArraySubset($expectedFinalArray, $resolvedResult->toArray(), $message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Type\Definition\ScalarType;
|
|
||||||
use GraphQL\Utils\Utils;
|
|
||||||
|
|
||||||
class Dog
|
|
||||||
{
|
|
||||||
function __construct($name, $woofs)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->woofs = $woofs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Cat
|
|
||||||
{
|
|
||||||
function __construct($name, $meows)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->meows = $meows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Human
|
|
||||||
{
|
|
||||||
function __construct($name)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Person
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $pets;
|
|
||||||
public $friends;
|
|
||||||
|
|
||||||
function __construct($name, $pets = null, $friends = null)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->pets = $pets;
|
|
||||||
$this->friends = $friends;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComplexScalar extends ScalarType
|
|
||||||
{
|
|
||||||
public static function create()
|
|
||||||
{
|
|
||||||
return new self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public $name = 'ComplexScalar';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function serialize($value)
|
|
||||||
{
|
|
||||||
if ($value === 'DeserializedValue') {
|
|
||||||
return 'SerializedValue';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Cannot serialize value as ComplexScalar: " . Utils::printSafe($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function parseValue($value)
|
|
||||||
{
|
|
||||||
if ($value === 'SerializedValue') {
|
|
||||||
return 'DeserializedValue';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Cannot represent value as ComplexScalar: " . Utils::printSafe($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function parseLiteral($valueNode, array $variables = null)
|
|
||||||
{
|
|
||||||
if ($valueNode->value === 'SerializedValue') {
|
|
||||||
return 'DeserializedValue';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Cannot represent literal as ComplexScalar: " . Utils::printSafe($valueNode->value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Special
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
public function __construct($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotSpecial
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
public function __construct($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Adder
|
|
||||||
{
|
|
||||||
public $num;
|
|
||||||
|
|
||||||
public $test;
|
|
||||||
|
|
||||||
public function __construct($num)
|
|
||||||
{
|
|
||||||
$this->num = $num;
|
|
||||||
|
|
||||||
$this->test = function($source, $args, $context) {
|
|
||||||
return $this->num + $args['addend1'] + $context['addend2'];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
23
tests/Executor/TestClasses/Adder.php
Normal file
23
tests/Executor/TestClasses/Adder.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Adder
|
||||||
|
{
|
||||||
|
/** @var float */
|
||||||
|
public $num;
|
||||||
|
|
||||||
|
/** @var callable */
|
||||||
|
public $test;
|
||||||
|
|
||||||
|
public function __construct(float $num)
|
||||||
|
{
|
||||||
|
$this->num = $num;
|
||||||
|
|
||||||
|
$this->test = function ($source, $args, $context) {
|
||||||
|
return $this->num + $args['addend1'] + $context['addend2'];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
20
tests/Executor/TestClasses/Cat.php
Normal file
20
tests/Executor/TestClasses/Cat.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Cat
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
public $meows;
|
||||||
|
|
||||||
|
public function __construct(string $name, bool $meows)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->meows = $meows;
|
||||||
|
}
|
||||||
|
}
|
56
tests/Executor/TestClasses/ComplexScalar.php
Normal file
56
tests/Executor/TestClasses/ComplexScalar.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
use GraphQL\Error\Error;
|
||||||
|
use GraphQL\Type\Definition\ScalarType;
|
||||||
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
|
class ComplexScalar extends ScalarType
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name = 'ComplexScalar';
|
||||||
|
|
||||||
|
public static function create() : self
|
||||||
|
{
|
||||||
|
return new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function serialize($value)
|
||||||
|
{
|
||||||
|
if ($value === 'DeserializedValue') {
|
||||||
|
return 'SerializedValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot serialize value as ComplexScalar: ' . Utils::printSafe($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function parseValue($value)
|
||||||
|
{
|
||||||
|
if ($value === 'SerializedValue') {
|
||||||
|
return 'DeserializedValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot represent value as ComplexScalar: ' . Utils::printSafe($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function parseLiteral($valueNode, ?array $variables = null)
|
||||||
|
{
|
||||||
|
if ($valueNode->value === 'SerializedValue') {
|
||||||
|
return 'DeserializedValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot represent literal as ComplexScalar: ' . Utils::printSafe($valueNode->value));
|
||||||
|
}
|
||||||
|
}
|
20
tests/Executor/TestClasses/Dog.php
Normal file
20
tests/Executor/TestClasses/Dog.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Dog
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
public $woofs;
|
||||||
|
|
||||||
|
public function __construct(string $name, bool $woofs)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->woofs = $woofs;
|
||||||
|
}
|
||||||
|
}
|
16
tests/Executor/TestClasses/Human.php
Normal file
16
tests/Executor/TestClasses/Human.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Human
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
public function __construct(string $name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
19
tests/Executor/TestClasses/NotSpecial.php
Normal file
19
tests/Executor/TestClasses/NotSpecial.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class NotSpecial
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
}
|
16
tests/Executor/TestClasses/NumberHolder.php
Normal file
16
tests/Executor/TestClasses/NumberHolder.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class NumberHolder
|
||||||
|
{
|
||||||
|
/** @var float */
|
||||||
|
public $theNumber;
|
||||||
|
|
||||||
|
public function __construct(float $originalNumber)
|
||||||
|
{
|
||||||
|
$this->theNumber = $originalNumber;
|
||||||
|
}
|
||||||
|
}
|
28
tests/Executor/TestClasses/Person.php
Normal file
28
tests/Executor/TestClasses/Person.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Person
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/** @var (Dog|Cat)[]|null */
|
||||||
|
public $pets;
|
||||||
|
|
||||||
|
/** @var (Dog|Cat|Person)[]|null */
|
||||||
|
public $friends;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param (Cat|Dog)[]|null $pets
|
||||||
|
* @param (Cat|Dog|Person)[]|null $friends
|
||||||
|
*/
|
||||||
|
public function __construct(string $name, $pets = null, $friends = null)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->pets = $pets;
|
||||||
|
$this->friends = $friends;
|
||||||
|
}
|
||||||
|
}
|
44
tests/Executor/TestClasses/Root.php
Normal file
44
tests/Executor/TestClasses/Root.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
use GraphQL\Deferred;
|
||||||
|
|
||||||
|
class Root
|
||||||
|
{
|
||||||
|
/** @var NumberHolder */
|
||||||
|
public $numberHolder;
|
||||||
|
|
||||||
|
public function __construct(float $originalNumber)
|
||||||
|
{
|
||||||
|
$this->numberHolder = new NumberHolder($originalNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promiseToChangeTheNumber($newNumber) : Deferred
|
||||||
|
{
|
||||||
|
return new Deferred(function () use ($newNumber) {
|
||||||
|
return $this->immediatelyChangeTheNumber($newNumber);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function immediatelyChangeTheNumber($newNumber) : NumberHolder
|
||||||
|
{
|
||||||
|
$this->numberHolder->theNumber = $newNumber;
|
||||||
|
|
||||||
|
return $this->numberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function failToChangeTheNumber() : void
|
||||||
|
{
|
||||||
|
throw new \Exception('Cannot change the number');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promiseAndFailToChangeTheNumber() : Deferred
|
||||||
|
{
|
||||||
|
return new Deferred(function () {
|
||||||
|
$this->failToChangeTheNumber();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
19
tests/Executor/TestClasses/Special.php
Normal file
19
tests/Executor/TestClasses/Special.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Special
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,38 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
|
|
||||||
use GraphQL\Error\Warning;
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Person;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class UnionInterfaceTest extends TestCase
|
class UnionInterfaceTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var */
|
||||||
public $schema;
|
public $schema;
|
||||||
|
|
||||||
|
/** @var Cat */
|
||||||
public $garfield;
|
public $garfield;
|
||||||
|
|
||||||
|
/** @var Dog */
|
||||||
public $odie;
|
public $odie;
|
||||||
|
|
||||||
|
/** @var Person */
|
||||||
public $liz;
|
public $liz;
|
||||||
|
|
||||||
|
/** @var Person */
|
||||||
public $john;
|
public $john;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -28,8 +40,8 @@ class UnionInterfaceTest extends TestCase
|
|||||||
$NamedType = new InterfaceType([
|
$NamedType = new InterfaceType([
|
||||||
'name' => 'Named',
|
'name' => 'Named',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -37,11 +49,11 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'interfaces' => [$NamedType],
|
'interfaces' => [$NamedType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
],
|
],
|
||||||
'isTypeOf' => function ($value) {
|
'isTypeOf' => function ($value) {
|
||||||
return $value instanceof Dog;
|
return $value instanceof Dog;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -49,11 +61,11 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'interfaces' => [$NamedType],
|
'interfaces' => [$NamedType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()]
|
'meows' => ['type' => Type::boolean()],
|
||||||
],
|
],
|
||||||
'isTypeOf' => function ($value) {
|
'isTypeOf' => function ($value) {
|
||||||
return $value instanceof Cat;
|
return $value instanceof Cat;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
@ -66,7 +78,7 @@ class UnionInterfaceTest extends TestCase
|
|||||||
if ($value instanceof Cat) {
|
if ($value instanceof Cat) {
|
||||||
return $CatType;
|
return $CatType;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PersonType = new ObjectType([
|
$PersonType = new ObjectType([
|
||||||
@ -75,23 +87,22 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'pets' => ['type' => Type::listOf($PetType)],
|
'pets' => ['type' => Type::listOf($PetType)],
|
||||||
'friends' => ['type' => Type::listOf($NamedType)]
|
'friends' => ['type' => Type::listOf($NamedType)],
|
||||||
],
|
],
|
||||||
'isTypeOf' => function ($value) {
|
'isTypeOf' => function ($value) {
|
||||||
return $value instanceof Person;
|
return $value instanceof Person;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->schema = new Schema([
|
$this->schema = new Schema([
|
||||||
'query' => $PersonType,
|
'query' => $PersonType,
|
||||||
'types' => [ $PetType ]
|
'types' => [$PetType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->garfield = new Cat('Garfield', false);
|
$this->garfield = new Cat('Garfield', false);
|
||||||
$this->odie = new Dog('Odie', true);
|
$this->odie = new Dog('Odie', true);
|
||||||
$this->liz = new Person('Liz');
|
$this->liz = new Person('Liz');
|
||||||
$this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]);
|
$this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute: Union and intersection types
|
// Execute: Union and intersection types
|
||||||
@ -101,7 +112,6 @@ class UnionInterfaceTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testCanIntrospectOnUnionAndIntersectionTypes() : void
|
public function testCanIntrospectOnUnionAndIntersectionTypes() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$ast = Parser::parse('
|
$ast = Parser::parse('
|
||||||
{
|
{
|
||||||
Named: __type(name: "Named") {
|
Named: __type(name: "Named") {
|
||||||
@ -131,16 +141,16 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'kind' => 'INTERFACE',
|
'kind' => 'INTERFACE',
|
||||||
'name' => 'Named',
|
'name' => 'Named',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
['name' => 'name']
|
['name' => 'name'],
|
||||||
],
|
],
|
||||||
'interfaces' => null,
|
'interfaces' => null,
|
||||||
'possibleTypes' => [
|
'possibleTypes' => [
|
||||||
['name' => 'Person'],
|
['name' => 'Person'],
|
||||||
['name' => 'Dog'],
|
['name' => 'Dog'],
|
||||||
['name' => 'Cat']
|
['name' => 'Cat'],
|
||||||
],
|
],
|
||||||
'enumValues' => null,
|
'enumValues' => null,
|
||||||
'inputFields' => null
|
'inputFields' => null,
|
||||||
],
|
],
|
||||||
'Pet' => [
|
'Pet' => [
|
||||||
'kind' => 'UNION',
|
'kind' => 'UNION',
|
||||||
@ -149,12 +159,12 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'interfaces' => null,
|
'interfaces' => null,
|
||||||
'possibleTypes' => [
|
'possibleTypes' => [
|
||||||
['name' => 'Dog'],
|
['name' => 'Dog'],
|
||||||
['name' => 'Cat']
|
['name' => 'Cat'],
|
||||||
],
|
],
|
||||||
'enumValues' => null,
|
'enumValues' => null,
|
||||||
'inputFields' => null
|
'inputFields' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast)->toArray());
|
||||||
}
|
}
|
||||||
@ -183,9 +193,9 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
@ -220,10 +230,10 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
|
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
}
|
}
|
||||||
@ -252,9 +262,9 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['__typename' => 'Person', 'name' => 'Liz'],
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
@ -288,9 +298,9 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['__typename' => 'Person', 'name' => 'Liz'],
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray(true));
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray(true));
|
||||||
@ -339,13 +349,13 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
],
|
],
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['__typename' => 'Person', 'name' => 'Liz'],
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
@ -364,14 +374,25 @@ class UnionInterfaceTest extends TestCase
|
|||||||
$NamedType2 = new InterfaceType([
|
$NamedType2 = new InterfaceType([
|
||||||
'name' => 'Named',
|
'name' => 'Named',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
],
|
],
|
||||||
'resolveType' => function ($obj, $context, ResolveInfo $info) use (&$encounteredContext, &$encounteredSchema, &$encounteredRootValue, &$PersonType2) {
|
'resolveType' => function (
|
||||||
|
$obj,
|
||||||
|
$context,
|
||||||
|
ResolveInfo $info
|
||||||
|
) use (
|
||||||
|
&$encounteredContext,
|
||||||
|
&
|
||||||
|
$encounteredSchema,
|
||||||
|
&$encounteredRootValue,
|
||||||
|
&$PersonType2
|
||||||
|
) {
|
||||||
$encounteredContext = $context;
|
$encounteredContext = $context;
|
||||||
$encounteredSchema = $info->schema;
|
$encounteredSchema = $info->schema;
|
||||||
$encounteredRootValue = $info->rootValue;
|
$encounteredRootValue = $info->rootValue;
|
||||||
|
|
||||||
return $PersonType2;
|
return $PersonType2;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PersonType2 = new ObjectType([
|
$PersonType2 = new ObjectType([
|
||||||
@ -383,9 +404,7 @@ class UnionInterfaceTest extends TestCase
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema2 = new Schema([
|
$schema2 = new Schema(['query' => $PersonType2]);
|
||||||
'query' => $PersonType2
|
|
||||||
]);
|
|
||||||
|
|
||||||
$john2 = new Person('John', [], [$this->liz]);
|
$john2 = new Person('John', [], [$this->liz]);
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Values;
|
use GraphQL\Executor\Values;
|
||||||
@ -10,19 +13,97 @@ use GraphQL\Type\Definition\ObjectType;
|
|||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
use function var_export;
|
||||||
|
use const PHP_EOL;
|
||||||
|
|
||||||
class ValuesTest extends TestCase
|
class ValuesTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var Schema */
|
||||||
|
private static $schema;
|
||||||
|
|
||||||
public function testGetIDVariableValues() : void
|
public function testGetIDVariableValues() : void
|
||||||
{
|
{
|
||||||
$this->expectInputVariablesMatchOutputVariables(['idInput' => '123456789']);
|
$this->expectInputVariablesMatchOutputVariables(['idInput' => '123456789']);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['errors' => [], 'coerced' => ['idInput' => '123456789']],
|
['errors' => [], 'coerced' => ['idInput' => '123456789']],
|
||||||
self::runTestCase(['idInput' => 123456789]),
|
$this->runTestCase(['idInput' => 123456789]),
|
||||||
'Integer ID was not converted to string'
|
'Integer ID was not converted to string'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectInputVariablesMatchOutputVariables($variables) : void
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
$variables,
|
||||||
|
$this->runTestCase($variables)['coerced'],
|
||||||
|
'Output variables did not match input variables' . PHP_EOL . var_export($variables, true) . PHP_EOL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $variables
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function runTestCase($variables) : array
|
||||||
|
{
|
||||||
|
return Values::getVariableValues(self::getSchema(), self::getVariableDefinitionNodes(), $variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getSchema() : Schema
|
||||||
|
{
|
||||||
|
if (! self::$schema) {
|
||||||
|
self::$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'test' => [
|
||||||
|
'type' => Type::boolean(),
|
||||||
|
'args' => [
|
||||||
|
'idInput' => Type::id(),
|
||||||
|
'boolInput' => Type::boolean(),
|
||||||
|
'intInput' => Type::int(),
|
||||||
|
'stringInput' => Type::string(),
|
||||||
|
'floatInput' => Type::float(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return VariableDefinitionNode[]
|
||||||
|
*/
|
||||||
|
private static function getVariableDefinitionNodes() : array
|
||||||
|
{
|
||||||
|
$idInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'idInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'ID'])]),
|
||||||
|
]);
|
||||||
|
$boolInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'boolInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Boolean'])]),
|
||||||
|
]);
|
||||||
|
$intInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'intInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Int'])]),
|
||||||
|
]);
|
||||||
|
$stringInputDefintion = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'stringInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'String'])]),
|
||||||
|
]);
|
||||||
|
$floatInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'floatInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Float'])]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [$idInputDefinition, $boolInputDefinition, $intInputDefinition, $stringInputDefintion, $floatInputDefinition];
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetBooleanVariableValues() : void
|
public function testGetBooleanVariableValues() : void
|
||||||
{
|
{
|
||||||
$this->expectInputVariablesMatchOutputVariables(['boolInput' => true]);
|
$this->expectInputVariablesMatchOutputVariables(['boolInput' => true]);
|
||||||
@ -64,11 +145,20 @@ class ValuesTest extends TestCase
|
|||||||
$this->expectGraphQLError(['idInput' => true]);
|
$this->expectGraphQLError(['idInput' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectGraphQLError($variables) : void
|
||||||
|
{
|
||||||
|
$result = $this->runTestCase($variables);
|
||||||
|
$this->assertGreaterThan(0, count($result['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
public function testFloatForIDVariableThrowsError() : void
|
public function testFloatForIDVariableThrowsError() : void
|
||||||
{
|
{
|
||||||
$this->expectGraphQLError(['idInput' => 1.0]);
|
$this->expectGraphQLError(['idInput' => 1.0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for running test cases and making assertions
|
||||||
|
*/
|
||||||
public function testStringForBooleanVariableThrowsError() : void
|
public function testStringForBooleanVariableThrowsError() : void
|
||||||
{
|
{
|
||||||
$this->expectGraphQLError(['boolInput' => 'true']);
|
$this->expectGraphQLError(['boolInput' => 'true']);
|
||||||
@ -98,77 +188,4 @@ class ValuesTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectGraphQLError(['intInput' => -2147483649]);
|
$this->expectGraphQLError(['intInput' => -2147483649]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers for running test cases and making assertions
|
|
||||||
|
|
||||||
private function expectInputVariablesMatchOutputVariables($variables)
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
$variables,
|
|
||||||
self::runTestCase($variables)['coerced'],
|
|
||||||
'Output variables did not match input variables' . PHP_EOL . var_export($variables, true) . PHP_EOL
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function expectGraphQLError($variables)
|
|
||||||
{
|
|
||||||
$result = self::runTestCase($variables);
|
|
||||||
$this->assertGreaterThan(0, count($result['errors']));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static $schema;
|
|
||||||
|
|
||||||
private static function getSchema()
|
|
||||||
{
|
|
||||||
if (!self::$schema) {
|
|
||||||
self::$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => [
|
|
||||||
'test' => [
|
|
||||||
'type' => Type::boolean(),
|
|
||||||
'args' => [
|
|
||||||
'idInput' => Type::id(),
|
|
||||||
'boolInput' => Type::boolean(),
|
|
||||||
'intInput' => Type::int(),
|
|
||||||
'stringInput' => Type::string(),
|
|
||||||
'floatInput' => Type::float()
|
|
||||||
]
|
|
||||||
],
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return self::$schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getVariableDefinitionNodes()
|
|
||||||
{
|
|
||||||
$idInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'idInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'ID'])])
|
|
||||||
]);
|
|
||||||
$boolInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'boolInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Boolean'])])
|
|
||||||
]);
|
|
||||||
$intInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'intInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Int'])])
|
|
||||||
]);
|
|
||||||
$stringInputDefintion = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'stringInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'String'])])
|
|
||||||
]);
|
|
||||||
$floatInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'floatInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Float'])])
|
|
||||||
]);
|
|
||||||
return [$idInputDefinition, $boolInputDefinition, $intInputDefinition, $stringInputDefintion, $floatInputDefinition];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function runTestCase($variables)
|
|
||||||
{
|
|
||||||
return Values::getVariableValues(self::getSchema(), self::getVariableDefinitionNodes(), $variables);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\ComplexScalar;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function json_encode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute: Handles inputs
|
* Execute: Handles inputs
|
||||||
@ -18,7 +21,6 @@ use PHPUnit\Framework\TestCase;
|
|||||||
*/
|
*/
|
||||||
class VariablesTest extends TestCase
|
class VariablesTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
public function testUsingInlineStructs() : void
|
public function testUsingInlineStructs() : void
|
||||||
{
|
{
|
||||||
// executes with complex input:
|
// executes with complex input:
|
||||||
@ -29,9 +31,7 @@ class VariablesTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'],
|
||||||
'fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -77,8 +77,9 @@ class VariablesTest extends TestCase
|
|||||||
'errors' => [[
|
'errors' => [[
|
||||||
'message' => 'Argument "input" has invalid value ["foo", "bar", "baz"].',
|
'message' => 'Argument "input" has invalid value ["foo", "bar", "baz"].',
|
||||||
'path' => ['fieldWithObjectInput'],
|
'path' => ['fieldWithObjectInput'],
|
||||||
'locations' => [['line' => 3, 'column' => 39]]
|
'locations' => [['line' => 3, 'column' => 39]],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $result->toArray());
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
|
|
||||||
@ -94,6 +95,77 @@ class VariablesTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function executeQuery($query, $variableValues = null)
|
||||||
|
{
|
||||||
|
$document = Parser::parse($query);
|
||||||
|
|
||||||
|
return Executor::execute($this->schema(), $document, null, null, $variableValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe: Handles nullable scalars
|
||||||
|
*/
|
||||||
|
public function schema() : Schema
|
||||||
|
{
|
||||||
|
$ComplexScalarType = ComplexScalar::create();
|
||||||
|
|
||||||
|
$TestInputObject = new InputObjectType([
|
||||||
|
'name' => 'TestInputObject',
|
||||||
|
'fields' => [
|
||||||
|
'a' => ['type' => Type::string()],
|
||||||
|
'b' => ['type' => Type::listOf(Type::string())],
|
||||||
|
'c' => ['type' => Type::nonNull(Type::string())],
|
||||||
|
'd' => ['type' => $ComplexScalarType],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$TestNestedInputObject = new InputObjectType([
|
||||||
|
'name' => 'TestNestedInputObject',
|
||||||
|
'fields' => [
|
||||||
|
'na' => ['type' => Type::nonNull($TestInputObject)],
|
||||||
|
'nb' => ['type' => Type::nonNull(Type::string())],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$TestType = new ObjectType([
|
||||||
|
'name' => 'TestType',
|
||||||
|
'fields' => [
|
||||||
|
'fieldWithObjectInput' => $this->fieldWithInputArg(['type' => $TestInputObject]),
|
||||||
|
'fieldWithNullableStringInput' => $this->fieldWithInputArg(['type' => Type::string()]),
|
||||||
|
'fieldWithNonNullableStringInput' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::string())]),
|
||||||
|
'fieldWithDefaultArgumentValue' => $this->fieldWithInputArg([
|
||||||
|
'type' => Type::string(),
|
||||||
|
'defaultValue' => 'Hello World',
|
||||||
|
]),
|
||||||
|
'fieldWithNestedInputObject' => $this->fieldWithInputArg([
|
||||||
|
'type' => $TestNestedInputObject,
|
||||||
|
'defaultValue' => 'Hello World',
|
||||||
|
]),
|
||||||
|
'list' => $this->fieldWithInputArg(['type' => Type::listOf(Type::string())]),
|
||||||
|
'nnList' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::string()))]),
|
||||||
|
'listNN' => $this->fieldWithInputArg(['type' => Type::listOf(Type::nonNull(Type::string()))]),
|
||||||
|
'nnListNN' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))]),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return new Schema(['query' => $TestType]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fieldWithInputArg($inputArg)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'args' => ['input' => $inputArg],
|
||||||
|
'resolve' => function ($_, $args) {
|
||||||
|
if (isset($args['input'])) {
|
||||||
|
return json_encode($args['input']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function testUsingVariables() : void
|
public function testUsingVariables() : void
|
||||||
{
|
{
|
||||||
$doc = '
|
$doc = '
|
||||||
@ -119,7 +191,7 @@ class VariablesTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}']
|
'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -135,9 +207,7 @@ class VariablesTest extends TestCase
|
|||||||
$params = ['input' => ['c' => 'foo', 'd' => 'SerializedValue']];
|
$params = ['input' => ['c' => 'foo', 'd' => 'SerializedValue']];
|
||||||
$result = $this->executeQuery($doc, $params);
|
$result = $this->executeQuery($doc, $params);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['fieldWithObjectInput' => '{"c":"foo","d":"DeserializedValue"}'],
|
||||||
'fieldWithObjectInput' => '{"c":"foo","d":"DeserializedValue"}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -152,9 +222,9 @@ class VariablesTest extends TestCase
|
|||||||
'{"a":"foo","b":"bar","c":null}; ' .
|
'{"a":"foo","b":"bar","c":null}; ' .
|
||||||
'Expected non-nullable type String! not to be null at value.c.',
|
'Expected non-nullable type String! not to be null at value.c.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql'
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
@ -170,8 +240,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected type TestInputObject to be an object.',
|
'Expected type TestInputObject to be an object.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -187,8 +257,8 @@ class VariablesTest extends TestCase
|
|||||||
'Field value.c of required type String! was not provided.',
|
'Field value.c of required type String! was not provided.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -216,12 +286,11 @@ class VariablesTest extends TestCase
|
|||||||
'Field value.nb of required type String! was not provided.',
|
'Field value.nb of required type String! was not provided.',
|
||||||
'locations' => [['line' => 2, 'column' => 19]],
|
'locations' => [['line' => 2, 'column' => 19]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
|
|
||||||
// errors on addition of unknown input field
|
// errors on addition of unknown input field
|
||||||
$params = ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'extra' => 'dog']];
|
$params = ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'extra' => 'dog']];
|
||||||
$result = $this->executeQuery($doc, $params);
|
$result = $this->executeQuery($doc, $params);
|
||||||
@ -234,14 +303,12 @@ class VariablesTest extends TestCase
|
|||||||
'Field "extra" is not defined by type TestInputObject.',
|
'Field "extra" is not defined by type TestInputObject.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Handles nullable scalars
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows nullable inputs to be omitted')
|
* @see it('allows nullable inputs to be omitted')
|
||||||
*/
|
*/
|
||||||
@ -253,7 +320,7 @@ class VariablesTest extends TestCase
|
|||||||
}
|
}
|
||||||
');
|
');
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['fieldWithNullableStringInput' => null]
|
'data' => ['fieldWithNullableStringInput' => null],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
@ -288,6 +355,9 @@ class VariablesTest extends TestCase
|
|||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Describe: Handles non-nullable scalars
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows nullable inputs to be set to null in a variable')
|
* @see it('allows nullable inputs to be set to null in a variable')
|
||||||
*/
|
*/
|
||||||
@ -332,9 +402,6 @@ class VariablesTest extends TestCase
|
|||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Describe: Handles non-nullable scalars
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows non-nullable inputs to be omitted given a default')
|
* @see it('allows non-nullable inputs to be omitted given a default')
|
||||||
*/
|
*/
|
||||||
@ -346,7 +413,7 @@ class VariablesTest extends TestCase
|
|||||||
}
|
}
|
||||||
');
|
');
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['fieldWithNonNullableStringInput' => '"default"']
|
'data' => ['fieldWithNonNullableStringInput' => '"default"'],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -367,9 +434,9 @@ class VariablesTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'Variable "$value" of required type "String!" was not provided.',
|
'message' => 'Variable "$value" of required type "String!" was not provided.',
|
||||||
'locations' => [['line' => 2, 'column' => 31]],
|
'locations' => [['line' => 2, 'column' => 31]],
|
||||||
'category' => 'graphql'
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -393,8 +460,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type String! not to be null.',
|
'Expected non-nullable type String! not to be null.',
|
||||||
'locations' => [['line' => 2, 'column' => 31]],
|
'locations' => [['line' => 2, 'column' => 31]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -445,17 +512,19 @@ class VariablesTest extends TestCase
|
|||||||
'locations' => [['line' => 3, 'column' => 9]],
|
'locations' => [['line' => 3, 'column' => 9]],
|
||||||
'path' => ['fieldWithNonNullableStringInput'],
|
'path' => ['fieldWithNonNullableStringInput'],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: Handles lists and nullability
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('reports error for array passed into string input')
|
* @see it('reports error for array passed into string input')
|
||||||
*/
|
*/
|
||||||
public function testReportsErrorForArrayPassedIntoStringInput() : void
|
public function testReportsErrorForArrayPassedIntoStringInput() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$doc = '
|
$doc = '
|
||||||
query SetsNonNullable($value: String!) {
|
query SetsNonNullable($value: String!) {
|
||||||
fieldWithNonNullableStringInput(input: $value)
|
fieldWithNonNullableStringInput(input: $value)
|
||||||
@ -471,9 +540,10 @@ class VariablesTest extends TestCase
|
|||||||
'String; String cannot represent an array value: [1,2,3]',
|
'String; String cannot represent an array value: [1,2,3]',
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
'locations' => [
|
'locations' => [
|
||||||
['line' => 2, 'column' => 31]
|
['line' => 2, 'column' => 31],
|
||||||
]
|
],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -512,13 +582,12 @@ class VariablesTest extends TestCase
|
|||||||
'locations' => [['line' => 3, 'column' => 48]],
|
'locations' => [['line' => 3, 'column' => 48]],
|
||||||
'path' => ['fieldWithNonNullableStringInput'],
|
'path' => ['fieldWithNonNullableStringInput'],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Handles lists and nullability
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows lists to be null')
|
* @see it('allows lists to be null')
|
||||||
*/
|
*/
|
||||||
@ -584,8 +653,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type [String]! not to be null.',
|
'Expected non-nullable type [String]! not to be null.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -669,8 +738,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type String! not to be null at value[1].',
|
'Expected non-nullable type String! not to be null at value[1].',
|
||||||
'locations' => [['line' => 2, 'column' => 17]],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -694,8 +763,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type [String!]! not to be null.',
|
'Expected non-nullable type [String!]! not to be null.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -715,6 +784,8 @@ class VariablesTest extends TestCase
|
|||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: Execute: Uses argument default values
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not allow non-null lists of non-nulls to contain null')
|
* @see it('does not allow non-null lists of non-nulls to contain null')
|
||||||
*/
|
*/
|
||||||
@ -734,8 +805,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type String! not to be null at value[1].',
|
'Expected non-nullable type String! not to be null at value[1].',
|
||||||
'locations' => [['line' => 2, 'column' => 17]],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -760,8 +831,8 @@ class VariablesTest extends TestCase
|
|||||||
'be used as an input type.',
|
'be used as an input type.',
|
||||||
'locations' => [['line' => 2, 'column' => 25]],
|
'locations' => [['line' => 2, 'column' => 25]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -787,13 +858,12 @@ class VariablesTest extends TestCase
|
|||||||
'cannot be used as an input type.',
|
'cannot be used as an input type.',
|
||||||
'locations' => [['line' => 2, 'column' => 25]],
|
'locations' => [['line' => 2, 'column' => 25]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Execute: Uses argument default values
|
|
||||||
/**
|
/**
|
||||||
* @see it('when no argument provided')
|
* @see it('when no argument provided')
|
||||||
*/
|
*/
|
||||||
@ -841,77 +911,10 @@ class VariablesTest extends TestCase
|
|||||||
'locations' => [['line' => 2, 'column' => 50]],
|
'locations' => [['line' => 2, 'column' => 50]],
|
||||||
'path' => ['fieldWithDefaultArgumentValue'],
|
'path' => ['fieldWithDefaultArgumentValue'],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function schema()
|
|
||||||
{
|
|
||||||
$ComplexScalarType = ComplexScalar::create();
|
|
||||||
|
|
||||||
$TestInputObject = new InputObjectType([
|
|
||||||
'name' => 'TestInputObject',
|
|
||||||
'fields' => [
|
|
||||||
'a' => ['type' => Type::string()],
|
|
||||||
'b' => ['type' => Type::listOf(Type::string())],
|
|
||||||
'c' => ['type' => Type::nonNull(Type::string())],
|
|
||||||
'd' => ['type' => $ComplexScalarType],
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$TestNestedInputObject = new InputObjectType([
|
|
||||||
'name' => 'TestNestedInputObject',
|
|
||||||
'fields' => [
|
|
||||||
'na' => [ 'type' => Type::nonNull($TestInputObject) ],
|
|
||||||
'nb' => [ 'type' => Type::nonNull(Type::string()) ],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$TestType = new ObjectType([
|
|
||||||
'name' => 'TestType',
|
|
||||||
'fields' => [
|
|
||||||
'fieldWithObjectInput' => $this->fieldWithInputArg(['type' => $TestInputObject]),
|
|
||||||
'fieldWithNullableStringInput' => $this->fieldWithInputArg(['type' => Type::string()]),
|
|
||||||
'fieldWithNonNullableStringInput' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::string())]),
|
|
||||||
'fieldWithDefaultArgumentValue' => $this->fieldWithInputArg([
|
|
||||||
'type' => Type::string(),
|
|
||||||
'defaultValue' => 'Hello World',
|
|
||||||
]),
|
|
||||||
'fieldWithNestedInputObject' => $this->fieldWithInputArg([
|
|
||||||
'type' => $TestNestedInputObject,
|
|
||||||
'defaultValue' => 'Hello World'
|
|
||||||
]),
|
|
||||||
'list' => $this->fieldWithInputArg(['type' => Type::listOf(Type::string())]),
|
|
||||||
'nnList' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::string()))]),
|
|
||||||
'listNN' => $this->fieldWithInputArg(['type' => Type::listOf(Type::nonNull(Type::string()))]),
|
|
||||||
'nnListNN' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))]),
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$schema = new Schema(['query' => $TestType]);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function fieldWithInputArg($inputArg)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'type' => Type::string(),
|
|
||||||
'args' => ['input' => $inputArg],
|
|
||||||
'resolve' => function ($_, $args) {
|
|
||||||
if (isset($args['input'])) {
|
|
||||||
return json_encode($args['input']);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executeQuery($query, $variableValues = null)
|
|
||||||
{
|
|
||||||
$document = Parser::parse($query);
|
|
||||||
return Executor::execute($this->schema(), $document, null, null, $variableValues);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user