Skip to content

Catch unhandled exception in abstract resolution #4392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion src/execution/__tests__/union-interface-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import { GraphQLBoolean, GraphQLString } from '../../type/scalars';
import { GraphQLSchema } from '../../type/schema';

import { executeSync } from '../execute';
import { execute, executeSync } from '../execute';

class Dog {
name: string;
Expand Down Expand Up @@ -154,6 +154,77 @@
const liz = new Person('Liz');
const john = new Person('John', [garfield, odie], [liz, odie]);

const SearchableInterface = new GraphQLInterfaceType({
name: 'Searchable',
fields: {
id: { type: GraphQLString },
},
});

const TypeA = new GraphQLObjectType({
name: 'TypeA',
interfaces: [SearchableInterface],
fields: () => ({
id: { type: GraphQLString },
nameA: { type: GraphQLString },
}),
isTypeOf: (_value, _context, _info) => {

Check failure on line 171 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`

Check failure on line 171 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`
return new Promise((_resolve, reject) => {
setTimeout(() => {

Check failure on line 173 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'setTimeout' is not defined

Check failure on line 173 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'setTimeout' is not defined
reject(new Error('TypeA_isTypeOf_rejected'));
}, 10);
});
},
});

const TypeB = new GraphQLObjectType({
name: 'TypeB',
interfaces: [SearchableInterface],
fields: () => ({
id: { type: GraphQLString },
nameB: { type: GraphQLString },
}),
isTypeOf: (value: any, _context, _info) => {

Check failure on line 187 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`

Check failure on line 187 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`
return value.id === 'b';
},
});

const queryTypeWithSearchable = new GraphQLObjectType({
name: 'Query',
fields: {
person: {
type: PersonType,
resolve: () => john,
},
search: {
type: SearchableInterface,
args: { id: { type: GraphQLString } },
resolve: (_source, { id }) => {
/* c8 ignore start */
if (id === 'a') {
return { id: 'a', nameA: 'Object A' };
/* c8 ignore end */
} else if (id === 'b') {
return { id: 'b', nameB: 'Object B' };
}
},
},
},
});

const schemaWithSearchable = new GraphQLSchema({
query: queryTypeWithSearchable,
types: [
PetType,
TypeA,
TypeB,
SearchableInterface,
PersonType,
DogType,
CatType,
],
});

describe('Execute: Union and intersection types', () => {
it('can introspect on union and intersection types', () => {
const document = parse(`
Expand Down Expand Up @@ -545,4 +616,50 @@
expect(encounteredRootValue).to.equal(rootValue);
expect(encounteredContext).to.equal(contextValue);
});

it('handles promises from isTypeOf correctly when a later type matches synchronously', async () => {
const document = parse(`
query TestSearch {
search(id: "b") {
__typename
id
... on TypeA {
nameA
}
... on TypeB {
nameB
}
}
}
`);

let unhandledRejection: any = null;
/* c8 ignore start */
const unhandledRejectionListener = (reason: any) => {
unhandledRejection = reason;
};
process.on('unhandledRejection', unhandledRejectionListener);

Check failure on line 641 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'process' is not defined

Check failure on line 641 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'process' is not defined
/* c8 ignore end */

const result = await execute({
schema: schemaWithSearchable,
document,
});

expect(result.errors).to.be.undefined;

Check failure on line 649 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Expected an assignment or function call and instead saw an expression

Check failure on line 649 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Expected an assignment or function call and instead saw an expression
expect(result.data).to.deep.equal({
search: {
__typename: 'TypeB',
id: 'b',
nameB: 'Object B',
},
});

// Give the TypeA promise a chance to reject and the listener to fire
await new Promise((resolve) => setTimeout(resolve, 20));

Check failure on line 659 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'setTimeout' is not defined

Check failure on line 659 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'setTimeout' is not defined

process.removeListener('unhandledRejection', unhandledRejectionListener);

Check failure on line 661 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'process' is not defined

Check failure on line 661 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

'process' is not defined

expect(unhandledRejection).to.be.null;

Check failure on line 663 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Expected an assignment or function call and instead saw an expression

Check failure on line 663 in src/execution/__tests__/union-interface-test.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Expected an assignment or function call and instead saw an expression
});
});
3 changes: 3 additions & 0 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,9 @@
if (isPromise(isTypeOfResult)) {
promisedIsTypeOfResults[i] = isTypeOfResult;
} else if (isTypeOfResult) {
if (promisedIsTypeOfResults.length) {
Promise.allSettled(promisedIsTypeOfResults);

Check failure on line 1006 in src/execution/execute.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator

Check failure on line 1006 in src/execution/execute.ts

View workflow job for this annotation

GitHub Actions / ci / Lint source files

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}
return type.name;
}
}
Expand Down
Loading