@@ -12,7 +12,7 @@ import {
12
12
import { GraphQLBoolean , GraphQLString } from '../../type/scalars' ;
13
13
import { GraphQLSchema } from '../../type/schema' ;
14
14
15
- import { executeSync } from '../execute' ;
15
+ import { execute , executeSync } from '../execute' ;
16
16
17
17
class Dog {
18
18
name : string ;
@@ -118,7 +118,6 @@ const PetType = new GraphQLUnionType({
118
118
if ( value instanceof Cat ) {
119
119
return CatType . name ;
120
120
}
121
- /* c8 ignore next 3 */
122
121
// Not reachable, all possible types have been considered.
123
122
expect . fail ( 'Not reachable' ) ;
124
123
} ,
@@ -154,6 +153,71 @@ odie.mother.progeny = [odie];
154
153
const liz = new Person ( 'Liz' ) ;
155
154
const john = new Person ( 'John' , [ garfield , odie ] , [ liz , odie ] ) ;
156
155
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
+
157
221
describe ( 'Execute: Union and intersection types' , ( ) => {
158
222
it ( 'can introspect on union and intersection types' , ( ) => {
159
223
const document = parse ( `
@@ -545,4 +609,51 @@ describe('Execute: Union and intersection types', () => {
545
609
expect ( encounteredRootValue ) . to . equal ( rootValue ) ;
546
610
expect ( encounteredContext ) . to . equal ( contextValue ) ;
547
611
} ) ;
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
+ } ) ;
548
659
} ) ;
0 commit comments