@@ -154,6 +154,61 @@ async function complete(document: DocumentNode, rootValue: unknown = { hero }) {
154154 return result ;
155155}
156156
157+ function getCountingHero ( ) {
158+ let stopped = false ;
159+ let count = 0 ;
160+ const counts = new Map < string , number > ( ) ;
161+ function increment ( ) {
162+ if ( stopped ) {
163+ return ;
164+ }
165+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
166+ Promise . resolve ( ) . then ( ( ) => {
167+ count ++ ;
168+ increment ( ) ;
169+ } ) ;
170+ }
171+ increment ( ) ;
172+ const countingHero = {
173+ stop : ( ) => {
174+ stopped = true ;
175+ } ,
176+ counts,
177+ hero : ( ) => {
178+ counts . set ( 'hero' , count ) ;
179+ return {
180+ id : ( ) => {
181+ counts . set ( 'id' , count ) ;
182+ return hero . id ;
183+ } ,
184+ name : ( ) => {
185+ counts . set ( 'name' , count ) ;
186+ return hero . name ;
187+ } ,
188+ nestedObject : ( ) => {
189+ counts . set ( 'nestedObject' , count ) ;
190+ return {
191+ deeperObject : ( ) => {
192+ counts . set ( 'deeperObject' , count ) ;
193+ return {
194+ foo : ( ) => {
195+ counts . set ( 'foo' , count ) ;
196+ return 'foo' ;
197+ } ,
198+ bar : ( ) => {
199+ counts . set ( 'bar' , count ) ;
200+ return 'bar' ;
201+ } ,
202+ } ;
203+ } ,
204+ } ;
205+ } ,
206+ } ;
207+ } ,
208+ } ;
209+ return countingHero ;
210+ }
211+
157212describe ( 'Execute: defer directive' , ( ) => {
158213 it ( 'Can defer fragments containing scalar types' , async ( ) => {
159214 const document = parse ( `
@@ -167,7 +222,8 @@ describe('Execute: defer directive', () => {
167222 name
168223 }
169224 ` ) ;
170- const result = await complete ( document ) ;
225+ const countingHero = getCountingHero ( ) ;
226+ const result = await complete ( document , { hero : countingHero . hero } ) ;
171227
172228 expectJSON ( result ) . toDeepEqual ( [
173229 {
@@ -192,6 +248,11 @@ describe('Execute: defer directive', () => {
192248 hasNext : false ,
193249 } ,
194250 ] ) ;
251+
252+ countingHero . stop ( ) ;
253+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 0 ) ;
254+ expect ( countingHero . counts . get ( 'id' ) ) . to . equal ( 0 ) ;
255+ expect ( countingHero . counts . get ( 'name' ) ) . to . equal ( 1 ) ;
195256 } ) ;
196257 it ( 'Can disable defer using if argument' , async ( ) => {
197258 const document = parse ( `
@@ -485,7 +546,8 @@ describe('Execute: defer directive', () => {
485546 }
486547 }
487548 ` ) ;
488- const result = await complete ( document ) ;
549+ const countingHero = getCountingHero ( ) ;
550+ const result = await complete ( document , { hero : countingHero . hero } ) ;
489551 expectJSON ( result ) . toDeepEqual ( [
490552 {
491553 data : {
@@ -516,6 +578,11 @@ describe('Execute: defer directive', () => {
516578 hasNext : false ,
517579 } ,
518580 ] ) ;
581+
582+ countingHero . stop ( ) ;
583+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 0 ) ;
584+ expect ( countingHero . counts . get ( 'id' ) ) . to . equal ( 1 ) ;
585+ expect ( countingHero . counts . get ( 'name' ) ) . to . equal ( 1 ) ;
519586 } ) ;
520587
521588 it ( 'Separately emits defer fragments with different labels with varying subfields' , async ( ) => {
@@ -533,7 +600,8 @@ describe('Execute: defer directive', () => {
533600 }
534601 }
535602 ` ) ;
536- const result = await complete ( document ) ;
603+ const countingHero = getCountingHero ( ) ;
604+ const result = await complete ( document , { hero : countingHero . hero } ) ;
537605 expectJSON ( result ) . toDeepEqual ( [
538606 {
539607 data : { } ,
@@ -564,6 +632,11 @@ describe('Execute: defer directive', () => {
564632 hasNext : false ,
565633 } ,
566634 ] ) ;
635+
636+ countingHero . stop ( ) ;
637+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 1 ) ;
638+ expect ( countingHero . counts . get ( 'id' ) ) . to . equal ( 1 ) ;
639+ expect ( countingHero . counts . get ( 'name' ) ) . to . equal ( 1 ) ;
567640 } ) ;
568641
569642 it ( 'Separately emits defer fragments with different labels with varying subfields that return promises' , async ( ) => {
@@ -634,7 +707,8 @@ describe('Execute: defer directive', () => {
634707 }
635708 }
636709 ` ) ;
637- const result = await complete ( document ) ;
710+ const countingHero = getCountingHero ( ) ;
711+ const result = await complete ( document , { hero : countingHero . hero } ) ;
638712 expectJSON ( result ) . toDeepEqual ( [
639713 {
640714 data : {
@@ -666,6 +740,11 @@ describe('Execute: defer directive', () => {
666740 hasNext : false ,
667741 } ,
668742 ] ) ;
743+
744+ countingHero . stop ( ) ;
745+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 0 ) ;
746+ expect ( countingHero . counts . get ( 'id' ) ) . to . equal ( 1 ) ;
747+ expect ( countingHero . counts . get ( 'name' ) ) . to . equal ( 1 ) ;
669748 } ) ;
670749
671750 it ( 'Separately emits nested defer fragments with varying subfields of same priorities but different level of defers' , async ( ) => {
@@ -681,7 +760,8 @@ describe('Execute: defer directive', () => {
681760 }
682761 }
683762 ` ) ;
684- const result = await complete ( document ) ;
763+ const countingHero = getCountingHero ( ) ;
764+ const result = await complete ( document , { hero : countingHero . hero } ) ;
685765 expectJSON ( result ) . toDeepEqual ( [
686766 {
687767 data : { } ,
@@ -716,6 +796,11 @@ describe('Execute: defer directive', () => {
716796 hasNext : false ,
717797 } ,
718798 ] ) ;
799+
800+ countingHero . stop ( ) ;
801+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 1 ) ;
802+ expect ( countingHero . counts . get ( 'name' ) ) . to . equal ( 1 ) ;
803+ expect ( countingHero . counts . get ( 'id' ) ) . to . equal ( 2 ) ;
719804 } ) ;
720805
721806 it ( 'Can deduplicate multiple defers on the same object' , async ( ) => {
@@ -854,9 +939,8 @@ describe('Execute: defer directive', () => {
854939 }
855940 }
856941 ` ) ;
857- const result = await complete ( document , {
858- hero : { nestedObject : { deeperObject : { foo : 'foo' , bar : 'bar' } } } ,
859- } ) ;
942+ const countingHero = getCountingHero ( ) ;
943+ const result = await complete ( document , { hero : countingHero . hero } ) ;
860944 expectJSON ( result ) . toDeepEqual ( [
861945 {
862946 data : {
@@ -893,6 +977,81 @@ describe('Execute: defer directive', () => {
893977 hasNext : false ,
894978 } ,
895979 ] ) ;
980+
981+ countingHero . stop ( ) ;
982+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 0 ) ;
983+ expect ( countingHero . counts . get ( 'nestedObject' ) ) . to . equal ( 1 ) ;
984+ expect ( countingHero . counts . get ( 'deeperObject' ) ) . to . equal ( 1 ) ;
985+ expect ( countingHero . counts . get ( 'foo' ) ) . to . equal ( 1 ) ;
986+ expect ( countingHero . counts . get ( 'bar' ) ) . to . equal ( 2 ) ;
987+ } ) ;
988+
989+ it ( 'Deduplicates subfields present in a parent defer payload' , async ( ) => {
990+ const document = parse ( `
991+ query {
992+ hero {
993+ ... @defer {
994+ nestedObject {
995+ deeperObject {
996+ foo
997+ }
998+ ... @defer {
999+ deeperObject {
1000+ foo
1001+ bar
1002+ }
1003+ }
1004+ }
1005+ }
1006+ }
1007+ }
1008+ ` ) ;
1009+ const countingHero = getCountingHero ( ) ;
1010+ const result = await complete ( document , { hero : countingHero . hero } ) ;
1011+ expectJSON ( result ) . toDeepEqual ( [
1012+ {
1013+ data : {
1014+ hero : { } ,
1015+ } ,
1016+ pending : [ { id : '0' , path : [ 'hero' ] } ] ,
1017+ hasNext : true ,
1018+ } ,
1019+ {
1020+ pending : [ { id : '1' , path : [ 'hero' , 'nestedObject' ] } ] ,
1021+ incremental : [
1022+ {
1023+ data : {
1024+ nestedObject : {
1025+ deeperObject : { foo : 'foo' } ,
1026+ } ,
1027+ } ,
1028+ id : '0' ,
1029+ } ,
1030+ ] ,
1031+ completed : [ { id : '0' } ] ,
1032+ hasNext : true ,
1033+ } ,
1034+ {
1035+ incremental : [
1036+ {
1037+ data : {
1038+ bar : 'bar' ,
1039+ } ,
1040+ id : '1' ,
1041+ subPath : [ 'deeperObject' ] ,
1042+ } ,
1043+ ] ,
1044+ completed : [ { id : '1' } ] ,
1045+ hasNext : false ,
1046+ } ,
1047+ ] ) ;
1048+
1049+ countingHero . stop ( ) ;
1050+ expect ( countingHero . counts . get ( 'hero' ) ) . to . equal ( 0 ) ;
1051+ expect ( countingHero . counts . get ( 'nestedObject' ) ) . to . equal ( 1 ) ;
1052+ expect ( countingHero . counts . get ( 'deeperObject' ) ) . to . equal ( 1 ) ;
1053+ expect ( countingHero . counts . get ( 'foo' ) ) . to . equal ( 1 ) ;
1054+ expect ( countingHero . counts . get ( 'bar' ) ) . to . equal ( 2 ) ;
8961055 } ) ;
8971056
8981057 it ( 'Deduplicates fields with deferred fragments at multiple levels' , async ( ) => {
0 commit comments