mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 12:56:05 +03:00
Add Executor Promise tests
This commit is contained in:
parent
35d7d83088
commit
76c31df1af
@ -4,8 +4,10 @@ namespace GraphQL\Tests\Executor;
|
|||||||
require_once __DIR__ . '/TestClasses.php';
|
require_once __DIR__ . '/TestClasses.php';
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
use GraphQL\Error\FormattedError;
|
||||||
|
use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Schema;
|
use GraphQL\Schema;
|
||||||
@ -16,9 +18,15 @@ 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\Utils;
|
use GraphQL\Utils;
|
||||||
|
use React\Promise\Promise;
|
||||||
|
|
||||||
class ExecutorTest extends \PHPUnit_Framework_TestCase
|
class ExecutorTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
Executor::setPromiseAdapter(null);
|
||||||
|
}
|
||||||
|
|
||||||
// Execute: Handles basic execution tasks
|
// Execute: Handles basic execution tasks
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,7 +34,16 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
public function testExecutesArbitraryCode()
|
public function testExecutesArbitraryCode()
|
||||||
{
|
{
|
||||||
|
Executor::setPromiseAdapter(new ReactPromiseAdapter());
|
||||||
$deepData = null;
|
$deepData = null;
|
||||||
|
$data = null;
|
||||||
|
|
||||||
|
$promiseData = function () use (&$data) {
|
||||||
|
return new Promise(function (callable $resolve) use (&$data) {
|
||||||
|
return $resolve($data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'a' => function () { return 'Apple';},
|
'a' => function () { return 'Apple';},
|
||||||
'b' => function () {return 'Banana';},
|
'b' => function () {return 'Banana';},
|
||||||
@ -37,8 +54,8 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
'pic' => function ($size = 50) {
|
'pic' => function ($size = 50) {
|
||||||
return 'Pic of size: ' . $size;
|
return 'Pic of size: ' . $size;
|
||||||
},
|
},
|
||||||
'promise' => function() use (&$data) {
|
'promise' => function() use ($promiseData) {
|
||||||
return $data;
|
return $promiseData();
|
||||||
},
|
},
|
||||||
'deep' => function () use (&$deepData) {
|
'deep' => function () use (&$deepData) {
|
||||||
return $deepData;
|
return $deepData;
|
||||||
@ -51,7 +68,7 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
'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];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -148,7 +165,7 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
]);
|
]);
|
||||||
$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, self::awaitPromise(Executor::execute($schema, $ast, $data, null, ['size' => 100], 'Example')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -342,12 +359,18 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testNullsOutErrorSubtrees()
|
public function testNullsOutErrorSubtrees()
|
||||||
{
|
{
|
||||||
$doc = '{
|
$doc = '{
|
||||||
sync,
|
sync
|
||||||
syncError,
|
syncError
|
||||||
syncRawError,
|
syncRawError
|
||||||
async,
|
syncReturnError
|
||||||
asyncReject,
|
syncReturnErrorList
|
||||||
|
async
|
||||||
|
asyncReject
|
||||||
|
asyncRawReject
|
||||||
|
asyncEmptyReject
|
||||||
asyncError
|
asyncError
|
||||||
|
asyncRawError
|
||||||
|
asyncReturnError
|
||||||
}';
|
}';
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@ -360,17 +383,42 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
'syncRawError' => function() {
|
'syncRawError' => function() {
|
||||||
throw new \Exception('Error getting syncRawError');
|
throw new \Exception('Error getting syncRawError');
|
||||||
},
|
},
|
||||||
// Following are inherited from JS reference implementation, but make no sense in this PHP impl
|
// inherited from JS reference implementation, but make no sense in this PHP impl
|
||||||
// leaving them just to simplify migrations from newer js versions
|
// leaving it just to simplify migrations from newer js versions
|
||||||
|
'syncReturnError' => function() {
|
||||||
|
return new \Exception('Error getting syncReturnError');
|
||||||
|
},
|
||||||
|
'syncReturnErrorList' => function () {
|
||||||
|
return [
|
||||||
|
'sync0',
|
||||||
|
new \Exception('Error getting syncReturnErrorList1'),
|
||||||
|
'sync2',
|
||||||
|
new \Exception('Error getting syncReturnErrorList3')
|
||||||
|
];
|
||||||
|
},
|
||||||
'async' => function() {
|
'async' => function() {
|
||||||
return 'async';
|
return new Promise(function(callable $resolve) { return $resolve('async'); });
|
||||||
},
|
},
|
||||||
'asyncReject' => function() {
|
'asyncReject' => function() {
|
||||||
throw new \Exception('Error getting asyncReject');
|
return new Promise(function($_, callable $reject) { return $reject('Error getting asyncReject'); });
|
||||||
|
},
|
||||||
|
'asyncRawReject' => function () {
|
||||||
|
return \React\Promise\reject('Error getting asyncRawReject');
|
||||||
|
},
|
||||||
|
'asyncEmptyReject' => function () {
|
||||||
|
return \React\Promise\reject();
|
||||||
},
|
},
|
||||||
'asyncError' => function() {
|
'asyncError' => function() {
|
||||||
throw new \Exception('Error getting asyncError');
|
return new Promise(function() { throw new \Exception('Error getting asyncError'); });
|
||||||
}
|
},
|
||||||
|
// inherited from JS reference implementation, but make no sense in this PHP impl
|
||||||
|
// leaving it just to simplify migrations from newer js versions
|
||||||
|
'asyncRawError' => function() {
|
||||||
|
return new Promise(function() { throw new \Exception('Error getting asyncRawError'); });
|
||||||
|
},
|
||||||
|
'asyncReturnError' => function() {
|
||||||
|
return \React\Promise\resolve(new \Exception('Error getting asyncReturnError'));
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
$docAst = Parser::parse($doc);
|
$docAst = Parser::parse($doc);
|
||||||
@ -380,10 +428,16 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'sync' => ['type' => Type::string()],
|
'sync' => ['type' => Type::string()],
|
||||||
'syncError' => ['type' => Type::string()],
|
'syncError' => ['type' => Type::string()],
|
||||||
'syncRawError' => [ 'type' => Type::string() ],
|
'syncRawError' => ['type' => Type::string()],
|
||||||
|
'syncReturnError' => ['type' => Type::string()],
|
||||||
|
'syncReturnErrorList' => ['type' => Type::listOf(Type::string())],
|
||||||
'async' => ['type' => Type::string()],
|
'async' => ['type' => Type::string()],
|
||||||
'asyncReject' => ['type' => Type::string() ],
|
'asyncReject' => ['type' => Type::string() ],
|
||||||
|
'asyncRawReject' => ['type' => Type::string() ],
|
||||||
|
'asyncEmptyReject' => ['type' => Type::string() ],
|
||||||
'asyncError' => ['type' => Type::string()],
|
'asyncError' => ['type' => Type::string()],
|
||||||
|
'asyncRawError' => ['type' => Type::string()],
|
||||||
|
'asyncReturnError' => ['type' => Type::string()],
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
@ -393,21 +447,79 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'syncError' => null,
|
'syncError' => null,
|
||||||
'syncRawError' => null,
|
'syncRawError' => null,
|
||||||
|
'syncReturnError' => null,
|
||||||
|
'syncReturnErrorList' => ['sync0', null, 'sync2', null],
|
||||||
'async' => 'async',
|
'async' => 'async',
|
||||||
'asyncReject' => null,
|
'asyncReject' => null,
|
||||||
|
'asyncRawReject' => null,
|
||||||
|
'asyncEmptyReject' => null,
|
||||||
'asyncError' => null,
|
'asyncError' => null,
|
||||||
|
'asyncRawError' => null,
|
||||||
|
'asyncReturnError' => null,
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create('Error getting syncError', [new SourceLocation(3, 7)]),
|
[
|
||||||
FormattedError::create('Error getting syncRawError', [new SourceLocation(4, 7)]),
|
'message' => 'Error getting syncError',
|
||||||
FormattedError::create('Error getting asyncReject', [new SourceLocation(6, 7)]),
|
'locations' => [['line' => 3, 'column' => 7]],
|
||||||
FormattedError::create('Error getting asyncError', [new SourceLocation(7, 7)])
|
'path' => ['syncError']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting syncRawError',
|
||||||
|
'locations' => [ [ 'line' => 4, 'column' => 7 ] ],
|
||||||
|
'path'=> [ 'syncRawError' ]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting syncReturnError',
|
||||||
|
'locations' => [['line' => 5, 'column' => 7]],
|
||||||
|
'path' => ['syncReturnError']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting syncReturnErrorList1',
|
||||||
|
'locations' => [['line' => 6, 'column' => 7]],
|
||||||
|
'path' => ['syncReturnErrorList', 1]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting syncReturnErrorList3',
|
||||||
|
'locations' => [['line' => 6, 'column' => 7]],
|
||||||
|
'path' => ['syncReturnErrorList', 3]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting asyncReject',
|
||||||
|
'locations' => [['line' => 8, 'column' => 7]],
|
||||||
|
'path' => ['asyncReject']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting asyncRawReject',
|
||||||
|
'locations' => [['line' => 9, 'column' => 7]],
|
||||||
|
'path' => ['asyncRawReject']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'An unknown error occurred.',
|
||||||
|
'locations' => [['line' => 10, 'column' => 7]],
|
||||||
|
'path' => ['asyncEmptyReject']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting asyncError',
|
||||||
|
'locations' => [['line' => 11, 'column' => 7]],
|
||||||
|
'path' => ['asyncError']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting asyncRawError',
|
||||||
|
'locations' => [ [ 'line' => 12, 'column' => 7 ] ],
|
||||||
|
'path' => [ 'asyncRawError' ]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'message' => 'Error getting asyncReturnError',
|
||||||
|
'locations' => [['line' => 13, 'column' => 7]],
|
||||||
|
'path' => ['asyncReturnError']
|
||||||
|
],
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Executor::setPromiseAdapter(new ReactPromiseAdapter());
|
||||||
$result = Executor::execute($schema, $docAst, $data);
|
$result = Executor::execute($schema, $docAst, $data);
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result->toArray());
|
$this->assertEquals($expected, self::awaitPromise($result));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -629,6 +741,62 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals(['data' => ['a' => 'b']], $subscriptionResult->toArray());
|
$this->assertEquals(['data' => ['a' => 'b']], $subscriptionResult->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCorrectFieldOrderingDespiteExecutionOrder()
|
||||||
|
{
|
||||||
|
Executor::setPromiseAdapter(new ReactPromiseAdapter());
|
||||||
|
|
||||||
|
$doc = '{
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
e
|
||||||
|
}';
|
||||||
|
$data = [
|
||||||
|
'a' => function () {
|
||||||
|
return 'a';
|
||||||
|
},
|
||||||
|
'b' => function () {
|
||||||
|
return new Promise(function (callable $resolve) { return $resolve('b'); });
|
||||||
|
},
|
||||||
|
'c' => function () {
|
||||||
|
return 'c';
|
||||||
|
},
|
||||||
|
'd' => function () {
|
||||||
|
return new Promise(function (callable $resolve) { return $resolve('d'); });
|
||||||
|
},
|
||||||
|
'e' => function () {
|
||||||
|
return 'e';
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'DeepDataType',
|
||||||
|
'fields' => [
|
||||||
|
'a' => [ 'type' => Type::string() ],
|
||||||
|
'b' => [ 'type' => Type::string() ],
|
||||||
|
'c' => [ 'type' => Type::string() ],
|
||||||
|
'd' => [ 'type' => Type::string() ],
|
||||||
|
'e' => [ 'type' => Type::string() ],
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$schema = new Schema(['query' => $queryType]);
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => [
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
'c' => 'c',
|
||||||
|
'd' => 'd',
|
||||||
|
'e' => 'e',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, self::awaitPromise(Executor::execute($schema, $ast, $data)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @it Avoids recursion
|
* @it Avoids recursion
|
||||||
*/
|
*/
|
||||||
@ -923,4 +1091,17 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
], $result->toArray());
|
], $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \GraphQL\Executor\Promise\Promise $promise
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function awaitPromise($promise)
|
||||||
|
{
|
||||||
|
$results = null;
|
||||||
|
$promise->then(function (ExecutionResult $executionResult) use (&$results) {
|
||||||
|
$results = $executionResult->toArray();
|
||||||
|
});
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user