expectPassesRule(new PossibleFragmentSpreads(), ' fragment objectWithinObject on Dog { ...dogFragment } fragment dogFragment on Dog { barkVolume } '); } /** * @it of the same object with inline fragment */ public function testOfTheSameObjectWithInlineFragment() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } '); } /** * @it object into an implemented interface */ public function testObjectIntoAnImplementedInterface() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment objectWithinInterface on Pet { ...dogFragment } fragment dogFragment on Dog { barkVolume } '); } /** * @it object into containing union */ public function testObjectIntoContainingUnion() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment objectWithinUnion on CatOrDog { ...dogFragment } fragment dogFragment on Dog { barkVolume } '); } /** * @it union into contained object */ public function testUnionIntoContainedObject() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment unionWithinObject on Dog { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } '); } /** * @it union into overlapping interface */ public function testUnionIntoOverlappingInterface() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment unionWithinInterface on Pet { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } '); } /** * @it union into overlapping union */ public function testUnionIntoOverlappingUnion() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } '); } /** * @it interface into implemented object */ public function testInterfaceIntoImplementedObject() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment interfaceWithinObject on Dog { ...petFragment } fragment petFragment on Pet { name } '); } /** * @it interface into overlapping interface */ public function testInterfaceIntoOverlappingInterface() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment interfaceWithinInterface on Pet { ...beingFragment } fragment beingFragment on Being { name } '); } /** * @it interface into overlapping interface in inline fragment */ public function testInterfaceIntoOverlappingInterfaceInInlineFragment() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment interfaceWithinInterface on Pet { ... on Being { name } } '); } /** * @it interface into overlapping union */ public function testInterfaceIntoOverlappingUnion() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment interfaceWithinUnion on CatOrDog { ...petFragment } fragment petFragment on Pet { name } '); } /** * @it ignores incorrect type (caught by FragmentsOnCompositeTypes) */ public function testIgnoresIncorrectTypeCaughtByFragmentsOnCompositeTypes() { $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment petFragment on Pet { ...badInADifferentWay } fragment badInADifferentWay on String { name } '); } /** * @it different object into object */ public function testDifferentObjectIntoObject() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } ', [$this->error('dogFragment', 'Cat', 'Dog', 2, 51)] ); } /** * @it different object into object in inline fragment */ public function testDifferentObjectIntoObjectInInlineFragment() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } ', [$this->errorAnon('Cat', 'Dog', 3, 9)] ); } /** * @it object into not implementing interface */ public function testObjectIntoNotImplementingInterface() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } ', [$this->error('humanFragment', 'Pet', 'Human', 2, 54)] ); } /** * @it object into not containing union */ public function testObjectIntoNotContainingUnion() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } ', [$this->error('humanFragment', 'CatOrDog', 'Human', 2, 55)] ); } /** * @it union into not contained object */ public function testUnionIntoNotContainedObject() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } ', [$this->error('catOrDogFragment', 'Human', 'CatOrDog', 2, 52)] ); } /** * @it union into non overlapping interface */ public function testUnionIntoNonOverlappingInterface() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } ', [$this->error('humanOrAlienFragment', 'Pet', 'HumanOrAlien', 2, 53)] ); } /** * @it union into non overlapping union */ public function testUnionIntoNonOverlappingUnion() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } ', [$this->error('humanOrAlienFragment', 'CatOrDog', 'HumanOrAlien', 2, 54)] ); } /** * @it interface into non implementing object */ public function testInterfaceIntoNonImplementingObject() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } ', [$this->error('intelligentFragment', 'Cat', 'Intelligent', 2, 54)] ); } /** * @it interface into non overlapping interface */ public function testInterfaceIntoNonOverlappingInterface() { // Ideally this should fail, but our new lazy schema doesn't scan through all types and fields // So we don't have enough knowledge to check interface intersection and always allow this to pass: $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment invalidInterfaceWithinInterface on Pet { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } '); } /** * @it interface into non overlapping interface in inline fragment */ public function testInterfaceIntoNonOverlappingInterfaceInInlineFragment() { // Ideally this should fail, but our new lazy schema doesn't scan through all types and fields // So we don't have enough knowledge to check interface intersection and always allow this to pass: $this->expectPassesRule(new PossibleFragmentSpreads, ' fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } '); } /** * @it interface into non overlapping union */ public function testInterfaceIntoNonOverlappingUnion() { $this->expectFailsRule(new PossibleFragmentSpreads, ' fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } ', [$this->error('petFragment', 'HumanOrAlien', 'Pet', 2, 62)] ); } private function error($fragName, $parentType, $fragType, $line, $column) { return FormattedError::create( PossibleFragmentSpreads::typeIncompatibleSpreadMessage($fragName, $parentType, $fragType), [new SourceLocation($line, $column)] ); } private function errorAnon($parentType, $fragType, $line, $column) { return FormattedError::create( PossibleFragmentSpreads::typeIncompatibleAnonSpreadMessage($parentType, $fragType), [new SourceLocation($line, $column)] ); } }