@@ -368,27 +368,36 @@ describe('Validate: Overlapping fields can be merged', () => {
368
368
const SomeBox = new GraphQLInterfaceType ( {
369
369
name : 'SomeBox' ,
370
370
resolveType : ( ) => StringBox ,
371
- fields : {
371
+ fields : ( ) => ( {
372
+ deepBox : { type : SomeBox } ,
372
373
unrelatedField : { type : GraphQLString }
373
- }
374
+ } )
374
375
} ) ;
375
376
376
377
const StringBox = new GraphQLObjectType ( {
377
378
name : 'StringBox' ,
378
379
interfaces : [ SomeBox ] ,
379
- fields : {
380
+ fields : ( ) => ( {
380
381
scalar : { type : GraphQLString } ,
382
+ deepBox : { type : StringBox } ,
381
383
unrelatedField : { type : GraphQLString } ,
382
- }
384
+ listStringBox : { type : new GraphQLList ( StringBox ) } ,
385
+ stringBox : { type : StringBox } ,
386
+ intBox : { type : IntBox } ,
387
+ } )
383
388
} ) ;
384
389
385
390
const IntBox = new GraphQLObjectType ( {
386
391
name : 'IntBox' ,
387
392
interfaces : [ SomeBox ] ,
388
- fields : {
393
+ fields : ( ) => ( {
389
394
scalar : { type : GraphQLInt } ,
395
+ deepBox : { type : IntBox } ,
390
396
unrelatedField : { type : GraphQLString } ,
391
- }
397
+ listStringBox : { type : new GraphQLList ( StringBox ) } ,
398
+ stringBox : { type : StringBox } ,
399
+ intBox : { type : IntBox } ,
400
+ } )
392
401
} ) ;
393
402
394
403
const NonNullStringBox1 = new GraphQLInterfaceType ( {
@@ -405,6 +414,7 @@ describe('Validate: Overlapping fields can be merged', () => {
405
414
fields : {
406
415
scalar : { type : new GraphQLNonNull ( GraphQLString ) } ,
407
416
unrelatedField : { type : GraphQLString } ,
417
+ deepBox : { type : SomeBox } ,
408
418
}
409
419
} ) ;
410
420
@@ -422,6 +432,7 @@ describe('Validate: Overlapping fields can be merged', () => {
422
432
fields : {
423
433
scalar : { type : new GraphQLNonNull ( GraphQLString ) } ,
424
434
unrelatedField : { type : GraphQLString } ,
435
+ deepBox : { type : SomeBox } ,
425
436
}
426
437
} ) ;
427
438
@@ -455,7 +466,7 @@ describe('Validate: Overlapping fields can be merged', () => {
455
466
connection : { type : Connection }
456
467
} )
457
468
} ) ,
458
- types : [ IntBox , NonNullStringBox1Impl , NonNullStringBox2Impl ]
469
+ types : [ IntBox , StringBox , NonNullStringBox1Impl , NonNullStringBox2Impl ]
459
470
} ) ;
460
471
461
472
it ( 'conflicting return types which potentially overlap' , ( ) => {
@@ -477,21 +488,187 @@ describe('Validate: Overlapping fields can be merged', () => {
477
488
` , [
478
489
{ message : fieldsConflictMessage (
479
490
'scalar' ,
480
- 'they return differing types Int and String!'
491
+ 'they return conflicting types Int and String!'
481
492
) ,
482
493
locations : [ { line : 5 , column : 15 } , { line : 8 , column : 15 } ] }
483
494
] ) ;
484
495
} ) ;
485
496
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.
488
501
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 , `
489
521
{
490
522
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 {
492
545
scalar
493
546
}
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 {
495
672
scalar
496
673
}
497
674
}
0 commit comments