@@ -2263,6 +2263,124 @@ describe('Execute: defer directive', () => {
22632263 ] ) ;
22642264 } ) ;
22652265
2266+ it ( 'Stops late initial-path completion before publishing a deferred response' , async ( ) => {
2267+ const lateSideType = new GraphQLObjectType ( {
2268+ name : 'LateInitialSide' ,
2269+ fields : {
2270+ value : { type : GraphQLString } ,
2271+ } ,
2272+ } ) ;
2273+ const lateParentType = new GraphQLObjectType ( {
2274+ name : 'LateInitialParent' ,
2275+ fields : {
2276+ boom : { type : new GraphQLNonNull ( GraphQLString ) } ,
2277+ side : { type : lateSideType } ,
2278+ } ,
2279+ } ) ;
2280+ const lateGType = new GraphQLObjectType ( {
2281+ name : 'LateInitialG' ,
2282+ fields : {
2283+ h : { type : GraphQLString } ,
2284+ } ,
2285+ } ) ;
2286+ const lateSchema = new GraphQLSchema ( {
2287+ query : new GraphQLObjectType ( {
2288+ name : 'LateInitialQuery' ,
2289+ fields : {
2290+ parent : { type : lateParentType } ,
2291+ g : { type : lateGType } ,
2292+ } ,
2293+ } ) ,
2294+ } ) ;
2295+ const document = parse ( `
2296+ query {
2297+ parent {
2298+ boom
2299+ side {
2300+ value
2301+ }
2302+ }
2303+ g {
2304+ ... @defer {
2305+ h
2306+ }
2307+ }
2308+ }
2309+ ` ) ;
2310+ const { promise : boomPromise , reject : rejectBoom } =
2311+ promiseWithResolvers < string > ( ) ;
2312+ const { promise : sidePromise , resolve : resolveSide } =
2313+ promiseWithResolvers < {
2314+ value : ( ) => string ;
2315+ } > ( ) ;
2316+ let lateValueCalls = 0 ;
2317+ const resultPromise = experimentalExecuteIncrementally ( {
2318+ schema : lateSchema ,
2319+ document,
2320+ rootValue : {
2321+ parent : {
2322+ boom : ( ) => boomPromise ,
2323+ side : ( ) => sidePromise ,
2324+ } ,
2325+ g : {
2326+ h : 'value' ,
2327+ } ,
2328+ } ,
2329+ } ) ;
2330+ rejectBoom ( new Error ( 'boom' ) ) ;
2331+ const result = await resultPromise ;
2332+ assert ( 'initialResult' in result ) ;
2333+ expectJSON ( result . initialResult ) . toDeepEqual ( {
2334+ data : {
2335+ parent : null ,
2336+ g : { } ,
2337+ } ,
2338+ errors : [
2339+ {
2340+ message : 'boom' ,
2341+ locations : [ { line : 4 , column : 11 } ] ,
2342+ path : [ 'parent' , 'boom' ] ,
2343+ } ,
2344+ ] ,
2345+ pending : [ { id : '0' , path : [ 'g' ] } ] ,
2346+ hasNext : true ,
2347+ } ) ;
2348+
2349+ const iterator = result . subsequentResults [ Symbol . asyncIterator ] ( ) ;
2350+ const result2 = await iterator . next ( ) ;
2351+ expectJSON ( result2 ) . toDeepEqual ( {
2352+ done : false ,
2353+ value : {
2354+ incremental : [
2355+ {
2356+ data : {
2357+ h : 'value' ,
2358+ } ,
2359+ id : '0' ,
2360+ } ,
2361+ ] ,
2362+ completed : [ { id : '0' } ] ,
2363+ hasNext : false ,
2364+ } ,
2365+ } ) ;
2366+
2367+ resolveSide ( {
2368+ value ( ) {
2369+ lateValueCalls += 1 ;
2370+ return 'late value' ;
2371+ } ,
2372+ } ) ;
2373+ await resolveOnNextTick ( ) ;
2374+ await resolveOnNextTick ( ) ;
2375+ expect ( lateValueCalls ) . to . equal ( 0 ) ;
2376+
2377+ const result3 = await iterator . next ( ) ;
2378+ expectJSON ( result3 ) . toDeepEqual ( {
2379+ value : undefined ,
2380+ done : true ,
2381+ } ) ;
2382+ } ) ;
2383+
22662384 it ( 'Cancels deferred fields when deferred result exhibits null bubbling' , async ( ) => {
22672385 const document = parse ( `
22682386 query {
@@ -2313,6 +2431,108 @@ describe('Execute: defer directive', () => {
23132431 ] ) ;
23142432 } ) ;
23152433
2434+ it ( 'Stops late deferred payload completion after deferred null bubbling' , async ( ) => {
2435+ const lateSideType = new GraphQLObjectType ( {
2436+ name : 'LateDeferredSide' ,
2437+ fields : {
2438+ value : { type : GraphQLString } ,
2439+ } ,
2440+ } ) ;
2441+ const lateParentType = new GraphQLObjectType ( {
2442+ name : 'LateDeferredParent' ,
2443+ fields : {
2444+ side : { type : lateSideType } ,
2445+ boom : { type : new GraphQLNonNull ( GraphQLString ) } ,
2446+ } ,
2447+ } ) ;
2448+ const lateSchema = new GraphQLSchema ( {
2449+ query : new GraphQLObjectType ( {
2450+ name : 'LateDeferredQuery' ,
2451+ fields : {
2452+ parent : { type : lateParentType } ,
2453+ } ,
2454+ } ) ,
2455+ } ) ;
2456+ const document = parse ( `
2457+ query {
2458+ ... @defer {
2459+ parent {
2460+ side {
2461+ value
2462+ }
2463+ boom
2464+ }
2465+ }
2466+ }
2467+ ` ) ;
2468+ const { promise : boomPromise , reject : rejectBoom } =
2469+ promiseWithResolvers < string > ( ) ;
2470+ const { promise : sidePromise , resolve : resolveSide } =
2471+ promiseWithResolvers < {
2472+ value : ( ) => string ;
2473+ } > ( ) ;
2474+ let lateValueCalls = 0 ;
2475+ const resultPromise = experimentalExecuteIncrementally ( {
2476+ schema : lateSchema ,
2477+ document,
2478+ rootValue : {
2479+ parent : {
2480+ side : ( ) => sidePromise ,
2481+ boom : ( ) => boomPromise ,
2482+ } ,
2483+ } ,
2484+ enableEarlyExecution : true ,
2485+ } ) ;
2486+ rejectBoom ( new Error ( 'boom' ) ) ;
2487+ const result = await resultPromise ;
2488+ assert ( 'initialResult' in result ) ;
2489+ expectJSON ( result . initialResult ) . toDeepEqual ( {
2490+ data : { } ,
2491+ pending : [ { id : '0' , path : [ ] } ] ,
2492+ hasNext : true ,
2493+ } ) ;
2494+ const iterator = result . subsequentResults [ Symbol . asyncIterator ] ( ) ;
2495+ const result2 = await iterator . next ( ) ;
2496+ expectJSON ( result2 ) . toDeepEqual ( {
2497+ done : false ,
2498+ value : {
2499+ incremental : [
2500+ {
2501+ data : {
2502+ parent : null ,
2503+ } ,
2504+ errors : [
2505+ {
2506+ message : 'boom' ,
2507+ locations : [ { line : 8 , column : 13 } ] ,
2508+ path : [ 'parent' , 'boom' ] ,
2509+ } ,
2510+ ] ,
2511+ id : '0' ,
2512+ } ,
2513+ ] ,
2514+ completed : [ { id : '0' } ] ,
2515+ hasNext : false ,
2516+ } ,
2517+ } ) ;
2518+
2519+ resolveSide ( {
2520+ value ( ) {
2521+ lateValueCalls += 1 ;
2522+ return 'late value' ;
2523+ } ,
2524+ } ) ;
2525+ await resolveOnNextTick ( ) ;
2526+ await resolveOnNextTick ( ) ;
2527+ expect ( lateValueCalls ) . to . equal ( 0 ) ;
2528+
2529+ const result3 = await iterator . next ( ) ;
2530+ expectJSON ( result3 ) . toDeepEqual ( {
2531+ value : undefined ,
2532+ done : true ,
2533+ } ) ;
2534+ } ) ;
2535+
23162536 it ( 'Deduplicates list fields' , async ( ) => {
23172537 const document = parse ( `
23182538 query {
0 commit comments