|
| 1 | +import { assert } from 'chai'; |
1 | 2 | import { describe, it } from 'mocha';
|
2 | 3 |
|
3 | 4 | import { expectJSON } from '../../__testUtils__/expectJSON';
|
@@ -162,6 +163,37 @@ const query = new GraphQLObjectType({
|
162 | 163 | yield await Promise.resolve({ string: friends[1].name });
|
163 | 164 | },
|
164 | 165 | },
|
| 166 | + asyncIterableListDelayed: { |
| 167 | + type: new GraphQLList(friendType), |
| 168 | + async *resolve() { |
| 169 | + for (const friend of friends) { |
| 170 | + // pause an additional ms before yielding to allow time |
| 171 | + // for tests to return or throw before next value is processed. |
| 172 | + // eslint-disable-next-line no-await-in-loop |
| 173 | + await resolveOnNextTick(); |
| 174 | + yield friend; /* c8 ignore start */ |
| 175 | + // Not reachable, early return |
| 176 | + } |
| 177 | + } /* c8 ignore stop */, |
| 178 | + }, |
| 179 | + asyncIterableListNoReturn: { |
| 180 | + type: new GraphQLList(friendType), |
| 181 | + resolve() { |
| 182 | + let i = 0; |
| 183 | + return { |
| 184 | + [Symbol.asyncIterator]: () => ({ |
| 185 | + async next() { |
| 186 | + const friend = friends[i++]; |
| 187 | + if (friend) { |
| 188 | + await resolveOnNextTick(); |
| 189 | + return { value: friend, done: false }; |
| 190 | + } |
| 191 | + return { value: undefined, done: true }; |
| 192 | + }, |
| 193 | + }), |
| 194 | + }; |
| 195 | + }, |
| 196 | + }, |
165 | 197 | asyncIterableListDelayedClose: {
|
166 | 198 | type: new GraphQLList(friendType),
|
167 | 199 | async *resolve() {
|
@@ -1344,4 +1376,220 @@ describe('Execute: stream directive', () => {
|
1344 | 1376 | },
|
1345 | 1377 | ]);
|
1346 | 1378 | });
|
| 1379 | + it('Returns underlying async iterables when returned generator is returned', async () => { |
| 1380 | + const document = parse(` |
| 1381 | + query { |
| 1382 | + asyncIterableListDelayed @stream(initialCount: 1) { |
| 1383 | + id |
| 1384 | + ... @defer { |
| 1385 | + name |
| 1386 | + } |
| 1387 | + } |
| 1388 | + } |
| 1389 | + `); |
| 1390 | + const schema = new GraphQLSchema({ query }); |
| 1391 | + |
| 1392 | + const executeResult = await execute({ schema, document, rootValue: {} }); |
| 1393 | + assert(isAsyncIterable(executeResult)); |
| 1394 | + const iterator = executeResult[Symbol.asyncIterator](); |
| 1395 | + |
| 1396 | + const result1 = await iterator.next(); |
| 1397 | + expectJSON(result1).toDeepEqual({ |
| 1398 | + done: false, |
| 1399 | + value: { |
| 1400 | + data: { |
| 1401 | + asyncIterableListDelayed: [ |
| 1402 | + { |
| 1403 | + id: '1', |
| 1404 | + }, |
| 1405 | + ], |
| 1406 | + }, |
| 1407 | + hasNext: true, |
| 1408 | + }, |
| 1409 | + }); |
| 1410 | + const returnPromise = iterator.return(); |
| 1411 | + |
| 1412 | + // these results had started processing before return was called |
| 1413 | + const result2 = await iterator.next(); |
| 1414 | + expectJSON(result2).toDeepEqual({ |
| 1415 | + done: false, |
| 1416 | + value: { |
| 1417 | + incremental: [ |
| 1418 | + { |
| 1419 | + data: { |
| 1420 | + name: 'Luke', |
| 1421 | + }, |
| 1422 | + path: ['asyncIterableListDelayed', 0], |
| 1423 | + }, |
| 1424 | + ], |
| 1425 | + hasNext: true, |
| 1426 | + }, |
| 1427 | + }); |
| 1428 | + const result3 = await iterator.next(); |
| 1429 | + expectJSON(result3).toDeepEqual({ |
| 1430 | + done: false, |
| 1431 | + value: { |
| 1432 | + incremental: [ |
| 1433 | + { |
| 1434 | + items: [ |
| 1435 | + { |
| 1436 | + id: '2', |
| 1437 | + }, |
| 1438 | + ], |
| 1439 | + path: ['asyncIterableListDelayed', 1], |
| 1440 | + }, |
| 1441 | + ], |
| 1442 | + hasNext: true, |
| 1443 | + }, |
| 1444 | + }); |
| 1445 | + const result4 = await iterator.next(); |
| 1446 | + expectJSON(result4).toDeepEqual({ |
| 1447 | + done: true, |
| 1448 | + value: undefined, |
| 1449 | + }); |
| 1450 | + await returnPromise; |
| 1451 | + }); |
| 1452 | + it('Can return async iterable when underlying iterable does not have a return method', async () => { |
| 1453 | + const document = parse(` |
| 1454 | + query { |
| 1455 | + asyncIterableListNoReturn @stream(initialCount: 1) { |
| 1456 | + name |
| 1457 | + id |
| 1458 | + } |
| 1459 | + } |
| 1460 | + `); |
| 1461 | + const schema = new GraphQLSchema({ query }); |
| 1462 | + |
| 1463 | + const executeResult = await execute({ schema, document, rootValue: {} }); |
| 1464 | + assert(isAsyncIterable(executeResult)); |
| 1465 | + const iterator = executeResult[Symbol.asyncIterator](); |
| 1466 | + |
| 1467 | + const result1 = await iterator.next(); |
| 1468 | + expectJSON(result1).toDeepEqual({ |
| 1469 | + done: false, |
| 1470 | + value: { |
| 1471 | + data: { |
| 1472 | + asyncIterableListNoReturn: [ |
| 1473 | + { |
| 1474 | + id: '1', |
| 1475 | + name: 'Luke', |
| 1476 | + }, |
| 1477 | + ], |
| 1478 | + }, |
| 1479 | + hasNext: true, |
| 1480 | + }, |
| 1481 | + }); |
| 1482 | + |
| 1483 | + const returnPromise = iterator.return(); |
| 1484 | + |
| 1485 | + // this result had started processing before return was called |
| 1486 | + const result2 = await iterator.next(); |
| 1487 | + expectJSON(result2).toDeepEqual({ |
| 1488 | + done: false, |
| 1489 | + value: { |
| 1490 | + incremental: [ |
| 1491 | + { |
| 1492 | + items: [ |
| 1493 | + { |
| 1494 | + id: '2', |
| 1495 | + name: 'Han', |
| 1496 | + }, |
| 1497 | + ], |
| 1498 | + path: ['asyncIterableListNoReturn', 1], |
| 1499 | + }, |
| 1500 | + ], |
| 1501 | + hasNext: true, |
| 1502 | + }, |
| 1503 | + }); |
| 1504 | + |
| 1505 | + // third result is not returned because async iterator has returned |
| 1506 | + const result3 = await iterator.next(); |
| 1507 | + expectJSON(result3).toDeepEqual({ |
| 1508 | + done: true, |
| 1509 | + value: undefined, |
| 1510 | + }); |
| 1511 | + await returnPromise; |
| 1512 | + }); |
| 1513 | + it('Returns underlying async iterables when returned generator is thrown', async () => { |
| 1514 | + const document = parse(` |
| 1515 | + query { |
| 1516 | + asyncIterableListDelayed @stream(initialCount: 1) { |
| 1517 | + ... @defer { |
| 1518 | + name |
| 1519 | + } |
| 1520 | + id |
| 1521 | + } |
| 1522 | + } |
| 1523 | + `); |
| 1524 | + const schema = new GraphQLSchema({ query }); |
| 1525 | + |
| 1526 | + const executeResult = await execute({ schema, document, rootValue: {} }); |
| 1527 | + assert(isAsyncIterable(executeResult)); |
| 1528 | + const iterator = executeResult[Symbol.asyncIterator](); |
| 1529 | + |
| 1530 | + const result1 = await iterator.next(); |
| 1531 | + expectJSON(result1).toDeepEqual({ |
| 1532 | + done: false, |
| 1533 | + value: { |
| 1534 | + data: { |
| 1535 | + asyncIterableListDelayed: [ |
| 1536 | + { |
| 1537 | + id: '1', |
| 1538 | + }, |
| 1539 | + ], |
| 1540 | + }, |
| 1541 | + hasNext: true, |
| 1542 | + }, |
| 1543 | + }); |
| 1544 | + |
| 1545 | + const throwPromise = iterator.throw(new Error('bad')); |
| 1546 | + |
| 1547 | + // these results had started processing before return was called |
| 1548 | + const result2 = await iterator.next(); |
| 1549 | + expectJSON(result2).toDeepEqual({ |
| 1550 | + done: false, |
| 1551 | + value: { |
| 1552 | + incremental: [ |
| 1553 | + { |
| 1554 | + data: { |
| 1555 | + name: 'Luke', |
| 1556 | + }, |
| 1557 | + path: ['asyncIterableListDelayed', 0], |
| 1558 | + }, |
| 1559 | + ], |
| 1560 | + hasNext: true, |
| 1561 | + }, |
| 1562 | + }); |
| 1563 | + const result3 = await iterator.next(); |
| 1564 | + expectJSON(result3).toDeepEqual({ |
| 1565 | + done: false, |
| 1566 | + value: { |
| 1567 | + incremental: [ |
| 1568 | + { |
| 1569 | + items: [ |
| 1570 | + { |
| 1571 | + id: '2', |
| 1572 | + }, |
| 1573 | + ], |
| 1574 | + path: ['asyncIterableListDelayed', 1], |
| 1575 | + }, |
| 1576 | + ], |
| 1577 | + hasNext: true, |
| 1578 | + }, |
| 1579 | + }); |
| 1580 | + |
| 1581 | + // this result is not returned because async iterator has returned |
| 1582 | + const result4 = await iterator.next(); |
| 1583 | + expectJSON(result4).toDeepEqual({ |
| 1584 | + done: true, |
| 1585 | + value: undefined, |
| 1586 | + }); |
| 1587 | + try { |
| 1588 | + await throwPromise; /* c8 ignore start */ |
| 1589 | + // Not reachable, always throws |
| 1590 | + /* c8 ignore stop */ |
| 1591 | + } catch (e) { |
| 1592 | + // ignore error |
| 1593 | + } |
| 1594 | + }); |
1347 | 1595 | });
|
0 commit comments