@@ -89,7 +89,17 @@ describe('Execute: Accepts async iterables as list value', () => {
89
89
90
90
function completeObjectList (
91
91
resolve : GraphQLFieldResolver < { index : number } , unknown > ,
92
+ nonNullable = false ,
92
93
) : PromiseOrValue < ExecutionResult > {
94
+ const ObjectWrapperType = new GraphQLObjectType ( {
95
+ name : 'ObjectWrapper' ,
96
+ fields : {
97
+ index : {
98
+ type : new GraphQLNonNull ( GraphQLString ) ,
99
+ resolve,
100
+ } ,
101
+ } ,
102
+ } ) ;
93
103
const schema = new GraphQLSchema ( {
94
104
query : new GraphQLObjectType ( {
95
105
name : 'Query' ,
@@ -101,15 +111,9 @@ describe('Execute: Accepts async iterables as list value', () => {
101
111
yield await Promise . resolve ( { index : 2 } ) ;
102
112
} ,
103
113
type : new GraphQLList (
104
- new GraphQLObjectType ( {
105
- name : 'ObjectWrapper' ,
106
- fields : {
107
- index : {
108
- type : new GraphQLNonNull ( GraphQLString ) ,
109
- resolve,
110
- } ,
111
- } ,
112
- } ) ,
114
+ nonNullable
115
+ ? new GraphQLNonNull ( ObjectWrapperType )
116
+ : ObjectWrapperType ,
113
117
) ,
114
118
} ,
115
119
} ,
@@ -216,6 +220,27 @@ describe('Execute: Accepts async iterables as list value', () => {
216
220
] ,
217
221
} ) ;
218
222
} ) ;
223
+
224
+ it ( 'Handles mixture of synchronous and asynchronous errors from `completeValue` in AsyncIterables' , async ( ) => {
225
+ expectJSON (
226
+ await completeObjectList ( ( { index } ) => {
227
+ if ( index === 0 ) {
228
+ return Promise . reject ( new Error ( 'bad' ) ) ;
229
+ }
230
+ throw new Error ( 'also bad' ) ;
231
+ } , true ) ,
232
+ ) . toDeepEqual ( {
233
+ data : { listField : null } ,
234
+ errors : [
235
+ {
236
+ message : 'also bad' ,
237
+ locations : [ { line : 1 , column : 15 } ] ,
238
+ path : [ 'listField' , 1 , 'index' ] ,
239
+ } ,
240
+ ] ,
241
+ } ) ;
242
+ } ) ;
243
+
219
244
it ( 'Handles nulls yielded by async generator' , async ( ) => {
220
245
async function * listField ( ) {
221
246
yield await Promise . resolve ( 1 ) ;
@@ -265,6 +290,11 @@ describe('Execute: Handles list nullability', () => {
265
290
expectJSON ( await executeQuery ( promisify ( listOfPromises ) ) ) . toDeepEqual (
266
291
result ,
267
292
) ;
293
+
294
+ // Test mix of synchronous and non-synchronous values
295
+ const [ first , ...rest ] = listField ;
296
+ const listOfSomePromises = [ first , ...rest . map ( promisify ) ] ;
297
+ expectJSON ( await executeQuery ( listOfSomePromises ) ) . toDeepEqual ( result ) ;
268
298
}
269
299
return result ;
270
300
@@ -322,6 +352,32 @@ describe('Execute: Handles list nullability', () => {
322
352
} ) ;
323
353
} ) ;
324
354
355
+ it ( 'Contains multiple nulls' , async ( ) => {
356
+ const listField = [ null , null , 2 ] ;
357
+ const errors = [
358
+ {
359
+ message : 'Cannot return null for non-nullable field Query.listField.' ,
360
+ locations : [ { line : 1 , column : 3 } ] ,
361
+ path : [ 'listField' , 0 ] ,
362
+ } ,
363
+ ] ;
364
+
365
+ expect ( await complete ( { listField, as : '[Int]' } ) ) . to . deep . equal ( {
366
+ data : { listField : [ null , null , 2 ] } ,
367
+ } ) ;
368
+ expect ( await complete ( { listField, as : '[Int]!' } ) ) . to . deep . equal ( {
369
+ data : { listField : [ null , null , 2 ] } ,
370
+ } ) ;
371
+ expectJSON ( await complete ( { listField, as : '[Int!]' } ) ) . toDeepEqual ( {
372
+ data : { listField : null } ,
373
+ errors,
374
+ } ) ;
375
+ expectJSON ( await complete ( { listField, as : '[Int!]!' } ) ) . toDeepEqual ( {
376
+ data : null ,
377
+ errors,
378
+ } ) ;
379
+ } ) ;
380
+
325
381
it ( 'Returns null' , async ( ) => {
326
382
const listField = null ;
327
383
const errors = [
@@ -376,6 +432,39 @@ describe('Execute: Handles list nullability', () => {
376
432
} ) ;
377
433
} ) ;
378
434
435
+ it ( 'Contains multiple errors' , async ( ) => {
436
+ const listField = [ new Error ( 'bad' ) , new Error ( 'also bad' ) , 2 ] ;
437
+
438
+ const firstError = {
439
+ message : 'bad' ,
440
+ locations : [ { line : 1 , column : 3 } ] ,
441
+ path : [ 'listField' , 0 ] ,
442
+ } ;
443
+
444
+ const secondError = {
445
+ message : 'also bad' ,
446
+ locations : [ { line : 1 , column : 3 } ] ,
447
+ path : [ 'listField' , 1 ] ,
448
+ } ;
449
+
450
+ expectJSON ( await complete ( { listField, as : '[Int]' } ) ) . toDeepEqual ( {
451
+ data : { listField : [ null , null , 2 ] } ,
452
+ errors : [ firstError , secondError ] ,
453
+ } ) ;
454
+ expectJSON ( await complete ( { listField, as : '[Int]!' } ) ) . toDeepEqual ( {
455
+ data : { listField : [ null , null , 2 ] } ,
456
+ errors : [ firstError , secondError ] ,
457
+ } ) ;
458
+ expectJSON ( await complete ( { listField, as : '[Int!]' } ) ) . toDeepEqual ( {
459
+ data : { listField : null } ,
460
+ errors : [ firstError ] ,
461
+ } ) ;
462
+ expectJSON ( await complete ( { listField, as : '[Int!]!' } ) ) . toDeepEqual ( {
463
+ data : null ,
464
+ errors : [ firstError ] ,
465
+ } ) ;
466
+ } ) ;
467
+
379
468
it ( 'Results in error' , async ( ) => {
380
469
const listField = new Error ( 'bad' ) ;
381
470
const errors = [
0 commit comments