Skip to content

Commit 9898ff8

Browse files
committed
fix support for fragment argument
1 parent a10c859 commit 9898ff8

7 files changed

+718
-16
lines changed
Lines changed: 389 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,389 @@
1+
import { expect } from 'chai';
2+
import { parse, print } from 'graphql';
3+
import { describe, it } from 'mocha';
4+
5+
import { dedentString } from '../../__testUtils__/dedent.js';
6+
7+
import { interpolateFragmentArguments } from '../interpolateFragmentArguments.js';
8+
9+
function testInterpolation(source: string, expected: string): void {
10+
const originalDocument = parse(source, {
11+
experimentalFragmentArguments: true,
12+
});
13+
const transformedDocument = interpolateFragmentArguments(originalDocument);
14+
expect(print(transformedDocument)).to.equal(dedentString(expected));
15+
}
16+
17+
describe('interpolateFragmentArguments', () => {
18+
it('should interpolate arguments', () => {
19+
testInterpolation(
20+
`
21+
query TestQuery {
22+
...MyFragment(fragVar: "hello")
23+
}
24+
25+
fragment MyFragment($fragVar: String) on Query {
26+
field(arg1: $fragVar)
27+
}
28+
`,
29+
`
30+
query TestQuery {
31+
...MyFragment_interpolated_0
32+
}
33+
34+
fragment MyFragment_interpolated_0 on Query {
35+
field(arg1: "hello")
36+
}
37+
`,
38+
);
39+
});
40+
41+
it('should use default value if argument not provided for an explicitly called fragment', () => {
42+
testInterpolation(
43+
`
44+
query TestQuery {
45+
...MyFragment(fragVar1: "specific")
46+
}
47+
48+
fragment MyFragment($fragVar1: String, $fragVar2: String = "defaultVal") on Query {
49+
field(arg1: $fragVar1, arg2: $fragVar2)
50+
}
51+
`,
52+
`
53+
query TestQuery {
54+
...MyFragment_interpolated_0
55+
}
56+
57+
fragment MyFragment_interpolated_0 on Query {
58+
field(arg1: "specific", arg2: "defaultVal")
59+
}
60+
`,
61+
);
62+
});
63+
64+
it('should not use default value if explicit null provided', () => {
65+
testInterpolation(
66+
`
67+
query TestQuery {
68+
...MyFragment(fragVar1: "specific", fragVar2: null)
69+
}
70+
71+
fragment MyFragment($fragVar1: String, $fragVar2: String = "defaultVal") on Query {
72+
field(arg1: $fragVar1, arg2: $fragVar2)
73+
}
74+
`,
75+
`
76+
query TestQuery {
77+
...MyFragment_interpolated_0
78+
}
79+
80+
fragment MyFragment_interpolated_0 on Query {
81+
field(arg1: "specific", arg2: null)
82+
}
83+
`,
84+
);
85+
});
86+
87+
it('should generate unique names for multiple interpolations of the same fragment', () => {
88+
testInterpolation(
89+
`
90+
query TestQuery {
91+
...MyFragment(fragVar: "val1")
92+
...MyFragment(fragVar: "val2")
93+
...MyFragment(fragVar: "val1")
94+
}
95+
96+
fragment MyFragment($fragVar: String) on Query {
97+
field(arg: $fragVar)
98+
}
99+
`,
100+
`
101+
query TestQuery {
102+
...MyFragment_interpolated_0
103+
...MyFragment_interpolated_1
104+
...MyFragment_interpolated_0
105+
}
106+
107+
fragment MyFragment_interpolated_0 on Query {
108+
field(arg: "val1")
109+
}
110+
111+
fragment MyFragment_interpolated_1 on Query {
112+
field(arg: "val2")
113+
}
114+
`,
115+
);
116+
});
117+
118+
it('should preserve operation-level variables used in arguments', () => {
119+
testInterpolation(
120+
`
121+
query TestQuery($opVar: String) {
122+
...MyFragment(fragVar: $opVar)
123+
}
124+
125+
fragment MyFragment($fragVar: String) on Query {
126+
field(arg: $fragVar)
127+
}
128+
`,
129+
`
130+
query TestQuery($opVar: String) {
131+
...MyFragment_interpolated_0
132+
}
133+
134+
fragment MyFragment_interpolated_0 on Query {
135+
field(arg: $opVar)
136+
}
137+
`,
138+
);
139+
});
140+
141+
it('should interpolate a new missing operation variable for missing fragment variables (without defaults)', () => {
142+
testInterpolation(
143+
`
144+
query TestQuery($varWithoutDefault: String) {
145+
...MyFragment(varWithArg: "supplied")
146+
}
147+
148+
fragment MyFragment($varWithArg: String, $varWithoutDefault: String) on Query {
149+
field1(arg: $varWithArg)
150+
field2(arg: $varWithoutDefault)
151+
}
152+
`,
153+
`
154+
query TestQuery($varWithoutDefault: String, $missing_fragment_variable_varWithoutDefault_0: String) {
155+
...MyFragment_interpolated_0
156+
}
157+
158+
fragment MyFragment_interpolated_0 on Query {
159+
field1(arg: "supplied")
160+
field2(arg: $missing_fragment_variable_varWithoutDefault_0)
161+
}
162+
`,
163+
);
164+
});
165+
166+
it('should interpolate a new missing operation variable for nested missing fragment variables (without defaults)', () => {
167+
testInterpolation(
168+
`
169+
query TestQuery {
170+
...Outer
171+
}
172+
173+
fragment Outer($varWithoutDefault: String) on Query {
174+
...Inner
175+
}
176+
177+
fragment Inner($varWithoutDefault: String) on Query {
178+
field(arg: $varWithoutDefault)
179+
}
180+
`,
181+
`
182+
query TestQuery($missing_fragment_variable_varWithoutDefault_1: String) {
183+
...Outer_interpolated_0
184+
}
185+
186+
fragment Inner_interpolated_0 on Query {
187+
field(arg: $missing_fragment_variable_varWithoutDefault_1)
188+
}
189+
190+
fragment Outer_interpolated_0 on Query {
191+
...Inner_interpolated_0
192+
}
193+
`,
194+
);
195+
});
196+
197+
it('should use default for fragment vars even if there is an operation var with the same name', () => {
198+
testInterpolation(
199+
`
200+
query TestQuery($varWithDefaultOnFragment: String) {
201+
...MyFragment(varWithArg: "supplied")
202+
}
203+
204+
fragment MyFragment($varWithArg: String, $varWithDefaultOnFragment: String = "default") on Query {
205+
field1(arg: $varWithArg)
206+
field2(arg: $varWithDefaultOnFragment)
207+
}
208+
`,
209+
`
210+
query TestQuery($varWithDefaultOnFragment: String) {
211+
...MyFragment_interpolated_0
212+
}
213+
214+
fragment MyFragment_interpolated_0 on Query {
215+
field1(arg: "supplied")
216+
field2(arg: "default")
217+
}
218+
`,
219+
);
220+
});
221+
222+
it('should correctly handle nested fragments with arguments', () => {
223+
testInterpolation(
224+
`
225+
query TestQuery($opVar: String) {
226+
...OuterFragment(outerVar: "outerValue")
227+
}
228+
229+
fragment InnerFragment($innerVar: String) on Query {
230+
innerField(arg: $innerVar)
231+
}
232+
233+
fragment OuterFragment($outerVar: String) on Query {
234+
outerField(arg: $outerVar)
235+
...InnerFragment(innerVar: $outerVar)
236+
}
237+
`,
238+
`
239+
query TestQuery($opVar: String) {
240+
...OuterFragment_interpolated_0
241+
}
242+
243+
fragment InnerFragment_interpolated_0 on Query {
244+
innerField(arg: "outerValue")
245+
}
246+
247+
fragment OuterFragment_interpolated_0 on Query {
248+
outerField(arg: "outerValue")
249+
...InnerFragment_interpolated_0
250+
}
251+
`,
252+
);
253+
});
254+
255+
it('should handle fragment spreads with arguments that are lists or objects', () => {
256+
testInterpolation(
257+
`
258+
query TestQuery {
259+
...MyFragment(listArg: [1, 2], objArg: {a: "val", b: 3})
260+
}
261+
262+
fragment MyFragment($listArg: [Int], $objArg: MyInput) on Query {
263+
field(l: $listArg, o: $objArg)
264+
}
265+
`,
266+
`
267+
query TestQuery {
268+
...MyFragment_interpolated_0
269+
}
270+
271+
fragment MyFragment_interpolated_0 on Query {
272+
field(l: [1, 2], o: { a: "val", b: 3 })
273+
}
274+
`,
275+
);
276+
});
277+
278+
it('should handle nested fragment spreads with arguments that are lists or objects, some of which are not provided', () => {
279+
testInterpolation(
280+
`
281+
query Q($opValue: String = "op") {
282+
...a
283+
}
284+
285+
fragment a($aValue: String, $bValue: String) on TestType {
286+
...b(aValue: { a: $aValue, b: "B" }, bValue: [$bValue, $opValue])
287+
}
288+
289+
fragment b($aValue: MyInput, $bValue: [String], $cValue: String) on TestType {
290+
aList: list(input: $aValue)
291+
bList: list(input: $bValue)
292+
cList: list(input: [$cValue])
293+
}
294+
`,
295+
`
296+
query Q($opValue: String = "op", $missing_fragment_variable_aValue_0: String, $missing_fragment_variable_bValue_0: String, $missing_fragment_variable_cValue_0: String) {
297+
...a_interpolated_0
298+
}
299+
300+
fragment b_interpolated_0 on TestType {
301+
aList: list(input: { a: $missing_fragment_variable_aValue_0, b: "B" })
302+
bList: list(input: [$missing_fragment_variable_bValue_0, $opValue])
303+
cList: list(input: [$missing_fragment_variable_cValue_0])
304+
}
305+
306+
fragment a_interpolated_0 on TestType {
307+
...b_interpolated_0
308+
}
309+
`,
310+
);
311+
});
312+
313+
it('should terminate when hitting a fragment cycle', () => {
314+
testInterpolation(
315+
`
316+
{
317+
...A(arg: "arg")
318+
}
319+
320+
fragment A($arg: String) on Query {
321+
...B(arg: $arg)
322+
}
323+
324+
fragment B($arg: String) on Query {
325+
...C(arg: $arg)
326+
}
327+
328+
fragment C($arg: String) on Query {
329+
...A
330+
}
331+
`,
332+
`
333+
{
334+
...A_interpolated_0
335+
}
336+
337+
fragment C_interpolated_0 on Query {
338+
...A
339+
}
340+
341+
fragment B_interpolated_0 on Query {
342+
...C_interpolated_0
343+
}
344+
345+
fragment A_interpolated_0 on Query {
346+
...B_interpolated_0
347+
}
348+
`,
349+
);
350+
});
351+
352+
it('should ignore unknown fragment arguments', () => {
353+
testInterpolation(
354+
`
355+
{
356+
...MyFragment(knownArg: "known", unknownArg: "unknown")
357+
}
358+
359+
fragment MyFragment($knownArg: String) on Query {
360+
field(arg: $knownArg)
361+
}
362+
`,
363+
`
364+
{
365+
...MyFragment_interpolated_0
366+
}
367+
368+
fragment MyFragment_interpolated_0 on Query {
369+
field(arg: "known")
370+
}
371+
`,
372+
);
373+
});
374+
375+
it('should ignore unknown fragments', () => {
376+
testInterpolation(
377+
`
378+
{
379+
...MyUnknownFragment(unknownArg: "unknown")
380+
}
381+
`,
382+
`
383+
{
384+
...MyUnknownFragment
385+
}
386+
`,
387+
);
388+
});
389+
});

0 commit comments

Comments
 (0)