@@ -45,7 +45,7 @@ async function complete(
4545const schema = buildSchema ( `
4646 type Todo {
4747 id: ID
48- text: String
48+ items: [ String]
4949 author: User
5050 }
5151
@@ -91,7 +91,6 @@ describe('Execute: Cancellation', () => {
9191 todo : async ( ) =>
9292 Promise . resolve ( {
9393 id : '1' ,
94- text : 'Hello, World!' ,
9594 /* c8 ignore next */
9695 author : ( ) => expect . fail ( 'Should not be called' ) ,
9796 } ) ,
@@ -186,7 +185,6 @@ describe('Execute: Cancellation', () => {
186185 todo : async ( ) =>
187186 Promise . resolve ( {
188187 id : '1' ,
189- text : 'Hello, World!' ,
190188 /* c8 ignore next */
191189 author : ( ) => expect . fail ( 'Should not be called' ) ,
192190 } ) ,
@@ -235,7 +233,6 @@ describe('Execute: Cancellation', () => {
235233 todo : async ( ) =>
236234 Promise . resolve ( {
237235 id : '1' ,
238- text : 'Hello, World!' ,
239236 /* c8 ignore next */
240237 author : ( ) => expect . fail ( 'Should not be called' ) ,
241238 } ) ,
@@ -280,7 +277,6 @@ describe('Execute: Cancellation', () => {
280277 rootValue : {
281278 todo : {
282279 id : '1' ,
283- text : 'Hello, World!' ,
284280 /* c8 ignore next 3 */
285281 author : async ( ) =>
286282 Promise . resolve ( ( ) => expect . fail ( 'Should not be called' ) ) ,
@@ -354,6 +350,56 @@ describe('Execute: Cancellation', () => {
354350 } ) ;
355351 } ) ;
356352
353+ it ( 'should stop the execution when aborted despite a hanging item' , async ( ) => {
354+ const abortController = new AbortController ( ) ;
355+ const document = parse ( `
356+ query {
357+ todo {
358+ id
359+ items
360+ }
361+ }
362+ ` ) ;
363+
364+ const resultPromise = execute ( {
365+ document,
366+ schema,
367+ abortSignal : abortController . signal ,
368+ rootValue : {
369+ todo : ( ) => ( {
370+ id : '1' ,
371+ items : [
372+ new Promise ( ( ) => {
373+ /* will never resolve */
374+ } ) ,
375+ ] ,
376+ } ) ,
377+ } ,
378+ } ) ;
379+
380+ abortController . abort ( ) ;
381+
382+ const result = await resultPromise ;
383+
384+ expect ( result . errors ?. [ 0 ] . originalError ?. name ) . to . equal ( 'AbortError' ) ;
385+
386+ expectJSON ( result ) . toDeepEqual ( {
387+ data : {
388+ todo : {
389+ id : '1' ,
390+ items : [ null ] ,
391+ } ,
392+ } ,
393+ errors : [
394+ {
395+ message : 'This operation was aborted' ,
396+ path : [ 'todo' , 'items' , 0 ] ,
397+ locations : [ { line : 5 , column : 11 } ] ,
398+ } ,
399+ ] ,
400+ } ) ;
401+ } ) ;
402+
357403 it ( 'should stop the execution when aborted with proper null bubbling' , async ( ) => {
358404 const abortController = new AbortController ( ) ;
359405 const document = parse ( `
@@ -375,7 +421,6 @@ describe('Execute: Cancellation', () => {
375421 nonNullableTodo : async ( ) =>
376422 Promise . resolve ( {
377423 id : '1' ,
378- text : 'Hello, World!' ,
379424 /* c8 ignore next */
380425 author : ( ) => expect . fail ( 'Should not be called' ) ,
381426 } ) ,
@@ -407,7 +452,6 @@ describe('Execute: Cancellation', () => {
407452 todo {
408453 id
409454 ... on Todo @defer {
410- text
411455 author {
412456 id
413457 }
@@ -423,7 +467,6 @@ describe('Execute: Cancellation', () => {
423467 todo : async ( ) =>
424468 Promise . resolve ( {
425469 id : '1' ,
426- text : 'hello world' ,
427470 /* c8 ignore next */
428471 author : ( ) => expect . fail ( 'Should not be called' ) ,
429472 } ) ,
@@ -456,7 +499,6 @@ describe('Execute: Cancellation', () => {
456499 ... on Query @defer {
457500 todo {
458501 id
459- text
460502 author {
461503 id
462504 }
@@ -471,7 +513,6 @@ describe('Execute: Cancellation', () => {
471513 todo : async ( ) =>
472514 Promise . resolve ( {
473515 id : '1' ,
474- text : 'hello world' ,
475516 /* c8 ignore next 2 */
476517 author : async ( ) =>
477518 Promise . resolve ( ( ) => expect . fail ( 'Should not be called' ) ) ,
@@ -512,6 +553,63 @@ describe('Execute: Cancellation', () => {
512553 ] ) ;
513554 } ) ;
514555
556+ it ( 'should stop streamed execution when aborted' , async ( ) => {
557+ const abortController = new AbortController ( ) ;
558+ const document = parse ( `
559+ query {
560+ todo {
561+ id
562+ items @stream
563+ }
564+ }
565+ ` ) ;
566+
567+ const resultPromise = complete (
568+ document ,
569+ {
570+ todo : {
571+ id : '1' ,
572+ items : [ Promise . resolve ( 'item' ) ] ,
573+ } ,
574+ } ,
575+ abortController . signal ,
576+ ) ;
577+
578+ abortController . abort ( ) ;
579+
580+ const result = await resultPromise ;
581+
582+ expectJSON ( result ) . toDeepEqual ( [
583+ {
584+ data : {
585+ todo : {
586+ id : '1' ,
587+ items : [ ] ,
588+ } ,
589+ } ,
590+ pending : [ { id : '0' , path : [ 'todo' , 'items' ] } ] ,
591+ hasNext : true ,
592+ } ,
593+ {
594+ incremental : [
595+ {
596+ items : [ null ] ,
597+ errors : [
598+ {
599+ message : 'This operation was aborted' ,
600+ path : [ 'todo' , 'items' , 0 ] ,
601+ locations : [ { line : 5 , column : 11 } ] ,
602+ } ,
603+ ] ,
604+ id : '0' ,
605+ } ,
606+ ] ,
607+ completed : [ { id : '0' } ] ,
608+ hasNext : false ,
609+ } ,
610+ ] ) ;
611+ } ) ;
612+
515613 it ( 'should stop the execution when aborted mid-mutation' , async ( ) => {
516614 const abortController = new AbortController ( ) ;
517615 const document = parse ( `
0 commit comments