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); } }