@@ -143,7 +143,7 @@ const PetType = new GraphQLUnionType({
143143 if ( value instanceof Cat ) {
144144 return CatType . name ;
145145 }
146- /* c8 ignore next 3 */
146+
147147 // Not reachable, all possible types have been considered.
148148 expect . fail ( 'Not reachable' ) ;
149149 } ,
@@ -191,6 +191,70 @@ const john = new Person(
191191 [ garfield , fern ] ,
192192) ;
193193
194+ const SearchableInterface = new GraphQLInterfaceType ( {
195+ name : 'Searchable' ,
196+ fields : {
197+ id : { type : GraphQLString } ,
198+ } ,
199+ } ) ;
200+
201+ const TypeA = new GraphQLObjectType ( {
202+ name : 'TypeA' ,
203+ interfaces : [ SearchableInterface ] ,
204+ fields : ( ) => ( {
205+ id : { type : GraphQLString } ,
206+ nameA : { type : GraphQLString } ,
207+ } ) ,
208+ isTypeOf : ( _value , _context , _info ) =>
209+ new Promise ( ( _resolve , reject ) =>
210+ setTimeout ( ( ) => reject ( new Error ( 'TypeA_isTypeOf_rejected' ) ) , 10 ) ,
211+ ) ,
212+ } ) ;
213+
214+ const TypeB = new GraphQLObjectType ( {
215+ name : 'TypeB' ,
216+ interfaces : [ SearchableInterface ] ,
217+ fields : ( ) => ( {
218+ id : { type : GraphQLString } ,
219+ nameB : { type : GraphQLString } ,
220+ } ) ,
221+ isTypeOf : ( value : any , _context , _info ) => value . id === 'b' ,
222+ } ) ;
223+
224+ const queryTypeWithSearchable = new GraphQLObjectType ( {
225+ name : 'Query' ,
226+ fields : {
227+ person : {
228+ type : PersonType ,
229+ resolve : ( ) => john ,
230+ } ,
231+ search : {
232+ type : SearchableInterface ,
233+ args : { id : { type : GraphQLString } } ,
234+ resolve : ( _source , { id } ) => {
235+ if ( id === 'a' ) {
236+ return { id : 'a' , nameA : 'Object A' } ;
237+ } else if ( id === 'b' ) {
238+ return { id : 'b' , nameB : 'Object B' } ;
239+ }
240+ } ,
241+ } ,
242+ } ,
243+ } ) ;
244+
245+ const schemaWithSearchable = new GraphQLSchema ( {
246+ query : queryTypeWithSearchable ,
247+ types : [
248+ PetType ,
249+ TypeA ,
250+ TypeB ,
251+ SearchableInterface ,
252+ PersonType ,
253+ DogType ,
254+ CatType ,
255+ ] ,
256+ } ) ;
257+
194258describe ( 'Execute: Union and intersection types' , ( ) => {
195259 it ( 'can introspect on union and intersection types' , ( ) => {
196260 const document = parse ( `
@@ -633,4 +697,51 @@ describe('Execute: Union and intersection types', () => {
633697 } ,
634698 } ) ;
635699 } ) ;
700+
701+ it ( 'handles promises from isTypeOf correctly when a later type matches synchronously' , async ( ) => {
702+ const document = parse ( `
703+ query TestSearch {
704+ search(id: "b") {
705+ __typename
706+ id
707+ ... on TypeA {
708+ nameA
709+ }
710+ ... on TypeB {
711+ nameB
712+ }
713+ }
714+ }
715+ ` ) ;
716+
717+ let unhandledRejection : any = null ;
718+ const unhandledRejectionListener = ( reason : any ) => {
719+ unhandledRejection = reason ;
720+ } ;
721+ // eslint-disable-next-line
722+ process . on ( 'unhandledRejection' , unhandledRejectionListener ) ;
723+
724+ const result = await execute ( {
725+ schema : schemaWithSearchable ,
726+ document,
727+ } ) ;
728+
729+ expect ( result . errors ) . to . equal ( undefined ) ;
730+ expect ( result . data ) . to . deep . equal ( {
731+ search : {
732+ __typename : 'TypeB' ,
733+ id : 'b' ,
734+ nameB : 'Object B' ,
735+ } ,
736+ } ) ;
737+
738+ // Give the TypeA promise a chance to reject and the listener to fire
739+
740+ await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) ) ;
741+
742+ // eslint-disable-next-line
743+ process . removeListener ( 'unhandledRejection' , unhandledRejectionListener ) ;
744+
745+ expect ( unhandledRejection ) . to . equal ( null ) ;
746+ } ) ;
636747} ) ;
0 commit comments