diff --git a/src/execution/__tests__/defer-test.ts b/src/execution/__tests__/defer-test.ts index 95c54479c2..417be98591 100644 --- a/src/execution/__tests__/defer-test.ts +++ b/src/execution/__tests__/defer-test.ts @@ -26,6 +26,10 @@ const friendType = new GraphQLObjectType({ fields: { id: { type: GraphQLID }, name: { type: GraphQLString }, + promiseNonNullErrorField: { + type: new GraphQLNonNull(GraphQLString), + resolve: () => Promise.resolve(null), + }, }, name: 'Friend', }); @@ -65,6 +69,12 @@ const heroType = new GraphQLObjectType({ type: new GraphQLList(friendType), resolve: () => friends, }, + asyncFriends: { + type: new GraphQLList(friendType), + async *resolve() { + yield await Promise.resolve(friends[0]); + }, + }, }, name: 'Hero', }); @@ -657,6 +667,38 @@ describe('Execute: defer directive', () => { ]); }); + it('Filters deferred payloads when a list item returned by an async iterable is nulled', async () => { + const document = parse(` + query { + hero { + asyncFriends { + promiseNonNullErrorField + ...NameFragment @defer + } + } + } + fragment NameFragment on Friend { + name + } + `); + const result = await complete(document); + expectJSON(result).toDeepEqual({ + data: { + hero: { + asyncFriends: [null], + }, + }, + errors: [ + { + message: + 'Cannot return null for non-nullable field Friend.promiseNonNullErrorField.', + locations: [{ line: 5, column: 11 }], + path: ['hero', 'asyncFriends', 0, 'promiseNonNullErrorField'], + }, + ], + }); + }); + it('original execute function throws error if anything is deferred and everything else is sync', () => { const doc = ` query Deferred { diff --git a/src/execution/execute.ts b/src/execution/execute.ts index 486a80fed5..5e19e66263 100644 --- a/src/execution/execute.ts +++ b/src/execution/execute.ts @@ -1027,6 +1027,7 @@ async function completeAsyncIteratorValue( pathToArray(fieldPath), ); const handledError = handleFieldError(error, itemType, errors); + filterSubsequentPayloads(exeContext, fieldPath); return handledError; }), ); @@ -1040,6 +1041,7 @@ async function completeAsyncIteratorValue( fieldNodes, pathToArray(fieldPath), ); + filterSubsequentPayloads(exeContext, fieldPath); handleFieldError(error, itemType, errors); } } catch (rawError) {