Skip to content

Commit

Permalink
fix: improve handling of promises in defaultTypeResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
hayes authored and hayes-mysten committed Aug 7, 2024
1 parent 02ee34f commit 3c32518
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 3 deletions.
94 changes: 91 additions & 3 deletions src/execution/__tests__/union-interface-test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';

import { expectJSON } from '../../__testUtils__/expectJSON.js';

import { parse } from '../../language/parser.js';

import {
Expand All @@ -12,7 +14,7 @@ import {
import { GraphQLBoolean, GraphQLString } from '../../type/scalars.js';
import { GraphQLSchema } from '../../type/schema.js';

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

class Dog {
name: string;
Expand Down Expand Up @@ -42,19 +44,30 @@ class Cat {
}
}

class Plant {
name: string;

constructor(name: string) {
this.name = name;
}
}

class Person {
name: string;
pets: ReadonlyArray<Dog | Cat> | undefined;
friends: ReadonlyArray<Dog | Cat | Person> | undefined;
responsibilities: ReadonlyArray<Dog | Cat | Plant> | undefined;

constructor(
name: string,
pets?: ReadonlyArray<Dog | Cat>,
friends?: ReadonlyArray<Dog | Cat | Person>,
responsibilities?: ReadonlyArray<Dog | Cat | Plant>,
) {
this.name = name;
this.pets = pets;
this.friends = friends;
this.responsibilities = responsibilities;
}
}

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

const PlantType: GraphQLObjectType = new GraphQLObjectType({
name: 'Plant',
interfaces: [NamedType],
fields: () => ({
name: { type: GraphQLString },
}),
// eslint-disable-next-line @typescript-eslint/require-await
isTypeOf: async () => {
throw new Error('Not sure if this is a plant');
},
});

const PetType = new GraphQLUnionType({
name: 'Pet',
types: [DogType, CatType],
Expand All @@ -124,13 +149,19 @@ const PetType = new GraphQLUnionType({
},
});

const PetOrPlantType = new GraphQLUnionType({
name: 'PetOrPlantType',
types: [PlantType, DogType, CatType],
});

const PersonType: GraphQLObjectType = new GraphQLObjectType({
name: 'Person',
interfaces: [NamedType, MammalType, LifeType],
fields: () => ({
name: { type: GraphQLString },
pets: { type: new GraphQLList(PetType) },
friends: { type: new GraphQLList(NamedType) },
responsibilities: { type: new GraphQLList(PetOrPlantType) },
progeny: { type: new GraphQLList(PersonType) },
mother: { type: PersonType },
father: { type: PersonType },
Expand All @@ -151,8 +182,14 @@ const odie = new Dog('Odie', true);
odie.mother = new Dog("Odie's Mom", true);
odie.mother.progeny = [odie];

const fern = new Plant('Fern');
const liz = new Person('Liz');
const john = new Person('John', [garfield, odie], [liz, odie]);
const john = new Person(
'John',
[garfield, odie],
[liz, odie],
[garfield, fern],
);

describe('Execute: Union and intersection types', () => {
it('can introspect on union and intersection types', () => {
Expand Down Expand Up @@ -195,7 +232,12 @@ describe('Execute: Union and intersection types', () => {
name: 'Named',
fields: [{ name: 'name' }],
interfaces: [],
possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }, { name: 'Person' }],
possibleTypes: [
{ name: 'Dog' },
{ name: 'Cat' },
{ name: 'Person' },
{ name: 'Plant' },
],
enumValues: null,
inputFields: null,
},
Expand Down Expand Up @@ -545,4 +587,50 @@ describe('Execute: Union and intersection types', () => {
expect(encounteredRootValue).to.equal(rootValue);
expect(encounteredContext).to.equal(contextValue);
});

it('it handles rejections from isTypeOf after after an isTypeOf returns true', async () => {
const document = parse(`
{
responsibilities {
__typename
... on Dog {
name
barks
}
... on Cat {
name
meows
}
}
}
`);

const rootValue = new Person('John', [], [liz], [garfield]);
const contextValue = { authToken: '123abc' };

/* c8 ignore next 4 */
// eslint-disable-next-line no-undef
process.on('unhandledRejection', () => {
expect.fail('Unhandled rejection');
});

const result = await execute({
schema,
document,
rootValue,
contextValue,
});

expectJSON(result).toDeepEqual({
data: {
responsibilities: [
{
__typename: 'Cat',
meows: false,
name: 'Garfield',
},
],
},
});
});
});
6 changes: 6 additions & 0 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,12 @@ export const defaultTypeResolver: GraphQLTypeResolver<unknown, unknown> =
if (isPromise(isTypeOfResult)) {
promisedIsTypeOfResults[i] = isTypeOfResult;
} else if (isTypeOfResult) {
if (promisedIsTypeOfResults.length > 0) {
Promise.all(promisedIsTypeOfResults).then(undefined, () => {
/* ignore errors */
});
}

return type.name;
}
}
Expand Down

0 comments on commit 3c32518

Please sign in to comment.