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