Skip to content

Commit d8237f7

Browse files
committed
fix: improve handling of promises in defaultTypeResolver
1 parent 2fb0662 commit d8237f7

File tree

4 files changed

+105
-35
lines changed

4 files changed

+105
-35
lines changed

src/execution/__tests__/union-interface-test.ts

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { expect } from 'chai';
22
import { describe, it } from 'mocha';
33

4+
import { expectJSON } from '../../__testUtils__/expectJSON.js';
5+
46
import { parse } from '../../language/parser.js';
57

68
import {
@@ -12,7 +14,7 @@ import {
1214
import { GraphQLBoolean, GraphQLString } from '../../type/scalars.js';
1315
import { GraphQLSchema } from '../../type/schema.js';
1416

15-
import { executeSync } from '../execute.js';
17+
import { execute, executeSync } from '../execute.js';
1618

1719
class Dog {
1820
name: string;
@@ -42,19 +44,30 @@ class Cat {
4244
}
4345
}
4446

47+
class Plant {
48+
name: string;
49+
50+
constructor(name: string) {
51+
this.name = name;
52+
}
53+
}
54+
4555
class Person {
4656
name: string;
4757
pets: ReadonlyArray<Dog | Cat> | undefined;
4858
friends: ReadonlyArray<Dog | Cat | Person> | undefined;
59+
responsibilities: ReadonlyArray<Dog | Cat | Plant> | undefined;
4960

5061
constructor(
5162
name: string,
5263
pets?: ReadonlyArray<Dog | Cat>,
5364
friends?: ReadonlyArray<Dog | Cat | Person>,
65+
responsibilities?: ReadonlyArray<Dog | Cat | Plant>,
5466
) {
5567
this.name = name;
5668
this.pets = pets;
5769
this.friends = friends;
70+
this.responsibilities = responsibilities;
5871
}
5972
}
6073

@@ -108,6 +121,18 @@ const CatType: GraphQLObjectType = new GraphQLObjectType({
108121
isTypeOf: (value) => value instanceof Cat,
109122
});
110123

124+
const PlantType: GraphQLObjectType = new GraphQLObjectType({
125+
name: 'Plant',
126+
interfaces: [NamedType],
127+
fields: () => ({
128+
name: { type: GraphQLString },
129+
}),
130+
// eslint-disable-next-line @typescript-eslint/require-await
131+
isTypeOf: async () => {
132+
throw new Error('Not sure if this is a plant');
133+
},
134+
});
135+
111136
const PetType = new GraphQLUnionType({
112137
name: 'Pet',
113138
types: [DogType, CatType],
@@ -124,13 +149,19 @@ const PetType = new GraphQLUnionType({
124149
},
125150
});
126151

152+
const PetOrPlantType = new GraphQLUnionType({
153+
name: 'PetOrPlantType',
154+
types: [PlantType, DogType, CatType],
155+
});
156+
127157
const PersonType: GraphQLObjectType = new GraphQLObjectType({
128158
name: 'Person',
129159
interfaces: [NamedType, MammalType, LifeType],
130160
fields: () => ({
131161
name: { type: GraphQLString },
132162
pets: { type: new GraphQLList(PetType) },
133163
friends: { type: new GraphQLList(NamedType) },
164+
responsibilities: { type: new GraphQLList(PetOrPlantType) },
134165
progeny: { type: new GraphQLList(PersonType) },
135166
mother: { type: PersonType },
136167
father: { type: PersonType },
@@ -151,8 +182,14 @@ const odie = new Dog('Odie', true);
151182
odie.mother = new Dog("Odie's Mom", true);
152183
odie.mother.progeny = [odie];
153184

185+
const fern = new Plant('Fern');
154186
const liz = new Person('Liz');
155-
const john = new Person('John', [garfield, odie], [liz, odie]);
187+
const john = new Person(
188+
'John',
189+
[garfield, odie],
190+
[liz, odie],
191+
[garfield, fern],
192+
);
156193

157194
describe('Execute: Union and intersection types', () => {
158195
it('can introspect on union and intersection types', () => {
@@ -195,7 +232,12 @@ describe('Execute: Union and intersection types', () => {
195232
name: 'Named',
196233
fields: [{ name: 'name' }],
197234
interfaces: [],
198-
possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }, { name: 'Person' }],
235+
possibleTypes: [
236+
{ name: 'Dog' },
237+
{ name: 'Cat' },
238+
{ name: 'Person' },
239+
{ name: 'Plant' },
240+
],
199241
enumValues: null,
200242
inputFields: null,
201243
},
@@ -545,4 +587,56 @@ describe('Execute: Union and intersection types', () => {
545587
expect(encounteredRootValue).to.equal(rootValue);
546588
expect(encounteredContext).to.equal(contextValue);
547589
});
590+
591+
it('it rejects if isTypeOf check rejects in defaultResolveType', async () => {
592+
const document = parse(`
593+
{
594+
responsibilities {
595+
__typename
596+
... on Dog {
597+
name
598+
barks
599+
}
600+
... on Cat {
601+
name
602+
meows
603+
}
604+
}
605+
}
606+
`);
607+
608+
const rootValue = new Person('John', [], [liz], [garfield]);
609+
const contextValue = { authToken: '123abc' };
610+
611+
/* c8 ignore next 4 */
612+
// eslint-disable-next-line no-undef
613+
process.on('unhandledRejection', () => {
614+
expect.fail('Unhandled rejection');
615+
});
616+
617+
const result = await execute({
618+
schema,
619+
document,
620+
rootValue,
621+
contextValue,
622+
});
623+
624+
expectJSON(result).toDeepEqual({
625+
data: {
626+
responsibilities: [null],
627+
},
628+
errors: [
629+
{
630+
message: 'Not sure if this is a plant',
631+
locations: [
632+
{
633+
column: 9,
634+
line: 3,
635+
},
636+
],
637+
path: ['responsibilities', 0],
638+
},
639+
],
640+
});
641+
});
548642
});

src/execution/execute.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,12 @@ export const defaultTypeResolver: GraphQLTypeResolver<unknown, unknown> =
16181618
if (isPromise(isTypeOfResult)) {
16191619
promisedIsTypeOfResults[i] = isTypeOfResult;
16201620
} else if (isTypeOfResult) {
1621+
if (promisedIsTypeOfResults.length > 0) {
1622+
Promise.all(promisedIsTypeOfResults).then(undefined, () => {
1623+
/* ignore errors */
1624+
});
1625+
}
1626+
16211627
return type.name;
16221628
}
16231629
}

src/utilities/__tests__/printSchema-test.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -509,23 +509,6 @@ describe('Type System Printer', () => {
509509
`);
510510
});
511511

512-
it('Print Input Type with @oneOf directive', () => {
513-
const InputType = new GraphQLInputObjectType({
514-
name: 'InputType',
515-
isOneOf: true,
516-
fields: {
517-
int: { type: GraphQLInt },
518-
},
519-
});
520-
521-
const schema = new GraphQLSchema({ types: [InputType] });
522-
expectPrintedSchema(schema).to.equal(dedent`
523-
input InputType @oneOf {
524-
int: Int
525-
}
526-
`);
527-
});
528-
529512
it('Custom Scalar', () => {
530513
const OddType = new GraphQLScalarType({ name: 'Odd' });
531514

@@ -680,7 +663,7 @@ describe('Type System Printer', () => {
680663
schema {
681664
query: Query
682665
}
683-
666+
684667
""""""
685668
directive @someDirective(
686669
""""""

src/utilities/printSchema.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,7 @@ function printInputObject(type: GraphQLInputObjectType): string {
204204
const fields = Object.values(type.getFields()).map(
205205
(f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f),
206206
);
207-
return (
208-
printDescription(type) +
209-
`input ${type.name}` +
210-
printOneOf(type.isOneOf) +
211-
printBlock(fields)
212-
);
207+
return printDescription(type) + `input ${type.name}` + printBlock(fields);
213208
}
214209

215210
function printFields(type: GraphQLObjectType | GraphQLInterfaceType): string {
@@ -292,14 +287,6 @@ function printDeprecated(reason: Maybe<string>): string {
292287
return ' @deprecated';
293288
}
294289

295-
function printOneOf(isOneOf: boolean): string {
296-
if (!isOneOf) {
297-
return '';
298-
}
299-
300-
return ' @oneOf';
301-
}
302-
303290
function printSpecifiedByURL(scalar: GraphQLScalarType): string {
304291
if (scalar.specifiedByURL == null) {
305292
return '';

0 commit comments

Comments
 (0)