@@ -59,6 +59,13 @@ const TestComplexScalar = new GraphQLScalarType({
59
59
} ,
60
60
} ) ;
61
61
62
+ const NestedType : GraphQLObjectType = new GraphQLObjectType ( {
63
+ name : 'NestedType' ,
64
+ fields : {
65
+ echo : fieldWithInputArg ( { type : GraphQLString } ) ,
66
+ } ,
67
+ } ) ;
68
+
62
69
const TestInputObject = new GraphQLInputObjectType ( {
63
70
name : 'TestInputObject' ,
64
71
fields : {
@@ -129,6 +136,10 @@ const TestType = new GraphQLObjectType({
129
136
defaultValue : 'Hello World' ,
130
137
} ) ,
131
138
list : fieldWithInputArg ( { type : new GraphQLList ( GraphQLString ) } ) ,
139
+ nested : {
140
+ type : NestedType ,
141
+ resolve : ( ) => ( { } ) ,
142
+ } ,
132
143
nnList : fieldWithInputArg ( {
133
144
type : new GraphQLNonNull ( new GraphQLList ( GraphQLString ) ) ,
134
145
} ) ,
@@ -153,6 +164,14 @@ function executeQuery(
153
164
return executeSync ( { schema, document, variableValues } ) ;
154
165
}
155
166
167
+ function executeQueryWithFragmentArguments (
168
+ query : string ,
169
+ variableValues ?: { [ variable : string ] : unknown } ,
170
+ ) {
171
+ const document = parse ( query , { experimentalFragmentArguments : true } ) ;
172
+ return executeSync ( { schema, document, variableValues } ) ;
173
+ }
174
+
156
175
describe ( 'Execute: Handles inputs' , ( ) => {
157
176
describe ( 'Handles objects and nullability' , ( ) => {
158
177
describe ( 'using inline structs' , ( ) => {
@@ -1136,4 +1155,284 @@ describe('Execute: Handles inputs', () => {
1136
1155
} ) ;
1137
1156
} ) ;
1138
1157
} ) ;
1158
+
1159
+ describe ( 'using fragment arguments' , ( ) => {
1160
+ it ( 'when there are no fragment arguments' , ( ) => {
1161
+ const result = executeQueryWithFragmentArguments ( `
1162
+ query {
1163
+ ...a
1164
+ }
1165
+ fragment a on TestType {
1166
+ fieldWithNonNullableStringInput(input: "A")
1167
+ }
1168
+ ` ) ;
1169
+ expect ( result ) . to . deep . equal ( {
1170
+ data : {
1171
+ fieldWithNonNullableStringInput : '"A"' ,
1172
+ } ,
1173
+ } ) ;
1174
+ } ) ;
1175
+
1176
+ it ( 'when a value is required and provided' , ( ) => {
1177
+ const result = executeQueryWithFragmentArguments ( `
1178
+ query {
1179
+ ...a(value: "A")
1180
+ }
1181
+ fragment a($value: String!) on TestType {
1182
+ fieldWithNonNullableStringInput(input: $value)
1183
+ }
1184
+ ` ) ;
1185
+ expect ( result ) . to . deep . equal ( {
1186
+ data : {
1187
+ fieldWithNonNullableStringInput : '"A"' ,
1188
+ } ,
1189
+ } ) ;
1190
+ } ) ;
1191
+
1192
+ it ( 'when a value is required and not provided' , ( ) => {
1193
+ const result = executeQueryWithFragmentArguments ( `
1194
+ query {
1195
+ ...a
1196
+ }
1197
+ fragment a($value: String!) on TestType {
1198
+ fieldWithNullableStringInput(input: $value)
1199
+ }
1200
+ ` ) ;
1201
+
1202
+ expect ( result ) . to . have . property ( 'errors' ) ;
1203
+ expect ( result . errors ) . to . have . length ( 1 ) ;
1204
+ expect ( result . errors ?. at ( 0 ) ?. message ) . to . match (
1205
+ / A r g u m e n t " v a l u e " o f r e q u i r e d t y p e " S t r i n g ! " / ,
1206
+ ) ;
1207
+ } ) ;
1208
+
1209
+ it ( 'when the definition has a default and is provided' , ( ) => {
1210
+ const result = executeQueryWithFragmentArguments ( `
1211
+ query {
1212
+ ...a(value: "A")
1213
+ }
1214
+ fragment a($value: String! = "B") on TestType {
1215
+ fieldWithNonNullableStringInput(input: $value)
1216
+ }
1217
+ ` ) ;
1218
+ expect ( result ) . to . deep . equal ( {
1219
+ data : {
1220
+ fieldWithNonNullableStringInput : '"A"' ,
1221
+ } ,
1222
+ } ) ;
1223
+ } ) ;
1224
+
1225
+ it ( 'when the definition has a default and is not provided' , ( ) => {
1226
+ const result = executeQueryWithFragmentArguments ( `
1227
+ query {
1228
+ ...a
1229
+ }
1230
+ fragment a($value: String! = "B") on TestType {
1231
+ fieldWithNonNullableStringInput(input: $value)
1232
+ }
1233
+ ` ) ;
1234
+ expect ( result ) . to . deep . equal ( {
1235
+ data : {
1236
+ fieldWithNonNullableStringInput : '"B"' ,
1237
+ } ,
1238
+ } ) ;
1239
+ } ) ;
1240
+
1241
+ it ( 'when a definition has a default, is not provided, and spreads another fragment' , ( ) => {
1242
+ const result = executeQueryWithFragmentArguments ( `
1243
+ query {
1244
+ ...a
1245
+ }
1246
+ fragment a($a: String! = "B") on TestType {
1247
+ ...b(b: $a)
1248
+ }
1249
+ fragment b($b: String!) on TestType {
1250
+ fieldWithNonNullableStringInput(input: $b)
1251
+ }
1252
+ ` ) ;
1253
+ expect ( result ) . to . deep . equal ( {
1254
+ data : {
1255
+ fieldWithNonNullableStringInput : '"B"' ,
1256
+ } ,
1257
+ } ) ;
1258
+ } ) ;
1259
+
1260
+ it ( 'when the definition has a non-nullable default and is provided null' , ( ) => {
1261
+ const result = executeQueryWithFragmentArguments ( `
1262
+ query {
1263
+ ...a(value: null)
1264
+ }
1265
+ fragment a($value: String! = "B") on TestType {
1266
+ fieldWithNullableStringInput(input: $value)
1267
+ }
1268
+ ` ) ;
1269
+
1270
+ expect ( result ) . to . have . property ( 'errors' ) ;
1271
+ expect ( result . errors ) . to . have . length ( 1 ) ;
1272
+ expect ( result . errors ?. at ( 0 ) ?. message ) . to . match (
1273
+ / A r g u m e n t " v a l u e " o f n o n - n u l l t y p e " S t r i n g ! " / ,
1274
+ ) ;
1275
+ } ) ;
1276
+
1277
+ it ( 'when the definition has no default and is not provided' , ( ) => {
1278
+ const result = executeQueryWithFragmentArguments ( `
1279
+ query {
1280
+ ...a
1281
+ }
1282
+ fragment a($value: String) on TestType {
1283
+ fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $value)
1284
+ }
1285
+ ` ) ;
1286
+ expect ( result ) . to . deep . equal ( {
1287
+ data : {
1288
+ fieldWithNonNullableStringInputAndDefaultArgumentValue :
1289
+ '"Hello World"' ,
1290
+ } ,
1291
+ } ) ;
1292
+ } ) ;
1293
+
1294
+ it ( 'when an argument is shadowed by an operation variable' , ( ) => {
1295
+ const result = executeQueryWithFragmentArguments ( `
1296
+ query($x: String! = "A") {
1297
+ ...a(x: "B")
1298
+ }
1299
+ fragment a($x: String) on TestType {
1300
+ fieldWithNullableStringInput(input: $x)
1301
+ }
1302
+ ` ) ;
1303
+ expect ( result ) . to . deep . equal ( {
1304
+ data : {
1305
+ fieldWithNullableStringInput : '"B"' ,
1306
+ } ,
1307
+ } ) ;
1308
+ } ) ;
1309
+
1310
+ it ( 'when a nullable argument with a field default is not provided and shadowed by an operation variable' , ( ) => {
1311
+ const result = executeQueryWithFragmentArguments ( `
1312
+ query($x: String = "A") {
1313
+ ...a
1314
+ }
1315
+ fragment a($x: String) on TestType {
1316
+ fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $x)
1317
+ }
1318
+ ` ) ;
1319
+ expect ( result ) . to . deep . equal ( {
1320
+ data : {
1321
+ fieldWithNonNullableStringInputAndDefaultArgumentValue :
1322
+ '"Hello World"' ,
1323
+ } ,
1324
+ } ) ;
1325
+ } ) ;
1326
+
1327
+ it ( 'when a fragment-variable is shadowed by an intermediate fragment-spread but defined in the operation-variables' , ( ) => {
1328
+ const result = executeQueryWithFragmentArguments ( `
1329
+ query($x: String = "A") {
1330
+ ...a
1331
+ }
1332
+ fragment a($x: String) on TestType {
1333
+ ...b
1334
+ }
1335
+
1336
+ fragment b on TestType {
1337
+ fieldWithNullableStringInput(input: $x)
1338
+ }
1339
+ ` ) ;
1340
+ expect ( result ) . to . deep . equal ( {
1341
+ data : {
1342
+ fieldWithNullableStringInput : '"A"' ,
1343
+ } ,
1344
+ } ) ;
1345
+ } ) ;
1346
+
1347
+ it ( 'when a fragment is used with different args' , ( ) => {
1348
+ const result = executeQueryWithFragmentArguments ( `
1349
+ query($x: String = "Hello") {
1350
+ a: nested {
1351
+ ...a(x: "a")
1352
+ }
1353
+ b: nested {
1354
+ ...a(x: "b", b: true)
1355
+ }
1356
+ hello: nested {
1357
+ ...a(x: $x)
1358
+ }
1359
+ }
1360
+ fragment a($x: String, $b: Boolean = false) on NestedType {
1361
+ a: echo(input: $x) @skip(if: $b)
1362
+ b: echo(input: $x) @include(if: $b)
1363
+ }
1364
+ ` ) ;
1365
+ expect ( result ) . to . deep . equal ( {
1366
+ data : {
1367
+ a : {
1368
+ a : '"a"' ,
1369
+ } ,
1370
+ b : {
1371
+ b : '"b"' ,
1372
+ } ,
1373
+ hello : {
1374
+ a : '"Hello"' ,
1375
+ } ,
1376
+ } ,
1377
+ } ) ;
1378
+ } ) ;
1379
+
1380
+ it ( 'when the argument variable is nested in a complex type' , ( ) => {
1381
+ const result = executeQueryWithFragmentArguments ( `
1382
+ query {
1383
+ ...a(value: "C")
1384
+ }
1385
+ fragment a($value: String) on TestType {
1386
+ list(input: ["A", "B", $value, "D"])
1387
+ }
1388
+ ` ) ;
1389
+ expect ( result ) . to . deep . equal ( {
1390
+ data : {
1391
+ list : '["A", "B", "C", "D"]' ,
1392
+ } ,
1393
+ } ) ;
1394
+ } ) ;
1395
+
1396
+ it ( 'when argument variables are used recursively' , ( ) => {
1397
+ const result = executeQueryWithFragmentArguments ( `
1398
+ query {
1399
+ ...a(aValue: "C")
1400
+ }
1401
+ fragment a($aValue: String) on TestType {
1402
+ ...b(bValue: $aValue)
1403
+ }
1404
+ fragment b($bValue: String) on TestType {
1405
+ list(input: ["A", "B", $bValue, "D"])
1406
+ }
1407
+ ` ) ;
1408
+ expect ( result ) . to . deep . equal ( {
1409
+ data : {
1410
+ list : '["A", "B", "C", "D"]' ,
1411
+ } ,
1412
+ } ) ;
1413
+ } ) ;
1414
+
1415
+ it ( 'when argument passed in as list' , ( ) => {
1416
+ const result = executeQueryWithFragmentArguments ( `
1417
+ query Q($opValue: String = "op") {
1418
+ ...a(aValue: "A")
1419
+ }
1420
+ fragment a($aValue: String, $bValue: String) on TestType {
1421
+ ...b(aValue: [$aValue, "B"], bValue: [$bValue, $opValue])
1422
+ }
1423
+ fragment b($aValue: [String], $bValue: [String], $cValue: String) on TestType {
1424
+ aList: list(input: $aValue)
1425
+ bList: list(input: $bValue)
1426
+ cList: list(input: [$cValue])
1427
+ }
1428
+ ` ) ;
1429
+ expect ( result ) . to . deep . equal ( {
1430
+ data : {
1431
+ aList : '["A", "B"]' ,
1432
+ bList : '[null, "op"]' ,
1433
+ cList : '[null]' ,
1434
+ } ,
1435
+ } ) ;
1436
+ } ) ;
1437
+ } ) ;
1139
1438
} ) ;
0 commit comments