@@ -12,7 +12,7 @@ import {
1212import { GraphQLBoolean , GraphQLString } from '../../type/scalars' ;
1313import { GraphQLSchema } from '../../type/schema' ;
1414
15- import { executeSync } from '../execute' ;
15+ import { execute , executeSync } from '../execute' ;
1616
1717class Dog {
1818 name : string ;
@@ -118,7 +118,6 @@ const PetType = new GraphQLUnionType({
118118 if ( value instanceof Cat ) {
119119 return CatType . name ;
120120 }
121- /* c8 ignore next 3 */
122121 // Not reachable, all possible types have been considered.
123122 expect . fail ( 'Not reachable' ) ;
124123 } ,
@@ -154,6 +153,71 @@ odie.mother.progeny = [odie];
154153const liz = new Person ( 'Liz' ) ;
155154const john = new Person ( 'John' , [ garfield , odie ] , [ liz , odie ] ) ;
156155
156+ const SearchableInterface = new GraphQLInterfaceType ( {
157+ name : 'Searchable' ,
158+ fields : {
159+ id : { type : GraphQLString } ,
160+ } ,
161+ } ) ;
162+
163+ const TypeA = new GraphQLObjectType ( {
164+ name : 'TypeA' ,
165+ interfaces : [ SearchableInterface ] ,
166+ fields : ( ) => ( {
167+ id : { type : GraphQLString } ,
168+ nameA : { type : GraphQLString } ,
169+ } ) ,
170+ isTypeOf : ( _value , _context , _info ) =>
171+ new Promise ( ( _resolve , reject ) =>
172+ // eslint-disable-next-line
173+ setTimeout ( ( ) => reject ( new Error ( 'TypeA_isTypeOf_rejected' ) ) , 10 ) ,
174+ ) ,
175+ } ) ;
176+
177+ const TypeB = new GraphQLObjectType ( {
178+ name : 'TypeB' ,
179+ interfaces : [ SearchableInterface ] ,
180+ fields : ( ) => ( {
181+ id : { type : GraphQLString } ,
182+ nameB : { type : GraphQLString } ,
183+ } ) ,
184+ isTypeOf : ( value : any , _context , _info ) => value . id === 'b' ,
185+ } ) ;
186+
187+ const queryTypeWithSearchable = new GraphQLObjectType ( {
188+ name : 'Query' ,
189+ fields : {
190+ person : {
191+ type : PersonType ,
192+ resolve : ( ) => john ,
193+ } ,
194+ search : {
195+ type : SearchableInterface ,
196+ args : { id : { type : GraphQLString } } ,
197+ resolve : ( _source , { id } ) => {
198+ if ( id === 'a' ) {
199+ return { id : 'a' , nameA : 'Object A' } ;
200+ } else if ( id === 'b' ) {
201+ return { id : 'b' , nameB : 'Object B' } ;
202+ }
203+ } ,
204+ } ,
205+ } ,
206+ } ) ;
207+
208+ const schemaWithSearchable = new GraphQLSchema ( {
209+ query : queryTypeWithSearchable ,
210+ types : [
211+ PetType ,
212+ TypeA ,
213+ TypeB ,
214+ SearchableInterface ,
215+ PersonType ,
216+ DogType ,
217+ CatType ,
218+ ] ,
219+ } ) ;
220+
157221describe ( 'Execute: Union and intersection types' , ( ) => {
158222 it ( 'can introspect on union and intersection types' , ( ) => {
159223 const document = parse ( `
@@ -545,4 +609,51 @@ describe('Execute: Union and intersection types', () => {
545609 expect ( encounteredRootValue ) . to . equal ( rootValue ) ;
546610 expect ( encounteredContext ) . to . equal ( contextValue ) ;
547611 } ) ;
612+
613+ it ( 'handles promises from isTypeOf correctly when a later type matches synchronously' , async ( ) => {
614+ const document = parse ( `
615+ query TestSearch {
616+ search(id: "b") {
617+ __typename
618+ id
619+ ... on TypeA {
620+ nameA
621+ }
622+ ... on TypeB {
623+ nameB
624+ }
625+ }
626+ }
627+ ` ) ;
628+
629+ let unhandledRejection : any = null ;
630+ const unhandledRejectionListener = ( reason : any ) => {
631+ unhandledRejection = reason ;
632+ } ;
633+ // eslint-disable-next-line
634+ process . on ( 'unhandledRejection' , unhandledRejectionListener ) ;
635+
636+ const result = await execute ( {
637+ schema : schemaWithSearchable ,
638+ document,
639+ } ) ;
640+
641+ expect ( result . errors ) . to . equal ( undefined ) ;
642+ expect ( result . data ) . to . deep . equal ( {
643+ search : {
644+ __typename : 'TypeB' ,
645+ id : 'b' ,
646+ nameB : 'Object B' ,
647+ } ,
648+ } ) ;
649+
650+ // Give the TypeA promise a chance to reject and the listener to fire
651+ // eslint-disable-next-line
652+ await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) ) ;
653+
654+ // eslint-disable-next-line
655+ process . removeListener ( 'unhandledRejection' , unhandledRejectionListener ) ;
656+
657+ expect ( unhandledRejection ) . to . equal ( null ) ;
658+ } ) ;
548659} ) ;
0 commit comments