Skip to content

Commit c3e5513

Browse files
authored
fix: DeferStreamDirectiveOnValidOperations fragment tracking (#4762)
Tracks all fragment spreads back to root usage also properly handles skip/include on fragments
1 parent 3aad6a3 commit c3e5513

2 files changed

Lines changed: 435 additions & 40 deletions

File tree

src/validation/__tests__/DeferStreamDirectiveOnValidOperationsRule-test.ts

Lines changed: 258 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,228 @@ describe('Validate: Defer/Stream directive on valid operations', () => {
201201
},
202202
]);
203203
});
204+
it('Defer fragment spread with @skip directive', () => {
205+
expectValid(`
206+
subscription MySubscription {
207+
subscriptionField {
208+
...myFragment @skip @defer
209+
}
210+
}
211+
fragment myFragment on Message {
212+
body
213+
}
214+
`);
215+
});
216+
it('Defer fragment spread with @skip(if: true) directive', () => {
217+
expectValid(`
218+
subscription MySubscription {
219+
subscriptionField {
220+
...myFragment @skip(if: true) @defer
221+
}
222+
}
223+
fragment myFragment on Message {
224+
body
225+
}
226+
`);
227+
});
228+
it('Defer fragment spread with @skip(if: false) directive', () => {
229+
expectErrors(`
230+
subscription MySubscription {
231+
subscriptionField {
232+
...myFragment @skip(if: false) @defer
233+
}
234+
}
235+
fragment myFragment on Message {
236+
body
237+
}
238+
`).toDeepEqual([
239+
{
240+
locations: [{ column: 42, line: 4 }],
241+
message:
242+
'Defer directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
243+
},
244+
]);
245+
});
246+
it('Defer in fragment spread nested under @skip(if: true) directive', () => {
247+
expectValid(`
248+
subscription MySubscription {
249+
subscriptionField {
250+
...outerFragment @skip(if: true)
251+
}
252+
}
253+
fragment outerFragment on Message {
254+
...myFragment @defer
255+
}
256+
fragment myFragment on Message {
257+
body
258+
}
259+
`);
260+
});
261+
it('Defer in fragment spread nested under @skip(if: false) directive', () => {
262+
expectErrors(`
263+
subscription MySubscription {
264+
subscriptionField {
265+
...outerFragment @skip(if: false)
266+
}
267+
}
268+
fragment outerFragment on Message {
269+
...myFragment @defer
270+
}
271+
fragment myFragment on Message {
272+
body
273+
}
274+
`).toDeepEqual([
275+
{
276+
locations: [
277+
{ column: 23, line: 8 },
278+
{ column: 11, line: 4 },
279+
],
280+
message:
281+
'Defer directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
282+
},
283+
]);
284+
});
285+
it('Defer in fragment spread nested under @skip(if: $variable) directive', () => {
286+
expectValid(`
287+
subscription MySubscription($variable: Boolean) {
288+
subscriptionField {
289+
...outerFragment @skip(if: $variable)
290+
}
291+
}
292+
fragment outerFragment on Message {
293+
...myFragment @defer
294+
}
295+
fragment myFragment on Message {
296+
body
297+
}
298+
`);
299+
});
300+
it('Defer fragment spread with @skip(if: $variable) directive', () => {
301+
expectValid(`
302+
subscription MySubscription($variable: Boolean) {
303+
subscriptionField {
304+
...myFragment @skip(if: $variable) @defer
305+
}
306+
}
307+
fragment myFragment on Message {
308+
body
309+
}
310+
`);
311+
});
312+
it('Defer fragment spread with @include directive', () => {
313+
expectErrors(`
314+
subscription MySubscription {
315+
subscriptionField {
316+
...myFragment @include @defer
317+
}
318+
}
319+
fragment myFragment on Message {
320+
body
321+
}
322+
`).toDeepEqual([
323+
{
324+
locations: [{ column: 34, line: 4 }],
325+
message:
326+
'Defer directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
327+
},
328+
]);
329+
});
330+
it('Defer fragment spread with @include(if: true) directive', () => {
331+
expectErrors(`
332+
subscription MySubscription {
333+
subscriptionField {
334+
...myFragment @include(if: true) @defer
335+
}
336+
}
337+
fragment myFragment on Message {
338+
body
339+
}
340+
`).toDeepEqual([
341+
{
342+
locations: [{ column: 44, line: 4 }],
343+
message:
344+
'Defer directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
345+
},
346+
]);
347+
});
348+
it('Defer fragment spread with @include(if: false) directive', () => {
349+
expectValid(`
350+
subscription MySubscription {
351+
subscriptionField {
352+
...myFragment @include(if: false) @defer
353+
}
354+
}
355+
fragment myFragment on Message {
356+
body
357+
}
358+
`);
359+
});
360+
it('Defer in fragment spread nested under @include(if: true) directive', () => {
361+
expectErrors(`
362+
subscription MySubscription {
363+
subscriptionField {
364+
...outerFragment @include(if: true)
365+
}
366+
}
367+
fragment outerFragment on Message {
368+
...myFragment @defer
369+
}
370+
fragment myFragment on Message {
371+
body
372+
}
373+
`).toDeepEqual([
374+
{
375+
locations: [
376+
{ column: 23, line: 8 },
377+
{ column: 11, line: 4 },
378+
],
379+
message:
380+
'Defer directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.',
381+
},
382+
]);
383+
});
384+
it('Defer in fragment spread nested under @include(if: false) directive', () => {
385+
expectValid(`
386+
subscription MySubscription {
387+
subscriptionField {
388+
...outerFragment @include(if: false)
389+
}
390+
}
391+
fragment outerFragment on Message {
392+
...myFragment @defer
393+
}
394+
fragment myFragment on Message {
395+
body
396+
}
397+
`);
398+
});
399+
it('Defer in fragment spread nested under @include(if: $variable) directive', () => {
400+
expectValid(`
401+
subscription MySubscription($variable: Boolean) {
402+
subscriptionField {
403+
...outerFragment @include(if: $variable)
404+
}
405+
}
406+
fragment outerFragment on Message {
407+
...myFragment @defer
408+
}
409+
fragment myFragment on Message {
410+
body
411+
}
412+
`);
413+
});
414+
it('Defer fragment spread with @include(if: $variable) directive', () => {
415+
expectValid(`
416+
subscription MySubscription ($variable: Boolean) {
417+
subscriptionField {
418+
...myFragment @include(if: $variable) @defer
419+
}
420+
}
421+
fragment myFragment on Message {
422+
body
423+
}
424+
`);
425+
});
204426
it('Stream on query field', () => {
205427
expectValid(`
206428
{
@@ -260,7 +482,10 @@ describe('Validate: Defer/Stream directive on valid operations', () => {
260482
{
261483
message:
262484
'Stream directive not supported on subscription operations. Disable `@stream` by setting the `if` argument to `false`.',
263-
locations: [{ line: 8, column: 18 }],
485+
locations: [
486+
{ line: 8, column: 18 },
487+
{ line: 4, column: 11 },
488+
],
264489
},
265490
]);
266491
});
@@ -302,7 +527,38 @@ describe('Validate: Defer/Stream directive on valid operations', () => {
302527
{
303528
message:
304529
'Stream directive not supported on subscription operations. Disable `@stream` by setting the `if` argument to `false`.',
305-
locations: [{ line: 15, column: 18 }],
530+
locations: [
531+
{ line: 15, column: 18 },
532+
{ line: 10, column: 13 },
533+
],
534+
},
535+
]);
536+
});
537+
it('Stream on subscription in document with fragment used multiple times', () => {
538+
expectErrors(`
539+
subscription MySubscription {
540+
subscriptionField {
541+
message {
542+
...myOtherFragment
543+
...myFragment # not visited twice
544+
}
545+
}
546+
}
547+
fragment myOtherFragment on Message {
548+
...myFragment
549+
}
550+
fragment myFragment on Message {
551+
messages @stream
552+
}
553+
`).toDeepEqual([
554+
{
555+
message:
556+
'Stream directive not supported on subscription operations. Disable `@stream` by setting the `if` argument to `false`.',
557+
locations: [
558+
{ line: 14, column: 18 },
559+
{ line: 11, column: 9 },
560+
{ line: 5, column: 13 },
561+
],
306562
},
307563
]);
308564
});

0 commit comments

Comments
 (0)