Example #1
0
 /**
  * @it isTypeOf used to resolve runtime type for Union
  */
 public function testIsTypeOfUsedToResolveRuntimeTypeForUnion()
 {
     $dogType = new ObjectType(['name' => 'Dog', 'isTypeOf' => function ($obj) {
         return $obj instanceof Dog;
     }, 'fields' => ['name' => ['type' => Type::string()], 'woofs' => ['type' => Type::boolean()]]]);
     $catType = new ObjectType(['name' => 'Cat', 'isTypeOf' => function ($obj) {
         return $obj instanceof Cat;
     }, 'fields' => ['name' => ['type' => Type::string()], 'meows' => ['type' => Type::boolean()]]]);
     $petType = new UnionType(['name' => 'Pet', 'types' => [$dogType, $catType]]);
     $schema = new Schema(['query' => new ObjectType(['name' => 'Query', 'fields' => ['pets' => ['type' => Type::listOf($petType), 'resolve' => function () {
         return [new Dog('Odie', true), new Cat('Garfield', false)];
     }]]])]);
     $query = '{
       pets {
         name
         ... on Dog {
           woofs
         }
         ... on Cat {
           meows
         }
       }
     }';
     $expected = new ExecutionResult(['pets' => [['name' => 'Odie', 'woofs' => true], ['name' => 'Garfield', 'meows' => false]]]);
     $this->assertEquals($expected, Executor::execute($schema, Parser::parse($query)));
 }
Example #2
0
 /**
  * @it evaluates mutations correctly in the presense of a failed mutation
  */
 public function testEvaluatesMutationsCorrectlyInThePresenseOfAFailedMutation()
 {
     $doc = 'mutation M {
   first: immediatelyChangeTheNumber(newNumber: 1) {
     theNumber
   },
   second: promiseToChangeTheNumber(newNumber: 2) {
     theNumber
   },
   third: failToChangeTheNumber(newNumber: 3) {
     theNumber
   }
   fourth: promiseToChangeTheNumber(newNumber: 4) {
     theNumber
   },
   fifth: immediatelyChangeTheNumber(newNumber: 5) {
     theNumber
   }
   sixth: promiseAndFailToChangeTheNumber(newNumber: 6) {
     theNumber
   }
 }';
     $ast = Parser::parse($doc);
     $mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
     $expected = ['data' => ['first' => ['theNumber' => 1], 'second' => ['theNumber' => 2], 'third' => null, 'fourth' => ['theNumber' => 4], 'fifth' => ['theNumber' => 5], 'sixth' => null], 'errors' => [FormattedError::create('Cannot change the number', [new SourceLocation(8, 7)]), FormattedError::create('Cannot change the number', [new SourceLocation(17, 7)])]];
     $this->assertArraySubset($expected, self::awaitPromise($mutationResult));
 }
Example #3
0
 function expectInvalid($schema, $rules, $queryString, $errors)
 {
     $result = DocumentValidator::validate($schema, Parser::parse($queryString), $rules);
     $this->assertEquals(false, $result['isValid'], 'GraphQL should not validate');
     $this->assertEquals($errors, $result['errors']);
     return $result;
 }
Example #4
0
 function expectInvalid($schema, $rules, $queryString, $expectedErrors)
 {
     $errors = DocumentValidator::validate($schema, Parser::parse($queryString), $rules);
     $this->assertNotEmpty($errors, 'GraphQL should not validate');
     $this->assertEquals($expectedErrors, array_map(['GraphQL\\Error\\Error', 'formatError'], $errors));
     return $errors;
 }
 /**
  * Set up the graphql request.
  *
  * @param  $query string
  * @return void
  */
 public function setupRequest($query = 'GraphGL request', $operation = 'query')
 {
     $source = new Source($query);
     $ast = GraphQLParser::parse($source);
     if (isset($ast->definitions[0])) {
         $d = $ast->definitions[0];
         $operation = $d->operation ?: 'query';
         $selectionSet = $d->selectionSet->selections;
         $this->parseSelections($selectionSet, $operation);
     }
 }
    public function testExecutesUsingASchema()
    {
        $BlogArticle = null;
        $BlogImage = new ObjectType(['name' => 'Image', 'fields' => ['url' => ['type' => Type::string()], 'width' => ['type' => Type::int()], 'height' => ['type' => Type::int()]]]);
        $BlogAuthor = new ObjectType(['name' => 'Author', 'fields' => ['id' => ['type' => Type::string()], 'name' => ['type' => Type::string()], 'pic' => ['args' => ['width' => ['type' => Type::int()], 'height' => ['type' => Type::int()]], 'type' => $BlogImage, 'resolve' => function ($obj, $args) {
            return $obj['pic']($args['width'], $args['height']);
        }], 'recentArticle' => ['type' => function () use(&$BlogArticle) {
            return $BlogArticle;
        }]]]);
        $BlogArticle = new ObjectType(['name' => 'Article', 'fields' => ['id' => ['type' => Type::nonNull(Type::string())], 'isPublished' => ['type' => Type::boolean()], 'author' => ['type' => $BlogAuthor], 'title' => ['type' => Type::string()], 'body' => ['type' => Type::string()], 'keywords' => ['type' => Type::listOf(Type::string())]]]);
        $BlogQuery = new ObjectType(['name' => 'Query', 'fields' => ['article' => ['type' => $BlogArticle, 'args' => ['id' => ['type' => Type::id()]], 'resolve' => function ($_, $args) {
            return $this->article($args['id']);
        }], 'feed' => ['type' => Type::listOf($BlogArticle), 'resolve' => function () {
            return [$this->article(1), $this->article(2), $this->article(3), $this->article(4), $this->article(5), $this->article(6), $this->article(7), $this->article(8), $this->article(9), $this->article(10)];
        }]]]);
        $BlogSchema = new Schema($BlogQuery);
        $request = '
      {
        feed {
          id,
          title
        },
        article(id: "1") {
          ...articleFields,
          author {
            id,
            name,
            pic(width: 640, height: 480) {
              url,
              width,
              height
            },
            recentArticle {
              ...articleFields,
              keywords
            }
          }
        }
      }

      fragment articleFields on Article {
        id,
        isPublished,
        title,
        body,
        hidden,
        notdefined
      }
    ';
        $expected = ['data' => ['feed' => [['id' => '1', 'title' => 'My Article 1'], ['id' => '2', 'title' => 'My Article 2'], ['id' => '3', 'title' => 'My Article 3'], ['id' => '4', 'title' => 'My Article 4'], ['id' => '5', 'title' => 'My Article 5'], ['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' => ['id' => '1', 'isPublished' => true, 'title' => 'My Article 1', 'body' => 'This is a post', 'author' => ['id' => '123', 'name' => 'John Smith', 'pic' => ['url' => 'cdn://123', 'width' => 640, 'height' => 480], 'recentArticle' => ['id' => '1', 'isPublished' => true, 'title' => 'My Article 1', 'body' => 'This is a post', 'keywords' => ['foo', 'bar', '1', 'true', null]]]]]];
        $this->assertEquals($expected, Executor::execute($BlogSchema, Parser::parse($request))->toArray());
    }
Example #7
0
    public function testParseCreatesAst()
    {
        $source = new Source('{
  node(id: 4) {
    id,
    name
  }
}
');
        $result = Parser::parse($source);
        $expected = new Document(array('loc' => new Location(0, 41, $source), 'definitions' => array(new OperationDefinition(array('loc' => new Location(0, 40, $source), 'operation' => 'query', 'name' => null, 'variableDefinitions' => null, 'directives' => array(), 'selectionSet' => new SelectionSet(array('loc' => new Location(0, 40, $source), 'selections' => array(new Field(array('loc' => new Location(4, 38, $source), 'alias' => null, 'name' => new Name(array('loc' => new Location(4, 8, $source), 'value' => 'node')), 'arguments' => array(new Argument(array('name' => new Name(array('loc' => new Location(9, 11, $source), 'value' => 'id')), 'value' => new IntValue(array('loc' => new Location(13, 14, $source), 'value' => '4')), 'loc' => new Location(9, 14, $source)))), 'directives' => [], 'selectionSet' => new SelectionSet(array('loc' => new Location(16, 38, $source), 'selections' => array(new Field(array('loc' => new Location(22, 24, $source), 'alias' => null, 'name' => new Name(array('loc' => new Location(22, 24, $source), 'value' => 'id')), 'arguments' => [], 'directives' => [], 'selectionSet' => null)), new Field(array('loc' => new Location(30, 34, $source), 'alias' => null, 'name' => new Name(array('loc' => new Location(30, 34, $source), 'value' => 'name')), 'arguments' => [], 'directives' => [], 'selectionSet' => null)))))))))))))));
        $this->assertEquals($expected, $result);
    }
 /**
  * Handles execution of a lazily created interface
  */
 public function testReturnsFragmentsWithLazyCreatedInterface()
 {
     $request = '
     {
         lazyInterface {
             ... on TestObject {
                 name
             }
         }
     }
     ';
     $expected = ['data' => ['lazyInterface' => ['name' => 'testname']]];
     $this->assertEquals($expected, Executor::execute($this->schema, Parser::parse($request))->toArray());
 }
Example #9
0
 private function check($testType, $testData, $expected)
 {
     $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());
 }
Example #10
0
 /**
  * @param Schema $schema
  * @param $requestString
  * @param mixed $rootValue
  * @param array <string, string>|null $variableValues
  * @param string|null $operationName
  * @return array
  */
 public static function execute(Schema $schema, $requestString, $rootValue = null, $variableValues = null, $operationName = null)
 {
     try {
         $source = new Source($requestString ?: '', 'GraphQL request');
         $documentAST = Parser::parse($source);
         $validationErrors = DocumentValidator::validate($schema, $documentAST);
         if (!empty($validationErrors)) {
             return ['errors' => array_map(['GraphQL\\Error', 'formatError'], $validationErrors)];
         } else {
             return Executor::execute($schema, $documentAST, $rootValue, $variableValues, $operationName)->toArray();
         }
     } catch (Error $e) {
         return ['errors' => [Error::formatError($e)]];
     }
 }
Example #11
0
 /**
  * @param Schema $schema
  * @param $requestString
  * @param mixed $rootObject
  * @param array <string, string>|null $variableValues
  * @param string|null $operationName
  * @return array
  */
 public static function execute(Schema $schema, $requestString, $rootObject = null, $variableValues = null, $operationName = null)
 {
     try {
         $source = new Source($requestString ?: '', 'GraphQL request');
         $ast = Parser::parse($source);
         $validationResult = DocumentValidator::validate($schema, $ast);
         if (empty($validationResult['isValid'])) {
             return ['errors' => $validationResult['errors']];
         } else {
             return Executor::execute($schema, $rootObject, $ast, $operationName, $variableValues);
         }
     } catch (\Exception $e) {
         return ['errors' => Error::formatError($e)];
     }
 }
Example #12
0
 /**
  * @param Schema $schema
  * @param $requestString
  * @param null $rootValue
  * @param null $variableValues
  * @param null $operationName
  * @return array|ExecutionResult
  */
 public static function executeAndReturnResult(Schema $schema, $requestString, $rootValue = null, $variableValues = null, $operationName = null)
 {
     try {
         $source = new Source($requestString ?: '', 'GraphQL request');
         $documentAST = Parser::parse($source);
         $validationErrors = DocumentValidator::validate($schema, $documentAST);
         if (!empty($validationErrors)) {
             return new ExecutionResult(null, $validationErrors);
         } else {
             return Executor::execute($schema, $documentAST, $rootValue, $variableValues, $operationName);
         }
     } catch (Error $e) {
         return new ExecutionResult(null, [$e]);
     }
 }
Example #13
0
    public function testPrintsKitchenSink()
    {
        $kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
        $ast = Parser::parse($kitchenSink);
        $printed = Printer::doPrint($ast);
        $expected = <<<'EOT'
query queryName($foo: ComplexType, $site: Site = MOBILE) {
  whoever123is: node(id: [123, 456]) {
    id,
    ... on User @defer {
      field2 {
        id,
        alias: field1(first: 10, after: $foo) @if: $foo {
          id,
          ...frag
        }
      }
    }
  }
}

mutation likeStory {
  like(story: 123) @defer {
    story {
      id
    }
  }
}

fragment frag on Friend {
  foo(size: $size, bar: $b, obj: {key: "value"})
}

{
  unnamed(truthy: true, falsey: false),
  query
}

EOT;
        $this->assertEquals($expected, $printed);
    }
Example #14
0
 /**
  * @param Schema $schema
  * @param $requestString
  * @param null $rootValue
  * @param null $variableValues
  * @param null $operationName
  * @return array|ExecutionResult
  */
 public static function executeAndReturnResult(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
 {
     try {
         if ($requestString instanceof Document) {
             $documentAST = $requestString;
         } else {
             $source = new Source($requestString ?: '', 'GraphQL request');
             $documentAST = Parser::parse($source);
         }
         /** @var QueryComplexity $queryComplexity */
         $queryComplexity = DocumentValidator::getRule('QueryComplexity');
         $queryComplexity->setRawVariableValues($variableValues);
         $validationErrors = DocumentValidator::validate($schema, $documentAST);
         if (!empty($validationErrors)) {
             return new ExecutionResult(null, $validationErrors);
         } else {
             return Executor::execute($schema, $documentAST, $rootValue, $contextValue, $variableValues, $operationName);
         }
     } catch (Error $e) {
         return new ExecutionResult(null, [$e]);
     }
 }
Example #15
0
    public function testPrintsKitchenSink()
    {
        $kitchenSink = file_get_contents(__DIR__ . '/schema-kitchen-sink.graphql');
        $ast = Parser::parse($kitchenSink);
        $printed = Printer::doPrint($ast);
        $expected = 'schema {
  query: QueryType
  mutation: MutationType
}

type Foo implements Bar {
  one: Type
  two(argument: InputType!): Type
  three(argument: InputType, other: String): Int
  four(argument: String = "string"): String
  five(argument: [String] = ["string", "string"]): String
  six(argument: InputType = {key: "value"}): Type
}

type AnnotatedObject @onObject(arg: "value") {
  annotatedField(arg: Type = "default" @onArg): Type @onField
}

interface Bar {
  one: Type
  four(argument: String = "string"): String
}

interface AnnotatedInterface @onInterface {
  annotatedField(arg: Type @onArg): Type @onField
}

union Feed = Story | Article | Advert

union AnnotatedUnion @onUnion = A | B

scalar CustomScalar

scalar AnnotatedScalar @onScalar

enum Site {
  DESKTOP
  MOBILE
}

enum AnnotatedEnum @onEnum {
  ANNOTATED_VALUE @onEnumValue
  OTHER_VALUE
}

input InputType {
  key: String!
  answer: Int = 42
}

input AnnotatedInput @onInputObjectType {
  annotatedField: Type @onField
}

extend type Foo {
  seven(argument: [String]): Type
}

extend type Foo @onType {}

type NoFields {}

directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
';
        $this->assertEquals($expected, $printed);
    }
Example #16
0
 private function executeTestQuery($doc)
 {
     return Executor::execute(self::getSchema(), Parser::parse($doc), self::getData())->toArray();
 }
Example #17
0
 /**
  * @see https://github.com/webonyx/graphql-php/issues/59
  */
 public function testSerializesToEmptyObjectVsEmptyArray()
 {
     $iface = null;
     $a = new ObjectType(['name' => 'A', 'fields' => ['id' => Type::id()], 'interfaces' => function () use(&$iface) {
         return [$iface];
     }]);
     $b = new ObjectType(['name' => 'B', 'fields' => ['id' => Type::id()], 'interfaces' => function () use(&$iface) {
         return [$iface];
     }]);
     $iface = new InterfaceType(['name' => 'Iface', 'fields' => ['id' => Type::id()], 'resolveType' => function ($v) use($a, $b) {
         return $v['type'] === 'A' ? $a : $b;
     }]);
     $schema = new Schema(['query' => new ObjectType(['name' => 'Query', 'fields' => ['ab' => Type::listOf($iface)]]), 'types' => [$a, $b]]);
     $data = ['ab' => [['id' => 1, 'type' => 'A'], ['id' => 2, 'type' => 'A'], ['id' => 3, 'type' => 'B'], ['id' => 4, 'type' => 'B']]];
     $query = Parser::parse('
         {
             ab {
                 ... on A{
                     id
                 }
             }
         }
     ');
     $result = Executor::execute($schema, $query, $data, null);
     $this->assertEquals(['data' => ['ab' => [['id' => '1'], ['id' => '2'], new \stdClass(), new \stdClass()]]], $result->toArray());
 }
Example #18
0
 /**
  * @it when argument provided cannot be parsed
  */
 public function testWhenArgumentProvidedCannotBeParsed()
 {
     $ast = Parser::parse('{
         fieldWithDefaultArgumentValue(input: WRONG_TYPE)
     }');
     $this->assertEquals(['data' => ['fieldWithDefaultArgumentValue' => '"Hello World"']], Executor::execute($this->schema(), $ast)->toArray());
 }
Example #19
0
    /**
     * @it Simple input object with args should fail
     */
    public function testSimpleInputObjectWithArgsShouldFail()
    {
        $body = '
input Hello {
  world(foo: Int): String
}';
        $this->setExpectedException('GraphQL\\Error\\SyntaxError');
        Parser::parse($body);
    }
Example #20
0
 public function testNullsTheTopLevelIfAsyncNonNullableFieldResolvesNull()
 {
     $doc = '
   query Q { nonNullPromise }
 ';
     $ast = Parser::parse($doc);
     $expected = ['data' => null, 'errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.nonNullPromise.', [new SourceLocation(2, 17)])]];
     Executor::setPromiseAdapter(new ReactPromiseAdapter());
     $this->assertArraySubsetPromise($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q'));
 }
Example #21
0
 public function testDoesNotAllowNonNullListsOfNonNullsToContainNull()
 {
     $doc = '
     query q($input:[String!]!) {
       nnListNN(input: $input)
     }
     ';
     $ast = Parser::parse($doc);
     $expected = ['data' => null, 'errors' => [new FormattedError('Variable $input expected value of type [String!]! but got: ["A",null,"B"].', [new SourceLocation(2, 17)])]];
     $this->assertEquals($expected, Executor::execute($this->schema(), null, $ast, null, ['input' => ['A', null, 'B']]));
 }
Example #22
0
 public function testResolvedValueIsMemoized()
 {
     $doc = '
   query Q {
     a {
       b {
         c
         d
       }
     }
   }
   ';
     $memoizedValue = new \ArrayObject(['b' => 'id1']);
     $A = null;
     $Test = new ObjectType(['name' => 'Test', 'fields' => ['a' => ['type' => function () use(&$A) {
         return Type::listOf($A);
     }, 'resolve' => function () use($memoizedValue) {
         return [$memoizedValue, new \ArrayObject(['b' => 'id2']), $memoizedValue, new \ArrayObject(['b' => 'id2'])];
     }]]]);
     $callCounts = ['id1' => 0, 'id2' => 0];
     $A = new ObjectType(['name' => 'A', 'fields' => ['b' => ['type' => new ObjectType(['name' => 'B', 'fields' => ['c' => ['type' => Type::string()], 'd' => ['type' => Type::string()]]]), 'resolve' => function ($value) use(&$callCounts) {
         $callCounts[$value['b']]++;
         switch ($value['b']) {
             case 'id1':
                 return ['c' => 'c1', 'd' => 'd1'];
             case 'id2':
                 return ['c' => 'c2', 'd' => 'd2'];
         }
     }]]]);
     // Test that value resolved once is memoized for same query field
     $schema = new Schema($Test);
     $query = Parser::parse($doc);
     $result = Executor::execute($schema, $query);
     $expected = ['data' => ['a' => [['b' => ['c' => 'c1', 'd' => 'd1']], ['b' => ['c' => 'c2', 'd' => 'd2']], ['b' => ['c' => 'c1', 'd' => 'd1']], ['b' => ['c' => 'c2', 'd' => 'd2']]]]];
     $this->assertEquals($expected, $result->toArray());
     $this->assertSame($callCounts['id1'], 1);
     // Result for id1 is expected to be memoized after first call
     $this->assertSame($callCounts['id2'], 2);
 }
 /**
  * Helper function to test a query and the expected response.
  */
 private function validationErrors($query)
 {
     $ast = Parser::parse($query);
     return DocumentValidator::validate(StarWarsSchema::build(), $ast);
 }
Example #24
0
 public function testDoesNotIncludeArgumentsThatWereNotSet()
 {
     $schema = new Schema(new ObjectType(['name' => 'Type', 'fields' => ['field' => ['type' => Type::string(), 'resolve' => function ($data, $args) {
         return $args ? json_encode($args) : '';
     }, 'args' => ['a' => ['type' => Type::boolean()], 'b' => ['type' => Type::boolean()], 'c' => ['type' => Type::boolean()], 'd' => ['type' => Type::int()], 'e' => ['type' => Type::int()]]]]]));
     $query = Parser::parse('{ field(a: true, c: false, e: 0) }');
     $result = Executor::execute($schema, $query);
     $expected = ['data' => ['field' => '{"a":true,"c":false,"e":0}']];
     $this->assertEquals($expected, $result->toArray());
     /*
        var query = parse('{ field(a: true, c: false, e: 0) }');
        var result = await execute(schema, query);
     
        expect(result).to.deep.equal({
          data: {
            field: '{"a":true,"c":false,"e":0}'
          }
        });
      });
     
      it('fails when an isTypeOf check is not met', async () => {
        class Special {
          constructor(value) {
            this.value = value;
          }
        }
     
        class NotSpecial {
          constructor(value) {
            this.value = value;
          }
        }
     
        var SpecialType = new GraphQLObjectType({
          name: 'SpecialType',
          isTypeOf(obj) {
            return obj instanceof Special;
          },
          fields: {
            value: { type: GraphQLString }
          }
        });
     
        var schema = new GraphQLSchema({
          query: new GraphQLObjectType({
            name: 'Query',
            fields: {
              specials: {
                type: new GraphQLList(SpecialType),
                resolve: rootValue => rootValue.specials
              }
            }
          })
        });
     
        var query = parse('{ specials { value } }');
        var value = {
          specials: [ new Special('foo'), new NotSpecial('bar') ]
        };
        var result = await execute(schema, query, value);
     
        expect(result.data).to.deep.equal({
          specials: [
            { value: 'foo' },
            null
          ]
        });
        expect(result.errors).to.have.lengthOf(1);
        expect(result.errors).to.containSubset([
          { message:
              'Expected value of type "SpecialType" but got: [object Object].',
            locations: [ { line: 1, column: 3 } ] }
        ]);
      });
     */
 }
Example #25
0
 /**
  * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for
  * that type.
  * Throws GraphQLError if a syntax error is encountered.
  *
  * This is useful within tools that operate upon GraphQL Types directly and
  * in isolation of complete GraphQL documents.
  *
  * Consider providing the results to the utility function: typeFromAST().
  * @param Source|string $source
  * @param array $options
  * @return ListType|Name|NonNullType
  */
 public static function parseType($source, array $options = [])
 {
     $sourceObj = $source instanceof Source ? $source : new Source($source);
     $parser = new Parser($sourceObj, $options);
     $parser->expect(Token::SOF);
     $type = $parser->parseTypeReference();
     $parser->expect(Token::EOF);
     return $type;
 }
Example #26
0
    /**
     * @it prints kitchen sink
     */
    public function testPrintsKitchenSink()
    {
        $kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
        $ast = Parser::parse($kitchenSink);
        $printed = Printer::doPrint($ast);
        $expected = <<<'EOT'
query queryName($foo: ComplexType, $site: Site = MOBILE) {
  whoever123is: node(id: [123, 456]) {
    id
    ... on User @defer {
      field2 {
        id
        alias: field1(first: 10, after: $foo) @include(if: $foo) {
          id
          ...frag
        }
      }
    }
    ... @skip(unless: $foo) {
      id
    }
    ... {
      id
    }
  }
}

mutation likeStory {
  like(story: 123) @defer {
    story {
      id
    }
  }
}

subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) {
  storyLikeSubscribe(input: $input) {
    story {
      likers {
        count
      }
      likeSentence {
        text
      }
    }
  }
}

fragment frag on Friend {
  foo(size: $size, bar: $b, obj: {key: "value"})
}

{
  unnamed(truthy: true, falsey: false)
  query
}

EOT;
        $this->assertEquals($expected, $printed);
    }
Example #27
0
 /**
  * @it serializes to include message and locations
  */
 public function testSerializesToIncludeMessageAndLocations()
 {
     $node = Parser::parse('{ field }')->definitions[0]->selectionSet->selections[0];
     $e = new Error('msg', [$node]);
     $this->assertEquals(['message' => 'msg', 'locations' => [['line' => 1, 'column' => 3]]], $e->toSerializableArray());
 }
Example #28
0
    public function testAllowsFragmentConditionsToBeAbstractTypes()
    {
        $ast = Parser::parse('
      {
        __typename
        name
        pets { ...PetFields }
        friends { ...FriendFields }
      }

      fragment PetFields on Pet {
        __typename
        ... on Dog {
          name
          barks
        }
        ... on Cat {
          name
          meows
        }
      }

      fragment FriendFields on Named {
        __typename
        name
        ... on Dog {
          barks
        }
        ... on Cat {
          meows
        }
      }
    ');
        $expected = ['data' => ['__typename' => 'Person', 'name' => 'John', 'pets' => [['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false], ['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]], 'friends' => [['__typename' => 'Person', 'name' => 'Liz'], ['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]]]];
        $this->assertEquals($expected, Executor::execute($this->schema, $this->john, $ast));
    }
Example #29
0
 public function testNullsTheTopLevelIfSyncNonNullableFieldReturnsNull()
 {
     // nulls the top level if sync non-nullable field returns null
     $doc = '
   query Q { nonNullSync }
     ';
     $expected = ['data' => null, 'errors' => [FormattedError::create('Cannot return null for non-nullable type.', [new SourceLocation(2, 17)])]];
     $this->assertEquals($expected, Executor::execute($this->schema, Parser::parse($doc), $this->nullingData)->toArray());
 }
Example #30
0
 /**
  * @it maintains type info during edit
  */
 public function testMaintainsTypeInfoDuringEdit()
 {
     $visited = [];
     $typeInfo = new TypeInfo(TestCase::getDefaultSchema());
     $ast = Parser::parse('{ human(id: 4) { name, pets }, alien }');
     $editedAst = Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, ['enter' => function ($node) use($typeInfo, &$visited) {
         $parentType = $typeInfo->getParentType();
         $type = $typeInfo->getType();
         $inputType = $typeInfo->getInputType();
         $visited[] = ['enter', $node->kind, $node->kind === 'Name' ? $node->value : null, $parentType ? (string) $parentType : null, $type ? (string) $type : null, $inputType ? (string) $inputType : null];
         // Make a query valid by adding missing selection sets.
         if ($node->kind === 'Field' && !$node->selectionSet && Type::isCompositeType(Type::getNamedType($type))) {
             return new FieldNode(['alias' => $node->alias, 'name' => $node->name, 'arguments' => $node->arguments, 'directives' => $node->directives, 'selectionSet' => new SelectionSetNode(['kind' => 'SelectionSet', 'selections' => [new FieldNode(['name' => new NameNode(['value' => '__typename'])])]])]);
         }
     }, 'leave' => function ($node) use($typeInfo, &$visited) {
         $parentType = $typeInfo->getParentType();
         $type = $typeInfo->getType();
         $inputType = $typeInfo->getInputType();
         $visited[] = ['leave', $node->kind, $node->kind === 'Name' ? $node->value : null, $parentType ? (string) $parentType : null, $type ? (string) $type : null, $inputType ? (string) $inputType : null];
     }]));
     $this->assertEquals(Printer::doPrint(Parser::parse('{ human(id: 4) { name, pets }, alien }')), Printer::doPrint($ast));
     $this->assertEquals(Printer::doPrint(Parser::parse('{ human(id: 4) { name, pets { __typename } }, alien { __typename } }')), Printer::doPrint($editedAst));
     $this->assertEquals([['enter', 'Document', null, null, null, null], ['enter', 'OperationDefinition', null, null, 'QueryRoot', null], ['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null], ['enter', 'Field', null, 'QueryRoot', 'Human', null], ['enter', 'Name', 'human', 'QueryRoot', 'Human', null], ['leave', 'Name', 'human', 'QueryRoot', 'Human', null], ['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'], ['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'], ['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'], ['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'], ['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'], ['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'], ['enter', 'SelectionSet', null, 'Human', 'Human', null], ['enter', 'Field', null, 'Human', 'String', null], ['enter', 'Name', 'name', 'Human', 'String', null], ['leave', 'Name', 'name', 'Human', 'String', null], ['leave', 'Field', null, 'Human', 'String', null], ['enter', 'Field', null, 'Human', '[Pet]', null], ['enter', 'Name', 'pets', 'Human', '[Pet]', null], ['leave', 'Name', 'pets', 'Human', '[Pet]', null], ['enter', 'SelectionSet', null, 'Pet', '[Pet]', null], ['enter', 'Field', null, 'Pet', 'String!', null], ['enter', 'Name', '__typename', 'Pet', 'String!', null], ['leave', 'Name', '__typename', 'Pet', 'String!', null], ['leave', 'Field', null, 'Pet', 'String!', null], ['leave', 'SelectionSet', null, 'Pet', '[Pet]', null], ['leave', 'Field', null, 'Human', '[Pet]', null], ['leave', 'SelectionSet', null, 'Human', 'Human', null], ['leave', 'Field', null, 'QueryRoot', 'Human', null], ['enter', 'Field', null, 'QueryRoot', 'Alien', null], ['enter', 'Name', 'alien', 'QueryRoot', 'Alien', null], ['leave', 'Name', 'alien', 'QueryRoot', 'Alien', null], ['enter', 'SelectionSet', null, 'Alien', 'Alien', null], ['enter', 'Field', null, 'Alien', 'String!', null], ['enter', 'Name', '__typename', 'Alien', 'String!', null], ['leave', 'Name', '__typename', 'Alien', 'String!', null], ['leave', 'Field', null, 'Alien', 'String!', null], ['leave', 'SelectionSet', null, 'Alien', 'Alien', null], ['leave', 'Field', null, 'QueryRoot', 'Alien', null], ['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null], ['leave', 'OperationDefinition', null, null, 'QueryRoot', null], ['leave', 'Document', null, null, null, null]], $visited);
 }