Skip to content

Commit

Permalink
fix: handle more unhandled promise rejections
Browse files Browse the repository at this point in the history
including mixture of sync/async errors in lists

following graphql#3706 fix for field execution
  • Loading branch information
yaacovCR committed Oct 19, 2022
1 parent 5009d9f commit 86106a7
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 99 deletions.
107 changes: 98 additions & 9 deletions src/execution/__tests__/lists-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,17 @@ describe('Execute: Accepts async iterables as list value', () => {

function completeObjectList(
resolve: GraphQLFieldResolver<{ index: number }, unknown>,
nonNullable = false,
): PromiseOrValue<ExecutionResult> {
const ObjectWrapperType = new GraphQLObjectType({
name: 'ObjectWrapper',
fields: {
index: {
type: new GraphQLNonNull(GraphQLString),
resolve,
},
},
});
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
Expand All @@ -101,15 +111,9 @@ describe('Execute: Accepts async iterables as list value', () => {
yield await Promise.resolve({ index: 2 });
},
type: new GraphQLList(
new GraphQLObjectType({
name: 'ObjectWrapper',
fields: {
index: {
type: new GraphQLNonNull(GraphQLString),
resolve,
},
},
}),
nonNullable
? new GraphQLNonNull(ObjectWrapperType)
: ObjectWrapperType,
),
},
},
Expand Down Expand Up @@ -216,6 +220,27 @@ describe('Execute: Accepts async iterables as list value', () => {
],
});
});

it('Handles mixture of synchronous and asynchronous errors from `completeValue` in AsyncIterables', async () => {
expectJSON(
await completeObjectList(({ index }) => {
if (index === 0) {
return Promise.reject(new Error('bad'));
}
throw new Error('also bad');
}, true),
).toDeepEqual({
data: { listField: null },
errors: [
{
message: 'also bad',
locations: [{ line: 1, column: 15 }],
path: ['listField', 1, 'index'],
},
],
});
});

it('Handles nulls yielded by async generator', async () => {
async function* listField() {
yield await Promise.resolve(1);
Expand Down Expand Up @@ -265,6 +290,11 @@ describe('Execute: Handles list nullability', () => {
expectJSON(await executeQuery(promisify(listOfPromises))).toDeepEqual(
result,
);

// Test mix of synchronous and non-synchronous values
const [first, ...rest] = listField;
const listOfSomePromises = [first, ...rest.map(promisify)];
expectJSON(await executeQuery(listOfSomePromises)).toDeepEqual(result);
}
return result;

Expand Down Expand Up @@ -322,6 +352,32 @@ describe('Execute: Handles list nullability', () => {
});
});

it('Contains multiple nulls', async () => {
const listField = [null, null, 2];
const errors = [
{
message: 'Cannot return null for non-nullable field Query.listField.',
locations: [{ line: 1, column: 3 }],
path: ['listField', 0],
},
];

expect(await complete({ listField, as: '[Int]' })).to.deep.equal({
data: { listField: [null, null, 2] },
});
expect(await complete({ listField, as: '[Int]!' })).to.deep.equal({
data: { listField: [null, null, 2] },
});
expectJSON(await complete({ listField, as: '[Int!]' })).toDeepEqual({
data: { listField: null },
errors,
});
expectJSON(await complete({ listField, as: '[Int!]!' })).toDeepEqual({
data: null,
errors,
});
});

it('Returns null', async () => {
const listField = null;
const errors = [
Expand Down Expand Up @@ -376,6 +432,39 @@ describe('Execute: Handles list nullability', () => {
});
});

it('Contains multiple errors', async () => {
const listField = [new Error('bad'), new Error('also bad'), 2];

const firstError = {
message: 'bad',
locations: [{ line: 1, column: 3 }],
path: ['listField', 0],
};

const secondError = {
message: 'also bad',
locations: [{ line: 1, column: 3 }],
path: ['listField', 1],
};

expectJSON(await complete({ listField, as: '[Int]' })).toDeepEqual({
data: { listField: [null, null, 2] },
errors: [firstError, secondError],
});
expectJSON(await complete({ listField, as: '[Int]!' })).toDeepEqual({
data: { listField: [null, null, 2] },
errors: [firstError, secondError],
});
expectJSON(await complete({ listField, as: '[Int!]' })).toDeepEqual({
data: { listField: null },
errors: [firstError],
});
expectJSON(await complete({ listField, as: '[Int!]!' })).toDeepEqual({
data: null,
errors: [firstError],
});
});

it('Results in error', async () => {
const listField = new Error('bad');
const errors = [
Expand Down
5 changes: 0 additions & 5 deletions src/execution/__tests__/stream-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,6 @@ describe('Execute: stream directive', () => {
},
],
},
],
hasNext: true,
},
{
incremental: [
{
items: [{ name: 'Leia', id: '3' }],
path: ['friendList', 2],
Expand Down

0 comments on commit 86106a7

Please sign in to comment.