@@ -4,6 +4,9 @@ import { describe, it } from 'mocha';
44import { expectJSON } from '../../__testUtils__/expectJSON' ;
55import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick' ;
66
7+ import { invariant } from '../../jsutils/invariant' ;
8+ import { isAsyncIterable } from '../../jsutils/isAsyncIterable' ;
9+
710import { parse } from '../../language/parser' ;
811
912import { GraphQLObjectType } from '../../type/definition' ;
@@ -50,6 +53,13 @@ class Root {
5053const numberHolderType = new GraphQLObjectType ( {
5154 fields : {
5255 theNumber : { type : GraphQLInt } ,
56+ promiseToGetTheNumber : {
57+ type : GraphQLInt ,
58+ resolve : async ( root ) => {
59+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
60+ return root . theNumber ;
61+ } ,
62+ } ,
5363 } ,
5464 name : 'NumberHolder' ,
5565} ) ;
@@ -191,4 +201,122 @@ describe('Execute: Handles mutation execution ordering', () => {
191201 ] ,
192202 } ) ;
193203 } ) ;
204+ it ( 'Mutation fields with @defer do not block next mutation' , async ( ) => {
205+ const document = parse ( `
206+ mutation M {
207+ first: promiseToChangeTheNumber(newNumber: 1) {
208+ ...DeferFragment @defer(label: "defer-label")
209+ },
210+ second: immediatelyChangeTheNumber(newNumber: 2) {
211+ theNumber
212+ }
213+ }
214+ fragment DeferFragment on NumberHolder {
215+ promiseToGetTheNumber
216+ }
217+ ` ) ;
218+
219+ const rootValue = new Root ( 6 ) ;
220+ const mutationResult = await execute ( {
221+ schema,
222+ document,
223+ rootValue,
224+ } ) ;
225+ const patches = [ ] ;
226+
227+ invariant ( isAsyncIterable ( mutationResult ) ) ;
228+ for await ( const patch of mutationResult ) {
229+ patches . push ( patch ) ;
230+ }
231+
232+ expect ( patches ) . to . deep . equal ( [
233+ {
234+ data : {
235+ first : { } ,
236+ second : { theNumber : 2 } ,
237+ } ,
238+ hasNext : true ,
239+ } ,
240+ {
241+ label : 'defer-label' ,
242+ path : [ 'first' ] ,
243+ data : {
244+ promiseToGetTheNumber : 2 ,
245+ } ,
246+ hasNext : false ,
247+ } ,
248+ ] ) ;
249+ } ) ;
250+ it ( 'Mutation inside of a fragment' , async ( ) => {
251+ const document = parse ( `
252+ mutation M {
253+ ...MutationFragment
254+ second: immediatelyChangeTheNumber(newNumber: 2) {
255+ theNumber
256+ }
257+ }
258+ fragment MutationFragment on Mutation {
259+ first: promiseToChangeTheNumber(newNumber: 1) {
260+ theNumber
261+ },
262+ }
263+ ` ) ;
264+
265+ const rootValue = new Root ( 6 ) ;
266+ const mutationResult = await execute ( { schema, document, rootValue } ) ;
267+
268+ expect ( mutationResult ) . to . deep . equal ( {
269+ data : {
270+ first : { theNumber : 1 } ,
271+ second : { theNumber : 2 } ,
272+ } ,
273+ } ) ;
274+ } ) ;
275+ it ( 'Mutation with @defer is not executed serially' , async ( ) => {
276+ const document = parse ( `
277+ mutation M {
278+ ...MutationFragment @defer(label: "defer-label")
279+ second: immediatelyChangeTheNumber(newNumber: 2) {
280+ theNumber
281+ }
282+ }
283+ fragment MutationFragment on Mutation {
284+ first: promiseToChangeTheNumber(newNumber: 1) {
285+ theNumber
286+ },
287+ }
288+ ` ) ;
289+
290+ const rootValue = new Root ( 6 ) ;
291+ const mutationResult = await execute ( {
292+ schema,
293+ document,
294+ rootValue,
295+ } ) ;
296+ const patches = [ ] ;
297+
298+ invariant ( isAsyncIterable ( mutationResult ) ) ;
299+ for await ( const patch of mutationResult ) {
300+ patches . push ( patch ) ;
301+ }
302+
303+ expect ( patches ) . to . deep . equal ( [
304+ {
305+ data : {
306+ second : { theNumber : 2 } ,
307+ } ,
308+ hasNext : true ,
309+ } ,
310+ {
311+ label : 'defer-label' ,
312+ path : [ ] ,
313+ data : {
314+ first : {
315+ theNumber : 1 ,
316+ } ,
317+ } ,
318+ hasNext : false ,
319+ } ,
320+ ] ) ;
321+ } ) ;
194322} ) ;
0 commit comments