graphql-php/tests/Executor/SyncTest.php
2018-10-05 10:47:57 +02:00

224 lines
7.3 KiB
PHP

<?php
declare(strict_types=1);
namespace GraphQL\Tests\Executor;
use GraphQL\Deferred;
use GraphQL\Error\FormattedError;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Executor;
use GraphQL\Executor\Promise\Adapter\SyncPromise;
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\Executor\Promise\Promise;
use GraphQL\GraphQL;
use GraphQL\Language\Parser;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use GraphQL\Utils\Utils;
use GraphQL\Validator\DocumentValidator;
use PHPUnit\Framework\TestCase;
class SyncTest extends TestCase
{
/** @var Schema */
private $schema;
/** @var SyncPromiseAdapter */
private $promiseAdapter;
public function setUp()
{
$this->schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'syncField' => [
'type' => Type::string(),
'resolve' => static function ($rootValue) {
return $rootValue;
},
],
'asyncField' => [
'type' => Type::string(),
'resolve' => static function ($rootValue) {
return new Deferred(static function () use ($rootValue) {
return $rootValue;
});
},
],
],
]),
'mutation' => new ObjectType([
'name' => 'Mutation',
'fields' => [
'syncMutationField' => [
'type' => Type::string(),
'resolve' => static function ($rootValue) {
return $rootValue;
},
],
],
]),
]);
$this->promiseAdapter = new SyncPromiseAdapter();
}
// Describe: Execute: synchronously when possible
/**
* @see it('does not return a Promise for initial errors')
*/
public function testDoesNotReturnAPromiseForInitialErrors() : void
{
$doc = 'fragment Example on Query { syncField }';
$result = $this->execute(
$this->schema,
Parser::parse($doc),
'rootValue'
);
self::assertSync(['errors' => [['message' => 'Must provide an operation.']]], $result);
}
private function execute($schema, $doc, $rootValue = null)
{
return Executor::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
}
private static function assertSync($expectedFinalArray, $actualResult) : void
{
$message = 'Failed assertion that execution was synchronous';
self::assertInstanceOf(Promise::class, $actualResult, $message);
self::assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
self::assertEquals(SyncPromise::FULFILLED, $actualResult->adoptedPromise->state, $message);
self::assertInstanceOf(ExecutionResult::class, $actualResult->adoptedPromise->result, $message);
self::assertArraySubset(
$expectedFinalArray,
$actualResult->adoptedPromise->result->toArray(),
false,
$message
);
}
/**
* @see it('does not return a Promise if fields are all synchronous')
*/
public function testDoesNotReturnAPromiseIfFieldsAreAllSynchronous() : void
{
$doc = 'query Example { syncField }';
$result = $this->execute(
$this->schema,
Parser::parse($doc),
'rootValue'
);
self::assertSync(['data' => ['syncField' => 'rootValue']], $result);
}
// Describe: graphqlSync
/**
* @see it('does not return a Promise if mutation fields are all synchronous')
*/
public function testDoesNotReturnAPromiseIfMutationFieldsAreAllSynchronous() : void
{
$doc = 'mutation Example { syncMutationField }';
$result = $this->execute(
$this->schema,
Parser::parse($doc),
'rootValue'
);
self::assertSync(['data' => ['syncMutationField' => 'rootValue']], $result);
}
/**
* @see it('returns a Promise if any field is asynchronous')
*/
public function testReturnsAPromiseIfAnyFieldIsAsynchronous() : void
{
$doc = 'query Example { syncField, asyncField }';
$result = $this->execute(
$this->schema,
Parser::parse($doc),
'rootValue'
);
$this->assertAsync(['data' => ['syncField' => 'rootValue', 'asyncField' => 'rootValue']], $result);
}
private function assertAsync($expectedFinalArray, $actualResult)
{
$message = 'Failed assertion that execution was asynchronous';
self::assertInstanceOf(Promise::class, $actualResult, $message);
self::assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
self::assertEquals(SyncPromise::PENDING, $actualResult->adoptedPromise->state, $message);
$resolvedResult = $this->promiseAdapter->wait($actualResult);
self::assertInstanceOf(ExecutionResult::class, $resolvedResult, $message);
self::assertArraySubset($expectedFinalArray, $resolvedResult->toArray(), false, $message);
}
/**
* @see it('does not return a Promise for syntax errors')
*/
public function testDoesNotReturnAPromiseForSyntaxErrors() : void
{
$doc = 'fragment Example on Query { { { syncField }';
$result = $this->graphqlSync(
$this->schema,
$doc
);
self::assertSync(
[
'errors' => [
[
'message' => 'Syntax Error: Expected Name, found {',
'locations' => [['line' => 1, 'column' => 29]],
],
],
],
$result
);
}
private function graphqlSync($schema, $doc, $rootValue = null)
{
return GraphQL::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
}
/**
* @see it('does not return a Promise for validation errors')
*/
public function testDoesNotReturnAPromiseForValidationErrors() : void
{
$doc = 'fragment Example on Query { unknownField }';
$validationErrors = DocumentValidator::validate($this->schema, Parser::parse($doc));
$result = $this->graphqlSync(
$this->schema,
$doc
);
$expected = [
'errors' => Utils::map(
$validationErrors,
static function ($e) {
return FormattedError::createFromException($e);
}
),
];
self::assertSync($expected, $result);
}
/**
* @see it('does not return a Promise for sync execution')
*/
public function testDoesNotReturnAPromiseForSyncExecution() : void
{
$doc = 'query Example { syncField }';
$result = $this->graphqlSync(
$this->schema,
$doc,
'rootValue'
);
self::assertSync(['data' => ['syncField' => 'rootValue']], $result);
}
}