schema = new Schema([ 'query' => new ObjectType([ 'name' => 'Query', 'fields' => [ 'syncField' => [ 'type' => Type::string(), 'resolve' => function ($rootValue) { return $rootValue; } ], 'asyncField' => [ 'type' => Type::string(), 'resolve' => function ($rootValue) { return new Deferred(function () use ($rootValue) { return $rootValue; }); } ] ] ]), 'mutation' => new ObjectType([ 'name' => 'Mutation', 'fields' => [ 'syncMutationField' => [ 'type' => Type::string(), 'resolve' => 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' ); $this->assertSync(['errors' => [['message' => 'Must provide an operation.']]], $result); } /** * @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' ); $this->assertSync(['data' => ['syncField' => 'rootValue']], $result); } /** * @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' ); $this->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); } // Describe: graphqlSync /** * @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 ); $this->assertSync([ 'errors' => [ ['message' => 'Syntax Error: Expected Name, found {', 'locations' => [['line' => 1, 'column' => 29]]] ] ], $result); } /** * @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, function ($e) { return FormattedError::createFromException($e); }) ]; $this->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' ); $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); } }