@@ -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,30 @@ 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
+ if ( index === 1 ) {
231
+ throw new Error ( 'also bad' ) ;
232
+ }
233
+ return Promise . resolve ( index ) ;
234
+ } , true ) ,
235
+ ) . toDeepEqual ( {
236
+ data : { listField : null } ,
237
+ errors : [
238
+ {
239
+ message : 'also bad' ,
240
+ locations : [ { line : 1 , column : 15 } ] ,
241
+ path : [ 'listField' , 1 , 'index' ] ,
242
+ } ,
243
+ ] ,
244
+ } ) ;
245
+ } ) ;
246
+
219
247
it ( 'Handles nulls yielded by async generator' , async ( ) => {
220
248
async function * listField ( ) {
221
249
yield await Promise . resolve ( 1 ) ;
@@ -265,6 +293,11 @@ describe('Execute: Handles list nullability', () => {
265
293
expectJSON ( await executeQuery ( promisify ( listOfPromises ) ) ) . toDeepEqual (
266
294
result ,
267
295
) ;
296
+
297
+ // Test mix of synchronous and non-synchronous values
298
+ const [ first , ...rest ] = listField ;
299
+ const listOfSomePromises = [ first , ...rest . map ( promisify ) ] ;
300
+ expectJSON ( await executeQuery ( listOfSomePromises ) ) . toDeepEqual ( result ) ;
268
301
}
269
302
return result ;
270
303
@@ -322,6 +355,32 @@ describe('Execute: Handles list nullability', () => {
322
355
} ) ;
323
356
} ) ;
324
357
358
+ it ( 'Contains multiple nulls' , async ( ) => {
359
+ const listField = [ null , null , 2 ] ;
360
+ const errors = [
361
+ {
362
+ message : 'Cannot return null for non-nullable field Query.listField.' ,
363
+ locations : [ { line : 1 , column : 3 } ] ,
364
+ path : [ 'listField' , 0 ] ,
365
+ } ,
366
+ ] ;
367
+
368
+ expect ( await complete ( { listField, as : '[Int]' } ) ) . to . deep . equal ( {
369
+ data : { listField : [ null , null , 2 ] } ,
370
+ } ) ;
371
+ expect ( await complete ( { listField, as : '[Int]!' } ) ) . to . deep . equal ( {
372
+ data : { listField : [ null , null , 2 ] } ,
373
+ } ) ;
374
+ expectJSON ( await complete ( { listField, as : '[Int!]' } ) ) . toDeepEqual ( {
375
+ data : { listField : null } ,
376
+ errors,
377
+ } ) ;
378
+ expectJSON ( await complete ( { listField, as : '[Int!]!' } ) ) . toDeepEqual ( {
379
+ data : null ,
380
+ errors,
381
+ } ) ;
382
+ } ) ;
383
+
325
384
it ( 'Returns null' , async ( ) => {
326
385
const listField = null ;
327
386
const errors = [
@@ -376,6 +435,39 @@ describe('Execute: Handles list nullability', () => {
376
435
} ) ;
377
436
} ) ;
378
437
438
+ it ( 'Contains multiple errors' , async ( ) => {
439
+ const listField = [ new Error ( 'bad' ) , new Error ( 'also bad' ) , 2 ] ;
440
+
441
+ const firstError = {
442
+ message : 'bad' ,
443
+ locations : [ { line : 1 , column : 3 } ] ,
444
+ path : [ 'listField' , 0 ] ,
445
+ } ;
446
+
447
+ const secondError = {
448
+ message : 'also bad' ,
449
+ locations : [ { line : 1 , column : 3 } ] ,
450
+ path : [ 'listField' , 1 ] ,
451
+ } ;
452
+
453
+ expectJSON ( await complete ( { listField, as : '[Int]' } ) ) . toDeepEqual ( {
454
+ data : { listField : [ null , null , 2 ] } ,
455
+ errors : [ firstError , secondError ] ,
456
+ } ) ;
457
+ expectJSON ( await complete ( { listField, as : '[Int]!' } ) ) . toDeepEqual ( {
458
+ data : { listField : [ null , null , 2 ] } ,
459
+ errors : [ firstError , secondError ] ,
460
+ } ) ;
461
+ expectJSON ( await complete ( { listField, as : '[Int!]' } ) ) . toDeepEqual ( {
462
+ data : { listField : null } ,
463
+ errors : [ firstError ] ,
464
+ } ) ;
465
+ expectJSON ( await complete ( { listField, as : '[Int!]!' } ) ) . toDeepEqual ( {
466
+ data : null ,
467
+ errors : [ firstError ] ,
468
+ } ) ;
469
+ } ) ;
470
+
379
471
it ( 'Results in error' , async ( ) => {
380
472
const listField = new Error ( 'bad' ) ;
381
473
const errors = [
0 commit comments