@@ -1215,4 +1215,226 @@ describe('Execute: stream directive', () => {
1215
1215
done : true ,
1216
1216
} ) ;
1217
1217
} ) ;
1218
+ it ( 'Returns underlying async iterables when returned generator is returned' , async ( ) => {
1219
+ let returned = false ;
1220
+ let index = 0 ;
1221
+ const iterable = {
1222
+ [ Symbol . asyncIterator ] : ( ) => ( {
1223
+ next : ( ) => {
1224
+ const friend = friends [ index ++ ] ;
1225
+ if ( ! friend ) {
1226
+ return Promise . resolve ( { done : true , value : undefined } ) ;
1227
+ }
1228
+ return Promise . resolve ( { done : false , value : friend } ) ;
1229
+ } ,
1230
+ return : ( ) => {
1231
+ returned = true ;
1232
+ } ,
1233
+ } ) ,
1234
+ } ;
1235
+
1236
+ const document = parse ( `
1237
+ query {
1238
+ friendList @stream(initialCount: 1) {
1239
+ id
1240
+ ... @defer {
1241
+ name
1242
+ }
1243
+ }
1244
+ }
1245
+ ` ) ;
1246
+
1247
+ const executeResult = await execute ( {
1248
+ schema,
1249
+ document,
1250
+ rootValue : {
1251
+ friendList : iterable ,
1252
+ } ,
1253
+ } ) ;
1254
+ assert ( isAsyncIterable ( executeResult ) ) ;
1255
+ const iterator = executeResult [ Symbol . asyncIterator ] ( ) ;
1256
+
1257
+ const result1 = await iterator . next ( ) ;
1258
+ expectJSON ( result1 ) . toDeepEqual ( {
1259
+ done : false ,
1260
+ value : {
1261
+ data : {
1262
+ friendList : [ { id : '1' } ] ,
1263
+ } ,
1264
+ hasNext : true ,
1265
+ } ,
1266
+ } ) ;
1267
+ const returnPromise = iterator . return ( ) ;
1268
+
1269
+ // these results had started processing before return was called
1270
+ const result2 = await iterator . next ( ) ;
1271
+ expectJSON ( result2 ) . toDeepEqual ( {
1272
+ done : false ,
1273
+ value : {
1274
+ incremental : [
1275
+ {
1276
+ data : { name : 'Luke' } ,
1277
+ path : [ 'friendList' , 0 ] ,
1278
+ } ,
1279
+ ] ,
1280
+ hasNext : true ,
1281
+ } ,
1282
+ } ) ;
1283
+ const result3 = await iterator . next ( ) ;
1284
+ expectJSON ( result3 ) . toDeepEqual ( {
1285
+ done : true ,
1286
+ value : undefined ,
1287
+ } ) ;
1288
+ await returnPromise ;
1289
+ assert ( returned ) ;
1290
+ } ) ;
1291
+ it ( 'Can return async iterable when underlying iterable does not have a return method' , async ( ) => {
1292
+ let index = 0 ;
1293
+ const iterable = {
1294
+ [ Symbol . asyncIterator ] : ( ) => ( {
1295
+ next : ( ) => {
1296
+ const friend = friends [ index ++ ] ;
1297
+ if ( ! friend ) {
1298
+ return Promise . resolve ( { done : true , value : undefined } ) ;
1299
+ }
1300
+ return Promise . resolve ( { done : false , value : friend } ) ;
1301
+ } ,
1302
+ } ) ,
1303
+ } ;
1304
+
1305
+ const document = parse ( `
1306
+ query {
1307
+ friendList @stream(initialCount: 1) {
1308
+ name
1309
+ id
1310
+ }
1311
+ }
1312
+ ` ) ;
1313
+
1314
+ const executeResult = await execute ( {
1315
+ schema,
1316
+ document,
1317
+ rootValue : {
1318
+ friendList : iterable ,
1319
+ } ,
1320
+ } ) ;
1321
+ assert ( isAsyncIterable ( executeResult ) ) ;
1322
+ const iterator = executeResult [ Symbol . asyncIterator ] ( ) ;
1323
+
1324
+ const result1 = await iterator . next ( ) ;
1325
+ expectJSON ( result1 ) . toDeepEqual ( {
1326
+ done : false ,
1327
+ value : {
1328
+ data : {
1329
+ friendList : [ { id : '1' , name : 'Luke' } ] ,
1330
+ } ,
1331
+ hasNext : true ,
1332
+ } ,
1333
+ } ) ;
1334
+
1335
+ const returnPromise = iterator . return ( ) ;
1336
+
1337
+ // this result had started processing before return was called
1338
+ const result2 = await iterator . next ( ) ;
1339
+ expectJSON ( result2 ) . toDeepEqual ( {
1340
+ done : false ,
1341
+ value : {
1342
+ incremental : [
1343
+ {
1344
+ items : [ { id : '2' , name : 'Han' } ] ,
1345
+ path : [ 'friendList' , 1 ] ,
1346
+ } ,
1347
+ ] ,
1348
+ hasNext : true ,
1349
+ } ,
1350
+ } ) ;
1351
+
1352
+ // third result is not returned because async iterator has returned
1353
+ const result3 = await iterator . next ( ) ;
1354
+ expectJSON ( result3 ) . toDeepEqual ( {
1355
+ done : true ,
1356
+ value : undefined ,
1357
+ } ) ;
1358
+ await returnPromise ;
1359
+ } ) ;
1360
+ it ( 'Returns underlying async iterables when returned generator is thrown' , async ( ) => {
1361
+ let index = 0 ;
1362
+ let returned = false ;
1363
+ const iterable = {
1364
+ [ Symbol . asyncIterator ] : ( ) => ( {
1365
+ next : ( ) => {
1366
+ const friend = friends [ index ++ ] ;
1367
+ if ( ! friend ) {
1368
+ return Promise . resolve ( { done : true , value : undefined } ) ;
1369
+ }
1370
+ return Promise . resolve ( { done : false , value : friend } ) ;
1371
+ } ,
1372
+ return : ( ) => {
1373
+ returned = true ;
1374
+ } ,
1375
+ } ) ,
1376
+ } ;
1377
+ const document = parse ( `
1378
+ query {
1379
+ friendList @stream(initialCount: 1) {
1380
+ ... @defer {
1381
+ name
1382
+ }
1383
+ id
1384
+ }
1385
+ }
1386
+ ` ) ;
1387
+ const executeResult = await execute ( {
1388
+ schema,
1389
+ document,
1390
+ rootValue : {
1391
+ friendList : iterable ,
1392
+ } ,
1393
+ } ) ;
1394
+ assert ( isAsyncIterable ( executeResult ) ) ;
1395
+ const iterator = executeResult [ Symbol . asyncIterator ] ( ) ;
1396
+
1397
+ const result1 = await iterator . next ( ) ;
1398
+ expectJSON ( result1 ) . toDeepEqual ( {
1399
+ done : false ,
1400
+ value : {
1401
+ data : {
1402
+ friendList : [ { id : '1' } ] ,
1403
+ } ,
1404
+ hasNext : true ,
1405
+ } ,
1406
+ } ) ;
1407
+
1408
+ const throwPromise = iterator . throw ( new Error ( 'bad' ) ) ;
1409
+
1410
+ // these results had started processing before return was called
1411
+ const result2 = await iterator . next ( ) ;
1412
+ expectJSON ( result2 ) . toDeepEqual ( {
1413
+ done : false ,
1414
+ value : {
1415
+ incremental : [
1416
+ {
1417
+ data : { name : 'Luke' } ,
1418
+ path : [ 'friendList' , 0 ] ,
1419
+ } ,
1420
+ ] ,
1421
+ hasNext : true ,
1422
+ } ,
1423
+ } ) ;
1424
+
1425
+ // this result is not returned because async iterator has returned
1426
+ const result3 = await iterator . next ( ) ;
1427
+ expectJSON ( result3 ) . toDeepEqual ( {
1428
+ done : true ,
1429
+ value : undefined ,
1430
+ } ) ;
1431
+ try {
1432
+ await throwPromise ; /* c8 ignore start */
1433
+ // Not reachable, always throws
1434
+ /* c8 ignore stop */
1435
+ } catch ( e ) {
1436
+ // ignore error
1437
+ }
1438
+ assert ( returned ) ;
1439
+ } ) ;
1218
1440
} ) ;
0 commit comments