@@ -143,7 +143,7 @@ const PetType = new GraphQLUnionType({
143
143
if ( value instanceof Cat ) {
144
144
return CatType . name ;
145
145
}
146
- /* c8 ignore next 3 */
146
+
147
147
// Not reachable, all possible types have been considered.
148
148
expect . fail ( 'Not reachable' ) ;
149
149
} ,
@@ -191,6 +191,70 @@ const john = new Person(
191
191
[ garfield , fern ] ,
192
192
) ;
193
193
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
+
194
258
describe ( 'Execute: Union and intersection types' , ( ) => {
195
259
it ( 'can introspect on union and intersection types' , ( ) => {
196
260
const document = parse ( `
@@ -633,4 +697,51 @@ describe('Execute: Union and intersection types', () => {
633
697
} ,
634
698
} ) ;
635
699
} ) ;
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
+ } ) ;
636
747
} ) ;
0 commit comments