@@ -368,27 +368,36 @@ describe('Validate: Overlapping fields can be merged', () => {
368368 const SomeBox = new GraphQLInterfaceType ( {
369369 name : 'SomeBox' ,
370370 resolveType : ( ) => StringBox ,
371- fields : {
371+ fields : ( ) => ( {
372+ deepBox : { type : SomeBox } ,
372373 unrelatedField : { type : GraphQLString }
373- }
374+ } )
374375 } ) ;
375376
376377 const StringBox = new GraphQLObjectType ( {
377378 name : 'StringBox' ,
378379 interfaces : [ SomeBox ] ,
379- fields : {
380+ fields : ( ) => ( {
380381 scalar : { type : GraphQLString } ,
382+ deepBox : { type : StringBox } ,
381383 unrelatedField : { type : GraphQLString } ,
382- }
384+ listStringBox : { type : new GraphQLList ( StringBox ) } ,
385+ stringBox : { type : StringBox } ,
386+ intBox : { type : IntBox } ,
387+ } )
383388 } ) ;
384389
385390 const IntBox = new GraphQLObjectType ( {
386391 name : 'IntBox' ,
387392 interfaces : [ SomeBox ] ,
388- fields : {
393+ fields : ( ) => ( {
389394 scalar : { type : GraphQLInt } ,
395+ deepBox : { type : IntBox } ,
390396 unrelatedField : { type : GraphQLString } ,
391- }
397+ listStringBox : { type : new GraphQLList ( StringBox ) } ,
398+ stringBox : { type : StringBox } ,
399+ intBox : { type : IntBox } ,
400+ } )
392401 } ) ;
393402
394403 const NonNullStringBox1 = new GraphQLInterfaceType ( {
@@ -405,6 +414,7 @@ describe('Validate: Overlapping fields can be merged', () => {
405414 fields : {
406415 scalar : { type : new GraphQLNonNull ( GraphQLString ) } ,
407416 unrelatedField : { type : GraphQLString } ,
417+ deepBox : { type : SomeBox } ,
408418 }
409419 } ) ;
410420
@@ -422,6 +432,7 @@ describe('Validate: Overlapping fields can be merged', () => {
422432 fields : {
423433 scalar : { type : new GraphQLNonNull ( GraphQLString ) } ,
424434 unrelatedField : { type : GraphQLString } ,
435+ deepBox : { type : SomeBox } ,
425436 }
426437 } ) ;
427438
@@ -455,7 +466,7 @@ describe('Validate: Overlapping fields can be merged', () => {
455466 connection : { type : Connection }
456467 } )
457468 } ) ,
458- types : [ IntBox , NonNullStringBox1Impl , NonNullStringBox2Impl ]
469+ types : [ IntBox , StringBox , NonNullStringBox1Impl , NonNullStringBox2Impl ]
459470 } ) ;
460471
461472 it ( 'conflicting return types which potentially overlap' , ( ) => {
@@ -477,21 +488,187 @@ describe('Validate: Overlapping fields can be merged', () => {
477488 ` , [
478489 { message : fieldsConflictMessage (
479490 'scalar' ,
480- 'they return differing types Int and String!'
491+ 'they return conflicting types Int and String!'
481492 ) ,
482493 locations : [ { line : 5 , column : 15 } , { line : 8 , column : 15 } ] }
483494 ] ) ;
484495 } ) ;
485496
486- it ( 'allows differing return types which cannot overlap' , ( ) => {
487- // This is valid since an object cannot be both an IntBox and a StringBox.
497+ it ( 'compatible return shapes on different return types' , ( ) => {
498+ // In this case `deepBox` returns `SomeBox` in the first usage, and
499+ // `StringBox` in the second usage. These return types are not the same!
500+ // however this is valid because the return *shapes* are compatible.
488501 expectPassesRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
502+ {
503+ someBox {
504+ ... on SomeBox {
505+ deepBox {
506+ unrelatedField
507+ }
508+ }
509+ ... on StringBox {
510+ deepBox {
511+ unrelatedField
512+ }
513+ }
514+ }
515+ }
516+ ` ) ;
517+ } ) ;
518+
519+ it ( 'disallows differing return types despite no overlap' , ( ) => {
520+ expectFailsRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
489521 {
490522 someBox {
491- ...on IntBox {
523+ ... on IntBox {
524+ scalar
525+ }
526+ ... on StringBox {
527+ scalar
528+ }
529+ }
530+ }
531+ ` , [
532+ { message : fieldsConflictMessage (
533+ 'scalar' ,
534+ 'they return conflicting types Int and String'
535+ ) ,
536+ locations : [ { line : 5 , column : 15 } , { line : 8 , column : 15 } ] }
537+ ] ) ;
538+ } ) ;
539+
540+ it ( 'disallows differing return type nullability despite no overlap' , ( ) => {
541+ expectFailsRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
542+ {
543+ someBox {
544+ ... on NonNullStringBox1 {
492545 scalar
493546 }
494- ...on StringBox {
547+ ... on StringBox {
548+ scalar
549+ }
550+ }
551+ }
552+ ` , [
553+ { message : fieldsConflictMessage (
554+ 'scalar' ,
555+ 'they return conflicting types String! and String'
556+ ) ,
557+ locations : [ { line : 5 , column : 15 } , { line : 8 , column : 15 } ] }
558+ ] ) ;
559+ } ) ;
560+
561+ it ( 'disallows differing return type list despite no overlap' , ( ) => {
562+ expectFailsRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
563+ {
564+ someBox {
565+ ... on IntBox {
566+ box: listStringBox {
567+ scalar
568+ }
569+ }
570+ ... on StringBox {
571+ box: stringBox {
572+ scalar
573+ }
574+ }
575+ }
576+ }
577+ ` , [
578+ { message : fieldsConflictMessage (
579+ 'box' ,
580+ 'they return conflicting types [StringBox] and StringBox'
581+ ) ,
582+ locations : [ { line : 5 , column : 15 } , { line : 10 , column : 15 } ] }
583+ ] ) ;
584+
585+ expectFailsRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
586+ {
587+ someBox {
588+ ... on IntBox {
589+ box: stringBox {
590+ scalar
591+ }
592+ }
593+ ... on StringBox {
594+ box: listStringBox {
595+ scalar
596+ }
597+ }
598+ }
599+ }
600+ ` , [
601+ { message : fieldsConflictMessage (
602+ 'box' ,
603+ 'they return conflicting types StringBox and [StringBox]'
604+ ) ,
605+ locations : [ { line : 5 , column : 15 } , { line : 10 , column : 15 } ] }
606+ ] ) ;
607+ } ) ;
608+
609+ it ( 'disallows differing subfields' , ( ) => {
610+ expectFailsRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
611+ {
612+ someBox {
613+ ... on IntBox {
614+ box: stringBox {
615+ val: scalar
616+ val: unrelatedField
617+ }
618+ }
619+ ... on StringBox {
620+ box: stringBox {
621+ val: scalar
622+ }
623+ }
624+ }
625+ }
626+ ` , [
627+ { message : fieldsConflictMessage (
628+ 'val' ,
629+ 'scalar and unrelatedField are different fields'
630+ ) ,
631+ locations : [ { line : 6 , column : 17 } , { line : 7 , column : 17 } ] }
632+ ] ) ;
633+ } ) ;
634+
635+ it ( 'disallows differing deep return types despite no overlap' , ( ) => {
636+ expectFailsRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
637+ {
638+ someBox {
639+ ... on IntBox {
640+ box: stringBox {
641+ scalar
642+ }
643+ }
644+ ... on StringBox {
645+ box: intBox {
646+ scalar
647+ }
648+ }
649+ }
650+ }
651+ ` , [
652+ { message : fieldsConflictMessage (
653+ 'box' ,
654+ [ [ 'scalar' , 'they return conflicting types String and Int' ] ]
655+ ) ,
656+ locations : [
657+ { line : 5 , column : 15 } ,
658+ { line : 6 , column : 17 } ,
659+ { line : 10 , column : 15 } ,
660+ { line : 11 , column : 17 } ] }
661+ ] ) ;
662+ } ) ;
663+
664+ it ( 'allows non-conflicting overlaping types' , ( ) => {
665+ expectPassesRuleWithSchema ( schema , OverlappingFieldsCanBeMerged , `
666+ {
667+ someBox {
668+ ... on IntBox {
669+ scalar: unrelatedField
670+ }
671+ ... on StringBox {
495672 scalar
496673 }
497674 }
0 commit comments