Пример #1
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));
 }
 /**
  * @it output types are invalid
  */
 public function testOutputTypesAreInvalid()
 {
     $this->expectFailsRule(new VariablesAreInputTypes(), '
   query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) {
     field(a: $a, b: $b, c: $c)
   }
     ', [FormattedError::create(VariablesAreInputTypes::nonInputTypeOnVarMessage('a', 'Dog'), [new SourceLocation(2, 21)]), FormattedError::create(VariablesAreInputTypes::nonInputTypeOnVarMessage('b', '[[CatOrDog!]]!'), [new SourceLocation(2, 30)]), FormattedError::create(VariablesAreInputTypes::nonInputTypeOnVarMessage('c', 'Pet'), [new SourceLocation(2, 50)])]);
 }
Пример #3
0
 /**
  * @describe [T!]!
  */
 public function testHandlesNonNullListOfNonNulls()
 {
     $type = Type::nonNull(Type::listOf(Type::nonNull(Type::int())));
     // Contains values
     $this->check($type, [1, 2], ['data' => ['nest' => ['test' => [1, 2]]]]);
     // Contains null
     $this->check($type, [1, null, 2], ['data' => ['nest' => null], 'errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.test.', [new SourceLocation(1, 10)])]]);
     // Returns null
     $this->check($type, null, ['data' => ['nest' => null], 'errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.test.', [new SourceLocation(1, 10)])]]);
 }
Пример #4
0
 private function unknownType($typeName, $line, $column)
 {
     return FormattedError::create(KnownTypeNames::unknownTypeMessage($typeName), [new SourceLocation($line, $column)]);
 }
 private function duplicateField($name, $l1, $c1, $l2, $c2)
 {
     return FormattedError::create(UniqueInputFieldNames::duplicateInputFieldMessage($name), [new SourceLocation($l1, $c1), new SourceLocation($l2, $c2)]);
 }
Пример #6
0
 /**
  * @it nulls out error subtrees
  */
 public function testNullsOutErrorSubtrees()
 {
     $doc = '{
   sync,
   syncError,
   syncRawError,
   async,
   asyncReject,
   asyncError
     }';
     $data = ['sync' => function () {
         return 'sync';
     }, 'syncError' => function () {
         throw new \Exception('Error getting syncError');
     }, 'syncRawError' => function () {
         throw new \Exception('Error getting syncRawError');
     }, 'async' => function () {
         return 'async';
     }, 'asyncReject' => function () {
         throw new \Exception('Error getting asyncReject');
     }, 'asyncError' => function () {
         throw new \Exception('Error getting asyncError');
     }];
     $docAst = Parser::parse($doc);
     $schema = new Schema(['query' => new ObjectType(['name' => 'Type', 'fields' => ['sync' => ['type' => Type::string()], 'syncError' => ['type' => Type::string()], 'syncRawError' => ['type' => Type::string()], 'async' => ['type' => Type::string()], 'asyncReject' => ['type' => Type::string()], 'asyncError' => ['type' => Type::string()]]])]);
     $expected = ['data' => ['sync' => 'sync', 'syncError' => null, 'syncRawError' => null, 'async' => 'async', 'asyncReject' => null, 'asyncError' => null], 'errors' => [FormattedError::create('Error getting syncError', [new SourceLocation(3, 7)]), FormattedError::create('Error getting syncRawError', [new SourceLocation(4, 7)]), FormattedError::create('Error getting asyncReject', [new SourceLocation(6, 7)]), FormattedError::create('Error getting asyncError', [new SourceLocation(7, 7)])]];
     $result = Executor::execute($schema, $docAst, $data);
     $this->assertArraySubset($expected, $result->toArray());
 }
 private function error($fragName, $typeName, $line, $column)
 {
     return FormattedError::create(FragmentsOnCompositeTypes::fragmentOnNonCompositeErrorMessage($fragName, $typeName), [new SourceLocation($line, $column)]);
 }
 private function undefinedField($field, $type, $suggestions, $line, $column)
 {
     return FormattedError::create(FieldsOnCorrectType::undefinedFieldMessage($field, $type, $suggestions), [new SourceLocation($line, $column)]);
 }
Пример #9
0
 private function missingObjSubselection($field, $type, $line, $column)
 {
     return FormattedError::create(ScalarLeafs::requiredSubselectionMessage($field, $type), [new SourceLocation($line, $column)]);
 }
 /**
  * @it String => Boolean! in directive
  */
 public function testStringXBooleanNonNullInDirective()
 {
     // String => Boolean! in directive
     $this->expectFailsRule(new VariablesInAllowedPosition(), '
   query Query($stringVar: String) {
     dog @include(if: $stringVar)
   }
     ', [FormattedError::create(VariablesInAllowedPosition::badVarPosMessage('stringVar', 'String', 'Boolean!'), [new SourceLocation(2, 19), new SourceLocation(3, 26)])]);
 }
Пример #11
0
 private function unusedFrag($fragName, $line, $column)
 {
     return FormattedError::create(NoUnusedFragments::unusedFragMessage($fragName), [new SourceLocation($line, $column)]);
 }
 private function undefVar($varName, $line, $column, $opName = null, $l2 = null, $c2 = null)
 {
     $locs = [new SourceLocation($line, $column)];
     if ($l2 && $c2) {
         $locs[] = new SourceLocation($l2, $c2);
     }
     return FormattedError::create(NoUndefinedVariables::undefinedVarMessage($varName, $opName), $locs);
 }
    /**
     * @it compares deep types including list
     */
    public function testComparesDeepTypesIncludingList()
    {
        $this->expectFailsRuleWithSchema($this->getTestSchema(), new OverlappingFieldsCanBeMerged(), '
        {
          connection {
            ...edgeID
            edges {
              node {
                id: name
              }
            }
          }
        }

        fragment edgeID on Connection {
          edges {
            node {
              id
            }
          }
        }
      ', [FormattedError::create(OverlappingFieldsCanBeMerged::fieldsConflictMessage('edges', [['node', [['id', 'id and name are different fields']]]]), [new SourceLocation(14, 11), new SourceLocation(15, 13), new SourceLocation(16, 15), new SourceLocation(5, 13), new SourceLocation(6, 15), new SourceLocation(7, 17)])]);
    }
 private function missingDirectiveArg($directiveName, $argName, $typeName, $line, $column)
 {
     return FormattedError::create(ProvidedNonNullArguments::missingDirectiveArgMessage($directiveName, $argName, $typeName), [new SourceLocation($line, $column)]);
 }
Пример #15
0
 private function undefFrag($fragName, $line, $column)
 {
     return FormattedError::create(KnownFragmentNames::unknownFragmentMessage($fragName), [new SourceLocation($line, $column)]);
 }
Пример #16
0
    $appContext->rootUrl = 'http://localhost:8080';
    $appContext->request = $_REQUEST;
    // Parse incoming query and variables
    if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
        $raw = file_get_contents('php://input') ?: '';
        $data = json_decode($raw, true);
    } else {
        $data = $_REQUEST;
    }
    $data += ['query' => null, 'variables' => null];
    if (null === $data['query']) {
        $data['query'] = '{hello}';
    }
    // GraphQL schema to be passed to query executor:
    $schema = new Schema(['query' => Types::query()]);
    $result = GraphQL::execute($schema, $data['query'], null, $appContext, (array) $data['variables']);
    // Add reported PHP errors to result (if any)
    if (!empty($_GET['debug']) && !empty($phpErrors)) {
        $result['extensions']['phpErrors'] = array_map(['GraphQL\\Error\\FormattedError', 'createFromPHPError'], $phpErrors);
    }
    $httpStatus = 200;
} catch (\Exception $error) {
    $httpStatus = 500;
    if (!empty($_GET['debug'])) {
        $result['extensions']['exception'] = FormattedError::createFromException($error);
    } else {
        $result['errors'] = [FormattedError::create('Unexpected Error')];
    }
}
header('Content-Type: application/json', true, $httpStatus);
echo json_encode($result);
Пример #17
0
 function badValue($argName, $typeName, $value, $line, $column, $errors = null)
 {
     $realErrors = !$errors ? ["Expected type \"{$typeName}\", found {$value}."] : $errors;
     return FormattedError::create(ArgumentsOfCorrectType::badValueMessage($argName, $typeName, $value, $realErrors), [new SourceLocation($line, $column)]);
 }
 private function duplicateVariable($name, $l1, $c1, $l2, $c2)
 {
     return FormattedError::create(UniqueVariableNames::duplicateVariableMessage($name), [new SourceLocation($l1, $c1), new SourceLocation($l2, $c2)]);
 }
Пример #19
0
 /**
  * @it resolveType on Union yields useful error
  */
 public function testResolveTypeOnUnionYieldsUsefulError()
 {
     $HumanType = new ObjectType(['name' => 'Human', 'fields' => ['name' => ['type' => Type::string()]]]);
     $DogType = new ObjectType(['name' => 'Dog', 'fields' => ['name' => ['type' => Type::string()], 'woofs' => ['type' => Type::boolean()]]]);
     $CatType = new ObjectType(['name' => 'Cat', 'fields' => ['name' => ['type' => Type::string()], 'meows' => ['type' => Type::boolean()]]]);
     $PetType = new UnionType(['name' => 'Pet', 'resolveType' => function ($obj) use($DogType, $CatType, $HumanType) {
         if ($obj instanceof Dog) {
             return $DogType;
         }
         if ($obj instanceof Cat) {
             return $CatType;
         }
         if ($obj instanceof Human) {
             return $HumanType;
         }
     }, '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), new Human('Jon')];
     }]]])]);
     $query = '{
       pets {
         ... on Dog {
           name
           woofs
         }
         ... on Cat {
           name
           meows
         }
       }
     }';
     $result = GraphQL::execute($schema, $query);
     $expected = ['data' => ['pets' => [['name' => 'Odie', 'woofs' => true], ['name' => 'Garfield', 'meows' => false], null]], 'errors' => [FormattedError::create('Runtime Object type "Human" is not a possible type for "Pet".', [new SourceLocation(2, 11)])]];
     $this->assertEquals($expected, $result);
 }
Пример #20
0
 private function cycleError($fargment, $spreadNames, $line, $column)
 {
     return FormattedError::create(NoFragmentCycles::cycleErrorMessage($fargment, $spreadNames), [new SourceLocation($line, $column)]);
 }
 private function anonNotAlone($line, $column)
 {
     return FormattedError::create(LoneAnonymousOperation::anonOperationNotAloneMessage(), [new SourceLocation($line, $column)]);
 }
Пример #22
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'));
 }
 private function badValue($varName, $typeName, $val, $line, $column, $errors = null)
 {
     $realErrors = !$errors ? ["Expected type \"{$typeName}\", found {$val}."] : $errors;
     return FormattedError::create(DefaultValuesOfCorrectType::badValueForDefaultArgMessage($varName, $typeName, $val, $realErrors), [new SourceLocation($line, $column)]);
 }
Пример #24
0
 /**
  * @describe [T!]!
  */
 public function testHandlesNonNullListOfNonNullsWithArrayPromise()
 {
     // Contains values
     $this->checkHandlesNonNullListOfNonNulls([\React\Promise\resolve(1), \React\Promise\resolve(2)], ['data' => ['nest' => ['test' => [1, 2]]]]);
     // Contains null
     $this->checkHandlesNonNullListOfNonNulls([\React\Promise\resolve(1), \React\Promise\resolve(null), \React\Promise\resolve(2)], ['data' => ['nest' => null], 'errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.test.', [new SourceLocation(1, 10)])]]);
     // Contains reject
     $this->checkHandlesNonNullListOfNonNulls(function () {
         return [\React\Promise\resolve(1), \React\Promise\reject(new \Exception('bad')), \React\Promise\resolve(2)];
     }, ['data' => ['nest' => null], 'errors' => [['message' => 'bad', 'locations' => [['line' => 1, 'column' => 10]], 'path' => ['nest', 'test']]]]);
 }
 private function errorAnon($parentType, $fragType, $line, $column)
 {
     return FormattedError::create(PossibleFragmentSpreads::typeIncompatibleAnonSpreadMessage($parentType, $fragType), [new SourceLocation($line, $column)]);
 }
Пример #26
0
 public function testNullsTheTopLevelIfSyncNonNullableFieldReturnsNull()
 {
     // nulls the top level if sync non-nullable field returns null
     $doc = '
   query Q { nonNullSync }
     ';
     $expected = ['errors' => [FormattedError::create('Cannot return null for non-nullable field DataType.nonNullSync.', [new SourceLocation(2, 17)])]];
     $this->assertArraySubset($expected, Executor::execute($this->schema, Parser::parse($doc), $this->nullingData)->toArray());
 }
Пример #27
0
 /**
  * @it does not allow unknown types to be used as values
  */
 public function testDoesNotAllowUnknownTypesToBeUsedAsValues()
 {
     $doc = '
     query q($input: UnknownType!) {
       fieldWithObjectInput(input: $input)
     }
     ';
     $ast = Parser::parse($doc);
     $vars = ['input' => 'whoknows'];
     try {
         Executor::execute($this->schema(), $ast, null, null, $vars);
         $this->fail('Expected exception not thrown');
     } catch (Error $error) {
         $expected = FormattedError::create('Variable "$input" expected value of type "UnknownType!" which ' . 'cannot be used as an input type.', [new SourceLocation(2, 17)]);
         $this->assertEquals($expected, Error::formatError($error));
     }
 }
 private function duplicateArg($argName, $l1, $c1, $l2, $c2)
 {
     return FormattedError::create(UniqueArgumentNames::duplicateArgMessage($argName), [new SourceLocation($l1, $c1), new SourceLocation($l2, $c2)]);
 }
Пример #29
0
 /**
  * @it fails as expected on the __type root field without an arg
  */
 public function testFailsAsExpectedOnThe__typeRootFieldWithoutAnArg()
 {
     $TestType = new ObjectType(['name' => 'TestType', 'fields' => ['testField' => ['type' => Type::string()]]]);
     $schema = new Schema(['query' => $TestType]);
     $request = '
   {
     __type {
       name
     }
   }
 ';
     $expected = ['errors' => [FormattedError::create(ProvidedNonNullArguments::missingFieldArgMessage('__type', 'name', 'String!'), [new SourceLocation(3, 9)])]];
     $this->assertEquals($expected, GraphQL::execute($schema, $request));
 }
Пример #30
0
 private function unknownDirectiveArg($argName, $directiveName, $line, $column)
 {
     return FormattedError::create(KnownArgumentNames::unknownDirectiveArgMessage($argName, $directiveName), [new SourceLocation($line, $column)]);
 }